Skill v1.0.1
currentAutomated scan85/10055 files
name: iterative-planner description: > State-machine driven iterative planning and execution for complex coding tasks. Cycle: Explore → Plan → Execute → Reflect → Pivot. Filesystem as persistent memory. Use for multi-file tasks, migrations, refactoring, failed tasks, or anything non-trivial. version: __SKILL_VERSION__ released: __SKILL_DATE__ commit: __SKILL_COMMIT__
Iterative Planner
Core Principle: Context Window = RAM. Filesystem = Disk. Write to disk immediately. The context window will rot. The files won't.
`{plan-dir}` = plans/plan-YYYY-MM-DDTHHMMSS-XXXXXXXX/ (active plan directory under project root; UTC timestamp, colon-free, 8-hex tail). Directories created before v2.36.0 use the legacy shape plans/plan_YYYY-MM-DD_XXXXXXXX/ — never generated again, but always still read: every id-recognizing path (pointer, retire, anchor scan, ## <plan-id> sections, *Plan:* preamble, sliding-window trim, INDEX date) accepts the union of both grammars. Discovery: plans/.current_plan contains the plan directory name. One active plan at a time. Cross-plan context: plans/FINDINGS.md, plans/DECISIONS.md (merged on close), plans/LESSONS.md (rewritten on close), plans/SYSTEM.md (system atlas — domain-neutral map of the target system, rewritten on close), plans/INDEX.md (topic→directory map, survives sliding-window trim). Caps + R/W rules: File Lifecycle Matrix.
Orchestrator Role Assumption (READ FIRST)
This skill is driven by a state-machine orchestrator. The authoritative runtime dispatch logic — sub-agent spawning, the six Presentation Contracts, the PLAN compression gate, and the EXECUTE pre-step gate — lives in agents/ip-orchestrator.md, NOT in this file. This file is the protocol and state-machine specification; agents/ip-orchestrator.md is the procedure you execute.
On activation, determine your mode:
- Already the orchestrator — if you were launched as
iterative-planner-orchestrator(viaclaude --agent iterative-planner-orchestrator) OR you have already readagents/ip-orchestrator.mdand assumed that role earlier in this conversation: do NOT re-read it and do NOT spawn another orchestrator. You ARE the orchestrator — continue with the dispatch logic you already hold. This guard is evaluated FIRST and short-circuits the reload loop that would otherwise arise becauseagents/ip-orchestrator.mddeclaresskills: [iterative-planner](loading it re-loads this skill). - Agent definitions installed — if
agents/ip-orchestrator.mdis readable and you are NOT already operating as the orchestrator: immediately Readagents/ip-orchestrator.mdand assume that role for the remainder of this conversation. Resolveagents/ip-orchestrator.mdagainst the skill base directory the harness announces on activation (the "Base directory for this skill: ..." line). Treat its Sub-Agent Dispatch Rules, Presentation Contracts, compression gate, and pre-step gate as your operating procedure. Adopt the role in-thread — do NOT spawn or launch a separateiterative-planner-orchestratoragent. On first activation, FIRST emit the version + credit banner as the load-up line — runnode <skill-path>/scripts/bootstrap.mjs bannerand surface its stdout verbatim — then announce the live mode with one user-visible line — e.g.[iterative-planner] orchestrator engaged — dispatching specialized sub-agents.— so the user sees the version and credit and knows sub-agent dispatch is active. Then begin bootstrapping. - Monolithic fallback — if
agents/ip-orchestrator.md(and theagents/ip-*.mddefinitions) are NOT installed: run the full protocol yourself in this single thread, driving the state machine from this file's spec — the per-state operative rules come from theemit-staterouter (see below), NOT from inline bodies (the Per-State Rules section is summaries + pointers only) — and FIRST emit the version + credit banner as the load-up line — runnode <skill-path>/scripts/bootstrap.mjs bannerand surface its stdout verbatim — then announce the degraded mode with one user-visible line on activation — e.g.[iterative-planner] sub-agent definitions not found — running monolithic (single-thread) mode.— so the user sees the version and credit and silent degradation becomes a visible signal. UseTasksubagents where this file calls for parallel work (EXPLORE, REFLECT review). The state machine, gates, leash, and Presentation Contracts (references/file-formats.md) are identical — you are simply both coordinator and worker. In this mode you also runnode <skill-path>/scripts/emit-state.mjs --state <state>on entering each of EXPLORE/PLAN/EXECUTE/REFLECT/PIVOT and follow its output as the operative per-state rules (the Per-State Rules section here is now a summary + pointer; the scripts ship with the skill bundle, so the router resolves even without agent definitions installed).
Idempotency rule: the trigger for reading agents/ip-orchestrator.md is "not yet operating as the orchestrator." Once you have read it once in this conversation, condition 1 holds for every subsequent skill re-trigger — you never read it twice, and there is no spawn, so no reload loop.
Resolving <skill-path>
<skill-path> is the skill's installed base directory — the one the harness announces to the activating conversation ("Base directory for this skill: ..."). It is the single definition; everything below is a pointer to it.
- The orchestrator sees that announcement and holds the absolute path.
- Sub-agents do not. So the orchestrator MUST pass it down: every spawn prompt opens with a
SKILL PATH: <absolute-path>line. A sub-agent resolves<skill-path>from that line — nowhere else. - Fallback (line absent, e.g. an out-of-band dispatch): use the installed skill bundle,
~/.claude/skills/iterative-planner/. - It is NEVER a path relative to the target project's root. A shipped prompt that says
src/scripts/<x>.mjsis always wrong: a consuming project has nosrc/scripts/and the invocation silently resolves to nothing, disabling whatever check it was supposed to run. This failure is mechanically gated —scripts/check-agent-wiring.mjsrules (a) and (d).
State Machine
stateDiagram-v2[*] --> EXPLOREEXPLORE --> PLAN : enough contextPLAN --> EXPLORE : need more contextPLAN --> PLAN : user rejects / revisePLAN --> EXECUTE : user approvesEXECUTE --> REFLECT : phase ends/failed/surprise/leashREFLECT --> CLOSE : all criteria metREFLECT --> PIVOT : failed / better approachREFLECT --> EXPLORE : need more contextREFLECT --> EXECUTE : same-iteration completion-fixPIVOT --> PLAN : new approach readyCLOSE --> [*]
| State | Purpose | Allowed Actions | |
|---|---|---|---|
| EXPLORE | Gather context | Read-only on project. Write only to {plan-dir}. | |
| PLAN | Design approach | Write plan.md. NO code changes. | |
| EXECUTE | Implement step-by-step | Edit files, run commands, write code. | |
| REFLECT | Evaluate results | Read outputs, run tests, review diffs. Update verification.md, decisions.md. | |
| PIVOT | Revise direction | Log pivot in decisions.md. Do NOT write plan.md yet. | |
| CLOSE | Finalize | Audit decision anchors. Append this plan's anchored decisions to plans/ANCHORS.md. Write summary.md. Merge findings/decisions. Rewrite LESSONS.md (trim by importance-then-recency, never drop [I:5] — see ip-archivist Step 4) + SYSTEM.md atlas (demote-by-staleness — see ip-archivist Step 5). Compress consolidated files if needed. Caps: Lifecycle Matrix. |
Transitions
| From → To | Trigger | |
|---|---|---|
| EXPLORE → PLAN | Sufficient context. ≥3 indexed findings in findings.md. | |
| PLAN → EXPLORE | Can't state problem, can't list files, or insufficient findings. | |
| PLAN → PLAN | User rejects plan. Revise and re-present. | |
| PLAN → EXECUTE | User explicitly approves. | |
| EXECUTE → REFLECT | Execution phase ends (all steps done, failure, surprise, or leash hit). | |
| REFLECT → CLOSE | All criteria verified PASS in verification.md, no regressions, no simplification blockers. User confirms. | |
| REFLECT → PIVOT | Failure or better approach found. | |
| REFLECT → EXPLORE | Need more context. | |
| REFLECT → EXECUTE | Completion-fix remediation surfaced during REFLECT: small fixes to finish the SAME iteration's work (not a new approach → not PIVOT; not more context → not EXPLORE). Same iteration only — iter does not increment. Not a general re-loop. A fix that repairs plan step M is numbered as a sub-step of it, iter-N/step-M.K (K counts 1, 2, … over successive fixes to that same step), so the changelog step field always names a numbered step. The declared counter stays flat across these round trips, but the enforced iteration cap does not (see Iteration Limits, below). | |
| PIVOT → PLAN | New approach formulated. Decision logged. |
Bootstrap shortcuts:bootstrap.mjs closeallows closing from any state (EXPLORE→CLOSE, PLAN→CLOSE, EXECUTE→CLOSE, PIVOT→CLOSE). These are administrative exits — the protocol CLOSE steps (summary.md, decision audit, LESSONS.md update) should be completed by the agent before runningclose. These four edges — plus two more bootstrap-generated ones,UNKNOWN→CLOSE(fallback close from a corrupt/unreadable state.md) andCLOSE→CLOSE(idempotent re-close) — are deliberately absent from the Mermaid diagram above and from the Transitions table; the diagram and table show only the primary protocol flow.VALID_TRANSITIONSinvalidate-plan.mjsis the authoritative list of every transition the validator accepts — read it, not the diagram, for the complete transition set.
Every transition → log in state.md. PIVOT transitions → also log in decisions.md (what failed, what learned, why new direction). At CLOSE → audit decision anchors (references/decision-anchoring.md). Merge per-plan findings/decisions to plans/FINDINGS.md and plans/DECISIONS.md. Update plans/LESSONS.md with significant lessons (rewrite to ≤200 lines). Compress consolidated files if >500 lines (see "Consolidated File Management").
Protocol Tiers
Check tiers: CORE (always enforced) | EXTENDED (iter ≥ 2 unless a rule's own marker states otherwise; marked (EXTENDED) in rules below). EXTENDED checks address anchoring bias, ghost constraints, prediction drift.
Mandatory Re-reads (CRITICAL)
These files are active working memory. Re-read during the conversation, not just at start.
| When | Read | Why | |
|---|---|---|---|
| Before any EXECUTE step | state.md, plan.md, progress.md | Confirm step, manifest, fix attempts, progress sync | |
| Before writing a fix | decisions.md | Don't repeat failed approaches. Check 3-strike. | |
Before modifying DECISION-commented code | Referenced decisions.md entry | Understand why before changing | |
| Before PLAN or PIVOT | decisions.md, findings.md, findings/*, plans/LESSONS.md, plans/SYSTEM.md, plans/DECISIONS.md (PLAN only), changelog.md (PIVOT only) | Ground plan in known facts + institutional memory + system atlas | |
| Before any REFLECT | plan.md (criteria + verification strategy + assumptions), progress.md, verification.md, findings.md, checkpoints/*, decisions.md, changelog.md | Phase 1 Gate-In: full context before evaluating | |
| Every 10 tool calls | state.md | Reorient. Right step? Scope crept? |
|messages| > 50 → re-read state.md + plan.md before every response. Files are truth, not memory.
When decisions.md or changelog.md contain a <!-- COMPRESSED-SUMMARY --> block, the block is your fast-path for D-NNN lookup / changelog overview — the raw entries below the block remain authoritative.
Bootstrapping
node <skill-path>/scripts/bootstrap.mjs "goal" # Create new plan (backward-compatible)node <skill-path>/scripts/bootstrap.mjs new "goal" # Create new plannode <skill-path>/scripts/bootstrap.mjs new --force "goal" # Close active plan, create new onenode <skill-path>/scripts/bootstrap.mjs resume # Re-entry summary for new sessionsnode <skill-path>/scripts/bootstrap.mjs status # One-line state summarynode <skill-path>/scripts/bootstrap.mjs close # Close plan (preserves directory)node <skill-path>/scripts/bootstrap.mjs list # Show all plan directoriesnode <skill-path>/scripts/bootstrap.mjs banner # Print version + credit banner (no active plan needed)node <skill-path>/scripts/bootstrap.mjs retire <plan-id> # Mark a removed plan's DECISION anchors [STALE], drop its dirnode <skill-path>/scripts/bootstrap.mjs reset-attempts # Clear active plan's Fix Attempts (unjam stale leash counter)node <skill-path>/scripts/validate-plan.mjs # Validate active plan compliance
new refuses if active plan exists — use resume, close, or --force. new ensures .gitignore includes plans/ — prevents plan files from being committed during EXECUTE step commits. close merges per-plan findings/decisions to consolidated files, updates state.md, appends to plans/INDEX.md, snapshots plans/LESSONS.md to the plan directory, and removes the .current_plan pointer. The protocol CLOSE state (writing summary.md, auditing decision anchors, updating plans/LESSONS.md) should be completed by the agent before running close. After bootstrap → read every file in `{plan-dir}` (state.md, plan.md, decisions.md, findings.md, progress.md, verification.md, changelog.md) before doing anything else. Then begin EXPLORE. User-provided context → write to findings.md first.
Filesystem Structure
plans/├── .current_plan # → active plan directory name├── FINDINGS.md # Consolidated findings across all plans (merged on close)├── DECISIONS.md # Consolidated decisions across all plans (merged on close)├── LESSONS.md # Cross-plan lessons learned (≤200 lines, rewritten on close)├── LESSONS-archive.md # Lines dropped by the LESSONS.md trim, appended on close (conditional — not created by bootstrap)├── SYSTEM.md # System atlas — domain-neutral map of the target system (≤300 lines, rewritten on close)├── INDEX.md # Topic→directory mapping (updated on close, survives trim)├── ANCHORS.md # Committed, append-only manifest — one line per anchored decision (appended on close)└── plan-2026-02-14T103055-a3f1b2c9/ # {plan-dir} (legacy dirs: plan_2026-02-14_a3f1b2c9/)├── state.md # Current state + transition log├── plan.md # Living plan (rewritten each iteration)├── decisions.md # Append-only decision/pivot log├── findings.md # Summary + index of findings├── findings/ # Detailed finding files (subagents write here)├── progress.md # Done vs remaining├── verification.md # Verification results per REFLECT cycle├── changelog.md # Per-edit ledger (one line per file edit, append-only)├── checkpoints/ # Snapshots before risky changes├── lessons_snapshot.md # LESSONS.md snapshot at close (auto-created)└── summary.md # Written at CLOSE
Templates: references/file-formats.md
File Lifecycle Matrix
R = read only | W = update (implicit read + write) | R+W = distinct read and write operations | — = do not touch (wrong state if you are).
Read-before-write rule: Always read a plan file before writing/overwriting it — even on the first update after bootstrap. Claude Code's Write tool will reject writes to files you haven't read in the current session. This applies to every W and R+W cell below.
| File | EXPLORE | PLAN | EXECUTE | REFLECT | PIVOT | CLOSE | |
|---|---|---|---|---|---|---|---|
| state.md | W | W | R+W | W | W | W | |
| plan.md | — | W | R+W | R | R | R | |
| decisions.md | — | R+W* | R+W | R+W | R+W | R+W‡ | |
| findings.md | W | R | — | R | R+W | R | |
| findings/* | W | R | — | R+W† | R+W | R | |
| findings/hygiene-iter-N[-passM].md | — | — | — | R+W | — | R | |
| progress.md | — | W | R+W | R+W | W | R | |
| verification.md | — | W | — | W | R | R | |
| changelog.md | — | W* | W (append) | R | R | R | |
| checkpoints/* | — | — | W | R | R | — | |
| summary.md | — | — | — | — | — | W | |
| plans/FINDINGS.md | R(600) | R? | — | — | — | W(merge+compress) | |
| plans/DECISIONS.md | R(600) | R(600) | — | — | — | W(merge+compress) | |
| plans/LESSONS.md | R | R | — | — | R | W(rewrite≤200) | |
| plans/LESSONS-archive.md | — | — | — | — | — | W (overflow archive) | |
| plans/SYSTEM.md | R | R | — | — | R | W(rewrite≤300) | |
| plans/INDEX.md | R? | — | — | — | — | W(append via bootstrap) | |
| plans/ANCHORS.md | — | — | — | — | — | W(append) | |
| lessons_snapshot.md | — | — | — | — | — | W(auto via bootstrap) |
R? = read on demand only, not as part of the eager cross-plan read set. See EXPLORE rules below for the triggers that warrant an INDEX.md read. plans/FINDINGS.md at PLAN is R? because the plan-writer reads per-plan findings/* files (already in PLAN dispatch), not the cross-plan consolidated plans/FINDINGS.md, unless explicitly needed for cross-plan context.
* Intra-plan compression runs at PLAN gate-in (decisions.md >300 lines, changelog.md >200 lines). The two files compress differently, and the difference matters when you later read them as evidence:
decisions.mdis bounded: a<!-- COMPRESSED-SUMMARY -->block is inserted above the entries and nothing else is written. Every## D-NNNentry survives verbatim.changelog.mdis lossy: a run of 5 or more low-decision-impact lines is DELETED and replaced by one- (compressed: N low-decision-impact edits, ...)line. So a compressed changelog is not a complete per-edit ledger — anything that reads it as one (PIVOT keep-vs-revert, the reviewer's REFLECT scan) must treat an elision line as unexpanded evidence and fall back to git history.
† At REFLECT two files under findings/ are written: the Reviewer's own findings/review-iter-N[-passM].md, and the BoyScout's findings/hygiene-iter-N[-passM].md when the hygiene sweep runs. The explorer topic files stay read-only. The Ownership table below carries a matching row for each of the two.
‡ decisions.md is append-only and past entries are never edited. The one authorized exception: at CLOSE, the Archivist may back-fill a past entry's **Anchor-Refs**: line (Step 1 remediation) — that field, that agent, that phase, and nothing else. (agents/ip-archivist.md Step 1 is where the Archivist performs it.) No new entries are authored at CLOSE.
See references/file-formats.md § Intra-plan compression.
Consolidated File Management
plans/FINDINGS.md and plans/DECISIONS.md grow across plans. Two mechanisms prevent context window bloat:
Sliding window: on each close, bootstrap keeps the 25 most recent plan sections. A section past the window is dropped only when its per-plan directory still exists on disk (trimConsolidatedWindow in scripts/bootstrap.mjs tests existsSync per section) — that directory is then the second copy, so dropping loses nothing. A section whose directory is gone is the last copy of that plan's findings/decisions and is RETAINED past the window, with a RETAINED: N section(s)… line printed by close. Plan directories are ephemeral and the plans/ glob is gitignored, so retention is normal, not exceptional: the window bounds how many live plans are carried, not the file's size. Use plans/INDEX.md to locate trimmed plans by topic, and the compression protocol below once a file passes 500 lines.
Read limit: Always read consolidated files with limit: 600. The compressed summary + most recent plan sections fit within this.
Compression (rarely needed — sliding window keeps files bounded): Threshold: >500 lines → compressed summary needed. Bootstrap prints ACTION NEEDED after merge.
Compression protocol (during CLOSE, after merge):
- Check line count. If ≤500 → no action needed.
- If >500 and NO
<!-- COMPRESSED-SUMMARY -->marker exists → create new summary. - If >500 and marker already exists → REPLACE content between markers. Never summarize the old summary — read only the raw plan sections below the markers to write the new summary.
Format — insert between H1 header and first ## <plan-id> section:
<!-- COMPRESSED-SUMMARY -->## Summary (compressed)*Auto-compressed from N lines. Read full content below line 600 if needed.*### Key Findings-(≤50 lines of consolidated findings across all plans)### Key Decisions-(≤50 lines of consolidated decisions across all plans)<!-- /COMPRESSED-SUMMARY -->
Rules:
- Max 100 lines between markers (total, including section headers).
- Focus on: outcomes, active constraints, things NOT to do (failed approaches), anchored decisions.
- Drop: iteration details, timestamps, verbose reasoning — those survive in full content below.
- Failsafe: when writing the summary, SKIP everything between
<!-- COMPRESSED-SUMMARY -->and<!-- /COMPRESSED-SUMMARY -->markers. Only summarize the actual plan sections (## <plan-id>). This prevents summaries of summaries.
Intra-plan compression (v2.18.0+): per-plan {plan-dir}/decisions.md and {plan-dir}/changelog.md have their own compression triggered at PLAN gate-in (different thresholds, different shapes). See references/file-formats.md § Intra-plan compression (under each file's section).
Lessons Learned (plans/LESSONS.md)
Institutional memory across plans. Unlike FINDINGS.md / DECISIONS.md (append+merge), LESSONS.md is rewritten every CLOSE; cap in Lifecycle Matrix.
- Read: EXPLORE start, before PLAN, before PIVOT.
- Update (CLOSE, before
bootstrap.mjs close): read current, integrate significant lessons, rewrite. Each lesson carries an inline[I:N]importance tag (1-5; untagged = implicit[I:3]). If update would exceed cap → consolidate aggressively (merge related, tighten) and trim by importance then recency: drop lowest-[I:N]entries first, oldest first within a tier, never dropping an[I:5]. - Rewrite, don't append. No "added on date X" markers.
- Keep: recurring patterns, failed approaches + why, successful strategies, codebase gotchas, surprising constraints.
- Drop: one-off findings (→ FINDINGS.md), decision reasoning (→ DECISIONS.md), plan-specific detail.
- Created automatically by bootstrap on first
new.
Per-State Rules
The operative rules for each state are emitted on demand by the routerscripts/emit-state.mjs, not inlined here. On entering a state, runnode <skill-path>/scripts/emit-state.mjs --state <state>and follow its stdout as the authoritative per-state rules. Full module text lives inscripts/modules/state-<state>.md. (This keeps SKILL.md's resident context to the spine; per-state detail is pulled only for the active state. CLOSE has no module — it lives in the State Machine / Transitions table and the ip-archivist.)
EXPLORE
Gather context: research (code, grep, glob, subagents; web via WebFetch/WebSearch when local search is insufficient), flush findings to findings.md + findings/ every 2 reads, classify constraints (hard/soft/ghost), self-assess Exploration Confidence, and reach ≥3 indexed findings covering scope/files/patterns before PLAN. → Operative rules: node <skill-path>/scripts/emit-state.mjs --state explore (module: scripts/modules/state-explore.md).
PLAN
Design the approach: pass the gate check + compression gate, write Problem Statement first, then plan.md with all 11 validator-required sections (Steps, verification strategy, assumptions, failure modes, pre-mortem), log decisions.md as "X at the cost of Y", seed verification.md/state.md/progress.md, then emit PC-PLAN and wait for explicit user approval. → Operative rules: node <skill-path>/scripts/emit-state.mjs --state plan (module: scripts/modules/state-plan.md).
EXECUTE
Implement one step at a time: run the Pre-Step Checklist, create the iteration-1 nuclear checkpoint, checkpoint before risky changes, commit each successful step, append the per-edit changelog line, run the 4-item Post-Step Gate, and on breakage follow the Autonomy Leash (revert-first, 2 attempts max). → Operative rules: node <skill-path>/scripts/emit-state.mjs --state execute (module: scripts/modules/state-execute.md).
REFLECT
Run the 3-phase gate: Gate-In (7 mandatory reads), Evaluate (cross-validate, diff review, run verification + regression + scope-drift + simplification checks + validate-plan.mjs), then Gate-Out (write verification.md/decisions.md/progress.md/state.md), and present the 5-item PC-REFLECT contract before routing to CLOSE / PIVOT / EXPLORE / EXECUTE. → Operative rules: node <skill-path>/scripts/emit-state.mjs --state reflect (module: scripts/modules/state-reflect.md).
PIVOT
Re-route after failure: read decisions.md/findings.md/changelog.md/plans/LESSONS.md + checkpoints/*, decide keep-vs-revert, run the ghost-constraint scan, correct stale findings, log the pivot + Complexity Assessment in decisions.md, update state.md/progress.md, then present PC-PIVOT options and get approval before returning to PLAN. → Operative rules: node <skill-path>/scripts/emit-state.mjs --state pivot (module: scripts/modules/state-pivot.md).
Complexity Control (CRITICAL)
Default response to failure = simplify, not add. See references/complexity-control.md.
These guards operationalize three principles already wired into the protocol — name them when applying: KISS (Simplification Checks #3 essential/accidental + #4 junior-dev test, references/complexity-control.md), YAGNI (Complexity Budget + earned-abstraction rule), DRY (reuse-before-write — EXECUTE Pre-Step Checklist + references/code-hygiene.md § Interface Contracts for Shared Assets).
Revert-First — when something breaks: (1) STOP (2) revert? (3) delete? (4) one-liner? (5) none → REFLECT. 10-Line Rule — fix needs >10 new lines → it's not a fix → REFLECT. 3-Strike Rule — same area breaks 3× → PIVOT with fundamentally different approach. Revert to checkpoint covering the struck area. (Advisory-only — no script counts strikes; same-iteration completion-fix/leash-override retries can blur the "across iterations" scoping — see `references/complexity-control.md` § 3-Strike Rule.) Complexity Budget — tracked in plan.md: files added 0/3, abstractions 0/2, lines net negative or neutral target. Forbidden: wrapper cascades, config toggles, copy-paste, exception swallowing, type escapes, adapters, "temporary" workarounds. Nuclear Option — iteration 5 + bloat >2× scope → recommend full revert to cp-000 (or later checkpoint if user agrees). Otherwise proceed with caution. See references/complexity-control.md.
Autonomy Leash (CRITICAL)
When a step fails during EXECUTE:
- 2 fix attempts max — each must follow Revert-First + 10-Line Rule.
- The unit: a fix attempt is one try at repairing the failed step, counted in
state.mdno matter who performs it. The step's original failure is not an attempt. Two is the total for the step, not a per-spawn allowance: with agents installed the executor makes at most ONE fix try before reporting back, so the two attempts are the two executor spawns the orchestrator records and the gate counts. Running single-threaded, you make the same two tries and record each one yourself.
- Both fail → STOP COMPLETELY. No 3rd fix. No silent alternative. No skipping ahead.
- Revert uncommitted changes to last clean commit. Codebase must be known-good before presenting.
- Present: what step should do, what happened, 2 attempts, root cause guess, available checkpoints for rollback.
- Transition → REFLECT. Log leash hit in
state.md. Wait for user.
Attempt counter in state.md. Resets on: user direction | new step | PIVOT. Reset mechanically — run bootstrap.mjs reset-attempts (clears the ## Fix Attempts section to placeholder) rather than hand-editing state.md; a stale counter carried across a PIVOT or new step otherwise HARD-blocks the pre-step gate on the next step (GATE:FAIL [leash-cap]). Known reset gap: the mechanical reset-attempts fires at three orchestrator sites — EXECUTE success, PIVOT dispatch, and REFLECT→EXECUTE re-entry. The path REFLECT→EXPLORE→PLAN→EXECUTE that starts a NEW iteration (no PIVOT, no completion-fix) passes through none of them, so a stale counter from a prior iteration's failed step can trip the leash-cap gate on the new iteration's first step. This is an accepted gap — clear it by running bootstrap.mjs reset-attempts when you start a new iteration after a leash hit. No exceptions. Unguided fix chains derail projects.
Disclosed exception — the leash-override "continue": the 2-attempt cap has exactly one sanctioned exception, and it requires the user's explicit approval every time. After a leash hit, PC-EXECUTE-LEASH item 5 asks the user to choose continue / pivot / rollback; a user-approved continue routes REFLECT → EXECUTE for a fresh attempt window on the same step (agents/ip-orchestrator.md § REFLECT State, dispatch step 6), and bootstrap.mjs reset-attempts clears the counter before re-entry so the new window is not itself pre-tripped. This is not a silent 3rd autonomous fix — "No exceptions" above governs unapproved continuation; a user-gated continue is the protocol's one designed escape hatch, not a violation of it.
Pre-step gate (v2.18.0+): node <skill-path>/scripts/validate-plan.mjs --pre-step runs before each attempt to start an EXECUTE step — in the orchestrator before each ip-executor spawn, and, when no agent definitions are installed, in the single thread itself. Both paths get the imperative from the same place, scripts/modules/state-execute.md (what emit-state --state execute emits). Exit code 2 emits one of four GATE:FAIL slugs — [no-plan], [wrong-state], [leash-cap], [iteration-cap]. [leash-cap] mechanically halts EXECUTE when 2 fix attempts are recorded — converting the leash from advisory to enforced. See agents/ip-orchestrator.md EXECUTE dispatch for the integration point and the full slug→action mapping.
Enforcement tiers — the leash is enforced at two different points, with intentionally different thresholds. Do not "align" them:
- Real-time gate (
--pre-step, exit 2): HARD-blocks the 3rd spawn — fires atattempts >= 2. This is the actual cap (2 attempts per step). - Retrospective audit (full
validate-plan.mjs,[leash]): runs over a finished/in-progress plan where 2 recorded attempts is legal (a step is allowed 2). So it WARNs at 3 (a 3rd attempt slipped past the gate) and ERRORs at 4+ (the gate was bypassed). ERRORing at 2 would false-positive on every plan that correctly used both attempts then pivoted.
Code Hygiene (CRITICAL)
Failed code must not survive. Track changes in change manifest in state.md. Failed step → revert all uncommitted. PIVOT → explicitly decide keep vs revert. Codebase must be known-good before any PLAN. See references/code-hygiene.md.
Decision Anchoring (CRITICAL)
Code from failed iterations carries invisible context. Anchor # DECISION <plan-id>/D-NNN at point of impact — state what NOT to do and why. Audit at CLOSE. See references/decision-anchoring.md.
Register Discipline (CRITICAL)
Plans are re-read every run, so their register conditions the next run's register — a positive-feedback loop that, left undamped, accretes jargon until plans stop being legible to a human (or a fresh model). The counter-force is a setpoint, not a jargon ban: coined terms are earned, not free.
- Define on first use. A coined term or
[bracket-slug]must be defined in plain words
where it first appears in a plan (or point to where it is defined). An undefined coinage is a defect, not shorthand.
- Plainest exact word wins. Prefer the plainest wording that stays precise. Jargon earns
its place only by naming a real mechanism more exactly than plain words can — density for its own sake is accidental complexity (KISS).
- Ratchet down, never up. The register-carrying docs (CLAUDE.md, SKILL.md, agents,
references) are gated by node <skill-path>/scripts/check-register.mjs: it measures jargon density against a committed per-file ceiling in register-baseline.json and fails a build whose density RISES past the ceiling. Density may fall or hold freely; raising a ceiling is a deliberate, review-visible edit — the same discipline as bumping TEST_COUNT.
- Normalize at CLOSE. ip-archivist rewrites
plans/LESSONS.md/plans/SYSTEM.mdtoward
plainness at CLOSE (define terms, drop dead jargon) so institutional memory does not carry the register forward uncorrected.
Iteration Limits
iter counter: increments on PLAN → EXECUTE. iter=0 = EXPLORE-only (pre-plan).
iter = 5: mandatory decomposition analysis indecisions.md(2-3 independent sub-goals + deps). Seereferences/planning-rigor.md.iter ≥ 6: hard STOP. Present decomposition to user. Break into smaller tasks.- Derived vs declared: the enforced cap does not trust the declared
## Iteration:
field alone. checkIterationLimits (validate-plan.mjs) computes iter = max(declared, derived), where derived counts every literal EXECUTE → REFLECT line in state.md's Transition History — including completion-fix and leash-override round trips, which leave the declared field unchanged (see Transitions table, REFLECT → EXECUTE row). This is deliberately safety-conservative (over-counting is the safe direction for a hard cap), but it means several same-iteration retries can consume iteration-cap headroom the declared field never shows, and [iteration-cap] may HARD-fail at --pre-step while ## Iteration: still reads low.
Recovery from Context Loss
- If
plans/.current_planis missing or corrupted: runbootstrap.mjs listto find plan directories — but BEFORE recreating the pointer, check the newest directory for close evidence (state.mdCurrent State: CLOSEand/orlessons_snapshot.mdpresent): if found, that plan closed legitimately — item 13 governs (nothing to resume; do not resurrect the pointer). Otherwise recreate it:echo "plan-YYYY-MM-DDTHHMMSS-XXXXXXXX" > plans/.current_plan(substitute the actual directory name — a legacyplan_YYYY-MM-DD_XXXXXXXXname is equally valid here). plans/.current_plan→ plan dir namestate.md→ where you areplan.md→ current plandecisions.md→ what was tried / failedprogress.md→ done vs remainingfindings.md+findings/*→ discovered contextcheckpoints/*→ available rollback points and their git hashesplans/FINDINGS.md+plans/DECISIONS.md→ cross-plan context from previous plansplans/LESSONS.md→ institutional memory (read before planning)plans/SYSTEM.md→ system atlas / structural prior (read before PLAN or EXPLORE)plans/INDEX.md→ grep by topic keyword (each row is one line; do not read the whole file) — topic-to-directory mapping (find old findings by topic when sliding window has trimmed them)- Resume from current state. Never start over. When resuming mid-EXECUTE (state.md names a current step), first derive the step's plan-qualified commit tag (Git Integration below: drop the plan-dir name's
THHMMSSsegment) and checkgit log --oneline --fixed-strings --grep="plan-YYYY-MM-DD-HASH/iter-N/step-M]"— keep the closing]; a bareiter-N/step-Mgrep false-positives against other plans' commits andstep-1/step-10substrings. If a commit already exists, the step completed before the interruption — run the Post-Step Gate for it instead of re-executing the step. If NO matching commit exists, checkgit status --porcelainbefore re-executing — a dirty tree means the executor died mid-step: revert uncommitted changes to the last clean commit first. Also cross-checkchangelog.md's trailing lines againstgit log— a changelog line whose commit field names no existing commit (or saysuncommitted) is limbo from the interrupted step; note it indecisions.mdbefore re-executing. - Resuming at/near CLOSE: check
plans/.current_plan. Pointer GONE = close completed — nothing to resume. Pointer PRESENT with CLOSE-shaped artifacts (summary.md exists, LESSONS.md/SYSTEM.md freshly rewritten) = the archivist was interrupted — applyagents/ip-orchestrator.mdCLOSE State step 3 (re-run archivist Steps 1-5 only as needed — they are batch-safe, see ip-archivist Rules; the Step-4/5 post-rewrite validator gates always re-run, even over rewrites the interrupted run already completed — then runbootstrap.mjs closeonce). Note the lag: state.md's CLOSE transition is written INSIDEbootstrap.mjs close(archivist Step 6), so a kill during Steps 1-5 leaves state.md at the pre-CLOSE state while the artifacts already look CLOSE-shaped;bootstrap.mjs resume/statusflag the inverse signature (state.md=CLOSE, pointer present) with an explicitINCOMPLETE CLOSEline.
Git Integration
- EXPLORE/PLAN/REFLECT/PIVOT: no commits.
- EXECUTE: commit per successful step
[plan-YYYY-MM-DD-HASH/iter-N/step-M] desc. Failed step → revert uncommitted. - Deriving the tag id: take the plan-dir name and drop the `THHMMSS` segment.
plan-2026-07-14T051317-317362c4→[plan-2026-07-14-317362c4/iter-3/step-2] desc. A legacy plan dir (plan_YYYY-MM-DD_XXXXXXXX, still executing under this protocol) derives identically, normalizing the_separators to-:plan_2026-07-14_79ee0f59→[plan-2026-07-14-79ee0f59/iter-3/step-2] desc. - The changelog `step` field carries no plan-id prefix — it always names a numbered step,
iter-N/step-M, oriter-N/step-M.Kwhen a completion fix repairs step M. Do not "fix" the apparent inconsistency with the commit tag by prefixing it. That field is sourced fromstate.md, never parsed from a commit subject; nothing in the codebase reads a commit message. Prefixing it would drag inschema.mjs/STEP_REand the compressionfrom/torange bounds for zero benefit. - PIVOT: keep successful commits if valid under new plan, or
git checkout <checkpoint-commit> -- .to revert. No partial state. Log choice indecisions.md. - CLOSE: finalizes on disk only — writes
summary.md, audits DECISION anchors, rewritesplans/LESSONS.md+plans/SYSTEM.md, merges the consolidated cross-plan files, then runsbootstrap.mjs close. No git commit or tag is created — a summarizing commit/tag at CLOSE is a documented, deferred spec item, not yet implemented (no agent or script issues any git commit/tag).
User Interaction
Sub-agents are invisible to the user — only the orchestrator's chat text reaches them. Every state transition that requires user input MUST be preceded by the corresponding Presentation Contract in the same assistant turn. Canonical definitions: references/file-formats.md "Presentation Contracts" section. The orchestrator inlines each contract's required content list at the point of dispatch in agents/ip-orchestrator.md.
| State | Contract | Behavior | |
|---|---|---|---|
| EXPLORE | PC-EXPLORE (Findings Digest) | Ask focused questions, one at a time. At handoff, emit findings index + key constraints (HARD/SOFT/GHOST) verbatim, plus exploration confidence and a synthesis paragraph. | |
| PLAN | PC-PLAN (Plan Presentation) | Goal verbatim + 2-4 sentence summary + every step verbatim + the plan.md path for the rest (assumptions, failure modes, success criteria, verification strategy, pre-mortem, complexity budget). Never truncate the Steps. Wait for approval. Re-present same contract if modified. | |
| EXECUTE | PC-EXECUTE-STEP (Per-Step Status) / PC-EXECUTE-LEASH (Leash Failure) | After each successful step: 5 fields (step + files + commit + surprises + next-preview). On leash hit: 5 fields (step intent + 2 attempts + root-cause guess + checkpoint registry + prompt). | |
| REFLECT | PC-REFLECT (Phase-3 Gate-Out 5-Item Block) | Exactly 5 items: completed / remaining / verification table verbatim / issues + reviewer concerns / recommendation + prompt. Ask user: close, pivot, explore, or execute. Never auto-close. | |
| PIVOT | PC-PIVOT (Pivot Options) | Pivot reason + checkpoint registry (verbatim) + ghost constraints + 1-3 candidate directions ("X at the cost of Y") + explicit prompt for direction and keep-vs-revert. |
Sub-Agent Architecture
The iterative planner supports optional specialized sub-agents that parallelize work within each state. If sub-agent definitions (agents/ip-*.md) are installed, the orchestrator dispatches them. If not, the monolithic skill works as before — sub-agents are an optimization layer, not a requirement.
Key constraint: Sub-agents cannot spawn other sub-agents. The orchestrator (or main agent) is the sole coordinator.
Sub-Agent Non-Response
A sub-agent can terminate WITHOUT reporting — killed by the user, harness interruption, or API failure. This is distinct from reported FAILURE (leash, revert-first, 3-strike all assume a report came back). Detection is artifact-based: the expected artifact or return value is absent, or present but partial. Never re-run a whole state from zero on a non-response — check the evidence first, then apply the per-state partial-state rule:
- EXPLORE: expected
findings/{topic-slug}.mdmissing or empty → re-spawn that topic once (orchestrator dispatch step 5; delete an empty stale copy first). - PLAN:
plan.mdtruncated or sections missing → orchestrator section-verify catches it (dispatch step 3); re-spawn naming the defective sections. - EXECUTE: killed executor → Recovery step 12 (commit-tag grep, then dirty-tree check, then changelog-tail cross-check).
- REFLECT: partial
verification.md(fewer Criteria rows than plan.md's Success Criteria) or a review file missing its## Verdictline → treat as interrupted evidence and re-spawn (for a reviewer, per the-passMnaming rule; a re-spawned verifier just returns results — verification.md has no passM scheme) (REFLECT Gate-In). Afindings/hygiene-iter-N[-passM].mdthat is missing, or that is present without its## Verdictline, is interrupted evidence in the same way: re-spawn the BoyScout under the-passMnaming rule, and do not read the file's existence as proof the sweep finished. - CLOSE: archivist interrupted → Recovery item 13 (pointer check; archivist Steps 1-5 batch-safe, Step 6 exactly once).
Agent Definitions
| Agent | File | Role | Tools | Model | |
|---|---|---|---|---|---|
| Orchestrator | agents/ip-orchestrator.md | State machine owner, coordinator | Agent, Read, Write, Edit, Bash, Grep, Glob | inherit | |
| Explorer | agents/ip-explorer.md | Codebase-first research, with web fallback | Read, Write, Grep, Glob, Bash, WebFetch, WebSearch | sonnet | |
| Plan-Writer | agents/ip-plan-writer.md | Generates plan.md + verification.md | Read, Write, Edit, Grep, Glob | inherit | |
| Executor | agents/ip-executor.md | Implements one plan step | Read, Edit, Write, Bash, Grep, Glob | inherit | |
| Verifier | agents/ip-verifier.md | Runs verification checks | Read, Bash, Grep, Glob | sonnet | |
| Reviewer | agents/ip-reviewer.md | Adversarial review (iteration ≥ 2 by default; earlier by orchestrator choice, e.g. an iteration-1 attack-before-release pass) | Read, Write, Grep, Glob, Bash | opus | |
| BoyScout | agents/ip-boyscout.md | Read-only hygiene sweep (REFLECT) | Read, Write, Bash, Grep, Glob | sonnet | |
| Archivist | agents/ip-archivist.md | CLOSE housekeeping | Read, Write, Edit, Grep, Glob, Bash | sonnet |
Known gap — unscoped Bash on read-only agents. Explorer, Verifier, Reviewer, and BoyScout are documented as read-only / never-mutate (their own Rules sections say so; all four also carry disallowedTools: Edit, Agent, and Verifier has no Write tool at all), but none of the four has any mechanical restriction on what its full, unscoped Bash grant may invoke — the read-only property is prose-enforced only for the Bash surface. This is the same parenthetical-scoping mechanism agents/ip-orchestrator.md's own YAML frontmatter demonstrates for Agent(...); whether Claude Code's subagent frontmatter supports the equivalent syntax for Bash was not confirmed as of this note, so no scoped-Bash syntax has been risked on these four production agent files. Disclosed, not fixed.
File Ownership Model
Each file has a clear owner. Only the owner writes. Others read. Co-ownership (multiple writers) is permitted where the writes are disjoint in scope and never concurrent — the orchestrator sequences the writers, and each co-owner's scope is named in the table below. In most co-owned files the orchestrator is the non-authoring co-writer: its writes are confined to Post-Step Gate cursor/ledger updates, and the named content owner does all authoring. decisions.md inverts this — the Orchestrator and Plan-writer author the entries, while the Executor writes into entries it did not author (back-filling **Anchor-Refs**:, recording DRY exceptions) inside its own step's commit rather than at a Post-Step Gate.
| File | Owner (Writes) | Readers | |
|---|---|---|---|
state.md | Orchestrator | All agents | |
plan.md | Plan-writer (full rewrite) + Orchestrator (Post-Step Gate: step checkbox, marker, complexity budget) | Orchestrator, Executor, Verifier, Reviewer | |
decisions.md | Orchestrator + Plan-writer (author entries) + Executor (back-fills Anchor-Refs on anchored entries, records DRY exceptions) + Archivist (CLOSE-time Anchor-Refs backfill remediation, ip-archivist.md Step 1) | All agents | |
findings.md (index) | Orchestrator | Plan-writer, Reviewer | |
findings/{topic}.md | Explorer (one per file; orchestrator may delete an empty stale copy before a re-spawn, and appends [CORRECTED iter-N] annotations at PIVOT) | Orchestrator, Plan-writer | |
findings/review-iter-N[-passM].md | Reviewer | Orchestrator | |
findings/hygiene-iter-N[-passM].md | BoyScout | Orchestrator | |
progress.md | Orchestrator (Post-Step Gate) | All agents | |
verification.md | Plan-writer (template) + Orchestrator (merges Verifier's returned results) | Orchestrator, Reviewer | |
changelog.md | Executor (append per edit) + Orchestrator (PLAN gate-in compression, which deletes elidable lines; Post-Step Gate: confirm one line per edited file) | Orchestrator (REFLECT Gate-In), Reviewer (REFLECT scan) | |
checkpoints/* | Executor | Orchestrator (for PIVOT + EXECUTE leash-hit) | |
summary.md | Archivist | — | |
plans/FINDINGS.md | Archivist (via bootstrap) | Orchestrator, Plan-writer | |
plans/DECISIONS.md | Archivist (via bootstrap) | Orchestrator, Plan-writer | |
plans/LESSONS.md | Archivist | Orchestrator, Explorer, Plan-writer | |
plans/LESSONS-archive.md | Archivist (append-only; created on first over-cap LESSONS trim) | — (forensic aid, read by no protocol step) | |
plans/SYSTEM.md | Archivist | Orchestrator, Plan-writer, Explorer | |
plans/INDEX.md | Archivist (via bootstrap) | Orchestrator | |
plans/ANCHORS.md | Archivist (append-only; one line per anchored decision at CLOSE; created by bootstrap) | validate-plan.mjs (anchor resolution), Orchestrator, Archivist |
Dispatch Rules by State
Runtime dispatch — which agents to spawn per state, in what order, with the compression gate (PLAN step 0.5) and pre-step gate (EXECUTE step 1.5) — is owned by agents/ip-orchestrator.md § "Sub-Agent Dispatch Rules". That file is authoritative; do not duplicate its sequencing here. The per-state protocol (gate checks, leash, rigor) is specified above under the Per-State Rules. Monolithic mode (no agents installed) runs the same sequence single-threaded using Task subagents for the parallel steps.
Conflict Prevention
- No concurrent writes to the same file — orchestrator sequences agents accordingly.
- Explorer agents write to distinct
findings/{topic}.mdfiles — unique topic slugs. - Verifiers never write
verification.md— they RETURN structured results; the orchestrator is the sole writer, merging each verifier's returned results into distinct sections (so there are no concurrent writes). - Exactly one Executor is spawned at a time (plan steps are sequential), so no two executors are ever concurrent and executor file conflicts cannot arise.
When NOT to Use
Simple single-file changes, obvious solutions, known-root-cause bugs, or "just do it".
References
references/file-formats.md— templates for all{plan-dir}filesreferences/complexity-control.md— anti-complexity protocol, forbidden patternsreferences/code-hygiene.md— change manifest, revert proceduresreferences/decision-anchoring.md— when/how to anchor decisions in codereferences/planning-rigor.md— assumption tracking, pre-mortem, falsification signals, exploration confidence, prediction accuracyreferences/root-cause-analysis.md— structured methods for the failure-time RCA step (5 Whys, fishbone category scan, optional fault tree, Cynefin selector); domain-agnostic corereferences/convergence-metrics.md— convergence score, momentum tracker, iteration health signalsreferences/blast-radius.md— per-edit blast-radius signals + scoring (used byscripts/blast-radius.mjs, written tochangelog.md)references/python-software.md— domain caveats for software-engineering tasks, any language including Python (consult only for software-engineering work; not part of the domain-neutral core)