Disposable Docker images that run Claude Code autonomously to upgrade any stack. Point it at a repo, tell it the target version, and it produces an upgrade branch with one commit per phase.
Currently supports: Laravel. Coming soon: React, Rails, Django.
Multi-arch: linux/amd64 and linux/arm64 — runs on any major cloud/k8s provider.
npx @reyemtech/stack-upgradeThe CLI auto-detects your repos, Claude credentials, and runtime (Docker or Kubernetes). It supports queuing multiple upgrades to run in parallel.
- Docker or kubectl in PATH
- GitHub CLI (
gh) authenticated — for repo discovery and PR creation - Claude credentials — Claude Max token or Anthropic API key
- Deploy key — repo-scoped SSH key (only needed for manual Docker usage)
| Stack | Image | Status |
|---|---|---|
| Laravel | ghcr.io/reyemtech/laravel-upgrade-agent |
Available |
| React | — | Planned |
| Rails | — | Planned |
| Django | — | Planned |
- Clones your repo, creates an
upgrade/{stack}-{version}branch - Installs dependencies, runs baseline verification
- Runs recon — analyzes package usage, component counts, test suite shape
- Fetches the official upgrade guide for the target version
- Launches Claude Code inside a restart loop ("Ralph loop")
- Claude works through upgrade phases, committing after each
- Captures before/after dependency snapshots for review
- Pushes the branch (optionally creates a PR with a generated changelog)
- Writes structured results to
/output
| Phase | What it does |
|---|---|
| 1. Core Framework | laravel/framework to target version, fix breaking changes |
| 2. First-Party Packages | Horizon, Telescope, Sanctum, Breeze, Pennant, etc. |
| 3. Filament + Livewire | Major version bumps (Filament v4/v5, Flux) |
| 4. Third-Party Composer | Remaining Composer packages |
| 5. NPM + Frontend | Tailwind v4, Vite, build tooling |
| 6. Config Drift | Reconcile config files against latest Laravel stubs |
| 7. PHP Version | Bump PHP constraint to latest compatible version |
Unused packages are removed instead of upgraded. Each phase runs verification before committing.
You need one of:
Generate a token with claude setup-token, then pass CLAUDE_CODE_OAUTH_TOKEN.
Pass ANTHROPIC_API_KEY from console.anthropic.com.
The CLI auto-detects credentials from ~/.claude/.credentials.json, env vars, or saved config at ~/.stack-upgrade/config.json.
Config is persisted to ~/.stack-upgrade/config.json:
- Claude credentials (OAuth token or API key)
- GitHub token
- Preferred run target (Docker or Kubernetes)
docker run --rm \
-e REPO_URL=git@github.com:your-org/your-app.git \
-e TARGET_LARAVEL=12 \
-e CLAUDE_CODE_OAUTH_TOKEN=$CLAUDE_CODE_OAUTH_TOKEN \
-e GIT_SSH_KEY_B64=$(base64 < ~/.ssh/deploy_key) \
-v ./output:/output \
ghcr.io/reyemtech/laravel-upgrade-agent:latestdocker run --rm \
-e REPO_URL=git@github.com:your-org/your-app.git \
-e TARGET_LARAVEL=12 \
-e GH_TOKEN=$GH_TOKEN \
-e CLAUDE_CODE_OAUTH_TOKEN=$CLAUDE_CODE_OAUTH_TOKEN \
-e GIT_SSH_KEY_B64=$(base64 < ~/.ssh/deploy_key) \
-v ./output:/output \
ghcr.io/reyemtech/laravel-upgrade-agent:latestdocker run --rm \
-e REPO_URL=git@github.com:your-org/your-app.git \
-e TARGET_LARAVEL=12 \
-e BRANCH_SUFFIX=$(date +%Y-%m-%d) \
-e CLAUDE_CODE_OAUTH_TOKEN=$CLAUDE_CODE_OAUTH_TOKEN \
-e GIT_SSH_KEY_B64=$(base64 < ~/.ssh/deploy_key) \
-v ./output:/output \
ghcr.io/reyemtech/laravel-upgrade-agent:latestapiVersion: batch/v1
kind: Job
metadata:
name: laravel-upgrade
spec:
template:
spec:
containers:
- name: upgrade-agent
image: ghcr.io/reyemtech/laravel-upgrade-agent:latest
env:
- name: REPO_URL
value: "git@github.com:your-org/your-app.git"
- name: TARGET_LARAVEL
value: "12"
- name: CLAUDE_CODE_OAUTH_TOKEN
valueFrom:
secretKeyRef:
name: upgrade-agent-secrets
key: claude-token
- name: GIT_SSH_KEY_B64
valueFrom:
secretKeyRef:
name: upgrade-agent-secrets
key: deploy-key-b64
- name: GH_TOKEN
valueFrom:
secretKeyRef:
name: upgrade-agent-secrets
key: gh-token
volumeMounts:
- name: output
mountPath: /output
volumes:
- name: output
emptyDir: {}
restartPolicy: Never
backoffLimit: 0| Variable | Required | Default | Description |
|---|---|---|---|
REPO_URL |
Yes | — | Git clone URL (SSH) |
TARGET_LARAVEL |
Yes | — | Target major version (e.g., 12, 13) |
CLAUDE_CODE_OAUTH_TOKEN |
One of | — | Claude Max token |
ANTHROPIC_API_KEY |
One of | — | Anthropic API key |
GIT_SSH_KEY_B64 |
Yes | — | Base64-encoded deploy key |
GIT_PUSH |
No | true |
Push branch on completion |
GH_TOKEN |
No | — | GitHub token — creates a PR with changelog as body |
BRANCH_SUFFIX |
No | — | Append to branch name (e.g., 2026-02-26 -> upgrade/laravel-12-2026-02-26) |
MAX_RESTARTS |
No | 5 |
Max Claude Code restart attempts |
MAX_TURNS |
No | 200 |
Max agentic turns per Claude Code session |
After a run, the /output volume contains:
| File | Description |
|---|---|
result.json |
Structured outcome — success or incomplete, phase counts, elapsed time |
status.json |
Last status update (poll this for monitoring) |
changelog.md |
Agent-maintained changelog (also used as PR body) |
before-composer.json / after-composer.json |
Pre/post Composer packages |
before-npm.json / after-npm.json |
Pre/post NPM packages |
before-versions.txt / after-versions.txt |
Pre/post Laravel/PHP versions |
run-log.md |
Agent decision log |
checklist.yaml |
Final phase statuses |
commits.log |
Git log of the upgrade branch |
- Recon before action —
recon.shmaps the repo (package usage, component counts, test shape) so the agent can plan ahead - Three-file memory —
plan.md,checklist.yaml, andrun-log.mdsurvive context compaction and restarts - Ralph loop — if Claude Code exits before the checklist is complete, it restarts with full context (up to
MAX_RESTARTStimes) - Loop breaker — after 3 failed attempts on the same error, the agent logs the failure, marks the phase as
failed, and moves on - Verification gates — fast verification after every change, full verification before each phase commit
- No CLAUDE.md overwrite — upgrade instructions go to
.upgrade/AGENT.md; your project's ownCLAUDE.mdis preserved
- Create
stacks/{name}/withDockerfile,entrypoint.sh,templates/, andscripts/ - Add the stack to
cli/src/stacks.jswith detection logic, image name, and env key - Add the stack to the
matrix.stackarray in.github/workflows/release.yml
- Use a repo-scoped deploy key, not your personal SSH key
- API keys/tokens are passed as env vars, never baked into the image
- Container is ephemeral — destroyed after run
- Review the upgrade branch before merging
Business Source License 1.1 — You may use this software for any purpose except providing a commercial hosted service that runs it on behalf of third parties. Each release converts to Apache 2.0 four years after its release date.