| name | plan |
| description | Turn a ratified tests.manifest.json into an executable plan — scaffold phases, fill decision slots inline, run environment spikes as verification probes, lint, delta-review, bake baselines, and land one plan commit. The generation half of the build pipeline; everything it produces is a file, so /build resumes from disk. Run after /spec, before /build, for large multi-phase tasks. |
| argument-hint | Path to task spec (e.g., docs/tasks/043-harness-redesign) |
Plan
Turn ratified intent (tests.manifest.json from /spec) into an executable plan: phase files with filled decision slots, spike verdicts on disk, baked baselines, one plan commit. You (the main session) generate; agents only verify (spikes, delta review). Everything this stage produces is a file — /build reads them back and needs none of this context.
Bootstrap — fail loudly
- Spec artifacts in
<task-path>: requirements.md (R<n> ids), tests.manifest.json (schema 1, rows status: ratified), mechanics.md when the spec wrote one. Missing → stop; /spec has not run.
- Scripts in
~/.claude/skills/build/bin/: scaffold, plan-lint, join. --help on each (no task path needed) is the contract.
- Not on
master/main. On a default branch, stop and ask for a working branch.
Step 0: Baseline
- Parse
<task-path>. Record git rev-parse HEAD as <base> (scaffold writes it into checklist.json; /build reads it back).
- Run the fast gate once at
<base>. A pre-existing red baseline is a spec precondition defect — stop and report, never plan on red.
Step 1: Scaffold
bin/scaffold <task-path> partitions manifest rows by phase into plan/checklist.json + one plan/phase-<id>.md skeleton each (rows, touches, validation, seams, empty DECISION SLOTS). Filenames and schema are the script's — never hand-write them.
Step 2: Fill decision slots — inline
For each phase, fill its three slots yourself, editing only the SLOT lines:
- ordering-rationale: instantiation order and why (group by seam; where migrations sit; which rows share fixtures).
- batch-boundary: which rows land in one red batch vs separate red-green cycles, and why.
- fallback-scope: what gets stubbed first if the phase is stopped or blocked (stubAllow globs are the legal stub surface).
Read on demand: a phase's rows and the mechanics sections its touch paths reference. Load what the slot needs, not the whole spec.
Step 3: Spikes — agents verify environment boundaries
For each spike the manifest lists, spawn one agent (Workflow parallel, model: 'sonnet', schema-validated) to run a throwaway probe of an environment assumption the plan bets on (an index actually serving a query, a script reproducing a semantics, a migration keeping counters consistent). Rules the prompt carries: throwaway files under scratch only, never touch repo files, remove containers when done, evidence = actual command output. Verdicts return as data — alive | dead | inconclusive.
Record each verdict the moment it returns: bin/join <task-path> --spike '<row-json>'. A dead spike killed a mechanism the plan assumed — it becomes an amendment proposal (bin/join --propose) before any phase depending on it starts, and the task-tier join keeps blocking it until an amendment referencing the spike is ratified.
Step 4: Lint
bin/plan-lint <task-path> — row↔phase bijection, deps DAG, touches exist, row-report coverage (a --tests-filtered validation command must match every non-green-only row FQN, else its report never reaches the gate), drives seams resolve, exception globs, validation dry-run, parallel-phase touch disjointness, decision enforcement. Failures re-fill the offending slot (bounded: 2 rounds), then carry to the delta review as findings.
Step 5: Delta review — one agent
One agent (model: 'opus', effort: 'high') reads ONLY the filled slots + lint report + spike results (~20 lines) and challenges boundaries and ordering. Apply accepted changes yourself.
Step 6: Ratify + commit
- User gate: surface every proposed amendment with AskUserQuestion (ratify / reject / defer); record each via
bin/join <task-path> --resolve '{"id": …, "status": …}'. This is the plan stage's one blocking human gate — it sits here, at an idle boundary, so nothing downstream waits on it. Ratified structural decisions get their enforcement rule noted on the owning phase.
- Plan commit: stage
plan/ + tests.manifest.json explicitly and commit (self-contained message, no session narrative). Bake baselines in the same step: run the benchmark once at <base> and the slow analyzer once, saving both under <state-dir>/baselines/.
- Hand off: tell the user the plan is committed;
/build <task-path> resumes from these files.