Files
Skills/implement/SKILL.md
T
Brummel eb74f99bd4 feat(boss): bolder autonomous /boss — grounding-PASS auto-sign, rollback sandbox, reference issue
Retire the obligatory five-lens spec-skeptic auto-sign panel (worst case
18 agent runs per spec under /boss). The autonomous signature is now the
Step-5 grounding-check PASS alone — an independent fresh-context agent's
verdict against currently-green tests; a no-override BLOCK/INFRA_ERROR
routes to the human sign-off pause.

The judgement the panel applied moves upstream into specify Step 1.5,
whose stance inverts: a load-bearing fork the orchestrator can DERIVE an
answer for (sources, code, consistency, risk) is decided boldly and
recorded on the run's reference issue; only a pure-preference fork
bounces. spec-skeptic survives as an optional ad-hoc bias-breaker the
orchestrator pulls when unsure whether its leaning is judgement or bias —
not a gate, not a veto.

Every /boss run carries a mandatory reference issue (created if the cycle
had none): the fork-decision log, the orchestrator's cross-run memory,
and the only surviving trace of a hard-dropped attempt.

Relax main-sacrosanct below the session anchor: within an autonomous run
the orchestrator may git reset --hard its OWN UNPUSHED commits above the
anchor on a dead end — never below the anchor, never a pushed commit
(forward-only/revert). Discarded attempts are hard-dropped, no parking.

Verified across the 9 edited files by a 4-lens adversarial review
(retired-panel residue, cross-file contracts, rollback-boundary safety,
stance coherence): unanimous SOUND. Baseline tagged pre-autosign-rework.

closes #8
2026-06-19 00:06:44 +02:00

289 lines
16 KiB
Markdown

---
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: 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.
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.
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.
## 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: "<iter_id>",
plan_path: "<path under docs/plans>",
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-<short-symptom>", // tdd: "feat-<short-behaviour>"
red_test_path: "<absolute 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.
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:
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.