# Deploy Skill — Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Build a `deploy` skill — a per-project shell runbook that re-instantiates from the delta since the last deploy, hands control to the user for out-of-band execution, resumes cold (even in a new session), and learns from deploy errors in place. **Architecture:** A surgical-commit helper (`lib/deploy-commit.sh`, allowlist-scoped to `.claude/deploy/`) is the foundation. Five per-project artifacts under `.claude/deploy/` carry runbook, incident ledger, deploy oracle, in-flight bridge, and the instantiated checklist. The skill is a two-moment SKILL.md (before → user deploys out-of-band → after, on the user's report), resumable cold from the JSON bridge per the `audit-delta` state-file convention. Bootstrap scaffolds the runbook for a project that has none. **Tech Stack:** Bash (helper + git), Markdown (SKILL.md + runbook + ledger), JSON (oracle + bridge). No new runtime deps — Claude reads JSON natively in skill steps; the helper never parses JSON. ## Global Constraints - Surgical commits only: `deploy-commit.sh` commits via explicit argv pathspec, never `git add -A`. (mirror BDR-034/036) - Allowlist scope = `.claude/deploy/` ONLY; any other path is a loud rc-4 refusal. Inverse of `doc-commit.sh`'s `.claude/**` exclusion (BDR-022). Verified: real `doc-commit.sh` returns rc 4 on `.claude/deploy/PROCEDURE.md`. - Delta = `git diff --name-only HEAD` — **explicit two endpoints, no dots** (two-dot ≡ this; three-dot undercounts — verified). Never `git rev-list` ancestry (phantom deltas on rebase — verified). - First-deploy detection = `[ -f .claude/deploy/STATE.json ]` (deterministic). NEVER `git describe` (hard-errors rc 128 on no tag — verified). - Resume convention = `audit-delta`: "the state file is the only memory between runs; never infer prior scope from context." Bridge read at STEP 0. - Helper inherits from `lib/memory-commit.sh`/`lib/doc-commit.sh`: rc 3 on unsafe git state (detached/merge/rebase/cherry-pick), short-hash on stdout only on a real commit, per-file changed-paths filter, diagnostics to stderr. - User executes the deploy out-of-band (prod ssh) — the skill NEVER runs deploy commands itself. - Registries/spec language English; the spec of record is `docs/specs/2026-06-27-deploy-skill-design.md`. --- ## Decisions resolved at plan time **§10 (cross-session state) — TRANCHÉ: separate bridge artifact.** - Bridge = `.claude/deploy/PENDING.json` (JSON), **distinct from the ephemeral `NEXT.sh`**, **uncommitted** (transient local working state; gitignored). Schema: ```json { "base_sha": "", "target_sha": "", "delta": ["supabase/migrations/0033_x.sql", "docker-compose.yml"], "step_reached": "awaiting-user", "started_at": "", "runbook_rev": "" } ``` - Follows `audit-delta` ("state file is the only memory between runs"). Resolves the n°1↔n°3 coupling: NEXT.sh stays ephemeral per §3; the bridge persists and carries base+target+delta so moment 3 lays the correct marker and capitalizes the correct incident — **without re-parsing shell**, readable cold. - Form-novelty (mid-flow pause-resume) is new → `writing-skills` formalizes the convention in Task 3. - **LIMIT (acknowledged, not to be discovered):** `PENDING.json` is gitignored ⇒ cold-resume is **same-machine only** — it does not survive a clone or a move to another machine. Acceptable because a project's deploys run from one local; recorded as a constraint, not assumed away. **§8 item 1 — tag push:** annotated tag `git tag -a deploy/ -m ""` laid in MARK (success). **Project knob `# @config push_deploy_tags=true|false`** in the `PROCEDURE.md` header (default `false`): when true, MARK runs `git push origin deploy/` — always **best-effort/non-fatal** (the push never blocks the deploy; tag is a bookmark, STATE.json is the oracle). Same-day re-deploy → suffix `-N`. **§8 item 2 — INCIDENTS ID/name:** `.claude/deploy/INCIDENTS.md`, append-only, entries `DEP-NNN` (next = `grep '^## DEP-' | max+1`), fields mirror `blockers.md`: date, step, error (verbatim), root cause, fix. Resolution derivable from git: the commit that adds the entry IS the fix (atomic patch+incident); recover via `git log -S 'DEP-NNN' -- .claude/deploy/INCIDENTS.md`. Name confirmed `INCIDENTS.md` (not `ERRORS-LEARNED.md`). **§8 item 3 — `@delta:` grammar:** directives on a runbook step's preceding comment line, patterns matched against the delta file list. `glob=` carries TWO required semantics (a single "checklist-only" reading was REJECTED — it breaks the game example, where step 3 runs `psql -f 0033` THEN `psql -f 0034` = one command PER file): - `# @delta: glob=:each` — **repeat**: emit the step's command once per delta file matching `` (e.g. `psql -f `). - `# @delta: glob=:list` — **checklist**: emit the command once, with matching files as `# VERIFY:` items (e.g. `supabase migration up`). - `# @delta: when=[,...]` — **conditional**: include the step only if the delta intersects any pattern (e.g. rebuild when compose/Dockerfile changed). - Patterns are git-pathspec/shell-glob; comma-separates alternatives. **Un-annotated step = fixed**, always emitted verbatim. The exact `:each`/`:list` keyword spelling is DEFERRED to `writing-skills` (Task 3); both semantics are mandatory. **§8 item 4 — frontmatter / gates:** ```yaml name: deploy description: | Use when deploying a project via its per-project runbook — instantiates the delta since last deploy, hands off for out-of-band execution, resumes cold, learns from errors. Triggers: "deploy", "déploie", "run the deploy", "ship to prod", "deploy runbook". allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion] ``` Gate vocabulary reused from `capitalize`/`client-handover`: `all / pick / edit / skip-all`. Gates marked **[GATE]** in Task 3. --- ## File Structure - Create `lib/deploy-commit.sh` — surgical commit helper, allowlist `.claude/deploy/`. (Task 1) - Create `lib/tests/deploy-commit.test.sh` — real-git behavioral tests. (Task 1) - Create `skills/deploy/SKILL.md` — the two-moment skill. (Task 3) - Create `templates/deploy/PROCEDURE.md` — annotated starter runbook (scaffold source). (Task 2/4) - Create `templates/deploy/INCIDENTS.md` — empty ledger header. (Task 2) - Modify `.gitignore` — ignore `.claude/deploy/NEXT.sh` and `.claude/deploy/PENDING.json`. (Task 2) - Per-project, created at runtime (NOT in this repo): `.claude/deploy/{PROCEDURE.md, INCIDENTS.md, STATE.json, PENDING.json, NEXT.sh}`. **Artifact lifecycle:** | Artifact | Committed? | Lifecycle | |---|---|---| | `PROCEDURE.md` | yes (deploy-commit) | in-place edits (learning) | | `INCIDENTS.md` | yes (deploy-commit) | append-only `DEP-NNN` | | `STATE.json` | yes (deploy-commit) | overwritten on success = oracle | | `PENDING.json` | **no** (gitignored) | written at hand-back, deleted on success = cold-resume bridge | | `NEXT.sh` | **no** (gitignored) | regenerated per deploy, ephemeral checklist | --- ### Task 1: `lib/deploy-commit.sh` — surgical commit helper (FOUNDATION, TDD) **Files:** - Create: `lib/deploy-commit.sh` - Test: `lib/tests/deploy-commit.test.sh` **Interfaces:** - Produces: `deploy-commit.sh pending ...` → exit 0 if any passed file in-scope has changes, else 1. `deploy-commit.sh commit "" ...` → commits ONLY passed in-scope files, prints short hash on stdout; rc 0 success, rc 1 clean/no-op, rc 3 unsafe git state, rc 4 out-of-scope path. - Consumes: nothing (foundation). - [ ] **Step 1: Write the failing test harness** ```bash # lib/tests/deploy-commit.test.sh #!/usr/bin/env bash set -u H="$(cd "$(dirname "$0")/.." && pwd)/deploy-commit.sh" pass=0; fail=0 mkrepo() { local d; d=$(mktemp -d); git -C "$d" init -q; git -C "$d" config user.email t@t; git -C "$d" config user.name t; mkdir -p "$d/.claude/deploy"; printf 'x\n' >"$d/seed"; git -C "$d" add seed; git -C "$d" commit -q -m seed; printf '%s' "$d"; } check() { if [ "$2" = "$3" ]; then pass=$((pass+1)); else fail=$((fail+1)); printf 'FAIL %s: got[%s] want[%s]\n' "$1" "$2" "$3"; fi; } d=$(mkrepo); printf 'run\n' >"$d/.claude/deploy/PROCEDURE.md" out=$( cd "$d" && bash "$H" commit "docs(deploy): t" .claude/deploy/PROCEDURE.md ); rc=$? check T1-rc "$rc" 0 check T1-committed-only "$(git -C "$d" show --name-only --format= HEAD)" ".claude/deploy/PROCEDURE.md" check T1-hash-nonempty "$([ -n "$out" ] && echo y || echo n)" y d=$(mkrepo); printf 'b\n' >"$d/src.txt" ( cd "$d" && bash "$H" commit "x" src.txt ) >/dev/null 2>&1; check T2-out-of-scope-rc "$?" 4 d=$(mkrepo) ( cd "$d" && bash "$H" commit "x" ".claude/deploy/../memory/secret" ) >/dev/null 2>&1 check T3-traversal-rc "$?" 4 d=$(mkrepo); printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md"; printf 's\n' >"$d/src.txt" ( cd "$d" && bash "$H" commit "x" .claude/deploy/PROCEDURE.md src.txt ) >/dev/null 2>&1 check T4-mixed-refuses-all "$?" 4 check T4-nothing-committed "$(git -C "$d" rev-list --count HEAD)" 1 d=$(mkrepo); git -C "$d" checkout -q --detach printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md" ( cd "$d" && bash "$H" commit "x" .claude/deploy/PROCEDURE.md ) >/dev/null 2>&1 check T5-unsafe-rc "$?" 3 d=$(mkrepo) ( cd "$d" && bash "$H" pending .claude/deploy/PROCEDURE.md ); check T6-pending-clean-rc "$?" 1 d=$(mkrepo); printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md" printf 'i\n' >"$d/.claude/deploy/INCIDENTS.md"; printf '{}\n' >"$d/.claude/deploy/STATE.json" ( cd "$d" && bash "$H" commit "docs(deploy): learn" .claude/deploy/PROCEDURE.md \ .claude/deploy/INCIDENTS.md .claude/deploy/STATE.json ) >/dev/null 2>&1 check T7-atomic-rc "$?" 0 check T7-three-files "$(git -C "$d" show --name-only --format= HEAD | grep -c deploy)" 3 printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ] ``` - [ ] **Step 2: Run the test, verify it FAILS** Run: `bash lib/tests/deploy-commit.test.sh` Expected: FAIL (helper absent) — every check fails or the harness errors on missing `lib/deploy-commit.sh`. - [ ] **Step 3: Implement `lib/deploy-commit.sh`** ```bash #!/usr/bin/env bash # deploy-commit.sh — surgical commit for the .claude/deploy/ runbook family. # Allowlist scope = .claude/deploy/ ONLY (inverse of doc-commit's .claude exclusion). set -u _in_git_repo() { git rev-parse --is-inside-work-tree >/dev/null 2>&1; } _unsafe_state() { # 0 = unsafe local g; g=$(git rev-parse --git-dir 2>/dev/null) || return 0 git symbolic-ref -q HEAD >/dev/null 2>&1 || return 0 # detached HEAD [ -e "$g/MERGE_HEAD" ] || [ -d "$g/rebase-merge" ] || \ [ -d "$g/rebase-apply" ] || [ -e "$g/CHERRY_PICK_HEAD" ] && return 0 return 1 } _out_of_scope() { # 0 = forbidden, 1 = in scope case "$1" in *..*) return 0 ;; # traversal — forbidden FIRST .claude/deploy/*) return 1 ;; # allowed *) return 0 ;; # everything else forbidden esac } _scope_violations() { local p; for p in "$@"; do _out_of_scope "$p" && printf '%s\n' "$p"; done; } _changed_only() { # echo passed files that actually have changes local p; for p in "$@"; do [ -n "$(git status --porcelain -- "$p" 2>/dev/null)" ] && printf '%s\n' "$p"; done } cmd="${1:-}"; shift || true _in_git_repo || { echo "deploy-commit: not a git repo" >&2; exit 2; } case "$cmd" in pending) [ "$#" -gt 0 ] || { echo "deploy-commit: pending needs file args" >&2; exit 2; } [ -n "$(_changed_only "$@")" ] && exit 0 || exit 1 ;; commit) msg="${1:-}"; shift || true [ -n "$msg" ] && [ "$#" -gt 0 ] || { echo "deploy-commit: commit needs ..." >&2; exit 2; } viol=$(_scope_violations "$@") if [ -n "$viol" ]; then { echo "deploy-commit: REFUSED — path(s) outside .claude/deploy/ allowlist:"; printf ' - %s\n' $viol; echo "deploy-commit: NOTHING committed. Caller must pass only .claude/deploy/ files."; } >&2 exit 4 fi _unsafe_state && { echo "deploy-commit: unsafe git state (detached/merge/rebase) — not committing" >&2; exit 3; } mapfile -t changed < <(_changed_only "$@") [ "${#changed[@]}" -gt 0 ] || exit 1 git commit -q -m "$msg" -- "${changed[@]}" || { echo "deploy-commit: git commit failed" >&2; exit 1; } git rev-parse --short HEAD ;; *) echo "usage: deploy-commit.sh pending ... | commit \"\" ..." >&2; exit 2 ;; esac ``` - [ ] **Step 4: Run the test, verify it PASSES** Run: `bash lib/tests/deploy-commit.test.sh` Expected: `PASS=11 FAIL=0` (exit 0). - [ ] **Step 5: shellcheck** Run: `shellcheck lib/deploy-commit.sh lib/tests/deploy-commit.test.sh` Expected: clean (matches repo Health Stack norm). - [ ] **Step 6: Commit** ```bash git add lib/deploy-commit.sh lib/tests/deploy-commit.test.sh git commit -m "feat(deploy): deploy-commit.sh — allowlist surgical commit for .claude/deploy/" ``` --- ### Task 2: Artifacts + bridge formats (§10 materialized) **Files:** - Create: `templates/deploy/PROCEDURE.md`, `templates/deploy/INCIDENTS.md` - Modify: `.gitignore` **Interfaces:** - Produces: the on-disk shapes the skill reads/writes — `PROCEDURE.md` annotation grammar, `INCIDENTS.md` `DEP-NNN` template, `STATE.json` and `PENDING.json` schemas. - Consumes: nothing. - [ ] **Step 1: Write `templates/deploy/PROCEDURE.md`** (annotated starter — fixed steps verbatim, dynamic steps annotated) ```bash #!/usr/bin/env bash # === deploy runbook (reference) — NOT run directly. Instantiated to NEXT.sh per delta. === # Fixed steps run every deploy; `# @delta:` steps re-instantiate from the delta. # @config push_deploy_tags=false # NOTE grammar: glob=:each repeats the command per matching file (e.g. psql -f ); # glob=:list runs once + lists matching files as VERIFY items; when= is conditional. # 1) backup BEFORE any forward-only migration ssh "$DEPLOY_HOST" 'pg_dump "$DB" > ~/backups/pre-deploy-$(date +%F-%H%M).sql' # VERIFY: dump size > 0 # @delta:migrations glob=supabase/migrations/*.sql:list # 2) apply NEW migrations (one command; skill lists the delta migrations to VERIFY) ssh "$DEPLOY_HOST" 'supabase migration up' # VERIFY: "Applied" for each # @delta:rebuild when=docker-compose*.yml,Dockerfile,*.dockerfile # 3) rebuild + restart services (only if build inputs changed) ssh "$DEPLOY_HOST" 'docker compose up -d --build' # VERIFY: docker compose ps healthy # @delta:deps when=package.json,*lock*,requirements.txt,pyproject.toml # 4) install deps (only if manifests changed) ssh "$DEPLOY_HOST" 'cd app && npm ci' # VERIFY: exit 0 # 5) reload cache + smoke test (fixed) ssh "$DEPLOY_HOST" 'systemctl reload app' curl -fsS https://$DEPLOY_HOST/health # VERIFY: HTTP 200 ``` - [ ] **Step 2: Write `templates/deploy/INCIDENTS.md`** (ledger header) ```markdown # Deploy incidents (append-only) — DEP-NNN ``` - [ ] **Step 3: Record the JSON schemas** (no parsing in shell — Claude reads them in skill steps) `STATE.json` (committed oracle, overwritten on success): ```json { "deployed_sha": "", "deployed_at": "", "outcome": "ok", "tag": "deploy/" } ``` `PENDING.json` (gitignored bridge, deleted on success): schema as in "Decisions resolved at plan time / §10". - [ ] **Step 4: Update `.gitignore`** ```gitignore # deploy: transient per-deploy state (the runbook/ledger/oracle ARE committed) .claude/deploy/NEXT.sh .claude/deploy/PENDING.json ``` - [ ] **Step 5: Verify templates are well-formed** Run: `bash -n templates/deploy/PROCEDURE.md && grep -c '@delta:' templates/deploy/PROCEDURE.md` Expected: no syntax error; `3` annotations. - [ ] **Step 6: Commit** ```bash git add templates/deploy/PROCEDURE.md templates/deploy/INCIDENTS.md .gitignore git commit -m "feat(deploy): runbook/ledger templates + bridge schemas + gitignore transient state" ``` --- ### Task 3: `skills/deploy/SKILL.md` — the two-moment skill (REQUIRES writing-skills) > **At this task, invoke `superpowers:writing-skills`** to shape SKILL.md to house conventions AND to formalize the **cross-session cold-resume** form (deploy's defining novelty; `audit-delta` is the state-file precedent, `client-handover` only an in-context pause). The step behaviors below are the contract; writing-skills governs structure/frontmatter/spine. **Files:** - Create: `skills/deploy/SKILL.md` **Interfaces:** - Consumes: `lib/deploy-commit.sh` (Task 1); artifact shapes (Task 2). - Produces: the runtime behavior. STEP spine below. **STEP spine (each = a SKILL.md section; [GATE] = mandatory stop):** - [ ] **STEP 0 — PRE-FLIGHT + RESUME BRANCH.** Read `.claude/deploy/PENDING.json` FIRST (state file = only memory between runs). - `PENDING.json` present → **RESUME**: jump to STEP 3 with its `{base, target, delta, step_reached}` (do not recompute). - else `PROCEDURE.md` absent → **BOOTSTRAP** (Task 4). - else → FRESH: continue STEP 1. - [ ] **STEP 1 — DELTA.** `base = STATE.json.deployed_sha` (or, if `STATE.json` absent, first-deploy = full runbook). `git diff --name-only HEAD` → delta file list. `target = git rev-parse HEAD`. - [ ] **STEP 2 — INSTANTIATE + [GATE].** Expand `PROCEDURE.md`: emit fixed steps verbatim; expand `@delta:glob=…:each` steps by repeating the command per matching delta file, and `@delta:glob=…:list` steps once with matching files as `# VERIFY:` items; include `@delta:when=` steps only if the delta intersects. Read `INCIDENTS.md` and prepend matching `# PRE-WARN: DEP-NNN …` notes. Write `NEXT.sh`. **[GATE]** present `NEXT.sh` → `all / edit / skip-all`. On approve: write `PENDING.json` (`step_reached: awaiting-user`), then **hand back** (AskUserQuestion: "Run NEXT.sh step by step. Report back: Deployed OK / Failed at step X / Not yet"). - [ ] **STEP 3 — RESUME / REACT** (entry point on the user's report; may be a fresh session). - "Deployed OK" → STEP 5. - "Failed at step X: " → STEP 4. - "Not yet" → re-state pending, stop. - [ ] **STEP 4 — LEARN + [GATE] + ATOMIC COMMIT.** Diagnose. Draft: (a) in-place `PROCEDURE.md` patch to step X; (b) `INCIDENTS.md` append `DEP-NNN` (error verbatim). **[GATE]** `all / pick / edit / skip-all` (significant edit). On approve: write both, then **one atomic** `bash lib/deploy-commit.sh commit "docs(deploy): patch — recovered from " .claude/deploy/PROCEDURE.md .claude/deploy/INCIDENTS.md`. The commit that adds `DEP-NNN` IS its resolution (derive via git later). Then bump `PENDING.json.runbook_rev` to the new `PROCEDURE.md` commit sha (keep `step_reached` at X). **Resume = REGENERATE `NEXT.sh` from `step_reached` against the PATCHED runbook** (steps X…end — X+1…end never ran), NOT replay a single step. The bumped `runbook_rev` is exactly the trigger: runbook changed ⇒ prior `NEXT.sh` is stale ⇒ regenerate. Re-present via STEP 2's hand-back. - [ ] **STEP 5 — MARK (success).** Write `STATE.json` (`deployed_sha = PENDING.target_sha`, outcome ok, tag). `git tag -a deploy/ -m ""`; **if `@config push_deploy_tags=true`** then `git push origin deploy/` (best-effort, non-fatal). `bash lib/deploy-commit.sh commit "chore(deploy): mark @ " .claude/deploy/STATE.json`. **Delete `PENDING.json`** (+ `NEXT.sh`). Report. - [ ] **Verification scenarios** (dry-run walkthroughs, no prod): - First deploy (no `STATE.json`): full runbook fires; STATE laid; PENDING deleted. - Delta deploy: only changed-bucket steps instantiate; `git diff` form is ` HEAD`. - **Cold resume**: write a `PENDING.json` by hand, start `deploy` in a *fresh* context → STEP 0 detects it, resumes at STEP 3 from disk alone (no conversation memory). - Failure→learn: report "failed at step X" → patch + DEP append committed atomically (one sha, both files). - [ ] **Commit:** `git add skills/deploy/SKILL.md && git commit -m "feat(deploy): two-moment cross-session skill (resumes cold from PENDING.json)"` --- ### Task 4: Bootstrap (project without a runbook) **Files:** - Modify: `skills/deploy/SKILL.md` (STEP 0 BOOTSTRAP branch) **Interfaces:** - Consumes: `templates/deploy/*` (Task 2); STEP spine (Task 3). - [ ] **Step 1 — BOOTSTRAP branch + [GATE].** When `PROCEDURE.md` absent, offer two paths (AskUserQuestion): - **Paste** — user provides an existing runbook → adopt verbatim, then propose `@delta:` annotations for migration/build/deps steps. - **Scaffold** — detect artifacts (`supabase/migrations/`, `docker-compose*.yml`/`Dockerfile`, `package.json`/lockfiles, `.env*`) + short interview (ssh host, backup cmd, health URL, rollback note) → fill `templates/deploy/PROCEDURE.md`. - **[GATE]** present drafted `PROCEDURE.md` → `all / edit / skip-all`. On approve: write `PROCEDURE.md` + empty `INCIDENTS.md`; `bash lib/deploy-commit.sh commit "feat(deploy): bootstrap runbook" .claude/deploy/PROCEDURE.md .claude/deploy/INCIDENTS.md`. First deploy then proceeds (no STATE.json ⇒ full runbook). - [ ] **Step 2 — Verify:** dry-run on a repo with `supabase/migrations/` + `docker-compose.yml` present → scaffold proposes migration + rebuild steps annotated; on a bare repo → interview-only path. - [ ] **Commit:** `git add skills/deploy/SKILL.md && git commit -m "feat(deploy): bootstrap — paste-or-scaffold initial runbook"` --- ## Gates identified - **[GATE] STEP 2** — approve instantiated `NEXT.sh` before hand-back. - **[GATE] STEP 4** — approve runbook patch + `DEP-NNN` incident before the atomic learning commit. - **[GATE] STEP 0/Task 4** — approve scaffolded `PROCEDURE.md` before first write. - **Hand-back (STEP 2→3)** — AskUserQuestion is the resume point; the user executes out-of-band. - **Task gates** — each Task ends test-green + shellcheck-clean + committed before the next (deps: 1 → 2 → 3 → 4). ## Self-review - **Spec coverage:** 4 artifacts + bridge (§3/§10) → Task 2; STATE-oracle + ` HEAD` delta (§4) → Task 1 constraints + STEP 1; runbook+INCIDENTS learning, atomic couple (§5) → STEP 4; `deploy-commit.sh` inverse allowlist (§6) → Task 1; bootstrap (§7) → Task 4; two-moment cold resume (§10) → STEP 0/2/3 + PENDING.json. All §8 items resolved above. ✓ - **Placeholder scan:** none — helper code, test code, schemas, annotation grammar all concrete. - **Type consistency:** `STATE.json.deployed_sha` (STEP 1 base, STEP 5 write), `PENDING.json.{base_sha,target_sha,delta,step_reached}` (STEP 0 read, STEP 2 write, STEP 4 update), `deploy-commit.sh commit "" ...` (Tasks 1/3/4) — names align. - **Open at execution (not assumed):** the `writing-skills` consultation in Task 3 may rename/restructure SKILL.md sections to match the formalized cold-resume convention, and finalizes the `@delta:` `:each`/`:list` keyword spelling (both semantics mandatory); STEP behaviors and the §6 helper contract above are fixed regardless. ## Execution Handoff Build order is strict by dependency: **Task 1 (helper, foundation) → Task 2 (formats) → Task 3 (skill, writing-skills) → Task 4 (bootstrap)**.