Skip to content

Deployment automation with Claude Code

Deployment automation with Claude Code means the agent writes and runs the repeatable parts of a release: pre-deploy gates, migration safety reviews, paired deploy and rollback scripts, and release notes. Production credentials stay with CI or a human. Each output is proven by exit codes, a staging deploy, a smoke test, and a rehearsed rollback rather than by line-by-line reading.

This guide is for developers and tech leads who own a service’s release. You have 47 commits to ship, three of them touch the schema, production needs a different image tag and three environment variables nobody remembers, and last time the migration ran after the new code started, so users saw 500 errors until someone rolled back by hand. The steps below turn that checklist into scripts that Claude Code writes and your pipeline enforces. They assume you already run claude -p in scripts; if not, start with scripting Claude Code: headless runs, pipes, cron and Git hooks.

  • A CLAUDE.md deployment standard and a permissions block that keeps production out of the agent’s reach
  • A deploy-check.sh gate that runs your deterministic checks in shell and asks claude -p only the judgment questions, ending in a machine-readable GO or NO-GO
  • Copy-paste prompts for a migration safety review, a deploy and rollback script pair, a blue-green switch with a metric-gated rollback, and an incident rollback plan
  • A /release-notes skill that turns git history into a changelog entry anyone on the team can run
  • A verification routine (dry run, staging, smoke test, rollback rehearsal) that tells you the scripts work without reading every line

Where does Claude Code fit in a release, and where does it stop?

Section titled “Where does Claude Code fit in a release, and where does it stop?”

Claude Code is strong at the parts of a release that are text: scripts, reviews of a diff, and prose summaries of history. It should not be the thing that holds production credentials or presses the button. Deployment belongs to your CI pipeline, which runs the scripts Claude wrote after a person approves.

Release stepWhat Claude Code producesHow you prove it without reading every lineWho signs off
Pre-deploy gatedeploy-check.sh and a GO/NO-GO verdict on the diffExit codes of type check, lint, tests and build; the verdict file attached to the releaseThe developer cutting the release
Migration reviewA per-migration compatibility reportup, down, up against a copy of production data on stagingMigration author plus one reviewer
Deploy and rollback scriptsdeploy.sh and rollback.sh as a pairshellcheck, a DRY_RUN=1 run, a staging deploy, a rehearsed rollbackTech lead, once per script change
RolloutA blue-green or canary switch with a metric thresholdA deliberately broken image on staging that triggers the automatic switch backTech lead approves the production environment in CI
Release notesA changelog entry and release notesEvery line traces to a commit or PR numberRelease owner
Incident rollbackA rollback plan and the exact commandsRecovery visible on the dashboards named in the planOn-call engineer runs the commands

Two neighbouring jobs have their own pages. To generate and harden the pipeline itself, see pipeline configuration with Claude Code. For Dockerfiles and Kubernetes manifests, see Docker and Kubernetes setup via CLI. Using Codex instead? See deployment automation with Codex. For the tool-neutral version of this stage, see the deploy stage of the method.

Write your deployment rules into CLAUDE.md first

Section titled “Write your deployment rules into CLAUDE.md first”

Every deployment prompt on this page gets shorter and safer once the rules live in the project’s CLAUDE.md. Claude Code loads the file at the start of every session, so a new engineer asking for “a deploy script for the payments service” gets the same constraints as the person who wrote them.

## Deployment rules
- Deploys run only from CI (.github/workflows/deploy.yml). Never run a deploy or rollback against production from a local session.
- Every deploy script has a matching rollback script, and deploy.sh records the running image tag before it changes anything.
- Scripts start with `set -euo pipefail` and support DRY_RUN=1, which prints every command instead of running it.
- Image tags are the git SHA. Never deploy `latest` to production.
- Migrations are expand/contract: add columns and tables in one release, remove them in a later one. The migration runs before the new code starts.
- Every new environment variable is added to .env.example in the same commit.
- Secrets come from the environment or the secret store, never from a file in the repository.

Back the rules with deny rules in .claude/settings.json, so the agent is stopped even when a prompt asks for the forbidden step:

{
"permissions": {
"deny": [
"Bash(./scripts/deploy.sh prod*)",
"Bash(./scripts/rollback.sh prod*)",
"Bash(kubectl *)",
"Bash(terraform apply *)",
"Read(./.env.production)"
]
}
}

The common mistake is to ask Claude to “run the tests and report PASS or FAIL”. The model’s report is then the only evidence, and a model can summarise a red run as green. Split the work instead. Shell runs the deterministic gates, where the exit code decides. Claude answers only the questions that need judgment, such as whether a migration is safe for a rolling update.

Four details make this gate trustworthy:

  • It fails closed. If the budget runs out, the model formats the verdict differently, or the run errors, grep -qx finds no exact VERDICT: GO line and the script exits non-zero. A missing verdict is a NO-GO.
  • The agent cannot change anything. --permission-mode dontAsk denies every tool that the --allowedTools list does not pre-approve, and that list is read-only.
  • Spend is capped. --max-budget-usd stops a runaway run. --max-turns is no longer listed in claude --help (2.1.283), although the CLI still accepts it; cap spend with --max-budget-usd instead of relying on an undocumented flag.
  • The evidence travels. Attach the verdict file ($RUNNER_TEMP/deploy-check.txt in GitHub Actions, /tmp/deploy-check.txt locally) to the release pull request, next to the CI run, as part of the evidence bundle the reviewer checks instead of the diff.

To run the same gate in GitHub Actions, see running Claude Code in CI/CD with GitHub Actions and headless mode, which covers the token permissions and the untrusted-ref rules a CI job needs.

Review database migrations before they ship

Section titled “Review database migrations before they ship”

A migration is the change a rollback often cannot undo, because the old code may not run against the new schema. Ask Claude Code for a structured review of every pending migration, then prove the answer on data.

The review is a lead, not a proof. The proof is running the migration on staging against a recent, anonymised copy of production data, in the order up, down, up, and timing it. A migration that locks a table for minutes on real data looks harmless on an empty development database.

Generate deploy and rollback scripts as a pair

Section titled “Generate deploy and rollback scripts as a pair”

Ask for both scripts in one prompt. When Claude writes the rollback at the same time, it records the state that the rollback needs before the deploy changes it.

Verify the pair before any pipeline runs it:

  1. Run shellcheck scripts/deploy.sh scripts/rollback.sh and bash -n on both. Both must be clean.

  2. Run DRY_RUN=1 ./scripts/deploy.sh staging and compare the printed commands with your runbook. Check the order: migrations before kubectl set image, state recorded before anything changes.

  3. List every environment variable the scripts read and confirm each one exists in the target environment:

    Terminal window
    grep -ohE '\$\{?[A-Z_][A-Z0-9_]*\}?' scripts/deploy.sh scripts/rollback.sh | tr -d '${}' | sort -u
  4. Deploy to staging from CI, then run ./scripts/rollback.sh staging and confirm the previous tag is serving and the smoke test passes. A rollback you have never run is a hypothesis.

Automate a blue-green switch with a metric-gated rollback

Section titled “Automate a blue-green switch with a metric-gated rollback”

A traffic switch without a health signal only moves the risk. The detail that makes this prompt work is the monitoring endpoint and the threshold: with them, the script can decide on real error rates instead of hoping.

Prove the automatic rollback fires before you rely on it. On staging, deploy an image whose /health passes but whose API routes return 500, and confirm that the script switches back within the monitoring window and exits 1. Choose the threshold and the window from your service-level objective, not from this example. For canaries, feature flags, and a blast-radius budget per risk class, see progressive delivery for agent-written changes.

Generate the changelog and release notes from git history

Section titled “Generate the changelog and release notes from git history”

Changelog writing is where Claude Code saves the most tedium with the least risk, because every line can be checked against a commit. Pipe the log in and state the format.

Terminal window
# Terminal: draft a CHANGELOG entry from the commits since the last tag
git log --no-merges --format='%h %s' "$(git describe --tags --abbrev=0)..HEAD" | \
claude -p "Draft a CHANGELOG.md entry from these commits, dated $(date +%F).
Group under Added, Changed, Fixed and Removed. One line per user-visible change, in past tense.
Keep the PR number, for example (#412), when the subject has one. Skip version bumps and CI-only commits.
After the entry, list every commit hash you left out and why." \
--output-format text > "${TMPDIR:-/tmp}/changelog-draft.md"

The last instruction is the verification hook: the list of omitted commits lets you check coverage in seconds instead of re-reading the log.

For a procedure the whole team runs, save it as a project skill. A skill replaces the older .claude/commands/ file; both create a slash command, and custom commands and skills covers the differences.

disable-model-invocation: true means the skill runs only when you type it, which is the right setting for anything that feeds a release.

Diagnose a failed deploy with MCP and platform skills

Section titled “Diagnose a failed deploy with MCP and platform skills”

When a deploy fails in CI, pasting log fragments into the session loses context. Give Claude Code a read-only connection to the pipeline instead. The GitHub MCP server exposes a read-only Actions toolset at its own URL:

Terminal window
# Terminal: GITHUB_PAT is a fine-grained token with read access to Actions
claude mcp add --transport http github-actions \
https://api.githubcopilot.com/mcp/x/actions/readonly \
-H "Authorization: Bearer $GITHUB_PAT"

For a platform-specific deploy, a skill carries the platform’s commands and conventions so you stop re-explaining them. Cloudflare’s official skills and plugin, for example, install from the cloudflare/skills repository:

/plugin marketplace add cloudflare/skills
/plugin install cloudflare@cloudflare

The rule of thumb: a skill is best for knowledge about how to do one job, such as deploying to one platform. An MCP server is best when Claude needs a live connection to a system, such as CI runs or cloud resources, for the whole session. The GitHub MCP server guide covers toolsets and lockdown mode, and Cloudflare MCP servers covers the Cloudflare side.

The on-call engineer runs the commands, and the recovery metrics from step 4 are the sign-off. For the wider incident workflow, see AI-powered incident response.

What breaks when Claude Code automates your deploys?

Section titled “What breaks when Claude Code automates your deploys?”

The model reports a gate as passed without running it. A summary is not an exit code. Recovery: keep deterministic checks in shell with set -e, as in deploy-check.sh, and reserve the model for judgment questions whose answers cite file:line.

The verdict line never matches. The model wraps the verdict in Markdown bold or adds a sentence after it, and the gate reports NO-GO on a clean release. That is the safe direction. Recovery: keep “exactly one plain-text line and nothing after it” in the prompt, and read the verdict file at $OUT before rerunning. The script writes it outside the repository, so a rerun does not trip its own clean-tree check.

The gate reviews the wrong range in CI. A shallow checkout has no tags, so git describe falls back to the shallow root and Claude reviews the wrong diff; the changelog command fails outright. Recovery: set fetch-depth: 0 on actions/checkout. fetch-tags: true alone is not enough, because git describe also needs the history between the tag and HEAD.

The Dockerfile works locally but fails in CI. The runner usually has a different CPU architecture. Recovery: build with docker buildx build --platform linux/amd64, or ask Claude for a multi-platform build; containerization covers the rest.

The deploy succeeds and the app crashes on startup. Claude Code cannot see runtime behaviour on a target it has no access to. Recovery: the smoke test in deploy.sh must hit a real route, not only /health, and every script change goes through staging first.

A variable is missing in production. Generated scripts reference variables that no one has set. Recovery: the .env.example check in the gate, plus the grep in the verification steps above.

The changelog is useless. Commit subjects like “fix stuff” produce entries like “Fixed stuff”. Recovery: tell Claude to read the diff for vague commits, as the skill does, and enforce descriptive subjects in review.

The rollback fails because the migration was one-way. Many ORMs generate no down migration by default. Recovery: make expand/contract a CLAUDE.md rule, and run up, down, up on staging for every migration.

The agent reaches production anyway. A deny rule was bypassed by another spelling, or a production credential sat in the shell environment. Recovery: remove production credentials from developer machines and let only the CI deploy job hold them.

Where to go next with deployment automation

Section titled “Where to go next with deployment automation”