Supervised Delivery
Run one ticket through the full pipeline. Serial execution, one worktree. No parallel writers.
When this pipeline is the wrong tool
Four subagents cost four system prompts, four tool schemas, four handoffs, and four reviews before any code changes. That fixed prefix only repays itself on work with real correctness risk and enough substance to amortise it.
Downshift to the first row that covers the work:
| Work | Run it as |
|---|---|
| One-line fix, typo, mechanical rename, comment | Yourself, plus the one relevant check |
| Bounded change, one or two files, obvious oracle | Yourself, plus one reviewer pass on the diff |
| Copy-and-wrap or move-and-rewire: oracle is diff vs source plus existing suite | Light loop — see "Light loop" below |
| Real feature or refactor, non-obvious failure modes | Full pipeline below |
| Repo-wide sweep of N near-identical units | Full pipeline, batched — see Phase 3 |
The rows have moved down over time. Current models finish multi-file features end to end without leaving stubs when handed the complete specification up front, so work that once needed the pipeline to avoid half-done output now sits a row lower — the pipeline buys independent judgement on a diff, not completion. Escalating past the row the work sits in is a cost with no buyer. Name the row you picked, and why, in your first message so the user can push back before the delegation is paid for.
Light loop
For work whose diff is verifiable by one mechanical comparison — a file moved from one directory to another with only import lines changed, plus a thin wrapper — the reviewer and simplifier re-read a diff that diff -r already judges. Run tester and implementer only; the supervisor does the read-only verification.
The ticket carries loop: light (see references/ticket-shape.md); Phase 0 sets it from the downshift row. Phase 4 and Phase 7's reviewer/simplifier dispatch are skipped. Everything else — tester first, implementer, oracles, push verification, ticket close — is unchanged.
Supervisor verification checklist for a light-loop ticket, run at the implementer's head SHA:
diff -r <source dir> <destination dir> --exclude=node_modules --exclude=dist | grep -Ev '^(<|>) *import|^(<|>) *} from|^(diff|---|Only in)' # expect empty
git ls-files <destination dir> | grep -E 'node_modules|/dist/|\.tsbuildinfo|\.DS_Store' # expect empty
grep -rnE "^export (type|interface|enum) <Name>" <repo source roots> for each exported type the diff adds # one hit per name
<ticket Verification command> # exact pass/total
Escalate to the full loop mid-ticket, and dispatch Phase 4 on the same head SHA, when any of these hold:
- The first diff command above prints a non-import hunk.
- The implementer's return lists a non-empty "deviations from ticket".
- The tester's parity pins needed a threshold, tolerance, or normalisation the legacy suite did not have.
Across sibling light-loop tickets, reuse the same tester and implementer agents via SendMessage with a delta brief — the re-read of repo and conventions is the cost being cut, and a fresh agent pays it again.
Phase 0 — Ticket
The pipeline runs on a ticket in the shape of references/ticket-shape.md.
- If the user hands you a ticket, validate it against that shape: every Acceptance bullet has an
oracle; Out of scope and Pinned rules are present;
mode: AFK;effort: S|M;loop: full|lightset per the downshift table. - If the user hands you prose, inspect the repo and DRAFT the ticket yourself in that shape, write it to the repo's ticket directory, show it, and wait for approval. Phase 0 is the only place the pipeline blocks on the user — the ticket is the scope contract, and the intent pass below is part of that block.
- If the work is L, or is N similar units, draft a plan per
references/plan-shape.mdplus its tickets, and run one ticket at a time. - Anything answerable from the repo — base SHA, commands, conventions — you fill in yourself; never ask the user for it.
- Run the intent pass below over every ticket that arrives with
intent_recorded: null, before any delegation — one you drafted, and one the user handed you. A ticket the user wrote with an agent carries that agent's choices too. - Only
mode: AFKtickets enter Phase 1, and only withintent_recorded:set. - Run the supersession check (
references/ticket-shape.md) before writing a new ticket.
Intent pass
A ticket an agent drafted reads as settled work, which is exactly what hides the choices the agent made
on its own. The intent pass is an interactive review of those choices: the user reads each ticket by
answering for it, and the answers land in the ticket as ## Recorded intent.
Ask about choices, not facts. A repo fact — test command, conventions, base SHA — you answer yourself and never ask. A load-bearing choice the drafter made unilaterally you ask even when the ticket already states it: the ticket stating it is what makes the question worth asking, because a choice the user confirmed and a choice the drafter drifted into look identical on the page.
Two passes, after every ticket is drafted and before any delegation:
- Plan pass. Choices shared across tickets — framework, storage, auth, wire format — asked once and
recorded in the plan's
## Decision, taggeduser-decided. Tickets reference the plan and never re-ask. Without this pass, ten tickets ask the framework question ten times. - Ticket pass. Enumerate every candidate question across all tickets, rank each by how much work a wrong answer throws away, cut to the budget, then ask in dependency order.
Budget, because attention is the scarce resource here and ten tickets at four questions each is a wall nobody reads:
- 1 question per ticket minimum, 4 maximum.
- Plan-wide total:
<ticket count> + 4. Spend the slack on the tickets whose wrong answer costs most. - Pack four questions per
AskUserQuestioncall, drawn across tickets, withheadernaming the ticket id. Ten one-question tickets are three prompts, not ten.
Question shape: option 1 is what the ticket currently says, labelled (Recommended), with its reason
grounded in the repo wherever the repo has evidence — "apps/portal already runs Next 15", not taste.
Options 2–3 are the live alternatives. Taking the recommendation is a confirmation; taking another is an
override, and an override records the user's own words verbatim.
Candidates below the cut are not dropped into silence. Write each into the ticket as an Assumed. entry
in ## Recorded intent. An assumption the user can read and reverse costs no prompt; an assumption
nobody wrote down is the drift this pass exists to catch.
An override that invalidates a sibling ticket sends that sibling back for a redraft plus one more question. One redraft round, then proceed.
Roles and tools
| Role | Tool | Authority | Model | Effort |
|---|---|---|---|---|
| Supervisor | — (you) | Plan, delegate, gate, verdict | inherit | high |
| Tester | Agent(subagent_type: "subagent-tester") |
Tests only; acceptEdits |
sonnet | medium |
| Implementer | Agent(subagent_type: "subagent-implementer") |
Production changes; acceptEdits |
sonnet | high |
| Reviewer | Agent(subagent_type: "subagent-reviewer") |
Read-only diff review; dontAsk |
sonnet | medium |
| Simplifier | Agent(subagent_type: "subagent-simplifier") |
Read-only simplification audit; dontAsk |
sonnet | medium |
Effort applies where the runtime exposes it (Codex model_reasoning_effort); on Claude Code the Model
column is the lever.
Agent definitions live in ~/.claude/agents/subagent-*.md; if the session's agent list does not show them, stop and tell the user before Phase 2.
You coordinate and maintain the ticket, plan, and handoff documents. Production and test edits stay with their assigned roles unless the user explicitly asks you to make them. Documentation updates are serial too: do not write while another writer or a same-SHA review is active.
Runtime adapter
Abstract needs, per host. Delegate a role means "hand the role's roles/<role>.md body plus the ticket
brief to a fresh agent." Sources are cited per cell; a cell with no confirmed source says so.
| Need | Claude Code | Codex CLI |
|---|---|---|
| Skill install path | ~/.claude/skills/supervised-dev |
~/.agents/skills/supervised-dev (user-level; repo-level is <repo>/.agents/skills) — symlink one dir to serve both: ln -s ~/.claude/skills/supervised-dev ~/.agents/skills/supervised-dev. Source: developers.openai.com/codex/skills (redirects to learn.chatgpt.com/docs/build-skills). |
| Delegate a role | Agent(subagent_type: "subagent-<role>") |
No native subagent/spawn command found (R3; see codex --help command list, local codex-cli 0.153.2). Supervisor shells out per delegation: codex exec -s <sandbox> --approve-for-me -m <model> -c model_reasoning_effort=<effort> "$(cat roles/<role>.md)"$'\n\n'"<ticket brief>". Source: local codex exec --help. |
| Write-capable role permissions | permissionMode: acceptEdits |
-s workspace-write --approve-for-me (sandbox permits workspace writes; approvals routed through automatic review instead of prompting). Source: local codex exec --help. |
| Read-only role permissions | tools: list omits Edit/Write, plus permissionMode: dontAsk |
-s read-only (sandbox blocks writes outright). Source: local codex exec --help. |
| Model per role | sonnet (all four roles) |
unconfirmed — verify. No per-role Codex model recommendation found in R2/R4; only generic example ids (gpt-5.6-terra in docs, gpt-5.3-codex-spark in the local codex-cli-runtime skill for an unrelated "spark" mapping). Do not guess a model id. |
| Reasoning effort | No knob; the Model column is the lever | -c model_reasoning_effort=<value>, values minimal, low, medium, high, xhigh. Value vocabulary confirmed via local skill .../codex/skills/codex-cli-runtime/SKILL.md (--effort wrapper flag). Exact TOML key spelling model_reasoning_effort is unconfirmed — verify: developers.openai.com/codex/config returned HTTP 404 when fetched. |
| Handoff path | docs/<feature>/handoff.md, following repo convention |
Same tracked path; see Durable state |
| Optional scratch logs | Outside the repo | ${TMPDIR:-/tmp}/supervised-dev/<branch>/ |
| Continue a role agent across batches | SendMessage to the same agent |
No native resume-a-role feature (R3). Use codex exec resume --last (or by session id) on that role's own subprocess session, sending only the delta instruction. Source: local codex exec --help ("resume Resume a previous session by id or pick the most recent with --last"). |
Details, unconfirmed items, and a Codex smoke test: references/codex-host.md.
Model, and the four-role cap
Model choice is the primary cost lever, not just a style knob. Pick a cheaper model for read-only roles; step a role up only when the work demands it.
- Reviewer and simplifier run on
sonnet. Review precision does not need the strongest model, so one cheap pass per SHA beats one expensive pass. Escalate a single re-review to the strongest available model only for a diff touching auth, credentials, or destructive operations. - Step the implementer up to the strongest available model for demanding work: concurrency, teardown, wire formats, or a tracer unit that must establish the pattern for N siblings.
- Never run a searching role on the cheapest model. A cheaper model calls search and retrieval tools less and answers from memory instead. A simplifier that does this will assert "no consumer" without running the call-site grep that is the only thing making that finding admissible.
- Keep thinking enabled. Disabling it is the wrong cost lever — pick a cheaper model instead. With thinking off, an agent occasionally writes a tool call into its prose instead of calling the tool, and can leak internal XML tags into the return. A return that narrates a command it never ran is unexecuted work: re-delegate it, never read it as a result.
- A benign brief can come back as a safeguard refusal. Compile-check phrasing ("does this compile without errors?") and base64 blobs in tool output are the known triggers: ask "are there bugs in this", and never paste base64 into a brief. A refusal is a phrasing defect in your brief, not a finding, and not evidence about the code.
- Four delivery roles is the cap. No subagent spawning its own. The supervisor may dispatch one read-only context investigator for broad sweeps or costly exploration, before delivery agents run (see Phase 1). This is an optional context pass, not a fifth delivery role or another review gate.
Effort-specific guidance below applies where the runtime exposes an effort knob (Codex); on Claude Code pick the model tier instead.
- Effort labels are not portable. The same word buys different amounts of thinking on different models, so a level that worked for a role last quarter is a starting point, not a setting. Confirm against the model actually behind each role. (Codex; on Claude Code pick the model tier instead.)
- Step the implementer to
xhighonly for demanding work: concurrency, teardown, wire formats, or a tracer unit that must establish the pattern for N siblings. (Codex; on Claude Code pick the model tier instead.) - Never run a searching role at
low. At low effort models call search and retrieval tools less and answer from memory instead. A simplifier atlowwill assert "no consumer" without running the call-site grep that is the only thing making that finding admissible. (Codex; on Claude Code pick the model tier instead.) - At
xhighormax, leavemax_tokensheadroom for the thinking and the output. A long deliverable can get drafted inside the thinking and written again as the reply, which doubles the turn and can truncate it. Long prose deliverables run athigh. (Codex; on Claude Code pick the model tier instead.)
Sequence
Phase 1 — Scope
Inspect the repository to understand current state. Clarify only decisions with real consequences. Record:
- Exact file scope
- Acceptance criteria (pass/fail, not vague goals)
- Out-of-scope list
- Known decisions
- Architecture rules to pin: conventions this change must not break, read from the repo's
AGENTS.md/CLAUDE.mdand neighbouring code - Verification command: the cheapest relevant check for the affected workspace, read from the repo's own docs — never guessed
- Full gate set: read it off what the repo's own
verify:local/verify:push/ CI phase scripts actually compose. Do not hand-write the list, and do not inherit one from a previous session's handoff. A gate you never listed is a gate nobody runs (incidents.md #1). - Expected-red inventory: list the gates that are red by construction for the whole ticket, and record why — an end-state test can stay red for an entire sweep by design (incidents.md #2). Exclude these from the per-batch loop, never hand one to an implementer to "fix" into green, and route its teardown to a tester pass.
- Oracle per criterion: the exact command or state check that decides it. A criterion with no oracle is a wish — give it one or move it out of scope. You stop when the oracles pass, not when the work looks finished. When the build emits nondeterministic artifact names, the oracle must normalize before comparing (incidents.md #3).
- CI trigger map: read the repo's own workflow files and record what actually fires the gates Phase 8 depends on — including the branch filters, not just the event names. A push can fire no CI at all if the filters exclude it (incidents.md #4); read the filters in Phase 1, do not infer them from the event list.
- Capability preflight: confirm the tools the plan leans on actually work here, before planning around them — package registry reachability, auth for any host CLI, worktree cleanliness, write access (incidents.md #23). Never route around a failure by hand-editing a lockfile.
- Working branch or worktree: create it before recording base SHA, named per repo convention, and record the branch name in the handoff. A fresh worktree has no
node_modules, so a barenpx <tool>inside it can resolve a different tool version than the main checkout — run formatters and linters from an installed tree, or install first.
A ticket in the shape of references/ticket-shape.md already answers most of the above:
| Ticket section | Phase 1 field |
|---|---|
| Recorded intent | Known decisions |
| Required changes | File scope |
| Out of scope | Out-of-scope list |
| Pinned rules | Architecture rules to pin |
| Acceptance | Acceptance criteria, oracle per criterion |
| Verification | Verification command, full gate set seed |
source: |
Evidence index for scoped reading |
blocked_by/blocks |
Sequencing |
mode/effort |
Eligibility |
The ticket does not carry the expected-red inventory, the CI trigger map, or the capability preflight — derive those in Phase 1 regardless.
A recorded-intent decision that is testable is already a pinned rule (references/ticket-shape.md); the
rest are constraints you carry into the briefs, not tests.
Run: git rev-parse HEAD to record base SHA.
Collect context once, refresh the delta
Before the first tester dispatch, finish the scope recon. Persist decisions and resume information in
the ticket and docs/<feature>/handoff.md; put detailed, source-derived assignment context in temporary
briefs when useful (see Brief hygiene). Read all sources relevant to the ticket: scoped files, callers,
tests, configuration, and representative implementations. Collect:
- Branch/worktree, base SHA, and the SHA inspected; identify any relevant uncommitted changes separately.
- Exact source paths and symbols, their responsibilities, and dependencies that affect this ticket.
- Current allowlist contents with their owning file/symbol when applicable; label these as observed state, separate from the ticket's required end state.
- For sweeps, a per-service/unit table: unit, exact paths, migration state, remaining work, and commit SHA when completed. Include every target, including blocked and untouched units.
- Sample implementation and test pattern references (
path:symbol), with exceptions called out. Once the tracer passes its gates, make it the canonical reference for later batches. - Phase 1 gate commands and tiers, expected-red inventory, CI triggers, preflight results, and gaps. Mark missing coverage explicitly; do not imply an unread source was inspected.
The supervisor normally does this during Phase 1. For a broad sweep or costly exploration, it may use one read-only investigator/fork supported by the host, scoped to the ticket and these return fields. The investigator does not edit files or spawn agents. The supervisor checks its findings and places them in the appropriate durable document or temporary brief before delivery delegation. If that capability is unavailable, collect locally; no new installed role is required.
Before every tester or implementer dispatch, including batches and fix/retest cycles, compare the recorded branch, inspected SHA, and working-tree state with current state. Inspect intervening changes and refresh affected context, including allowlists and new tests. Reuse unchanged findings rather than repeating the full recon. A resumed Phase 1 still re-derives repository-owned gates and allowlists from their owners. Preserve the original base SHA; a branch/base mismatch must be reconciled before using the snapshot. Record the updated checkpoint and refresh any affected brief before dispatch.
Brief hygiene
Every template below is a contract, not prose. Applies to all four roles:
- Temporary assignment briefs. For detailed delegation, write a role/batch brief outside the repo,
for example
/tmp/supervised-dev/<ticket>/impl-batch-fg.txt, and instruct the agent to read it before starting. Include the assignment scope, source-derived values, pattern references, exact commands, and expected return. Shared source findings may serve several briefs. Keep short assignments inline; a brief does not change batch size, commit granularity, role permissions, or gate ownership. - Make briefs traceable. Include the exact starting SHA, repo/worktree and branch, real ticket and handoff paths, and source references for collected facts. Pin the SHA after the preceding checkpoint; never leave it as "the previous batch's commit". Distinguish observed values from required changes. The ticket owns scope and decisions; a temporary brief cannot silently override them.
- Shared context first. Every dispatch, including re-delegation, names the ticket and handoff paths
and any assignment brief. Read the brief first when supplied, then ticket status (
Current status, orNotes),Recorded intent, recentUpdates, and handoff findings before scoped source reading. The snapshot saves discovery; it does not replace the reviewer's full diff/call-path reading, the simplifier's consumer searches, or live gate evidence. - Point, do not paste. Give
path:symboland SHA-qualified findings. Temporary briefs may include exact allowlist entries, commands, or small examples needed for the assignment; avoid copying entire source files or duplicating that recipe into the ticket/handoff. Agents report stale facts or missing context to the supervisor, who maintains the shared documents. - State only the delta on re-delegation. An agent you already briefed still holds the recipe; re-sending the whole ticket invites it to redo settled work.
- Demand exact returns, and name the fields. SHAs, counts as
passed/total, verbatim failure text, and the commands actually run. Ban summary adjectives: "suite is green" is not a result;854/854is. Ask for the fields and the table explicitly — current models reach for structure less on their own, so an unspecified return format comes back as prose you have to parse. Ban adjectives, not status lines. Do not write "hold all findings for the final response" or otherwise suppress narration: models already go quiet through long tool chains, and a silent agent is indistinguishable from a stalled one. Ask for a line when it starts, a line when it changes direction, and the exact fields at the end. - A sent brief is not a started task. After delegating, confirm the agent actually picked the work up — new commits, or an agent-list check — instead of assuming a delivered message equals work in progress (incidents.md #5).
- Say the user is not watching. Every brief opens with it: the agent is operating autonomously, nobody can answer mid-task, so "shall I apply this?" blocks the work. Reversible steps that follow from the brief proceed without asking; only destructive actions and genuine scope changes stop. Without this, an agent describes its next step and ends the turn, and the step stays undone until you reply.
- Point at recorded intent; never re-open it. Briefs cite
<ticket path>## Recorded intentrather than pasting the decisions. An agent that reconsiders a recorded choice is re-running the intent pass with nobody in the room, and the answer it invents outranks nothing. - Carry the scope clause. Deliver what the brief asks at the scope asked; make routine judgment calls yourself; if the ticket looks mistaken, say so in one sentence and continue as asked rather than narrowing, widening, or transforming it. A pre-existing bug, a nearby performance smell, or undocumented behaviour found while working is a follow-up line in the return, not a change in this diff. Current models expand scope on their own judgment far more readily than they omit work, and an unasked-for improvement lands in the same diff the reviewer must clear.
- Ask for surgical edits. Say that edit tokens are to be minimized and a file should be patched, not rewritten, where that does not change the result. Left alone, models rewrite whole files for small changes — same content, but a diff the reviewer cannot read and a base SHA comparison full of noise.
- Do not ask an agent to double-check itself. Agents already verify their own work; "re-verify before reporting" or "add a final verification step" compounds with that and buys tokens, not quality. Brief the oracle instead — the exact command whose output decides the criterion. Supervisor verification is a different role reading a different signal, not the same agent looking twice.
- Never brief a read-only role to be conservative. "Only report high-severity issues" or "be conservative" is followed literally and suppresses real findings. Ask for everything at every severity; Phase 5 is the filter, and disproving a finding is cheaper than missing one.
- Ban correction narration and mannered prose. Returns state the final measured state, in direct language. An agent recounting what it first got wrong then fixed costs a re-read and buries the number you asked for, and metaphor in a return ("the dial worth turning") drags in connotations that make a fact ambiguous.
Phase 2 — Tester first
Call subagent-tester with this template:
Ticket: <ticket path>
Handoff: <handoff path>
Assignment brief: <path, if used>
Read first: assignment brief if supplied, then ticket status/Notes, Recorded intent,
recent Updates, and handoff findings.
Base SHA: <sha>
Current head SHA: <checkpoint sha>
Acceptance criteria: <list>
Out of scope: <list>
Architecture rules to pin: <list from Phase 1>
Write two test classes:
1. Acceptance tests, one roughly per stated behavior. These must FAIL against
the current production code — they assert what the ticket has not built yet.
2. Architecture-pin tests, one per architecture rule listed above. These assert
a rule the change must not break, so they must PASS against the current
production code. Their job is to catch the implementer breaking the rule
later, not to fail now.
Do NOT fix production code.
Do NOT soften assertions.
Size the suite to the ticket, in the style and file layout of the neighbouring
tests. Scratch scripts and throwaway checks are yours to use and are NOT
committed as permanent test files.
Commit your test changes.
Return: test commit SHA, list of test files changed, which acceptance tests fail
and exact failure message, which architecture-pin tests pass and their names.
Wait for result. Confirm acceptance tests fail on base SHA and architecture-pin tests pass on base SHA. If tester edits production code, reject and re-delegate.
Count the committed test files against the criteria before accepting. Models over-commit tests on
open-ended briefs — scratch checks get promoted into permanent files, and every extra file is surface the
implementer must keep green and the reviewer must read. An unasked-for test file is an in-diff S1 for
the simplifier, and it is cheaper to reject it here.
Phase 3 — Implement
Call subagent-implementer with this template:
Ticket: <ticket path>
Handoff: <handoff path>
Assignment brief: <path, if used>
Read first: assignment brief if supplied, then ticket status/Notes, Recorded intent,
recent Updates, and handoff findings.
Base SHA: <sha>
Current head SHA: <checkpoint sha>
Test commit SHA (do not modify these tests): <tester sha>
Acceptance criteria: <list>
Out of scope: <list>
You are operating autonomously; nobody can answer questions mid-task. Reversible
steps that follow from this brief proceed without asking. Stop only for a
destructive action or a real scope change.
Fix production code so the tester's tests pass.
Do NOT change test files or soften assertions.
Do NOT expand into other tickets. A pre-existing bug or nearby smell you find is a
follow-up line in your return, not an edit in this diff.
Do NOT rebase, merge, pull, fetch, or reset. If you think history must move, stop and report.
Patch files surgically; do not rewrite a whole file for a small change.
Oracle: <verification command from Phase 1>. Green on this command is the done condition.
Commit when done. Do NOT push.
Return: head SHA, changed files, verification commands run (fresh vs cached), deviations from ticket,
follow-ups you deliberately did not fix.
Wait for result. Confirm tester's tests pass at returned SHA without modification.
The rebase prohibition is not paranoia: an unasked rebase can move the base SHA and invalidate every later comparison (incidents.md #6). Every "record the measured fact with its SHA" rule below collapses the moment an agent can move the base underneath you.
Pushing is the supervisor's job, not the implementer's — see Phase 5. Then verify your own push actually
happened: "pushed" means "committed" until git rev-parse <remote-ref> says otherwise (incidents.md #7).
Run that command yourself after every push; do not trust the push command's own exit status as the signal.
Tickets made of repeatable units
N similar units is one plan and N tickets, serial where files overlap — see references/plan-shape.md.
When the ticket is N similar units (N services, N packages, N call sites), do not hand one agent all N — a single oversized batch burns hours on archaeology for one file where a re-briefed batch does three in the same span (incidents.md #8).
Batch for commit granularity and supervision, not for context — the model holds the whole ticket fine, and it works best given the complete specification for its batch and then left alone. So each batch brief carries the full spec for its units and nothing withheld. A batch briefed in fragments is a batch that stalls on questions the ticket already answered.
- Unit 1 is a tracer bullet. Take one unit through every gate, including the aggregate-only ones — composed build, parity, boundaries. A pattern that passes unit-local tests and breaks the composed build is cheaper to find once than N times. That verified unit is then the canonical reference; name it in every later brief, or reviewers infer the pattern from whichever sibling they read first.
- Delegate 2–3 units per run, and require a commit per unit before the next unit starts. Otherwise an agent finishes several units, holds them all uncommitted, and one interrupt loses the lot.
- Do the units that force a shared-config decision last, once the mechanical pattern is proven on the easy ones.
- Reuse the same agent across batches so it keeps the recipe, and state only the delta in each new brief.
Tier the gates
Knowing the full gate set does not mean running it per unit. Classify every gate by the smallest scope that can change its result, and run it only at that tier — re-scanning the whole repo per batch to validate a few new files catches almost nothing for the cost (incidents.md #9).
| Tier | What belongs there |
|---|---|
| Per unit | that workspace's own type-check, lint, unit tests — the mechanical-error class, in seconds |
| Per batch | the aggregate-only gates whose failures interact: composed build, parity |
| Once at the end | repo-wide scans no single unit can regress: boundaries, formatting, full browser suite, expected-red suites |
The tracer unit is the exception and still gets every gate — that is what makes it a tracer. Batches 2..N do not.
Split gate ownership along the same line: the implementer runs the per-unit tier only, the supervisor owns the per-batch and end tiers — a long gate handed to an implementer can burn the run in a stall-watchdog retry loop instead of producing work (incidents.md #10).
Verify the report, do not transcribe it
These evidence and gate-ownership rules apply equally to Codex and Claude Code. Use whichever command output or retained logs the host exposes; do not require a host-specific validator to run the delivery pipeline.
An implementer's summary alone is a claim, not evidence. Inspect the underlying command output or retained log, actual test-process exit status, pass/fail/skip counts, and evaluated SHA before accepting the result (incidents.md #11). A supervisor need not launch the same command to verify that evidence. Reuse an agent's measured result when those facts are available and the relevant inputs are unchanged. If evidence is missing or ambiguous, recover it first; rerun only the smallest gate needed to resolve the gap.
Assign one execution owner to each expensive gate before dispatch. Do not have implementer, tester, and supervisor each run the same full suite. An already completed qualifying run satisfies that gate; independent review and targeted regression checks provide separate scrutiny. Record elapsed time for expensive checks so the next dispatch can avoid duplicating their cost.
Your own commands lie the same way, through the shell rather than through prose. An exit code read
through a pipe is the last stage's status, not the command's (incidents.md #12). Read the pass/fail
counts out of the log, or the EXIT= line the script itself wrote — never the status the wrapper reports.
Establish your task runner's abort semantics in Phase 1, from its own docs. A runner that stops at the first failing task reports a total that is a truncation, not a census, so the "N total" in a wide run is not the size of the gate until you pass whatever flag makes it keep going.
Issue independent gates in one response. Type-check, lint, and unit tests for a batch do not depend on each other's results, and in coding loops the default drift is one tool call per turn — each extra turn costs a round trip and a full context read for nothing. Decide what you need next, then request all of it that has no ordering dependency at once.
Also check the brief was actually obeyed: diff the units it claims to have done against the units you asked for. An agent told to do one batch may quietly continue through the rest of the ticket. That is not automatically wrong, but it means nobody supervised the later units, so they need the same verification the first batch got, not less.
Cut the other way too, before blaming an agent for a diff it could not plausibly have produced: confirm the
SHA you are diffing from is still an ancestor (git merge-base --is-ancestor) — a diff crossing an
orphaned fork point can look like agent damage that was never there (incidents.md #13).
Phase 4 — Review and simplify (parallel, same SHA)
Finish the handoff checkpoint first. Use its committed head as <review head sha> in both briefs;
the implementer's returned SHA remains the SHA of its own changes and measured checks.
Call subagent-reviewer with this template:
Review the diff from base SHA <base sha> to head SHA <review head sha>.
Ticket: <ticket path>
Handoff: <handoff path>
Assignment brief: <path, if used>
Read first: assignment brief if supplied, then ticket status/Notes, Recorded intent,
recent Updates, and handoff findings.
Acceptance criteria: <list>
Run: git diff <base sha> <review head sha>
Read the full diff and surrounding call paths.
Review production code and tests together.
Check error paths, edge cases, and false-green test risk.
Report every issue you find, at every severity. Do NOT pre-filter, and do NOT
withhold a finding for being uncertain — mark it uncertain and report it.
Do NOT edit files.
Do NOT post GitHub comments or touch any PR.
Return findings ranked by severity:
P0: security, data loss, destructive behavior
P1: correctness defect or explicit acceptance violation
P2: valuable improvement, non-blocking
P3: style or preference
For each finding: file, line, severity, problem, high-level fix.
Call subagent-simplifier with this template:
Audit the diff from base SHA <base sha> to head SHA <review head sha> for simplifications.
Ticket: <ticket path>
Handoff: <handoff path>
Assignment brief: <path, if used>
Read first: assignment brief if supplied, then ticket status/Notes, Recorded intent,
recent Updates, and handoff findings.
Acceptance criteria: <list>
Run: git diff <base sha> <review head sha>
Read the changed files in full plus their call sites. Follow the code; do not guess.
Find surface this diff ADDED that costs more than it buys:
- New public method, export, config knob, event, helper, or type with no consumer outside tests
- Two representations of the same fact introduced by this diff
- Defensive copies, validators, or guards on values a typed same-process caller already guarantees
- Speculative generality: options, hooks, or extension points with no current caller
- Hand-rolled code where a maintained dependency or a runtime builtin already does the job, and the swap deletes the implementation plus its dedicated tests
- Added-then-unused test scaffolding, fixtures, or snapshot entries
- Comments that restate the code, or docs that duplicate a fact owned elsewhere
For each finding classify SCOPE, then SEVERITY.
SCOPE:
in-diff: th
…(truncated)