--- name: implement description: Use when an implementation plan exists under docs/plans and is ready to execute, OR when a debug/tdd RED-test is handed off for the GREEN side. Runs the `implement-loop` Workflow — a deterministic script that executes the per-task loop (implementer → spec-compliance → quality, each a separate agent call) and aggregates in code, writing edits, tests, and a stats file to the working tree without committing (and `BLOCKED.md` on PARTIAL/BLOCKED). The orchestrator reads the end-report, inspects the working tree, decides commit shape, and performs all commits. Also documents the `compiler-driven` light-edit arm. --- # implement — plan execution on the Workflow substrate > **Violating the letter of these rules is violating the spirit.** ## Overview Plan execution runs as the **`implement-loop` Workflow** (shipped at `workflows/implement-loop.js`, symlinked into `~/.claude/workflows/` by `install.sh`). The orchestrator invokes it through the Workflow tool; the script runs the entire per-task loop deterministically — for each task, implementer → spec-compliance → quality, **each a separate `agent()` call** dispatching the surviving phase agent-types (`implementer`, `spec-reviewer`, `quality-reviewer`, and `tester` for the E2E phase). The inter-phase re-loop, the aggregation, and the DONE/PARTIAL/BLOCKED verdict are code in the script, not natural-language reasoning between dispatches. This replaces the former `implement-orchestrator` agent, which carried the loop as inline role-switches inside one subagent context because Claude Code forbids nested-subagent dispatch. A Workflow orchestrates from the top level, so that workaround is retired: each phase is now a real, **independently-invokable** agent call, and the routing keys on the structured verdict each agent reports (which encodes the project's real build/test outcome). The four phase agents survive unchanged as the agent-types the script dispatches; only the dispatch/aggregation prose the orchestrator-agent carried is gone. All work lives in the working tree: code edits, the stats file, and — on PARTIAL/BLOCKED — `BLOCKED.md` at the repo root. The script **never commits** and never moves main HEAD. The orchestrator reads one end-report (the workflow's return value), inspects the unstaged tree, and decides commit shape. ## When to Use / Skipping Triggers: - A plan exists under `docs/plans` (standard mode → `implement-loop` with `mode: "standard"`). - A `debug` (RED test + cause) or `tdd` (RED executable-spec) handoff for the GREEN side (mini mode → `implement-loop` with `mode: "mini"`). **Never skipped when there is plan-driven or RED-handoff code to ship.** ### The compiler-driven arm (light path) A **behaviour-preserving type/signature edit at a definition site** — one the type checker enumerates across N sites, e.g. a carrier/newtype narrowing or a constructor rename propagated mechanically — does NOT go through the full per-task loop. It is the `compiler-driven` selector arm (see `../boss/SKILL.md` "Entry-path reflection"), routed here by a **positive** trigger matched on the edit's signature, not reached by elimination. Its executor is **observe-then-bounce**, shipped as `workflows/compiler-driven-edit.js`: 1. Make the edit; propagate it mechanically across the sites the build flags. Introduce no new behaviour; add or weaken no test. 2. **Run the project's real build + full suite.** This run — not an ex-ante guess that the change is "behaviour-preserving" — is the oracle. 3. **Done-signal: an edit actually landed AND clean build AND suite green unchanged → the edits sit unstaged for the orchestrator to commit.** That conjunction is the whole gate; it keeps the light path light without letting a green-but-wrong change through. The "edit actually landed" conjunct is load-bearing: `clean build AND suite green` is *vacuously* true on an empty tree, so a no-op edit would otherwise read as DONE. A clean working tree after the edit phase is a no-op, not a success → distinct `BLOCKED` (no-op-edit), never DONE. Positive evidence (tree differs from HEAD) is required, checked both at the edit phase and independently at verify. 4. **Bounce** otherwise — the change was not purely behaviour-preserving after all, so route up per the straddle rule: a site that forces a design decision → `specify`; a site that turns out to **encode new behaviour** pinnable as one assertion → `tdd`, RED-first; the suite not green-unchanged (a regression surfaced) → `debug`, RED-first. The fallible ex-ante guess becomes a cheap ex-post detection. A truly trivial mechanical edit (a one-line typo, a rename across a handful of files) the orchestrator MAY still do inline without running the workflow — but the **same done-signal binds**: clean build + suite green unchanged, or it bounces. No review-and-commit discipline is shed; the orchestrator still inspects and commits. **Hard gate — observed bugs never enter this arm.** An observed bug is `debug`'s job (RED-first), even when the fix is a one-line type edit. The selector places the observed-bug check *before* the type-edit arm for exactly this reason; "the fix is mechanical" must not reroute a regression around the RED-first gate. ## The Iron Law ``` THE LOOP NEVER COMMITS. CODE EDITS, TESTS, AND THE STATS FILE LIVE IN THE WORKING TREE AS UNSTAGED CHANGES UNTIL THE ORCHESTRATOR COMMITS THEM. WITHIN THIS LOOP, MAIN HEAD IS SACROSANCT — NO RESET, NO REVERT; THE LOOP ONLY EVER WRITES UNSTAGED CHANGES. MAIN MOVES FORWARD ONLY VIA ORCHESTRATOR COMMITS. (THE `/boss` ROLLBACK SANDBOX WINDS BACK ALREADY-COMMITTED AUTONOMOUS WORK — A BOSS-LEVEL RECOVERY, NOT A STEP IN THIS LOOP.) PER-TASK PHASES ARE SEPARATE AGENT CALLS IN THE WORKFLOW SCRIPT — implementer, then spec-compliance, then quality. SPEC COMPLIANCE IS GATED BEFORE QUALITY. TASKS RUN SEQUENTIALLY; A BLOCKED TASK STOPS THE LOOP — NO SKIP-AHEAD (TASK ORDERING DEPENDENCIES ARE UNKNOWN). NEVER PUSH PAST `BLOCKED` BY HAND. ON `PARTIAL` OR `BLOCKED`, THE SCRIPT WRITES `BLOCKED.md` AT THE REPO ROOT — UNCOMMITTED BY CONVENTION. ON `DONE`, NO SEPARATE FILE. (ONE EXCEPTION: A NO-OP ITERATION IS `BLOCKED` WITH NO `BLOCKED.md` — ITS TREE IS ALREADY CLEAN, SO THE STATUS + REASON RIDE THE END-REPORT AND THERE IS NOTHING TO CLEAN UP.) `DONE` REQUIRES POSITIVE EVIDENCE THAT AN EDIT LANDED — A NO-OP ITERATION (`git status --porcelain` EMPTY, untracked files INCLUDED) IS NEVER `DONE`, IT IS `BLOCKED` (the issue #11 vacuous-green shape, guarded on the main path). THE VERDICT IS THE GIT TREE COUNT, NEVER A SELF-REPORT. IN MINI MODE THE RED->GREEN IS OBSERVED, NOT ASSERTED: AN INDEPENDENT VERIFY RE-RUNS THE HANDED-OFF RED TEST AND THE SUITE; A STILL-RED TEST OR A REGRESSION IS `BLOCKED` (route back to debug, RED-first). THE COMPILER-DRIVEN ARM COMMITS ONLY ON CLEAN BUILD + SUITE GREEN UNCHANGED; ELSE IT BOUNCES (specify for a design hole, tdd for discovered new behaviour, debug for a regression). ``` ## Per-task loop mechanics The script runs, per task: implementer phase, then spec-compliance, then quality — gated in that order. Each is a separate `agent()` call with a structured-output schema, so the script branches on a real verdict. The re-loop limit is **2 repair retries per failure-mode per task; the 3rd unresolved attempt escalates to `BLOCKED`**. A `non_compliant` / `changes_requested` verdict re-dispatches the `implementer` with the review findings as the repair brief; `unclear` task text → `spec-ambiguous` BLOCKED; a tooling failure → `infra` BLOCKED. This logic lives as the loops in `workflows/implement-loop.js` — the single source; it is deliberately not restated as prose elsewhere, so the two cannot drift. **Positive-evidence precondition on `DONE`** (issue #12 — the issue #11 vacuous-green shape on the main path). `build green AND suite green` is not enough: it is satisfiable by doing nothing. So `DONE` also requires positive evidence that an edit landed. The verdict is taken from **git ground truth, never a self-report** — a self-report must never be able to *fail* a run that actually did the work: - **Iteration gate (standard mode)** — a dedicated `tree-check` agent runs `git status --porcelain | wc -l` after the per-task loop but **before** E2E and finalize. A `DONE` outcome with a zero count is a no-op iteration → `BLOCKED`. `git status --porcelain` (not `git diff HEAD`) is used so a brand-new **untracked** file — the implementer leaves edits unstaged — still counts; running before E2E/finalize keeps fixtures and the stats/`BLOCKED.md` artefacts from inflating it; and a non-returning agent is treated as `BLOCKED` (infra), never waved through. A clean-tree no-op writes no `BLOCKED.md` (nothing to clean up — see Step 4). - **Mini mode gate** — an independent `mini-verify` agent re-runs the handed-off RED test and the suite and checks the tree is dirty (`git status --porcelain`); a still-red test, a regression, or a clean tree is `BLOCKED`. The GREEN is observed, not taken from the implementer's self-report. - **Per-task `applied_changes`** (self-report, OR-ed across the initial dispatch and every repair) does NOT gate the outcome — a self-report must never be able to *fail* a run that actually did the work (e.g. the initial implementer no-ops but a repair writes the files). It feeds only a neutral concern when a task wrote nothing (it may be genuinely already-satisfied — the orchestrator weighs it). The E2E phase's `status` is also read now (not just its fixtures): a non-`DONE` E2E status or a zero-fixture run surfaces as a concern. ## The Process — orchestrator side ### Step 1 — Run the `implement-loop` workflow Before invoking: ensure the working tree is clean (`git status --porcelain` empty). The workflow's preflight refuses to start on a dirty tree. For a standard iteration: ``` Workflow({ name: "implement-loop", args: { mode: "standard", iter_id: "", plan_path: "", task_range: [3, 8] // optional }}) ``` For a RED-first handoff from `debug` or `tdd` (mini mode): ``` Workflow({ name: "implement-loop", args: { mode: "mini", iter_id: "bugfix-", // tdd: "feat-" red_test_path: "", cause_summary: "<1-2 sentences from debugger>", // tdd: the desired-behaviour line constraint: "minimal fix, no surrounding cleanup" // tdd: "minimal feature, no surrounding scope" }}) ``` The carrier fields are defined authoritatively at the top of `workflows/implement-loop.js`. The load-bearing `iter_id` rule is there too: it names the scratch dir and the stats filename, NOT a branch (there is no branch). ### Step 2 — Read the end-report The workflow returns a small structured end-report (its return value): `status`, `iter_id`, `started_from`, `tasks_total` / `tasks_completed`, per-task summaries, concerns, E2E fixtures, the stats path, and — on PARTIAL/BLOCKED — the blocked detail. Per-task chatter stayed inside the workflow's agent contexts and never reached the orchestrator. Read the end-report; it is the per-task summary you build the commit body from. ### Step 3 — Orchestrator inspect + commit step (on DONE) The workflow returns with code edits and the stats file sitting in the working tree as unstaged changes. Nothing is committed yet, and there is no `BLOCKED.md` (DONE never writes one). 1. Inspect: `git status` and `git diff` — confirm the changes match what the end-report claims. The end-report is the per-task summary; use it as the basis for the commit body. 2. Decide commit shape — by default one cohesive commit for the whole iter; split into a few logical commits only if the diff genuinely covers multiple unrelated changes. Per-task commit splitting is NOT a goal; the iter is the unit of consistency the orchestrator is committing to. 3. Write the commit body. It carries everything a future reader needs that the diff itself does not: the *why*, the alternatives considered and rejected, the verification steps run, and any concerns that remain. Detail-fill comes from the end-report. A concern phrased as a *held* or *unresolved quality finding* (the per-task quality gate kept a plan-prescribed element against a reviewer finding, or a repair was a no-op) is the gate handing you the judgement it could not make in code: verify that finding by hand against the diff before committing — do not auto-sign past it, even under `/boss`. Keep it if it is a principled plan-hold; if it is an unaddressed defect, send the iter back rather than commit. 4. Stage + commit the code edits and the stats file. 5. If the trigger is done-state and the user is away, run the project's configured notification command per `../boss/SKILL.md` "Done-state notifications". ### Step 4 — Orchestrator handling (on PARTIAL or BLOCKED) The workflow returns with whatever work-in-progress it managed plus `BLOCKED.md` at the repo root carrying the diagnostic. Nothing is committed. The orchestrator decides what to do with the dirty working tree: 0. **No-op `BLOCKED` special case** — if the end-report's status is `BLOCKED` with `blocked_md` null and a no-op `blocked_detail` (the reason names a no-op iteration or a clean-tree no-op fix; `files_touched` is 0 in standard mode, null in mini), there is **no `BLOCKED.md`** and the tree is already clean. The diagnostic is in the end-report's `blocked_detail`, not a file. Nothing to clean up or stash; re-plan or re-run from the same clean tree. 1. Read `BLOCKED.md` — `## What did not` names the failure mode and the blocked task's reason. Read `git diff` to see what was attempted. 2. Decide: - **Repair:** keep the working-tree changes in place (or `git stash` them if a clarifying read of clean main is needed first). Adjust plan or extend context; **delete `BLOCKED.md`** (`rm BLOCKED.md`) before re-running the workflow — its preflight clean-tree check counts the file as dirt. Either stash everything and re-run on a clean tree, or commit the known-good subset, then `rm BLOCKED.md`, then re-run. - **Discard:** `git checkout -- .` to drop unstaged file changes; `git clean -fd` / `rm BLOCKED.md` plus anything else new. main HEAD does NOT move. - **Escalate:** ask the user via the configured notification command. `BLOCKED.md` sits in the working tree until the conversation resumes. Within the `implement` loop the orchestrator does not `git reset` or `git revert` on main: there is nothing on main to undo — the workflow never commits, it only writes unstaged working-tree changes. (The one place autonomous work is ever wound back is the `/boss` rollback sandbox, which hard-resets *already-committed, unpushed* autonomous commits above the session anchor on a dead-ended run — a boss-level recovery, not a step in this loop. See `../boss/SKILL.md` § Direction freedom.) ## Handoff Contract `implement` consumes: | Source | Carrier | |--------|---------| | from `planner` | path to plan under `docs/plans` (+ optional `task_range`) → `implement-loop` standard mode | | from `debug` / `tdd` | RED-test path + cause/spec summary + minimal-change constraint → `implement-loop` mini mode | | from the `compiler-driven` selector arm | a type/signature edit + its definition site → `compiler-driven-edit` workflow | `implement` produces: an unstaged working tree containing the code edits and the stats file; on PARTIAL/BLOCKED, also `BLOCKED.md` at the repo root. The orchestrator inspects, commits the code + stats (DONE) or repairs/discards (PARTIAL/BLOCKED). The `compiler-driven-edit` workflow produces an unstaged edit on `DONE`, or a `BOUNCE` verdict naming `specify` / `debug`. No further hand-off — `audit` runs independently at cycle close. ## Common Rationalisations | Excuse | Reality | |--------|---------| | "Single task, running a whole workflow exceeds the work" | The workflow IS the discipline. Invoking it is cheap; the gated per-task phases and the working-tree isolation are the value. For a genuinely trivial mechanical edit, the inline compiler-driven path exists — but its done-signal still binds. | | "Let me have the workflow commit the per-task work, it's cleaner" | The workflow never commits. Orchestrator-only commit is a project-wide rule: only the orchestrator decides when a state is consistent enough to enter main history. | | "Per-task commits would help bisection later" | The workflow's per-task phases are review gates, not bisection points. Iter-level commits are the bisection unit — and they only exist if the whole iter passes review. | | "BLOCKED end-report, let me dig into BLOCKED.md and continue myself" | Read the `## What did not` section first. The loop stopped at the re-loop limit for a reason. Continuing by hand undoes the discipline. | | "End-report says PARTIAL with 4/5 tasks DONE — close enough, commit them" | The 5th task may carry an invariant the earlier 4 silently depend on. Either re-run for the missing task or `git checkout -- .` and re-plan. | | "BLOCKED.md feels redundant — the end-report already has the detail" | The end-report dies when the chat scrolls; `BLOCKED.md` sits in the working tree across pauses and inspection rounds. It is the durable handoff. | | "The compiler-driven edit built fine, ship it without running the suite" | Clean build is half the done-signal. Suite-green-UNCHANGED is the other half — it is what catches a behaviour change the build can't see. No suite run, no commit. | | "The compiler-driven suite went red but the fix is one line — I'll just fix it here" | A red suite means the edit was not behaviour-preserving. That is an observed regression → bounce to `debug`, RED-first. Patching it inline reintroduces exactly the green-but-wrong path the bounce prevents. | | "Nested-subagent dispatch is back via workflows, so an agent can spawn agents" | No. The Workflow orchestrates from the TOP level; the agents it spawns still cannot spawn further agents. The platform constraint is unchanged — the workflow simply does not need nesting. | ## Red Flags — STOP - Orchestrator dispatching `implementer` directly outside the workflow (bypassing the gated loop). - Orchestrator running `git reset` or `git revert` on main. - The workflow (or any agent it spawns) running `git commit`. - Two `implement-loop` runs overlapping on the same working tree. - `BLOCKED.md` staged or committed by anyone. - A compiler-driven edit committed without a clean build AND an unchanged-green suite. - An observed bug routed to the compiler-driven arm instead of `debug`. ## Cross-references - **Workflows dispatched:** - `workflows/implement-loop.js` — the per-task loop (standard + mini). Single source for the carrier contract, the re-loop limit, the stats schema, the `BLOCKED.md` template, and the end-report shape. - `workflows/compiler-driven-edit.js` — the observe-then-bounce light path for a behaviour-preserving type/signature edit. - **Phase agent-types the workflow dispatches** (they survive the migration; the inline-role-switch orchestrator-agent does not): - `agents/implementer.md` — implementer phase (TDD discipline) - `agents/spec-reviewer.md` — spec-compliance phase - `agents/quality-reviewer.md` — quality phase - `agents/tester.md` — E2E coverage phase - **Selector that routes here:** `../boss/SKILL.md` "Entry-path reflection" — the `compiler-driven` arm names this executor, and this file names that arm. They are co-located on purpose: a future edit re-routing the light path back through the full loop changes both cross-references and is a visible regression. - **Why the substrate, not nested subagents.** Claude Code still forbids a subagent from spawning subagents. A Workflow script orchestrates from the top level, so the per-task phases run as its own agent calls without nesting — see `../docs/design.md` § Plugin layer. - **Input sources:** `../planner/SKILL.md` (plans), `../debug/SKILL.md` and `../tdd/SKILL.md` (RED-test handoff for mini mode). - **Output target:** orchestrator reads the end-report, inspects, and commits; `../audit` runs at cycle close.