iteration-close — distill, shed, prove takeover, rehearse bootstrap, seed next
A product that iterates forever accumulates two silent debts, and this skill pays both down at
every iteration boundary — safely (nothing is lost) but ruthlessly (nothing dead is kept):
- Dead files linger and rot into two-truths — a deprecated tree sits around for weeks; a runbook
keeps claiming a component is "not built" long after it shipped.
- Knowledge that lives only in a chat window dies with it — a whole working pipeline once died in
a scratchpad; hard-won decisions nearly died in chat. Keep the lesson, not the artifact.
It is generic: it works on any repo by reading that repo's own conventions, and where a
convention is absent it creates the minimum rather than assuming or erroring. "A fresh window or
new machine can continue" is a HOPE until it is TESTED; being current (pull) is always safe, but
publishing (push) is a deliberate choice.
Step 0 — orient to THIS repo (discover, else plan to create)
Read whichever entry doc exists — CLAUDE.md / AGENTS.md / README / a docs/ index — and
discover five things. Use what you find; where something is absent, note it as a gap this close
will fill (each phase below says how), never invent a path that isn't there.
- Lesson/decision record — where does this repo bank decisions? (
CHANGELOG, docs/adr/,
DECISIONS.md, or a repo-specific register.) If none, Phase 1 creates a single DECISIONS.md.
- Confirmed-upload command — a deliberate push step (
bin/sync, make deploy, a documented
git push discipline)? If yes, that IS the upload channel; never bypass it. If none, Phase 3a
uses plain git push after a diffstat + confirm.
- Bootstrap command — how does a fresh clone come alive? (
bin/bootstrap, bin/sync-setup,
install.sh, make setup, a package-manager install.) If none, Phase 4 creates one.
- Test command — from CI config,
package.json scripts, a Makefile, or the language default
(pytest / go test / cargo test / npm test). If none is discoverable, the repo has no
runnable suite yet: treat that as an explicit state below — never read it as "green", never
REFUSE on a repo that legitimately has none.
- Grounding / gate skill — a product-grounding or pre-build gate skill? If so, its
"after-build" checklist is your pre-close gate. (Product-specific gates live inside the product
repo; this skill stays generic and defers to them.)
Refuse to run (fail-closed)
Do not close mid-iteration — you lose skin AND flesh. REFUSE if: the test suite exists and is
actually FAILING (an absent suite is not a failing one — see Step 0.4); an adversarial gate, if
the repo has one, is pending or CHANGES-REQUIRED; or another agent/lane has uncommitted mid-slice
work in paths you'd touch. Say what's blocking and stop.
Run the phases IN ORDER. Each has an exit test; never proceed past a failed exit.
Phase 1 — DISTILL (salvage gate: nothing dies before its lesson is banked)
- Sweep this iteration's chat-born decisions into the repo's decision record (Step 0.1), each
with its status and source. If the repo banks decisions nowhere yet, creating the record is
part of this phase — a single
DECISIONS.md at repo root is enough. A decision that exists
only in a chat window does not exist; do not leave distilled decisions with no tracked home.
- New invariants/rules discovered this iteration → the repo's contracts file, or lacking that the
decision record — ideally each as a test. If neither exists, create the decision record and put
them there. Delete the artifact, keep the invariant.
- Session-only-capability check: did this iteration rely on anything living ONLY in a prompt, a
scratchpad, or someone's memory? Promote it into the repo (code / skill / doc) or record its
deliberate exclusion. Name each one explicitly — this is where pipelines die.
- If the STRUCTURE changed, update — or, if none exists and the structure is now nontrivial,
create — a short architecture/system note so it still describes reality. Bring any status board
(e.g. a progress doc) current if the repo has one.
EXIT TEST: grep this iteration's key decisions and invariants inside the repo — every one findable
in a tracked file. Anything findable only in chat = Phase 1 not done.
Phase 2 — SHED (ruthless deletion; git history is the ONLY archive)
- Build a deletion inventory with evidence, one line each:
path | why dead | what supersedes it.
Cover superseded modules/specs, dead/empty dirs, dev residue (scratch files, mktemp-style
junk, test rows in real-shaped stores), completed plan/TODO docs, and STALE DOCS — run a
docs-vs-code contradiction pass; a doc that asserts what the code contradicts is worse than none.
- Rules:
git rm only. NO _archive/ dirs, NO .bak, NO old-/legacy- renames, NO
commented-out corpses. Recovery = git history, one git revert away — that is the archive; a
checkpoint commit before deleting makes it bulletproof.
- Never shed the product's real DATA as if it were dev residue. User/customer state, saved
sessions, real archives of user content look like clutter and are the product's soul. When a
directory could be either, treat it as data and keep it; verify before any
git rm.
- Commit deletions in themed groups; each message says WHY + what supersedes it.
- Post-deletion checks (all that apply must pass): if the repo has a test suite, it is green;
dangling-reference grep for every deleted module/symbol is empty (an import of a deleted file
crashes at startup — a real scar); the entry doc and skill docs reference no deleted path.
EXIT TEST: git status clean, no archive-shaped dirs exist, dangling grep empty, and the test
suite green if one exists.
Phase 3 — TWO READINESS CHANNELS (different needs; verify separately)
Uploading and being-continuable are NOT the same problem. Conflating them is how a repo gets
"pushed to the cloud" while its real state still lives in a chat log. Verify each on its own.
3a. Confirmed cloud upload (the TRANSPORT problem)
- Secret scan on TRACKED files only (sk-ant / ghp_ / gho_ / github_pat / AKIA / xox[baprs] /
consumer_secret / access_token / Bearer / BEGIN PRIVATE KEY / .env shapes). Any hit → stop,
scrub, re-scan.
- Check
git remote. If there is NO remote, upload needs one the USER provides — adding a remote
is a config change, so confirm it with the user or record "no remote yet — publish deferred"
and skip to 3b rather than erroring on a bare git command.
- With a remote: show
git log @{u}..HEAD --oneline + diffstat (fall back to "all local commits"
when there is no upstream yet) — exactly what will leave this machine.
- Upload via the repo's confirmed-upload command (Step 0.2) after the user confirms; if the repo
has none,
git push after the diffstat and a yes. Never auto-push.
3b. Zero-context takeover (the KNOWLEDGE-COMPLETENESS problem) — the cold-start probe
- Get ONE genuinely context-free reader onto the repo — in Claude Code: spawn a fresh subagent
(Task tool); in Codex: run a fresh
codex exec or a new session with no prior context; on any
bare harness: open a new session and paste ONLY the repo path plus the questions, never this
conversation. Give it only the repo path and: "Read this repo cold from its entry doc. Then
answer: (1) what is this product, in one sentence; (2) where does the work stand (done / next);
(3) what would you do next and why; (4) name three things you must never do here."
- Grade its answers against the repo's canonical docs. If the repo has no entry/canonical doc
at all, creating a minimal one (the product in one sentence, current state done/next, three
never-dos) is part of this close — it is the artifact the probe grades. Do not run the probe
against nothing.
- Every wrong or missing answer is a TAKEOVER-DOC BUG, not the probe's fault. Fix (or create) the
doc, re-run with a NEW fresh reader. Loop until a cold reader scores 4/4.
EXIT TEST: probe passes 4/4. Only then is "any new window / machine can continue" a tested fact.
Phase 4 — ONE-COMMAND BOOTSTRAP (rehearsed, not assumed)
- Ensure the repo's bootstrap (Step 0.3) exists and is current — idempotent, safe to re-run:
verify toolchain versions; wire sync/config; install deps; run the test suite if one exists;
print the current status + the NAMES of any missing local secrets (never values, e.g.
"config.local.json absent — needed only for live publish"); exit non-zero on any failure with a
one-line reason. If no bootstrap exists yet, this is the iteration to create one.
- REHEARSE it: clone the repo into a scratch dir (from the origin URL, or from the local repo path
when there is no remote yet) and run the bootstrap there. It must end green with ZERO manual
steps. Delete the rehearsal clone after.
- The new-machine story must be one line and TRUE after this rehearsal:
git clone <origin-url> <dir> && cd <dir> && <bootstrap command>. If no remote exists yet, note
that this line is not yet true until the user sets one — don't publish it as if it works.
EXIT TEST: the rehearsal clone bootstraps green, untouched by hands.
Phase 5 — CLOSE + SEED (continuity)
- Tag the iteration:
git tag iter-<N>-<slug> (annotated, one-line summary). N = 1 + the count of
existing iter-* tags (git tag --list "iter-*"); the first close is iter-1.
- Update the status board / log with one line, if the repo has one: what was distilled, how many
files shed, probe 4/4, bootstrap rehearsed.
- Emit the NEXT-ITERATION SEED into chat: the open questions this iteration surfaced + a
paste-ready kickoff prompt for the next slice (goal, acceptance, and a reminder to run the
repo's grounding gate before building, if it has one).
Major iteration — when the STRUCTURE itself is replaced (same rules, bigger skin)
A structural overhaul — new architecture, new module tree, even "the old approach was wrong" — is
still an ITERATION of one organism, not a restart. It keeps its git history, its decisions, its
lessons; only the skin is new. History is unambiguous that restarts bleed: every time a project
was reborn in a fresh repo, lesson-grade material was left behind. So:
- Grow the new structure IN THIS REPO alongside the old (strangler pattern): the new tree earns
tests and ownership first; the old tree dies in Phase 2 only once nothing references it.
- Opening a NEW repo is the expensive exception, not the default — it requires a recorded decision
stating why THIS history must be abandoned, approved before any files move.
- Same five phases; the deletion inventory is just larger and the cold-start probe matters more —
the new structure's docs have never met a stranger.
- If the product's name or entry command changes, Phase 4's one-line story updates in the SAME
iteration. Two live names is a two-truths bug.
Guardrails (non-negotiable)
- Phase order is the safety mechanism: NEVER shed (Phase 2) before distill (Phase 1) exits.
- Deletion needs evidence of supersession, not vibes. Genuinely unsure? Keep it ONE more iteration
and record the doubt in the decision record — not in an archive dir.
- Push is a confirmed act, always. No auto-push, no bypassing the repo's upload step.
- The cold-start reader must be genuinely context-free (fresh subagent /
codex exec / new
session — repo only) or the probe is theater.
- If the repo runs multiple agents/lanes in parallel, don't touch another lane's uncommitted paths;
hand off through its board if it has one.
- When this skill and the repo disagree about the repo's conventions, the repo wins.
1---2name: iteration-close-23description: Close a product iteration the safe-but-ruthless way, in ANY repo — not tied to one product. Distill this iteration's decisions into the repo's own record, DELETE superseded baggage (git history is the archive — no _archive dirs, no .bak, no legacy- renames), verify two SEPARATE readiness channels (a confirmed cloud upload AND a tested zero-context takeover probe), rehearse the one-command new-machine bootstrap, then tag and seed the next iteration. Adapts to each repo's conventions and creates the minimum where one is missing. Run when an iteration or slice is done/approved and the user says any of — 收口 / 迭代收口 / 迭代收尾 / 收尾 / 收工 / 封版 / 发版 / 甩包袱 / 清旧账 / 蜕壳 / 这个迭代做完了 / 收尾上云 / close the iteration / wrap up this iteration / ship this iteration / finalize this iteration / done with this iteration. Also handles a STRUCTURAL overhaul as an in-repo iteration, never a new-repo restart. Product-agnostic; works in Claude Code and Codex.4---56# iteration-close — distill, shed, prove takeover, rehearse bootstrap, seed next78A product that iterates forever accumulates two silent debts, and this skill pays both down at9every iteration boundary — safely (nothing is lost) but ruthlessly (nothing dead is kept):10- Dead files linger and rot into two-truths — a deprecated tree sits around for weeks; a runbook11 keeps claiming a component is "not built" long after it shipped.12- Knowledge that lives only in a chat window dies with it — a whole working pipeline once died in13 a scratchpad; hard-won decisions nearly died in chat. Keep the lesson, not the artifact.1415It is generic: it works on any repo by reading that repo's own conventions, and where a16convention is absent it creates the minimum rather than assuming or erroring. "A fresh window or17new machine can continue" is a HOPE until it is TESTED; being current (pull) is always safe, but18publishing (push) is a deliberate choice.1920## Step 0 — orient to THIS repo (discover, else plan to create)2122Read whichever entry doc exists — `CLAUDE.md` / `AGENTS.md` / `README` / a `docs/` index — and23discover five things. Use what you find; where something is absent, note it as a gap this close24will fill (each phase below says how), never invent a path that isn't there.25261. **Lesson/decision record** — where does this repo bank decisions? (`CHANGELOG`, `docs/adr/`,27 `DECISIONS.md`, or a repo-specific register.) If none, Phase 1 creates a single `DECISIONS.md`.282. **Confirmed-upload command** — a deliberate push step (`bin/sync`, `make deploy`, a documented29 `git push` discipline)? If yes, that IS the upload channel; never bypass it. If none, Phase 3a30 uses plain `git push` after a diffstat + confirm.313. **Bootstrap command** — how does a fresh clone come alive? (`bin/bootstrap`, `bin/sync-setup`,32 `install.sh`, `make setup`, a package-manager install.) If none, Phase 4 creates one.334. **Test command** — from CI config, `package.json` scripts, a Makefile, or the language default34 (`pytest` / `go test` / `cargo test` / `npm test`). If none is discoverable, the repo has no35 runnable suite yet: treat that as an explicit state below — never read it as "green", never36 REFUSE on a repo that legitimately has none.375. **Grounding / gate skill** — a product-grounding or pre-build gate skill? If so, its38 "after-build" checklist is your pre-close gate. (Product-specific gates live inside the product39 repo; this skill stays generic and defers to them.)4041## Refuse to run (fail-closed)4243Do not close mid-iteration — you lose skin AND flesh. REFUSE if: the test suite exists and is44actually FAILING (an absent suite is not a failing one — see Step 0.4); an adversarial gate, if45the repo has one, is pending or CHANGES-REQUIRED; or another agent/lane has uncommitted mid-slice46work in paths you'd touch. Say what's blocking and stop.4748Run the phases IN ORDER. Each has an exit test; never proceed past a failed exit.4950## Phase 1 — DISTILL (salvage gate: nothing dies before its lesson is banked)51521. Sweep this iteration's chat-born decisions into the repo's decision record (Step 0.1), each53 with its status and source. **If the repo banks decisions nowhere yet, creating the record is54 part of this phase — a single `DECISIONS.md` at repo root is enough.** A decision that exists55 only in a chat window does not exist; do not leave distilled decisions with no tracked home.562. New invariants/rules discovered this iteration → the repo's contracts file, or lacking that the57 decision record — ideally each as a test. If neither exists, create the decision record and put58 them there. Delete the artifact, keep the invariant.593. Session-only-capability check: did this iteration rely on anything living ONLY in a prompt, a60 scratchpad, or someone's memory? Promote it into the repo (code / skill / doc) or record its61 deliberate exclusion. Name each one explicitly — this is where pipelines die.624. If the STRUCTURE changed, update — or, if none exists and the structure is now nontrivial,63 create — a short architecture/system note so it still describes reality. Bring any status board64 (e.g. a progress doc) current if the repo has one.6566EXIT TEST: grep this iteration's key decisions and invariants inside the repo — every one findable67in a tracked file. Anything findable only in chat = Phase 1 not done.6869## Phase 2 — SHED (ruthless deletion; git history is the ONLY archive)70711. Build a deletion inventory with evidence, one line each: `path | why dead | what supersedes it`.72 Cover superseded modules/specs, dead/empty dirs, dev residue (scratch files, `mktemp`-style73 junk, test rows in real-shaped stores), completed plan/TODO docs, and STALE DOCS — run a74 docs-vs-code contradiction pass; a doc that asserts what the code contradicts is worse than none.752. Rules: `git rm` only. NO `_archive/` dirs, NO `.bak`, NO `old-`/`legacy-` renames, NO76 commented-out corpses. Recovery = git history, one `git revert` away — that is the archive; a77 checkpoint commit before deleting makes it bulletproof.783. **Never shed the product's real DATA as if it were dev residue.** User/customer state, saved79 sessions, real archives of user content look like clutter and are the product's soul. When a80 directory could be either, treat it as data and keep it; verify before any `git rm`.814. Commit deletions in themed groups; each message says WHY + what supersedes it.825. Post-deletion checks (all that apply must pass): if the repo has a test suite, it is green;83 dangling-reference grep for every deleted module/symbol is empty (an import of a deleted file84 crashes at startup — a real scar); the entry doc and skill docs reference no deleted path.8586EXIT TEST: `git status` clean, no archive-shaped dirs exist, dangling grep empty, and the test87suite green if one exists.8889## Phase 3 — TWO READINESS CHANNELS (different needs; verify separately)9091Uploading and being-continuable are NOT the same problem. Conflating them is how a repo gets92"pushed to the cloud" while its real state still lives in a chat log. Verify each on its own.9394### 3a. Confirmed cloud upload (the TRANSPORT problem)951. Secret scan on TRACKED files only (sk-ant / ghp_ / gho_ / github_pat / AKIA / xox[baprs] /96 consumer_secret / access_token / Bearer / BEGIN PRIVATE KEY / .env shapes). Any hit → stop,97 scrub, re-scan.982. Check `git remote`. If there is NO remote, upload needs one the USER provides — adding a remote99 is a config change, so confirm it with the user or record "no remote yet — publish deferred"100 and skip to 3b rather than erroring on a bare git command.1013. With a remote: show `git log @{u}..HEAD --oneline` + diffstat (fall back to "all local commits"102 when there is no upstream yet) — exactly what will leave this machine.1034. Upload via the repo's confirmed-upload command (Step 0.2) after the user confirms; if the repo104 has none, `git push` after the diffstat and a yes. Never auto-push.105106### 3b. Zero-context takeover (the KNOWLEDGE-COMPLETENESS problem) — the cold-start probe1071. Get ONE genuinely context-free reader onto the repo — in Claude Code: spawn a fresh subagent108 (Task tool); in Codex: run a fresh `codex exec` or a new session with no prior context; on any109 bare harness: open a new session and paste ONLY the repo path plus the questions, never this110 conversation. Give it only the repo path and: "Read this repo cold from its entry doc. Then111 answer: (1) what is this product, in one sentence; (2) where does the work stand (done / next);112 (3) what would you do next and why; (4) name three things you must never do here."1132. Grade its answers against the repo's canonical docs. **If the repo has no entry/canonical doc114 at all, creating a minimal one (the product in one sentence, current state done/next, three115 never-dos) is part of this close — it is the artifact the probe grades. Do not run the probe116 against nothing.**1173. Every wrong or missing answer is a TAKEOVER-DOC BUG, not the probe's fault. Fix (or create) the118 doc, re-run with a NEW fresh reader. Loop until a cold reader scores 4/4.119120EXIT TEST: probe passes 4/4. Only then is "any new window / machine can continue" a tested fact.121122## Phase 4 — ONE-COMMAND BOOTSTRAP (rehearsed, not assumed)1231241. Ensure the repo's bootstrap (Step 0.3) exists and is current — idempotent, safe to re-run:125 verify toolchain versions; wire sync/config; install deps; run the test suite if one exists;126 print the current status + the NAMES of any missing local secrets (never values, e.g.127 "config.local.json absent — needed only for live publish"); exit non-zero on any failure with a128 one-line reason. If no bootstrap exists yet, this is the iteration to create one.1292. REHEARSE it: clone the repo into a scratch dir (from the origin URL, or from the local repo path130 when there is no remote yet) and run the bootstrap there. It must end green with ZERO manual131 steps. Delete the rehearsal clone after.1323. The new-machine story must be one line and TRUE after this rehearsal:133 `git clone <origin-url> <dir> && cd <dir> && <bootstrap command>`. If no remote exists yet, note134 that this line is not yet true until the user sets one — don't publish it as if it works.135136EXIT TEST: the rehearsal clone bootstraps green, untouched by hands.137138## Phase 5 — CLOSE + SEED (continuity)1391401. Tag the iteration: `git tag iter-<N>-<slug>` (annotated, one-line summary). N = 1 + the count of141 existing `iter-*` tags (`git tag --list "iter-*"`); the first close is iter-1.1422. Update the status board / log with one line, if the repo has one: what was distilled, how many143 files shed, probe 4/4, bootstrap rehearsed.1443. Emit the NEXT-ITERATION SEED into chat: the open questions this iteration surfaced + a145 paste-ready kickoff prompt for the next slice (goal, acceptance, and a reminder to run the146 repo's grounding gate before building, if it has one).147148## Major iteration — when the STRUCTURE itself is replaced (same rules, bigger skin)149150A structural overhaul — new architecture, new module tree, even "the old approach was wrong" — is151still an ITERATION of one organism, not a restart. It keeps its git history, its decisions, its152lessons; only the skin is new. History is unambiguous that restarts bleed: every time a project153was reborn in a fresh repo, lesson-grade material was left behind. So:154155- Grow the new structure IN THIS REPO alongside the old (strangler pattern): the new tree earns156 tests and ownership first; the old tree dies in Phase 2 only once nothing references it.157- Opening a NEW repo is the expensive exception, not the default — it requires a recorded decision158 stating why THIS history must be abandoned, approved before any files move.159- Same five phases; the deletion inventory is just larger and the cold-start probe matters more —160 the new structure's docs have never met a stranger.161- If the product's name or entry command changes, Phase 4's one-line story updates in the SAME162 iteration. Two live names is a two-truths bug.163164## Guardrails (non-negotiable)165166- Phase order is the safety mechanism: NEVER shed (Phase 2) before distill (Phase 1) exits.167- Deletion needs evidence of supersession, not vibes. Genuinely unsure? Keep it ONE more iteration168 and record the doubt in the decision record — not in an archive dir.169- Push is a confirmed act, always. No auto-push, no bypassing the repo's upload step.170- The cold-start reader must be genuinely context-free (fresh subagent / `codex exec` / new171 session — repo only) or the probe is theater.172- If the repo runs multiple agents/lanes in parallel, don't touch another lane's uncommitted paths;173 hand off through its board if it has one.174- When this skill and the repo disagree about the repo's conventions, the repo wins.