# Execute Plan

> Execute a written implementation plan with staged reviews, per-task build/test cycles, milestone breakpoints, and optional parallel agent lanes.

- Skill: `garyld1962/execute-plan-7` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add garyld1962/execute-plan-7`
- Raw SKILL.md: https://api.skillmd.com/api/skills/garyld1962/execute-plan-7/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: garyld1962 (https://skillmd.com/u/garyld1962)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/garyld1962/execute-plan-7

---


# /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:

1. Parse `Mode`, `Ownership`, `Barriers`, `Single-Owner Files`, and
   `Parallel Safety Checks`.
2. If `Mode: sequential`, execute the task loop normally and report the
   rationale from the section.
3. 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.
4. 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-ambiguity` finding 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:

```bash
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:

1. Read `default_branch` from the repo-delivery `## Commands` schema.
2. **Refuse to run on the default branch.** If
   `git rev-parse --abbrev-ref HEAD` equals `default_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.
   ```
3. If invoked with `--create-branch`, or if HEAD is detached / in a
   special state, create and switch to a feature branch named
   `execute-plan/<plan-slug>-<YYYYMMDD-HHMM>` off `default_branch`.
   Otherwise, proceed on the current (non-default) branch.
4. Record the current commit SHA as `$EXECUTE_PLAN_BASE_SHA`.
   Every subsequent task commit carries `Base-SHA: <sha>` and
   `Plan-SHA: <plan-sha>` trailers so Phase 3d (plan alignment) and
   Task 3's `--resume` can reconstruct the run.
5. 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`:

1. Tag the last successful commit as
   `execute-plan/abort/<plan-slug>-<YYYYMMDD-HHMM>` so the abort point
   is locatable by name.
2. Leave the working branch intact. Leave the index intact. Do not
   stash, reset, or clean working-tree changes without explicit
   operator intent.
3. Surface:
   ```
   Run aborted. Branch preserved at <branch-name>.
   Last successful commit tagged: execute-plan/abort/<slug>-<timestamp>.
   Resume with: /execute-plan --resume <plan-file>
   ```
4. 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 -f` in 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's `slug` frontmatter field.
- `<NNNN>` — zero-padded sequence number within that plan-slug.
- `<kebab-slug>` — short imperative: `0042-route-validation-at-controller`.

Frontmatter (required):

```yaml
---
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:

1. **Context** — what the executor was doing; what the plan said.
2. **Decision** — what was chosen, stated as a complete imperative.
3. **Reasoning** — why; cite the options considered.
4. **Rejected alternatives** — each option considered with a one-line
   rejection reason.
5. **Consequences** — downstream effects. What now becomes easier, what
   becomes harder.
6. **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:

```json
[
  {
    "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-ambiguity` is resolved (Phase 1.5) — clarification answered
  in interactive mode, or operator resolved on resume.
- A `plan-deviation` is 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:

1. Compute the task's target file set from the plan.
2. Query `docs/decisions/index.json` for records where any `files`
   entry matches a target file (glob match).
3. Filter out records with `superseded_by != null`.
4. Read each matching record's full content.
5. 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-ambiguity` finding 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:

1. Write the new record with `supersedes: <old-id>` in frontmatter.
2. Rewrite the old record's frontmatter: set `superseded_by: <new-id>`.
3. Neither record is deleted. The chain is traversable forward and
   backward, preserving audit history.
4. Update both `INDEX.md` and `index.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

1. Command-line: `--max-retries=<N>` / `--max-minutes=<N>`.
2. Repo-delivery `## Commands` `retry_budget:` block:
   ```
   retry_budget:
     max_total_retries: 20
     max_wall_clock_minutes: 60
   ```
3. 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:

1. Stop immediately — do not start another retry or advance to the
   next task.
2. Follow the Phase 0c failure path: tag
   `execute-plan/abort/<plan-slug>-<YYYYMMDD-HHMM>`, preserve the
   branch.
3. Surface the exact message:
   ```
   Retry budget exhausted (<N> retries, <M> minutes).
   Aborted at Task <K>.
   Resume with: /execute-plan --resume <plan-file>
   ```
4. 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

1. Scan commits on the current branch for `Task N from <plan-file>`
   footers. Every completed task produced one of these in the prior run.
2. **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.
3. Extract the set of completed task numbers from the remaining commits.
4. For each task commit, read the `Plan-SHA: <sha>` trailer (written
   by Phase 0c). All task commits in the prior run must share the same
   `Plan-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:

1. Report: `Resuming <plan-file> at Task <N+1>/M. Skipping N completed tasks.`
2. 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).
3. If the breakpoint review raises any blocking finding, halt and ask
   the operator to disposition before continuing.
4. Proceed into Phase 2 at the next task.
5. 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

1. If no path argument, find the most recent `.md` in `docs/plans/`.
2. Parse the plan into an ordered task list. Tasks are numbered sections,
   headings, or checklist items.
3. Identify **milestones**: sections explicitly marked `## Milestone:` (or
   `### Milestone:`) in the plan, or a `milestones:` list in the plan's
   frontmatter. If neither exists, treat the end of every top-level `##`
   section as an implicit milestone.
4. Report: `Found N tasks across M milestones in <plan-file>. Starting execution.`
5. **Load Closed Decisions.** If the plan has a `## Closed Decisions`
   section, 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 this
   `execute-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.
6. **Load Parallel Execution.** If the plan has a `## Parallel Execution`
   section, 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.
7. **Load Waves.** If the plan has a `## Waves` section 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 (`sequential` or `parallel`). 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 a `plan-ambiguity`. If no `## Waves` section
   exists, treat the entire plan as a single sequential wave.

### Phase 1.1: Parallel lane readiness

When a lane registry exists:

1. Build a task-to-lane map from the `Ownership` table.
2. Build a single-owner map from `Single-Owner Files`.
3. For each lane, compute its target file set from the lane write
   scope plus the task descriptions.
4. Reject `parallel` mode if two lanes may write the same file/glob and
   that overlap is not owned by exactly one lane.
5. Reject `parallel` mode if a lane depends on a task or barrier that
   is not defined in the plan.
6. **Refuse ≥5 parallel teams in a single wave.** If `Mode: parallel`
   and the wave's lane count is greater than 4, halt with a
   `plan-ambiguity` finding:
   ```
   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).
   ```
   In interactive mode, ask the operator to fix the plan; in
   autonomous mode, abort via the Phase 0c failure path.
7. **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.
8. 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-deviation` finding
> (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:

1. Verify `templates/<name>/` exists (per the closed decision naming it).
2. Copy its contents into the destination under git.
3. Commit with the normal Task N footer.
4. 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

1. **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`, and
   `src/models/user.ts` all plausibly fit.
2. **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.
3. **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 `minor` finding.
- 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:

1. 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.
2. Implement until every bullet in the acceptance block passes (each
   test exits 0, each `grep`/`test` one-liner exits 0, each observable
   reaches its stated value).
3. Then run the repo's full `test` command 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 `test` command 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:

1. 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.
2. Re-run the repo's full `test` and `build` commands 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.
3. 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.
4. 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:

1. Create a worktree at `.worktrees/<plan-slug>-<lane-id>/` off
   `default_branch` on a new branch named
   `feat/<plan-slug>-<lane-id>`:
   ```
   git worktree add .worktrees/<plan-slug>-<lane-id> \
     -b feat/<plan-slug>-<lane-id> <default_branch>
   ```
2. Run `{install_cmd}` from the repo-delivery `## Commands` schema
   inside the worktree. **This is not optional.** Subagents do not
   inherit the parent's `node_modules` / `target/` / virtualenv;
   skipping install reliably produces "command not found" or stale
   bindings inside the worker.
3. 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:

1. **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 `Barriers` and
   `Single-Owner Files` describe this graph.
2. **Infrastructure before dependents.** Config, build setup,

…(truncated)
