/execute-plan — Plan Executor with Staged Reviews
Purpose: Execute a written implementation plan with a staged review sequence: validate-plan → per-task build/test → breakpoint review at each milestone → full code review + professional (craft) review at the PR boundary → optional adversarial review.
When to Use
- You have a written plan file ready to execute.
- You want per-task build/test cycles plus staged code reviews.
- You want a seniority-calibrated craft grade on the final output.
When NOT to Use
- No plan exists yet — write a plan first.
- Trivial single-file change — just make the edit directly.
Arguments
| Argument | Description |
|---|---|
<path> |
Path to the plan file (optional; if omitted, finds the most recent .md in docs/plans/). |
--interactive=<yes|no|auto> |
How to handle execution-time ambiguity (see Phase 1.5). Default: auto. yes = pause and ask on every ambiguity; use when a human is supervising. no = batch / CI mode; never prompt; on ambiguity, abort cleanly and log the question in the final report's ## Open Questions section. auto = detect TTY; prompt if present, otherwise abort. |
--force |
Bypass the refuse-on-FAIL contract (see Phase 0). validate-plan returning FAIL still runs /execute-plan anyway. For humans only; never set by the harness or by default. Use is logged prominently in the final execution report so the bypass is auditable. |
--resume |
Resume a previously aborted run instead of starting fresh. Scans commits on the current branch for Task N from <plan-file> footers, ignoring review( auto-fix commits. Verifies all prior task commits share the same Plan-SHA; if the current plan file's SHA has drifted, refuses to resume. After confirming matching Plan-SHA, re-runs the last milestone's breakpoint review against the accumulated diff for fresh scrutiny, then proceeds at the next task. Prior abort tags are preserved as audit markers. |
--create-branch |
In Phase 0c, create a feature branch even if HEAD is already on a non-default branch. Useful when the caller wants a clean slate. Branch is named execute-plan/<plan-slug>-<YYYYMMDD-HHMM> off default_branch. |
--max-retries=<N> |
Override the global retry budget for this run (see "Retry budget" below). Default: 20. |
--max-minutes=<N> |
Override the wall-clock budget for this run. Default: 60. |
--accept-risk=<finding-id> |
Explicitly accept a critical or major finding (see _internal/disposition). Can be repeated for multiple findings. For humans only — never set by the harness. Each use is logged in the final report with the finding it accepted. |
--adversarial=<auto|always|never|ask> |
When to run the adversarial review stage (Phase 3e). Default: auto. auto = fires when the cumulative diff is ≥200 lines OR touches a path listed in adversarial_triggers; otherwise skipped silently. always = always runs regardless of diff size or paths. never = never runs; no prompt, no invocation. ask = interactive legacy behaviour; prompt the user per the legacy flow. Use ask only when a human is supervising. |
--run-folder=<auto|off|path> |
Bundle run artefacts (execution-report.md/.json, disposition-log.md, optional postmortem.md) into a timestamped folder for audit retrieval. Default: auto (off unless the repo-delivery ## Commands schema declares runs_root:, in which case the folder is <runs_root>/<plan-slug>-<YYYYMMDD-HHMMSS>/). off keeps the legacy single-file report at --report-path. path writes the folder at the given location. |
--postmortem=<auto|always|never> |
When to run the Phase 5 postmortem. Default: auto (fires on WARN, FAIL, retry-budget exhaustion, or when escalation occurred; skipped on clean PASS). always runs regardless. never skips even on failure. |
--postmortem-mode=<auto|full|lightweight> |
How deep the Phase 5 postmortem goes. Default: auto (lightweight for PASS triggers, full for WARN/FAIL/blocked). lightweight writes only What happened, What broke down (free-form), and Recommendations. |
adversarial_triggers
An optional list of globs whose modification causes --adversarial=auto
to fire regardless of diff size. Read from the repo's CLAUDE.md
## Commands section (see _internal/repo-delivery). If absent, the
default list is used:
adversarial_triggers:
- src/auth/**
- src/payments/**
- migrations/**
- **/crypto/**
adversarial_triggers is defined in exactly one place (the repo's
CLAUDE.md or the default above); do not duplicate it inside individual
plans.
team_agents (parallel wave subagent overrides)
Phase 2.7 (wave dispatch) substitutes prompts into three default templates shipped with this skill:
<skill-root>/execute-plan/agents/implementer.md<skill-root>/execute-plan/agents/reviewer.md<skill-root>/execute-plan/agents/fixer.md
A consumer repo may override any of them via its ## Commands block:
team_agents:
implementer: docs/agents/our-implementer.md
reviewer: docs/agents/our-reviewer.md
fixer: docs/agents/our-fixer.md
implementer_model: sonnet # optional; defaults in Phase 2.7d apply
reviewer_model: sonnet
fixer_model: sonnet
Override paths are resolved relative to the repo root. Override templates must accept the same placeholder set as the defaults — the executor does not detect missing placeholders and will substitute whatever is present.
Workflow
Phase 0: Preflight
Two gates before any execution work:
0a. Repo-delivery contract. Read the ## Commands section of the
repo's CLAUDE.md per _internal/repo-delivery. If it's missing, fail
fast with this exact message and stop — do not infer, do not guess,
do not fall back to manifest detection:
Repo missing required CLAUDE.md ## Commands section.
See _internal/repo-delivery for the schema.
The lint / build / test / default_branch / package_manager
fields drive every subsequent phase. The rubric is the schema
definition; the message above is the exact user-facing string.
0b. Validate plan — refuse contract. Invoke /validate-plan <path>.
If it returns VERDICT: FAIL, refuse to execute and surface the
findings. Do not proceed under any circumstances except the explicit
--force override (see below). This refusal is non-negotiable — a bad
plan silently guessed through is the single biggest correctness risk
this flow exists to prevent.
The --force escape hatch exists for humans who have evaluated the
findings and decided to proceed anyway. It requires the explicit
argument — the harness never sets it; no default triggers it. Its use
is recorded prominently in the final execution report:
WARNING — plan validation FAILED and was overridden with --force.
Outstanding findings from validate-plan:
- [check N] ...
0b.25. Parallel metadata contract. If the plan contains a
## Parallel Execution section, treat it as executable metadata, not
advisory prose. validate-plan check #10 has verified its shape;
execute-plan must check the plan-governed parallel use case before
any worker dispatch:
- Parse
Mode,Ownership,Barriers,Single-Owner Files, andParallel Safety Checks. - If
Mode: sequential, execute the task loop normally and report the rationale from the section. - If
Mode: parallel, verify:- every lane has a concrete write scope, dependencies, and focused verification command;
- root manifests, lockfiles, shared exports, public contracts, migrations, generated files, and other shared surfaces have a single owner;
- contract-producing lanes complete before contract-consuming lanes;
- overlapping write scopes are either impossible by path/glob shape or explicitly assigned to one shared-surface owner;
- the integration lane owns final root gates and conflict resolution;
- worker prompts will include the multi-agent coordination warning from Phase 2b.
- If any condition fails, do not silently fall back to unsafe
parallelism. In interactive mode ask for a plan correction; in
autonomous mode abort with a
plan-ambiguityfinding that names the bad lane or overlapping scope.
If the section is absent, default to sequential execution and report:
Parallel Execution: absent; using sequential task loop.
0b.5. Tool-availability probe. Between plan validation and workspace
preparation, verify that every command declared in the repo-delivery
## Commands schema actually resolves on the executor's PATH. Subagent
shells do not source interactive shell profiles, so toolchains managed
by nvm, fnm, pyenv, rbenv, asdf, mise, or similar must be
on PATH before any subagent is spawned or the run will fail opaquely
with "command not found" in a worker that the operator can't inspect.
Probe explicitly — do not rely on the parent shell's PATH:
command -v "<package_manager>" # e.g. pnpm, npm, poetry, cargo
command -v "<lint_cmd first token>"
command -v "<build_cmd first token>"
command -v "<test_cmd first token>"
# JS projects only:
command -v node
If any probe fails, halt with this exact message and stop — do not attempt to install, do not guess an alternative, do not fall back to a different tool:
Required toolchain missing on PATH.
Missing: <cmd-a>, <cmd-b>, ...
Declared in: <repo>/CLAUDE.md ## Commands
Likely cause: node/pnpm/python managed by nvm/fnm/pyenv/asdf and the
PATH modification in your shell profile is not inherited by subagents.
Fix one of:
1. Run /execute-plan from a shell where `command -v <pm>` succeeds
AND the harness inherits that PATH. Most reliable: activate the
toolchain version (e.g. `nvm use`, `pyenv shell <ver>`), then
re-invoke.
2. Add the absolute path (e.g. ~/.local/share/pnpm, ~/.nvm/versions/
node/<ver>/bin) to CLAUDE.md alongside the ## Commands section
so the executor can set PATH deterministically.
3. Install the tool system-wide (outside a version manager) so it
lives on a default PATH.
When probes pass, echo a one-line confirmation:
Toolchain probe OK: <pm> <pm-version>, node <node-version>, <test-runner>.
All subagent Bash invocations from this skill onwards MUST be spawned
via a login shell (zsh -l -c "<cmd>" or bash -l -c "<cmd>") so the
same profile that populated PATH at probe time is populated again
inside the worker. Skills that dispatch workers via the Task tool must
surface this requirement in their spawn-context preamble.
0c. Prepare workspace. After Phase 0a (schema), Phase 0b (plan validation), and Phase 0b.5 (tool probe) succeed, establish the branch and baseline the run will operate on:
- Read
default_branchfrom the repo-delivery## Commandsschema. - Refuse to run on the default branch. If
git rev-parse --abbrev-ref HEADequalsdefault_branch, halt:/execute-plan refuses to run directly on the default branch (`<default_branch>`). Create a feature branch, or invoke with --create-branch to let execute-plan create one for you. - If invoked with
--create-branch, or if HEAD is detached / in a special state, create and switch to a feature branch namedexecute-plan/<plan-slug>-<YYYYMMDD-HHMM>offdefault_branch. Otherwise, proceed on the current (non-default) branch. - Record the current commit SHA as
$EXECUTE_PLAN_BASE_SHA. Every subsequent task commit carriesBase-SHA: <sha>andPlan-SHA: <plan-sha>trailers so Phase 3d (plan alignment) and Task 3's--resumecan reconstruct the run. - Record the active branch name for the failure-path preservation rules below.
Failure path — preserve, never destroy
On any unrecoverable failure — retry-budget exhaustion, a worker
refusing to continue, a review-fix spiral that can't converge,
validate-plan refusing mid-stream after --force:
- Tag the last successful commit as
execute-plan/abort/<plan-slug>-<YYYYMMDD-HHMM>so the abort point is locatable by name. - Leave the working branch intact. Leave the index intact. Do not stash, reset, or clean working-tree changes without explicit operator intent.
- Surface:
Run aborted. Branch preserved at <branch-name>. Last successful commit tagged: execute-plan/abort/<slug>-<timestamp>. Resume with: /execute-plan --resume <plan-file> - Exit non-zero so callers (CI, wrapping scripts) can detect abort.
Destructive git operations are forbidden in all code paths of this skill:
- Never
git reset --hard - Never
git push --force(push is out of scope anyway; Task 25's dogfood contract is local-only until the full flow is validated) - Never
git branch -D/git branch --delete --force - Never
git clean -fin the working tree - Never force-overwrite tags
The principle: the caller loses no work on abort. A failed run is a branch you can inspect, diff, cherry-pick from, or resume. It is never a silently-discarded state.
Decision records (cross-execution memory)
Unlike human engineers, LLMs accumulate no organic memory of decisions defeated along the way. Without a deliberate memory medium, every execution is knowledge-destroying — the next LLM touching the same code starts cold and may reverse choices the previous execution spent effort to make. Decision records fill that gap.
Record format
One markdown file per decision at:
docs/decisions/<plan-slug>/<NNNN>-<kebab-slug>.md
<plan-slug>— the executing plan'sslugfrontmatter field.<NNNN>— zero-padded sequence number within that plan-slug.<kebab-slug>— short imperative:0042-route-validation-at-controller.
Frontmatter (required):
---
id: YYYYMMDD-NNNN
plan: <plan-slug>
task: <task-id>
date: YYYY-MM-DD
files:
- path/to/affected/file.ts
- path/to/glob/**
tags: [routing, validation, ...]
supersedes: null # or the id of the decision this replaces
superseded_by: null # set when a later decision replaces this
---
Body sections, required in this order: Context · Decision · Reasoning · Rejected alternatives · Consequences · Revisit if.
Detail:
- Context — what the executor was doing; what the plan said.
- Decision — what was chosen, stated as a complete imperative.
- Reasoning — why; cite the options considered.
- Rejected alternatives — each option considered with a one-line rejection reason.
- Consequences — downstream effects. What now becomes easier, what becomes harder.
- Revisit if — named triggers under which this decision should be reconsidered.
Index
Two artefacts under docs/decisions/:
docs/decisions/INDEX.md— human-facing markdown with file globs → decision IDs.docs/decisions/index.json— machine-queryable counterpart for the read-trigger:
[
{
"id": "20260419-0042",
"files": ["src/services/auth.ts", "src/api/user/**"],
"tags": ["routing", "validation"],
"supersedes": null,
"superseded_by": null,
"path": "docs/decisions/user-validation-march/0042-controller-layer.md"
}
]
Both files are updated whenever a record is written or superseded.
Write triggers
execute-plan writes a record on exactly these events:
- A
plan-ambiguityis resolved (Phase 1.5) — clarification answered in interactive mode, or operator resolved on resume. - A
plan-deviationis dispositioned (Phase 3d) — the disposition and its rationale. - A non-trivial design call the plan didn't prescribe is made: API shape, pattern choice, layer placement, library selection, state machine, concurrency model, etc.
Filter rule to prevent noise. Write a record ONLY when a reasonable future LLM, seeing only the code, could plausibly reverse the choice. Forced, trivial, or fully-plan-prescribed choices do NOT get records. If in doubt, err toward not writing; the index is noise when it records every comma.
Read trigger
At the start of each task's implementation (Phase 2b), before any worker dispatch:
- Compute the task's target file set from the plan.
- Query
docs/decisions/index.jsonfor records where anyfilesentry matches a target file (glob match). - Filter out records with
superseded_by != null. - Read each matching record's full content.
- Include them in the implementing worker's context with the
directive: "These decisions govern files you're about to modify.
Do not reverse a non-superseded decision without raising a
plan-ambiguityfinding that cites the decision's ID. Workers who silently reverse prior decisions undo effort and introduce drift."
Supersede mechanism
When a new decision contradicts an existing one:
- Write the new record with
supersedes: <old-id>in frontmatter. - Rewrite the old record's frontmatter: set
superseded_by: <new-id>. - Neither record is deleted. The chain is traversable forward and backward, preserving audit history.
- Update both
INDEX.mdandindex.json.
Proliferation guard
/code-review flags any task that produces more than 5 decision
records in a single execution as a minor finding
(too-many-decisions). The filter rule above is the first defence;
this is the backstop against noise accretion.
Retry budget (global circuit breaker)
Local per-phase retries (build: max 3 attempts; test: max 3 attempts; auto-fix cycles in Phase 2.5 / 3b: max 3 each) prevent obvious loops — but they don't prevent a task from burning the whole session across many cheap retries. The global retry budget is the circuit breaker.
Values, in order of precedence
- Command-line:
--max-retries=<N>/--max-minutes=<N>. - Repo-delivery
## Commandsretry_budget:block:retry_budget: max_total_retries: 20 max_wall_clock_minutes: 60 - Defaults:
max_total_retries: 20,max_wall_clock_minutes: 60.
Counter semantics
The global retry counter increments on every:
- build retry (Phase 2c)
- test retry (Phase 2d)
- auto-fix cycle (Phase 2.5 breakpoint review)
- auto-fix cycle (Phase 3b full-review)
It does not increment on:
- successful first-try builds/tests
- phase transitions (e.g., moving from Task 1 → Task 2)
- validate-plan invocations
- review dispatches themselves (only their auto-fix follow-ups)
The wall-clock timer starts at Phase 0c (workspace prep) and runs through Phase 4 (final report).
Exhaustion behaviour
When either budget is hit mid-run:
- Stop immediately — do not start another retry or advance to the next task.
- Follow the Phase 0c failure path: tag
execute-plan/abort/<plan-slug>-<YYYYMMDD-HHMM>, preserve the branch. - Surface the exact message:
Retry budget exhausted (<N> retries, <M> minutes). Aborted at Task <K>. Resume with: /execute-plan --resume <plan-file> - Exit non-zero.
The budget is meant as a circuit breaker, not a deadline. A run that completes in 55 minutes with 18 retries is normal; a run that spends 60 minutes retrying the same task is stuck and needs a human.
Resume semantics (--resume)
When invoked with --resume, /execute-plan picks up from the last
completed task of a prior run instead of starting fresh.
How resume detects prior state
- Scan commits on the current branch for
Task N from <plan-file>footers. Every completed task produced one of these in the prior run. - Ignore commits whose subject starts with
review(— those are auto-fix commits from Phase 2.5 / 3b (see "Auto-fix commits" above), not task work. They must not inflate the completed-task count. - Extract the set of completed task numbers from the remaining commits.
- For each task commit, read the
Plan-SHA: <sha>trailer (written by Phase 0c). All task commits in the prior run must share the samePlan-SHA.
Plan-SHA drift refusal
If the current plan file's SHA differs from the Plan-SHA recorded in
prior task commits, refuse to resume:
Plan file has changed since the last run.
Prior Plan-SHA: <sha-a> (from commit <abbrev>)
Current Plan-SHA: <sha-b>
Resuming would mix tasks authored under different plan versions.
Re-run from scratch on a new branch, or revert the plan change.
Refuse because the meaning of "Task N" is plan-file-dependent. A changed plan may reorder, renumber, or reshape tasks, and resuming blindly would produce a run that conflates two different plans' intentions.
Resume flow
After confirming matching Plan-SHA:
- Report:
Resuming <plan-file> at Task <N+1>/M. Skipping N completed tasks. - Re-run the last milestone's breakpoint review against the diff accumulated so far (the codebase state is whatever survived the previous abort; it deserves fresh scrutiny).
- If the breakpoint review raises any blocking finding, halt and ask the operator to disposition before continuing.
- Proceed into Phase 2 at the next task.
- Phase 3 (PR-boundary reviews) still runs as normal once all tasks complete.
Tags and cleanup
Abort tags (execute-plan/abort/...) from the prior run are not
deleted automatically — they remain as audit markers. A successful
resume may leave multiple abort tags on the branch; that's fine. The
operator can garbage-collect them manually with git tag -d after the
run ships.
Phase 1: Load Plan
- If no path argument, find the most recent
.mdindocs/plans/. - Parse the plan into an ordered task list. Tasks are numbered sections, headings, or checklist items.
- Identify milestones: sections explicitly marked
## Milestone:(or### Milestone:) in the plan, or amilestones:list in the plan's frontmatter. If neither exists, treat the end of every top-level##section as an implicit milestone. - Report:
Found N tasks across M milestones in <plan-file>. Starting execution. - Load Closed Decisions. If the plan has a
## Closed Decisionssection, parse it. Resolve every@closed-decisions/<category>/<slug>reference by reading<claude-working-root>/closed-decisions/<category>/<slug>.md, where<claude-working-root>is the directory containing thisexecute-plan/skill (i.e. the library ships with the skill, not in the consumer repo). Inline the fragment's bullets into the working decision set. Cache the merged set for the whole run. - Load Parallel Execution. If the plan has a
## Parallel Executionsection, parse the mode, ownership lanes, barriers, single-owner files, and safety checklist into a lane registry. This registry governs task scheduling. Do not re-optimize the plan during execution; if the registry is wrong, halt as a plan ambiguity or deviation and require the plan to be corrected. - Load Waves. If the plan has a
## Wavessection and/or## --- WAVE N START ---markers in the body, parse the wave table into a wave registry: for each wave, capture its task range, focus, and execution mode (sequentialorparallel). The wave registry composes with the lane registry — lanes describe which tasks can fan out, waves describe when in the plan that fan-out happens. If wave markers and the wave table disagree on task ranges, halt as aplan-ambiguity. If no## Wavessection exists, treat the entire plan as a single sequential wave.
Phase 1.1: Parallel lane readiness
When a lane registry exists:
- Build a task-to-lane map from the
Ownershiptable. - Build a single-owner map from
Single-Owner Files. - For each lane, compute its target file set from the lane write scope plus the task descriptions.
- Reject
parallelmode if two lanes may write the same file/glob and that overlap is not owned by exactly one lane. - Reject
parallelmode if a lane depends on a task or barrier that is not defined in the plan. - Refuse ≥5 parallel teams in a single wave. If
Mode: paralleland the wave's lane count is greater than 4, halt with aplan-ambiguityfinding:
In interactive mode, ask the operator to fix the plan; in autonomous mode, abort via the Phase 0c failure path.Wave <N> declares <K> parallel lanes; max is 4. Coordination overhead dominates beyond 4 concurrent teams. Split into sequential parallel waves (e.g. Wave <N> with 3 lanes, Wave <N+1> with the rest). - Refuse undersized lanes. If any lane owns fewer than 3 tasks, warn but do not halt — a single-task lane is usually a sign the plan would be cleaner sequential, but is not unsafe.
- Report the chosen mode:
Parallel Execution: <mode> — <rationale> Lanes: <lane-a>, <lane-b>, ... Barriers: <barrier-a>, ... Waves: <wave-count> (<sequential | mixed | all-parallel>)
Treat conservative uncertainty about file overlap as a reason to pause or abort, not as permission to guess.
Phase 1.4: Closed Decisions are tablestakes
Before each task's implementation (Phase 2b), pass the merged Closed Decisions set to the implementing worker with this directive, verbatim:
These are tablestakes. Do not propose alternatives, do not deliberate, do not surface them as ambiguity. Execute as stated. If a task's own spec contradicts a closed decision, raise a
plan-deviationfinding (see code-review/references/controller-guide.md) and halt — do not attempt to reconcile.
Closed decisions pre-empt Phase 1.5 ambiguity categories 2 (existing-state) and 3 (scope-boundary). If an ambiguity would have fired but a closed decision disambiguates it, do not pause — the closed decision is the resolution.
Template-copy fast path
If a task's spec is shaped "scaffold from templates/<name>/" (a
common pattern for project setup — framework scaffolding, boilerplate),
execute runs the copy as a one-shot:
- Verify
templates/<name>/exists (per the closed decision naming it). - Copy its contents into the destination under git.
- Commit with the normal Task N footer.
- Move on.
No codebase exploration, no design-it-twice, no ambiguity checks during the copy task itself. Setup drift — historically ~20% of initial project bugs — is eliminated by refusing to think about choices that were already made.
Phase 1.5: Pre-execution clarification (codebase-aware)
This is NOT a re-validation of the plan. /validate-plan (Phase 0b)
has already passed — the plan's structure, acceptance criteria, and
closed decisions are fine. Phase 1.5 is a separate, codebase-aware gate
that fires only when the plan, read against the actual repo state,
has more than one reasonable execution. It cannot run until the repo is
present, which is why it happens here and not inside /validate-plan.
When Phase 1.5 pauses, surface it with this framing so the operator does not read it as "the plan is bad":
Plan validation: PASS (Phase 0b).
Pre-execution clarification needed:
<N> point(s) in the plan map to more than one thing in this codebase.
The plan itself is fine — I need you to pick a referent before I
start coding, so I don't silently guess wrong.
Never phrase Phase 1.5 output as "the plan tasks are not atomic" or "the plan has problems" — that contradicts the verdict that just passed and is the single biggest UX defect this flow has shipped.
The executor must distinguish ambiguity (→ pause or abort) from uncertainty (→ try). An ambiguity is a point where the plan has more than one reasonable reading given the repo and picking silently would produce code that might not match the author's intent. The heuristic:
Would a human reading the plan and seeing what I'm about to do say "yes, that's obviously what I meant"? If yes, proceed. If no, pause.
Three categories that count as ambiguity
- Referent ambiguity — the plan names a thing and the repo has
more than one candidate. "Modify the user service" when
src/services/user.ts,src/api/user/controller.ts, andsrc/models/user.tsall plausibly fit. - Existing-state ambiguity — the plan prescribes an addition and the repo already has something overlapping. "Add a rate limiter" when IP-level throttling is already present; add-on, replace, or stack are all defensible.
- Scope-boundary ambiguity — the plan prescribes a change and the change's natural boundary crosses something the plan didn't mention. "Refactor the auth middleware into a service class" when the middleware calls a helper in a sibling module and is hooked by a logger.
What is NOT ambiguity (proceed, do not pause)
- "I don't know how to implement this." That's an executor-skill issue; try.
- "There's a better way than the plan specifies." That's scope
discipline; follow the plan, log a
minorfinding. - General uncertainty about outcomes — not the same as the plan having multiple reasonable readings.
Behaviour by mode
Governed by the --interactive=<yes|no|auto> argument (default auto):
| Mode | TTY? | Behaviour on ambiguity |
|---|---|---|
yes |
— | Pause, print the question, read a one-line answer. Record as Clarification: <question>: <answer> in the commit trailer. |
no |
— | Abort cleanly. Log the question in the final report's ## Open Questions section. Resume (Task 3 of the hardening plan, when landed) can continue once the plan is updated. |
auto |
yes | Behave as yes. |
auto |
no | Behave as no. |
Record every ambiguity — answered or aborted — as a plan-ambiguity
finding in the final report.
Phase 2: Per-Task Loop
For each task in order:
2a. Read requirements
Read the task description. Understand what files to create/modify and what behavior is expected.
2b. Implement
Follow the plan exactly. Do not add unplanned features, refactors, or "improvements."
If Parallel Execution mode is parallel and the active user request
and runtime policy permit subagents, dispatch only currently unblocked
lanes whose write scopes are disjoint under the lane registry. Keep the
immediate blocking task on the main critical path; delegate sidecar
lanes that can run without blocking the next local step.
Every worker prompt must include:
You are not alone in the codebase. Own only the assigned write scope, do not revert edits made by others, and adjust your implementation to accommodate changes from other lanes. If your task requires editing a file outside your write scope, stop and report the needed scope change.
Workers must run their lane's focused verification before returning and list changed paths. The main executor waits at declared barriers, integrates lane results, then runs the task or milestone gates required by the plan. If subagents are not permitted, execute the same lanes locally in dependency order while preserving single-owner boundaries.
2c. Build
Run the build command from the repo-delivery schema (see
_internal/repo-delivery — the ## Commands section of the repo's
CLAUDE.md is the only source).
- If build fails: diagnose, fix, retry (max 3 attempts).
- If still failing: stop and report.
If runtime_probes are declared in the repo-delivery schema, run them
after build. These probes catch runtime/native dependency failures that
typecheck-only builds miss (native bindings against the wrong Node ABI,
generated clients that fail to load, missing drivers). Treat probe
failures like build failures: diagnose, fix, retry within the same
3-attempt budget, and report the exact probe that failed if it cannot
be fixed.
2d. Test — task's verifiable acceptance is the done-signal
The task's verify: frontmatter or Acceptance block (validated to be
mechanical per validate-plan check #4) IS the definition of "done"
for this task. Treat it as TDD:
- If the criterion names a test that doesn't yet exist, write the test first (failing) before any implementation change. This proves the test exercises the expected behaviour.
- Implement until every bullet in the acceptance block passes (each
test exits 0, each
grep/testone-liner exits 0, each observable reaches its stated value). - Then run the repo's full
testcommand from the repo-delivery schema. Framework- and language-level tests must also pass; the task-level criterion is the primary gate but not the only gate.
- If task-level acceptance fails: diagnose, fix, retry (max 3 attempts).
- If the framework
testcommand fails: diagnose, fix, retry (max 3 attempts). - If still failing: stop and report.
2e. Commit
Create a commit referencing the plan task. Task commits use the
standard <type>(<scope>) conventional form with a trailing
Task footer:
<type>(<scope>): <description>
<optional body>
Task N from <plan-file>
Plan-SHA: <sha>
Base-SHA: <sha>
The Task N from <plan-file> footer is reserved for this commit
class. Auto-fix commits (Phase 2.5 / 3b) never use it — they use a
distinct template (see "Auto-fix commits" below) so task progress and
review-fix progress are unambiguously distinguishable.
Auto-fix commits (Phase 2.5 / Phase 3b)
When a review phase's auto-fix cycle produces a code change, commit it separately from the task work using this template:
review(<profile>): fix <finding-id> — <short summary>
Milestone-K or PR-boundary review auto-fix.
Plan-SHA: <sha>
Finding: <file>:<line> — <severity> <domain>
<profile> is breakpoint for Phase 2.5, full for Phase 3b. The
commit subject's review( prefix is the grep-able discriminator
between auto-fix work and task work.
Never include the Task N from <plan-file> footer in an auto-fix
commit — that footer is the marker --resume uses to count completed
tasks (see "Resume semantics"). Auto-fix commits may appear between
task commits; they must not be counted as task progress.
Commit after each successful auto-fix cycle, not batched per phase.
A finding that required three fix cycles before passing review
produces three review(...) commits, each referencing the same
<finding-id> but with a different subject summary.
2f. Milestone check
If this task completes a milestone, proceed to Phase 2.5 before moving on. Otherwise, continue to the next task.
2f-bis. Wave barrier check
If this task is the last task in a wave (per the wave registry from Phase 1, step 7), enforce a hard barrier before starting the next wave's first task:
- If the completed wave was
parallel, wait for every lane in the wave to report DONE. Integrate any cross-lane review findings from the milestone breakpoint review (Phase 2.5) before crossing the barrier. - Re-run the repo's full
testandbuildcommands at the wave boundary even if no milestone fell on this task. Wave barriers are integration points; cross them silently and you'll discover the merge issue four tasks later, far from the cause. - If the next wave is
parallel, re-validate Phase 1.1 against the current repo state — a previous wave may have introduced files that change the single-owner picture. Treat any new conflict the same way as Phase 1.1's initial check. - Report:
Wave <K>/<W>: COMPLETE — <focus> Wave barrier: build PASS, tests PASS Next: Wave <K+1>/<W> (<mode>) — <focus>
Waves nest inside the task loop — they do not replace milestones. A wave may contain 0–many milestones; both fire when their conditions are met.
Phase 2.7: Wave dispatch mechanics (parallel waves)
When a wave's mode is parallel and it has ≥2 lanes, the lanes do
not run in the main checkout. They run in isolated git worktrees
with a fresh subagent per lane, then merge sequentially under the
rules in Phase 2.8. Sequential waves skip Phase 2.7 entirely and
execute in-place via the normal Phase 2 task loop.
The mechanics below are the only safe way to fan out: shared-checkout parallelism would force every lane to race the same index and produce non-deterministic merge artefacts.
2.7a. Worktree preparation
For each lane in the wave:
- Create a worktree at
.worktrees/<plan-slug>-<lane-id>/offdefault_branchon a new branch namedfeat/<plan-slug>-<lane-id>:git worktree add .worktrees/<plan-slug>-<lane-id> \ -b feat/<plan-slug>-<lane-id> <default_branch> - Run
{install_cmd}from the repo-delivery## Commandsschema inside the worktree. This is not optional. Subagents do not inherit the parent'snode_modules/target// virtualenv; skipping install reliably produces "command not found" or stale bindings inside the worker. - Record
<base-sha>per lane (the SHA the worktree was created from) so the reviewer subagent's{DIFF_RANGE}resolves.
If any worktree creation or install fails, halt the wave via the Phase 0c failure path. Do not attempt to dispatch lanes on a partial worktree set.
2.7b. Single-message dispatch
Dispatch all lane implementers in one message. Sequential dispatch silently kills concurrency — the fan-out is an illusion; each lane waits on the previous to return.
For each lane, build an implementer prompt from the template at
<skill-root>/execute-plan/agents/implementer.md (or the
override path declared in the consumer repo's CLAUDE.md ## Commands
under team_agents.implementer). Substitute every placeholder; use
absolute paths throughout — subagents have zero project context
and relative paths resolve unpredictably inside their shell.
Then send a single message containing one Task / Agent invocation per lane.
2.7c. Per-lane review and fix
When all implementers return, dispatch reviewers — also in a single
message — using the template at
<skill-root>/execute-plan/agents/reviewer.md (override:
team_agents.reviewer).
For each lane whose reviewer returns FAIL or WARN with critical
or major findings, dispatch a fresh fixer subagent using
<skill-root>/execute-plan/agents/fixer.md (override:
team_agents.fixer). Pass the findings and target files in the
prompt — never assume a prior subagent can be resumed; subagent state
is not durable across dispatches.
Each fixer pass increments the global retry counter. The 3-cycle
auto-fix limit from Phase 2.5 applies per finding inside the lane:
after 3 fixer cycles without resolution, the finding's status moves
to open (and blocks the wave verdict unless --accept-risk=<id>
was supplied).
2.7d. Model selection (default)
Lane subagents run on the following defaults; override via
team_agents.<role>_model in the repo-delivery schema if needed.
| Role | Default model | Rationale |
|---|---|---|
| Implementer (well-specified plan) | sonnet | Plan provides complete code; speed matters |
| Implementer (architectural lane) | opus | Novel design judgment required |
| Reviewer | sonnet | Checklist-driven, well-defined criteria |
| Fixer | sonnet | Targeted change against named finding |
The "architectural lane" trigger: a lane whose plan section contains
unresolved design choices the plan didn't pre-commit (no closed
decision applies, no template-copy fast path, no prescriptive code
block). In practice this is rare in plans that have passed
/validate-plan; sonnet is the right default.
Phase 2.8: Sequential merge after a parallel wave
After every lane in a parallel wave reaches reviewer PASS (or
WARN with no critical/major), the wave's branches merge into
default_branch sequentially. Concurrent merges produce
non-deterministic conflict resolution and defeat the integration
test.
2.8a. Merge order rules
Apply in order; the first matching rule decides:
- Dependency provider first. A lane that produces shared types,
generated clients, schemas, or migrations consumed by another lane
merges before its consumers. The lane registry's
BarriersandSingle-Owner Filesdescribe this graph. - Infrastructure before dependents. Config, build setup,
…(truncated)