Files
Skills/implement/SKILL.md
T
claude 615a76eb01 feat(implement-loop): retire the finalize dispatch; the end-report carries the artifacts
The finalize agent only templated the script's already-computed
aggregate into stats.json / BLOCKED.md — ~41k real tokens per run
(197 dispatches / 8.0M in the 206-run corpus) for pure formatting.
The templates now live in the script (single source): the end-report
carries artifacts.stats_json and artifacts.blocked_md (null on DONE
and clean no-ops), and the orchestrator writes them byte-identical,
filling exactly two runtime slots it owns anyway — {{DATE}} (date +%F)
and {{FILES_TOUCHED}} (git status --porcelain, its Step-3/4 inspection
duty). File paths, consumers (tdd decompose reads BLOCKED.md,
postmortem parses it), and content shape are unchanged; the
agent-authored 'suggested next step' line is dropped — blocked_detail
carries the diagnosis.

refs #29
2026-07-17 15:29:12 +02:00

398 lines
24 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 and tests to the working tree without committing. The orchestrator reads the end-report, writes the stats file (and `BLOCKED.md` on PARTIAL/BLOCKED) from the contents the end-report carries, 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 code edits live in the working tree. The stats file and — on
PARTIAL/BLOCKED — `BLOCKED.md` are **built by the script and carried in
the end-report** (`artifacts.stats_json` / `artifacts.blocked_md`): the
script has no filesystem access of its own, and dispatching an agent
just to template the script's own aggregate cost ~41k real tokens per
run (issue #29). The orchestrator writes them byte-identical, filling
the two runtime slots it owns anyway — `{{DATE}}` (`date +%F`) and
`{{FILES_TOUCHED}}` (`git status --porcelain`). The script **never
commits** and never moves main HEAD. The orchestrator reads one
end-report (the workflow's return value), writes the artifacts,
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. (A
malformed or missing carrier is likewise a distinct `BLOCKED`
(bad-carrier) before any agent runs — never a bounce.)
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 AND TESTS LIVE IN THE WORKING TREE AS UNSTAGED CHANGES UNTIL THE ORCHESTRATOR COMMITS THEM; THE STATS FILE AND BLOCKED.md ARE WRITTEN BY THE ORCHESTRATOR FROM THE CONTENTS THE END-REPORT CARRIES.
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.)
NO IN-LOOP AGENT EVER DISCARDS WORKING-TREE STATE VIA `git checkout` / `git restore` — WHOLE-FILE OR `--patch`: NOTHING COMMITS BETWEEN TASKS, SO A SHARED FILE CARRIES EARLIER TASKS' UNCOMMITTED DONE WORK, AND A CHECKOUT SILENTLY DESTROYS IT (issue #23). RECOVERY IS FORWARD — EDIT BACK, OR REPORT `BLOCKED`. (THE ORCHESTRATOR'S OWN END-OF-ITERATION `git checkout -- .` DISPOSITION HAPPENS OUTSIDE THE 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 END-REPORT CARRIES THE `BLOCKED.md` CONTENT (`artifacts.blocked_md`); THE ORCHESTRATOR'S FIRST ACTION ON READING SUCH A REPORT IS WRITING IT VERBATIM TO `BLOCKED.md` AT THE REPO ROOT — UNCOMMITTED BY CONVENTION. ON `DONE`, `artifacts.blocked_md` IS NULL. (EXCEPTIONS WHERE IT IS ALSO NULL: A NO-OP ITERATION — ITS TREE IS ALREADY CLEAN — AND ANY PRE-LOOP EARLY EXIT (MALFORMED CARRIER, DIRTY-TREE PREFLIGHT, PLAN-EXTRACT GUARD): NOTHING RAN AND NOTHING WAS WRITTEN, SO THE STATUS + `infra:`-PREFIXED REASON RIDE THE END-REPORT AND THERE IS NOTHING TO CLEAN UP OR EXPLAIN.)
`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`** — except that
a quality round whose findings are all `Minor`, arriving after at least
one repair dispatch, surfaces them as concerns and closes the task
instead of gating (cosmetic residue must not discard a green task). 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.
**Cross-task discard guard** (issue #23). In a multi-task run nothing
commits between tasks, so one task's file-level `git checkout`/`git
restore` can silently destroy an earlier task's DONE work in a shared
file — invisible to the reviewers (scoped to the current task's
footprint) and to the tree-count gate (the surviving changes keep the
count nonzero). The loop therefore records a snapshot boundary after
every task (`git stash create` — a dangling commit; HEAD, index, and
working tree untouched) and hard-`BLOCK`s when a path that was
HEAD-modified at one boundary is HEAD-identical at the next: the
end-report names the lost paths, the boundary, and the recovery
snapshot sha the discarded content can be read from
(`git show <sha>:<path>`). Coarse by design, in both directions: a
checkout followed by re-edits of the same file, or a `--patch`-level
restore of a single hunk, escapes the comparison (the path never
leaves the diff) — the snapshot still keeps any loss diagnosable and
recoverable; conversely a task that legitimately edits a shared file
back to byte-identical HEAD content trips the guard, so a tripped
verdict means *adjudicate against the snapshot*, not proven malice.
Renames do not trip it (the boundary diff runs `--no-renames`, so a
renamed file's old path stays listed as a deletion). Untracked files
sit outside the threat model (`git checkout -- <path>` cannot discard
them). Cost: one extra sonnet/medium snapshot call per task of a
multi-task run; single-task and mini runs skip the guard. The
detection details live in `workflows/implement-loop.js`, the single
source.
## 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
(the loop creates no branch of its own; it runs in whatever checkout
the session sits in — under the worktree convention, the run's
worktree 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 `artifacts` block
(`stats_json`, `stats_path_hint`, `blocked_md`), 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. **First action, before anything else:** materialise the
artifacts — write `artifacts.stats_json` to the stats path (fill
`{{DATE}}` with `date +%F`), and when `artifacts.blocked_md` is
non-null write it verbatim to `BLOCKED.md` at the repo root (fill
`{{DATE}}` and `{{FILES_TOUCHED}}` from `git status --porcelain`). The
contents are the script's single-sourced templates — do not rephrase,
restructure, or embellish them. An **infra early-exit** (malformed or missing carrier, dirty-tree
preflight, a plan-extract guard) returns a minimal report instead:
`status: BLOCKED` plus an `infra:`-prefixed `reason`, no `blocked_detail`
and none of the per-task fields — nothing ran.
### Step 3 — Orchestrator inspect + commit step (on DONE)
The workflow returns with code edits sitting in the working tree as
unstaged changes; the stats file was just written by you from
`artifacts.stats_json` (Step 2). Nothing is committed yet, and there
is no `BLOCKED.md` (`artifacts.blocked_md` is null on DONE).
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;
`BLOCKED.md` at the repo root carries the diagnostic — written by you
in Step 2 from `artifacts.blocked_md`. 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 `artifacts.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.
The same no-file shape occurs for an **infra early-exit** (`reason`
prefixed `infra:` — malformed/missing carrier, dirty preflight tree, a
plan-extract guard): no `BLOCKED.md`, no `blocked_detail`, and the tree
exactly as the loop found it. Fix the invocation (or clean the tree) and
re-invoke.
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.