| name | deploy |
| description | Test and deploy changes safely. Discovers deploy targets, runs fail-stop gates before going live, optionally shadow-deploys and swaps, then runs report-only post-deploy checks. This is a TEMPLATE — customize the commands and checks for your specific deployment pipeline. |
| user_invocable | true |
Deploy — Safe Deployment Pipeline
Pipeline shape: discover targets → fail-stop gate → deploy → report-only checks. The default scope is the whole project; module-level targeting is optional (see Target Discovery).
Input
/deploy [target(s)...] [--all] [--skip-tests]
target(s) (optional) — specific services/functions/apps to deploy. Omit to auto-detect from the git diff.
--all — deploy every target affected by the current diff.
--skip-tests — skip the pre-deploy test gate (use only when tests were just run).
Valid targets: [YOUR_TARGET_1], [YOUR_TARGET_2], ...
Target Discovery
The pipeline finds what to deploy by scanning for capability-marker files — the file that signals "this directory is independently deployable." Discover targets instead of hardcoding them, so a newly-added target works without editing this skill.
find . -maxdepth 2 -name '[YOUR_MARKER_FILE]' -not -path '*/node_modules/*'
If a marker is found at the repo root → the deploy target is the whole project (the common case). If markers exist in multiple subdirectories → each is an independent target; map the diff to the affected one(s).
Resolving deploy config (fallback hierarchy)
Read deploy config (app id, account/project identifier, region — whatever your provider needs) from the first source that exists:
- Committed config — a tracked file checked into the repo (canonical, worktree-safe).
- CLI-managed temp/state — whatever your provider's CLI writes after
link/login (often gitignored).
- Heuristic — derive from a convention (directory name, repo name, an env var).
If none resolve, STOP with an actionable message:
No deploy config for [target]. Run '[YOUR_LINK_COMMAND]', or create '[YOUR_COMMITTED_CONFIG_FILE]'.
Detect what changed
If no target was passed explicitly, map the diff to targets:
git diff --name-only HEAD
git diff --name-only --cached
Shared-code dependency awareness
If the diff touches shared/library code that other deployable units import, those importers must be redeployed too — they bundle the changed code.
grep -rl "[CHANGED_SHARED_PATH]" [YOUR_SOURCE_GLOB]
Each affected target then runs through the full deploy pipeline below.
Pipeline
Step 1 — Preflight
- Resolve target(s), the deploy list, and deploy config.
- Print a summary so the operator can sanity-check before anything ships:
Repo: <path>
Branch: <name> @ <short-sha>
Targets: <list>
- Classify each target as new vs. existing in production (see Step 3 — the two branches differ).
Step 2 — Pre-deploy gate (FAIL-STOP)
These run before anything goes live. A failure here means nothing is deployed — the live target is untouched.
[YOUR_TEST_COMMAND]
- Non-zero exit → STOP. Report which suite failed, pass/fail counts. Deploy nothing.
- Skipped only when
--skip-tests is set or no test command is discovered.
Step 3 — Deploy
Deploy targets one at a time. If one fails, stop and report — do not continue to the remaining targets.
3a. New target (does not yet exist in production)
Nothing live to protect, so deploy directly:
[YOUR_DEPLOY_COMMAND] [target]
- Then run the smoke probe (see below). A hard failure (target won't boot / not routable) → STOP and report. There is no previous version to fall back to; the operator inspects.
3b. Existing target — optional Shadow/Canary, then swap
Deploy a staging variant alongside the live one, probe it, and only swap if it passes. The live target keeps serving the old code until the swap.
-
Shadow-deploy a parallel variant (a separate slug / preview URL / canary slice):
[YOUR_SHADOW_DEPLOY_COMMAND]
- Shadow deploy fails → run Cleanup helper on the shadow, STOP. Live target untouched.
-
Smoke-probe gate (FAIL-STOP) — probe the shadow URL:
[YOUR_SHADOW_SMOKE_PROBE]
- Fail → run Cleanup helper on the shadow, STOP. Live target untouched.
-
Swap — promote the verified bundle to the live target:
[YOUR_SWAP_COMMAND]
- Swap fails → see Retry-once in Error handling. The live target may be mid-state; do NOT touch git.
-
Post-swap probe (REPORT-ONLY) — probe the live URL. See Step 4. On failure, report and keep the shadow live for inspection — do not roll back automatically.
-
Cleanup — on success, remove the shadow (see Cleanup helper).
Step 4 — Post-deploy verification (REPORT-ONLY)
These run after the target is live. They cannot un-deploy — by definition the new code is already serving. So they are report-only: surface the result, never trigger a destructive auto-rollback.
[YOUR_POST_DEPLOY_CHECK]
- Pass → report success.
- Fail → re-run once (post-deploy checks are flaky: cold starts, propagation lag, rate limits). Still failing → report it. If a shadow is still live (3b), keep it live for the operator to inspect. Do NOT auto-rollback via git or redeploy of old code.
The split that matters: gates fail-stop before the swap; post-deploy checks only report after it. A check that runs after code is live can warn but must never silently mutate the deployment or the repo.
Smoke probe semantics
A minimal "is it alive and routable?" check — no app secrets or auth needed.
curl -s -o /dev/null -w "%{http_code}" "[YOUR_TARGET_URL]"
- 5xx — crashed on boot or dispatch. FAIL.
- 404 — the router doesn't know this target (bad deploy / wrong name). FAIL.
- 401 / 403 — auth middleware rejected the unauthenticated probe, but the target is alive. PASS.
- 2xx / other 4xx — the target responded. PASS.
Cleanup helper
Remove a shadow/canary variant after a swap, or after a failed gate. Safe to run idempotently; cleanup failures are reported but never block an already-completed swap.
[YOUR_SHADOW_DELETE_COMMAND]
find [SHADOW_DIR] -depth -type f -delete
find [SHADOW_DIR] -depth -type d -empty -delete
Error handling
- Pre-deploy test failure → nothing deployed; report.
- Shadow deploy failure → run Cleanup helper on the shadow, stop; live target untouched.
- Gate (smoke-probe) failure → run Cleanup helper on the shadow, stop; live target untouched.
- Swap failure (Retry-once) → swaps are normally atomic but can hit a transient error. Re-run the swap command once. If it fails again, report — the live target may be in an unknown state (old code still serving, or partially updated). Do NOT mutate git state. Operator inspects.
- Post-swap / post-deploy check failure → report. Keep the shadow live (don't clean it up) so the operator can compare. Do NOT auto-rollback.
Rollback
[YOUR_NATIVE_ROLLBACK_COMMAND]
Do not rebuild old code with git checkout and redeploy as a rollback path. It's destructive (can clobber working-tree state), slow, and may not reproduce the exact bytes that were live. The shadow-then-swap flow above already gives you the real safety net: if anything fails before the swap, the live target was never touched — "rollback" is simply "don't swap."
Step — Report
Deploy Complete
───────────────
Targets: <target> @ <deploy-id>
Branch: <branch> @ <sha>
Tests: <X/X passed | skipped (none found) | skipped (--skip-tests)>
Results:
<target1>: shadow → gate PASS → swap → post-check OK → cleaned
<target2>: new → deploy → probe OK
Skip conditions
Do NOT deploy for:
- Documentation-only changes (
*.md)
- Client/frontend-only changes when deploying a backend (and vice-versa)
- Test-only changes (unless
--all is explicit)
- Config that doesn't require redeploy
Notes
- Gates are the safety net — the pre-deploy test gate and the shadow smoke-probe both fail-stop before the swap. If anything fails there, the live target was never touched.
- Post-deploy checks only report — once code is live they can't un-deploy it, so they warn but never auto-rollback.
- Shadow/canary is optional — use it when a bad deploy would reach users before you can verify. If your host already does atomic instant rollback, you may not need it.
- Rollback should be native and atomic — re-point traffic to a previous release; never rebuild old code from git.
- Every fresh worktree that deploys needs the committed deploy-config file (Target Discovery #1), or it falls back to CLI state / heuristic.