deploy-landed — Claude Code skill: prove your deploy landed
The skill checks that the revision being served is the commit you meant, that its env reached the running process, and that the product actually works. Useful after any deploy or restart.
npx skills add avelikiy/great_cto --skill deploy-landed -a claude-codeWhat deploy-landed does
An exit code only tells you the deploy command finished. This skill makes the agent show that the new code is serving, that its configuration arrived, and that the product does its job. Four checks, each with evidence: revision (live image tag or digest, deployment id, process start time, or the content of the served file), configuration, function, and startup errors in the logs.
Before a pull or build, it looks for hand patches on the host. git -C /srv/app status --porcelain lists anything not in git, and git -C /srv/app log -1 --format=%H shows what the host believes it runs. Uncommitted work gets committed or reported as drift. In a container, env vars are read from PID 1 with cat /proc/1/environ | tr '\0' '\n' — docker exec env does not inherit the entrypoint's environment, which is how you get a false “config is missing” reading.
The run ends with a DEPLOY-LANDED block covering revision, config, function and startup. A check that could not run is marked NOT CHECKED with the reason. Any FAIL means the deploy is not done, whatever the command printed. The skill uses Read, Bash and Grep.
What it helps with
- confirm the served revision matches the commit you meant
- catch a server-side hot-fix before the next
git pull - verify the running process sees its env vars and secrets
- tell a working product apart from a green
/health - find out why nothing updated after a rollout
Example prompts for the agent
- Deploy this and prove the right commit is serving in prod
- Check prod: are the env vars there and does an order go through?
- Why did it not update — run the deploy-landed checks and show me the report
How to install deploy-landed
1Skills CLI (Vercel)
npx skills add avelikiy/great_cto --skill deploy-landed -a claude-code2Manually: put the files in place
~/.claude/skills/deploy-landed/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/deploy-landed/
1Skills CLI (Vercel)
npx skills add avelikiy/great_cto --skill deploy-landed -a codex2Manually: put the files in place
.agents/skills/deploy-landed/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add avelikiy/great_cto --skill deploy-landed -a cursor2Manually: put the files in place
.cursor/skills/deploy-landed/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install avelikiy/great_cto deploy-landed2Manually: put the files in place
.github/skills/deploy-landed/SKILL.md1Skills CLI (Vercel)
npx skills add avelikiy/great_cto --skill deploy-landed -a gemini-cli2Platform CLI
gemini skills install https://github.com/avelikiy/great_cto --path skills/deploy-landedManually: put the files in place
.devin/skills/deploy-landed/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add avelikiy/great_cto --skill deploy-landed -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about deploy-landed
How do I install deploy-landed in Claude Code?
Run npx skills add avelikiy/great_cto --skill deploy-landed -a claude-code. The skill lands at ~/.claude/skills/deploy-landed/SKILL.md.
What does deploy-landed do?
It runs four post-deploy checks: which revision is serving, whether the running process has the expected variables, whether the product performs its job, and whether the logs show errors since startup.
How is this different from watching /health?
A green /health only means the process is up. The skill asks for one request that does the product's job and returns something comparable to a known value.
Source text
SKILL.md · MIT
---
name: deploy-landed
description: Prove a deploy landed — the served revision is the commit you meant, its env is present, and the product does its job — instead of trusting the deploy command's exit code. Also catches server drift before a pull or deploy. Use after any deploy, rollout, restart or server-side fix ("задеплой", "выкати", "проверь на проде", "почему не обновилось"). Loaded by devops, l3-support, infra-provisioner.
when_to_use: |
Apply when:
- you ran, or are about to report, a deploy, a rollout, a container restart, a hot-fix on a server
- the operator asks whether something is live, or says it "did not update" / "still broken"
- you are about to `git pull` or build on a server that someone may have patched by hand
Do NOT apply to:
- a change that does not reach a runtime (docs, tests only) — CI is the check there
effort: low
allowed-tools: Read, Bash, Grep
---
# deploy-landed — a deploy is done when the running thing is the thing you meant
A deploy command's exit code says the command finished. It does not say the new code
is serving, that its configuration arrived, or that the product works. Every trap
below produced a green exit and a broken or stale product on a real project:
| Trap | What happened |
|---|---|
| `git pull` failed, the build went on | The build succeeded from the **old** code and reported success |
| `nohup … &` | Exit 0 twice for a process that died at once |
| `docker exec` into a container | It does not inherit the entrypoint's env: two "config is missing" readings were false |
| `sed -i` / `docker cp` on a bind-mounted file | Replaced the inode; the container kept reading the old file |
| A fix applied only on the server | Lost on the next deploy — it was never in git |
| wrangler / Pages | `functions/` not deployed, `_headers` ignored, five deploys to notice |
| Prod behind SSO | Answers 401/302 to **every** path, including ones that do not exist — proves nothing about a route |
| `/health` green | For six hours while the engine made no trades |
## Before: is the server what git says it is?
Before pulling or building on a host someone can reach by hand:
```bash
git -C /srv/app status --porcelain # anything here is a patch that is not in git
git -C /srv/app log -1 --format=%H # what the host thinks it runs
```
Anything uncommitted on the host is either committed first or reported as drift — never
overwritten silently, and never left as the only copy of a fix.
## After: four checks, each with its evidence
1. **Revision.** What is serving equals the commit you meant.
- Cloud Run / k8s: the live revision's image tag or digest, then
`git merge-base --is-ancestor <commit> <image-tag-sha>`.
- Pages / Workers / Vercel: the deployment id and its commit.
- A plain host: the running process's start time is after the deploy, and the file
it serves has the new content (`grep` for a string the change introduced).
- A `/version` endpoint, when the app has one, beats all of the above.
2. **Configuration.** The variables and secrets the new code reads are present in the
**running process** — count them against the list the code expects. In a container,
read them from PID 1 (`cat /proc/1/environ | tr '\0' '\n'`), not from `docker exec env`.
After `--set-secrets`/`--set-env-vars`, check that the ones you did not name are still
there: those flags replace the whole set.
3. **Function.** One request that does the product's job and returns something you can
compare to a known value — an order created, a row written, a trade placed on paper.
A health endpoint proves the process is up, nothing more.
4. **Startup errors.** Logs for the new revision since it started, at WARNING and above.
Zero lines is a finding only if you saw the logs flowing at all.
## Report
End the deploy report with this block. A check you could not run is `NOT CHECKED` with
the reason — never omitted, never `PASS`.
```
DEPLOY-LANDED <service> @ <commit>
revision : PASS — serving <revision/deployment id> built from <sha>
config : PASS — 14/14 expected vars present in PID 1
function : PASS — POST /orders → 201, row id 8812 visible in DB
startup : PASS — 0 WARNING+ lines since 12:04:10
```
A FAIL in any line means the deploy is not done, whatever the command printed.
© avelikiy · MIT · avelikiy/great_cto