The user's six-stage feature pipeline (discuss → plan in native plan mode → validate + approve → delegated execute → one codex challenge per feature → ship), the parallel multi-agent mechanism picker, and the token-discipline rules for long-running agents. Invoke BEFORE starting any non-trivial feature — multiple steps, or work that benefits from a formal review cycle — and before any parallel/multi-agent fan-out. One-shot edits and small fixes outside an active pipeline skip it.
11 stars
0 votes
0 copies
0 views
Added September 25, 2026
ai-agentsgoshellbashgitapidatabasesecurity
Works with
cli
api
Security analysis
B75/100
criticalSends environment variables or credentials to an external URL
Installs into .claude/skills of the current project.
Are you the author of Feature Workflow?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/turbokach-feature-workflow)
---
name: feature-workflow
description: The user's six-stage feature pipeline (discuss → plan in native plan mode → validate + approve → delegated execute → one codex challenge per feature → ship), the parallel multi-agent mechanism picker, and the token-discipline rules for long-running agents. Invoke BEFORE starting any non-trivial feature — multiple steps, or work that benefits from a formal review cycle — and before any parallel/multi-agent fan-out. One-shot edits and small fixes outside an active pipeline skip it.
---
# Feature workflow
For pipeline-path work (global CLAUDE.md → Feature workflow): a design/product/UI choice, irreversible, or a real multi-step arc. One-shot work (no design choice, reversible, no plan needed — any file count) skips this skill entirely — but not the codex cross-review: it still runs one `codex-challenge.sh <pre-change-sha>..HEAD` run on its diff under the stage-5 rules before the change counts as done.
One **master session** owns the feature end-to-end. It stays thin by running every token-heavy stage **out of main context** — in a subagent or an agent-team agent. The master coordinates, authors the plan, and ingests summaries; it does not implement. Plan files live in the repo at `docs/prompts/<feature>-plan.md`.
Six stages:
1. **Discuss approach.** Explore the problem space, surface constraints, decide what's worth building. No code.
2. **Plan in native plan mode** → the master calls `EnterPlanMode`, then authors the plan itself, writing directly into the plan file named in the plan-mode system message — that file is the canonical plan until approval. Write it once; every later change is an `Edit` of the section that changed, never a whole-file rewrite — each rewrite re-enters the full plan into the master's context. Codebase discovery goes to `explorer` subagents (Sonnet, read-only), which return summaries; the master reads no product file itself in plan mode — a hard line in global CLAUDE.md, because exploration done in the master's own context is re-paid by every later turn of the arc. Revisions — reviewer blocking findings, user answers, ExitPlanMode "keep planning" feedback — are the master's own edits of the plan file, not a fresh spawn.
**Plan shape.** The plan states: the goal; the ordered steps; the parallel decision (below); every execution step names the subagent that executes it (`step-executor` for a sequential step, `team-executor` for each step of a pair) — never the master; steps sized so an executor finishes in roughly ≤100 tool calls — a step that edits or creates 7+ files, or sweeps existing call sites while adding behavior, is over it — split otherwise; each arc sized to one review gate and one master session — more than 5 execution steps, or steps that together touch 40+ files, is two arcs, split along feature blocks, each with its own session, its own stage 5 and a device/client pass between, and the plan names the checkpoint; acceptance criteria stated once per step; edge cases; for every existing identifier whose meaning or scope the plan changes, the explorer-produced list of its call sites (file:line) inside the step that changes it — the executor works a checklist, not a search, because a sweep run from search misses sites and each miss is a stage-5 finding; for every new mechanism (a parser, a cache, a transform, an undo basis), one line naming the invariant that must hold and its bound — max size, count, or memory, and what happens past it — because a fix loop never converges on a mechanism the plan left unbounded — fixers patch the trigger round after round; a verification step that drives the positive path through the real client (`/browse` for web, a simulator or device render for iOS, the built routes for a web build) — curl and unit suites prove only the negative path; per-step verification is the build plus the targeted suites the step touches, with the full suite run once as its own final step; any step marked Opus carries a one-line reason (a design call left to the executor, work spanning several subsystems or that no single test or build can check, or a hard class — concurrency, security, data migration, structural refactor); and a taste/open-decisions list, each item with a recommended option and the simplest option, never decided silently.
**Parallel decision.** Once the steps are drafted, weigh whether two of them should run at the same time, and write the result as one line in the plan: `Parallel: none — <reason>`, or `Parallel: Steps <a> + <b> — <gain; costs>`. Sequential is the default. Hard limits: at most two executors at once unless the owner asks for more; the pair shares no file, hub files included (a registry, router, barrel export, project file, entrypoint); neither step consumes the other's output (a type, API, schema or migration the other creates). Within those, weigh the time saved — worth it only when both steps are long, roughly 15+ minutes each — against what concurrency costs in this project: a build or test runtime both steps need exclusively (one device or simulator, one container stack, fixed ports, a shared local database) makes them queue or corrupt each other's state; each worktree is a fresh checkout, so its first build is cold — no build cache or gitignored files (`.env`, local config) unless `.worktreeinclude` copies them; and the pair adds one merge. The discovery brief asks explorer for those runtime facts unless the project's CLAUDE.md already records them.
3. **Validate + approve** → spawn `team-plan-reviewer` (no `model:` — it inherits the session's model; read-only, one pass) with the plan-file path; it checks the plan against the code and returns `blocking` / `advisory` findings. Blocking → the master revises the plan file → done (no re-review unless the revision was material; never more than two review passes). Advisory → reported to the user at the gate, never looped on. Then resolve the plan's taste/open decisions with **one** AskUserQuestion (per the Plan gate cap in global CLAUDE.md), edit the answers in, and call `ExitPlanMode` — Claude's native approval gate. Delegated approval (the owner said "approve it yourself") follows the AFK gate's two branches in global CLAUDE.md: not yet in plan mode → skip it, plan file straight to `docs/prompts/`, reviewer still runs; already in plan mode → say in one line that only the owner's click or Shift+Tab leaves plan mode, before they go. "No, keep planning" feedback goes back to the master's own revision of the plan file and through `ExitPlanMode` again; on approval the master copies the plan file to `docs/prompts/<feature>-plan.md` and commits it where the project tracks `docs/prompts/`, records the feature-base sha (`git rev-parse HEAD`) for the stage-5 range, and mirrors the plan into the native **task list** (`TaskCreate`): one task per execution step plus the fixed tail — codex verdict clean or round 2 final with the remainder deferred; standalone-P2/test-gap/theoretical fix-or-defer asked and tech-debt entries committed; test suite exits 0 with output shown; handoff written; no live agents and no executor worktrees left (`git worktree list`; a leftover goes to a `team-merger`). Chain them with `TaskUpdate addBlockedBy` where a step actually consumes an earlier one's output — it edits a file that step created, builds on a decision it made, or verifies its work; steps that need nothing from each other stay unblocked, and both steps of a pair carry the same `addBlockedBy` set. The codex task is blocked by every step, the fix-or-defer task by codex, tests/handoff/no-live-agents by everything before. The plan doc stays the source; the task list is its live summary (`Ctrl+T`). Then start stage 4 unprompted.
4. **Execute** → delegate each step to a subagent; commit per step. Spawn executors **unnamed** — `name:` reroutes delivery to the teammate mailbox, an extra hop an executor has no use for; unnamed spawns auto-deliver their final report. Sequential steps go to `step-executor` (session's own branch, no worktree — it's the only writer in flight). A pair from the plan's `Parallel:` line spawns as two `team-executor`s in one turn — each gets its own worktree from the agent's frontmatter, branched from the session's HEAD (`worktree.baseRef: "head"`) — and no other writer runs until it lands. When both report done, one `team-merger` — briefed with both branch names and worktree paths from the reports, and each step's build and targeted suites — merges both branches into the session branch, runs those, and removes the worktrees; each step's task completes when the merger reports it landed, and the per-step round then launches on the merged range as for one step — no `team-reviewer`. A unit that stops short (a blocker, an API death, a second cap) is landed as it stands — the merger commits its leftover edits as `WIP:` — and a `step-executor` finishes it on the session branch before the round launches. A conflict the merger doesn't resolve, or a red build or suite after the merge, goes to one `fixer` before the round launches. State each step's acceptance criteria once and stop there — no "re-verify", "double-check", or per-round verification rituals in spawn prompts. Size and split spawns here, not later: a plan step is sized so a step-executor finishes in roughly ≤100 tool calls (split it in the plan if it can't), and every spawn carries exactly one concern — one step, or one fix. Never bundle several playtest fixes, regressions, or finding sets into a single spawn; a fixer gets the plan section, the diff range, and the one finding set it is fixing. **Fixing reported-broken behavior is red-then-green, test-first:** the test is written and run red *before* the fix is applied — one red run, then the fix, one green run, both shown. Reverting a finished fix to show the test red is the fallback, not the default. This is an acceptance criterion, not a verification ritual. It applies to fixers and to any step whose job is a stated bug; a step that builds new behavior just states its criteria. **Test cadence:** a step's acceptance criteria name the build and the targeted suites that cover it; the whole test suite runs once after the last step lands (the master schedules it as the final execution task) and again after the fix loop — never per step. Test evidence from any agent — executor, fixer, or a base-comparison spawn — is the runner's executed/skipped/failed counts, never just the absence of failures: a suite whose environment gate skips silently reads green. **Per-step review:** round N launches in the same turn step N's commit lands, range `<previous round's head>..<HEAD now>` (round 1's base = the feature base) — contiguous by construction, since every commit between two rounds, including fixer commits, lands in exactly one round and the rounds jointly cover the range with no gap; the last step gets no per-step round, stage 5 covers it. Always `--pin` (a later executor may be writing) — the script creates and removes its own worktree, the master never adds or removes worktrees itself. Verbatim call: `~/.claude/skills/feature-workflow/scripts/codex-challenge.sh <base>..<head> --pin --trace --out <scratchpad>/codex-step<N>.md` as one `run_in_background` Bash with `timeout: 7200000` whose `description` names the round and range — `Codex challenge step <N> · <base>..<head>` — since that label is all the task list shows of a background shell; the master ends its turn or does work not depending on the verdict. On completion: one `codex-triage` spawn — file path(s), range, head sha, verified with `git show <head>:<path>` / `git diff <base> <head>` — and P0/P1 findings go to one `fixer` before the next executor that depends on the reviewed step spawns (fixer and executor are both single-writer, so the fixer goes first and the following round's range contains the fix). The step boundary is dependency-aware, using the task list the stage-3 mirror already builds (`addBlockedBy` where a step consumes an earlier step's output): an executor spawns only when every step it is blocked by has its per-step verdict in and its P0/P1 fixed; a step blocked by nothing pending spawns as soon as the writer in flight lands — a pair counts as one writer — and its round launches in the same turn; concurrent read-only runs are fine, each pinned at its own head. Stage 5 launches only when no per-step round is in flight and no fixer is pending — a fixer commit after the whole-range launch invalidates it. Per-step rounds flag correctness and requirement gaps only — no style, no speculative hardening — and they are bug-catching, not the gate: stage 5's whole-range challenge still decides clean. **Model:** the global spawn-pin rule applies; fixers spawn as `fixer`, not `step-executor`. **A returned report's open question is the owner's, not yours to resolve.** When an agent's report asks something — "say the word if you want it mirrored" — that question goes to the next gate verbatim, as its own AskUserQuestion or an explicit option, never replaced by the master's framing of the same decision. Same care in reverse: the owner can type directly into a running agent's chat and that message reaches only that agent, so an unexplained diff from a live agent is a question for the agent — read its transcript — not a rogue-agent finding. **Task list:** mark a step's task `in_progress` when its executor is spawned and `completed` when its commit lands and acceptance criteria are shown (`TaskUpdate`) — never completed with failing tests or a partial fix; a blocker becomes a new task, not a silent skip; a task is deferred only with the user's say-so, with the reason in the task. The arc is complete when no task is open, and the closing report shows the final `TaskList`.
5. **Independent review per feature** → after the last step is committed, ONE codex challenge on the feature's whole diff, where `<feature-base-sha>` is the commit the first step started from (recorded at plan approval). The master launches `~/.claude/skills/feature-workflow/scripts/codex-challenge.sh <feature-base-sha>..HEAD --trace --out <scratchpad>/codex-whole-round<N>.md` as one `run_in_background` Bash with `timeout: 7200000` described `Codex challenge round <N> · <feature-base-sha>..<head>` — no `--pin` (nothing writes during the gate; the fix loop is serial: challenge → fixer → re-challenge on the same command with the new HEAD, each round under its own `--out` name — `-round<N>` per the Verdict size contract's naming, never reusing a prior round's file, since the script truncates `$out` on each run and a discarded round's standalone findings would otherwise be lost before the fix-or-defer question below) — and spawns the kit's `codex-triage` agent on the completion notification — never a subagent for the run itself (why: Token discipline). Stage-4 per-step rounds and fixer-commit deltas never satisfy this gate — the gate is the whole range at a single HEAD; never `codex:codex-rescue`; a pass/fail codex review only when the user asks for it by name. In parallel with the whole-range run, one `spec-reviewer` spawn (Sonnet, read-only) checks `<feature-base-sha>...HEAD` against the approved plan file — unimplemented or incomplete requirements, scope creep, wrong-logic-vs-spec; gaps only, no style. A missing requirement routes into the P0/P1 lane; scope creep is reported at the gate. Triage real / regression / test-gap / theoretical, and give every real finding a priority: **P0** = crash, data loss, security, or a regression breaking a core flow — fixed immediately, and always blocks ship; **P1** = wrong behavior reachable in normal use (any other regression is at least P1, never P2); **P2** = real but reachable only through unusual or pathological input; test-gap and theoretical carry no priority — priority exists to route the fix loop, and neither class ever enters it. Every finding also carries the runner's own confidence, 0–1 — a finding the runner half-believes is a `conf:0.4` line, never a paragraph arguing itself down. **Clean = zero P0/P1.** Fix loop: the loop runs on P0/P1 only — one fresh fixer per finding set → re-challenge — and each set also picks up any P2 sharing a file or mechanism with its P0/P1s. **Two rounds, then stop:** round 1's P0/P1 go to fixers — a set whose findings are instances of one mechanism goes to one mechanism-fixer (the same-mechanism clause, Token discipline), never per-path patches; round 2 re-challenges the resulting HEAD and its verdict is final. There is no round 3: a large surface returns a fresh finding set every round, so the count never converges and a third round buys hours, not a clean verdict. **A contract the plan did not change never changes from the fix loop**, whatever the finding's priority: a wire schema version, an API field, a persisted data model, anything a server or a second client must also honor. That gate's options are *defer to its own arc* (a P0 blocks ship until that arc lands; a P1 ships with its index line) or *ship as-is* — never *fix here*: a contract change built by a fixer skips the plan and the plan-reviewer, and every later round then reviews the unplanned design one piece at a time. After round 2, an open P1 is deferred with an index line (the tech-debt path below) and named at the push gate; an open P0 goes to one AskUserQuestion (structural fix in its own arc, or defer — a P0 never ships), never silently to stage 6 — P2 and below are deferred with the report. Standalone P2, test-gap and theoretical findings are never looped on: once the verdict is clean or stopped, ask ONE AskUserQuestion listing the union of standalone findings across every round's verdict file (a round-1 finding round 2 does not repeat still belongs on the list — each round's `--out` file survives, per the per-round naming above) — *fix now* (one fixer spawn for the set) / *defer to the project's tech-debt file* / *let me pick* — where deferring copies that round's verdict file from the scratchpad to `docs/reviews/<feature>/<round>.md`, writes one **index line** per deferred finding — `[P2 conf:0.6] file:line — summary → docs/reviews/<feature>/<round>.md #finding-N` — to the project's index (`TODOS.md`, or `docs/tech-debt.md` if none), and commits both with the feature; a round with nothing deferred leaves no verdict file in the repo. A feature with no repo diff needs no verdict.
**Tell the runner to trace out of the diff.** The prompt says to follow the diff into the state machines, invariants and shared components it perturbs without changing their lines, and to report findings there. This is an instruction to the reviewer, not a list the master enumerates in advance.
**A range too big for one prompt is split, and the slices are still one gate.** "ONE challenge" above is about coverage and cadence — one gate per feature over the whole range — not about one process doing it. The trigger is behavioral — the run times out, truncates, or the runner reports it could not read the whole range — not a byte threshold. Split into contiguous commit sub-ranges so the slices **jointly cover the whole range with no gap**, run one `codex-challenge.sh` call per slice, concurrent, **unpinned** (no writer at stage 5, and an unpinned slice reads the final tree, so out-of-diff tracing sees the finished code), and hand ALL slice output files to a single `codex-triage` spawn, which merges and dedupes them into the one triaged verdict — the master never triages slices separately or hand-recomputes cross-slice dedup. The coverage claim is only as good as the gaplessness, which is by construction here, and each slice's range is recorded in its own header line; overlapping slices are fine, a gap is a failed gate. A single commit too large to review on its own can't be split into sub-ranges — relaunch once unsplit; if it stalls again, review by path is a script addition (`--paths`), deferred to tech-debt. Record the reviewed range in the verdict file — `<base-sha>..<head-sha>` — the next session cannot otherwise tell what has already been gated.
**Failure paths.** Exit 124 → relaunch once with the same arguments, under a different `--out` name (e.g. a `-r2` suffix). A second 124 → the range is too big: split it (above) or, when this fires inside a stage-4 per-step round, skip that round and note it in the cost checkpoint — stage 5 still covers the skipped range. Non-zero after the script's three attempts, or exit 0 in under 60 s with no findings text in the verdict body (auth or usage-limit failure — triage reports it verbatim) → park: push-notify, end the turn, no relaunch — the script already retried for 10 minutes. Exit 66 (pin refused, under the free-space threshold) → park like the other failures: push-notify, end the turn, no unpinned retry.
**Brief the defect and the invariant, never the patch.** A fixer's spawn prompt carries what is broken and what must hold afterward. If the master has a fix in mind it goes in labeled as a hypothesis to verify and overrule, because the fixer is the one who will read the call sites. A trap an earlier agent reported — a harness deadlock, a serializing mock, a flaky fixture — goes into every later brief that touches the same surface, verbatim from its report.
6. **Ship** → push (owner-approved) → PR → merge + deploy → post-deploy verify.
Rules:
- The always-on hard gates in global CLAUDE.md apply throughout: push approval, the codex gate, verified-claims, AFK-is-not-approval.
- **The master never touches product code** — the global hard gate, in force from the moment this skill loads.
- **A missing report is a read-the-transcript signal, never a wait.** An API error that ends a subagent early is never delivered as its result — the master gets nothing. If a delegate goes quiet past its expected window, read its transcript under the session's `subagents/` dir: the work is often already complete. Salvage it, and respawn a fresh agent for only the remainder. The check is mechanical, not a habit: at the arc's first spawn, `CronCreate` one recurring session-only job on an off-minute quarter-hour (`7,22,37,52 * * * *`) whose prompt is — list this session's `subagents/*.jsonl` by mtime; an agent with no write for 10 min, or whose last commands repeat a `pgrep`/`sleep` wait, is read, stopped (`TaskStop`) and respawned for the remainder — and `CronDelete` it at the no-live-agents checkpoint. Cron fires only while the REPL is idle, which is exactly the state of a master waiting on a notification.
- **Interactive gates never go to subagents.** Subagents are headless — they cannot call `AskUserQuestion` or `ExitPlanMode`, so a delegated gate either auto-picks silently or dies. Gates run in the master session; only headless work (drafting, reviewing, executing) is delegated.
- **Plan-approval is the trigger, not a suggestion.** The moment build approval lands, transition unprompted into the delegated tail — spawn the first executor in the same turn and run stages 4–6 to completion without returning to the user except at the real gates (a structural fix exceeding the plan's design contract, the gates stage 5 names, push approval).
- **A new arc gets a new master.** When an arc completes and a next one is queued, the master writes the next arc's brief to `<scratchpad>/handoff-<feature>.md` — goal, the plan path and which of its arcs the next session executes, feature-base sha, what landed and what was deferred, the owner's standing instructions verbatim, the sibling-repo sessions linked to the feature (the new master messages each on start with its own address), never push — and hands off. Attended: the turn ends with the brief's path and the owner's steps — the owner pastes the brief into a new session; never an offer to start the next arc in this session. Unattended, under delegated approval: launch it — `cd <repo> && claude --bg --name "<this session's name>" --permission-mode auto "$(cat <scratchpad>/handoff-<feature>.md)"` as one foreground Bash — then end this session. Reusing this session's name (the first line of `ListAgents`) keeps the address linked sibling sessions hold valid once this session ends. A `--bg` session is a full session (hooks, skills, agents and background-Bash wake-ups all work), outlives the session that launched it, and is listed by `claude agents`; an `AskUserQuestion` inside it parks the session under "Needs input" until someone attaches, so the brief must carry the delegation that makes gates self-resolving. The same handoff applies if the master approaches the context ceiling mid-arc (~500k tokens; 600k absolute max) — never silently push past it.
- **Master budget: a normal feature arc finishes under ~400k with no compression machinery.** Crossing ~400k mid-arc is a *defect signal*, not a reason to compress or hand off: stop, post the cost checkpoint, and name what's flooding the context so the flow gets fixed. During the unattended tail, post a one-line cost checkpoint at every step boundary (elapsed time, approx context size), and END the session the moment the arc completes — never leave a finished session idling.
- Make handoff artifacts cold-start-ready *without being asked*: one standalone root README a fresh session needs no other file for, and attach plans to their task/ticket so a future session finds them by reference.
- **A brief for another repo's session carries the way back.** When the feature needs work in sibling repos that each run in their own session — any number of them — each brief names the feature and every session already linked to it, this one first (the first line of `ListAgents`), and says when to `SendMessage` them: once on start, to every session it names, so every session linked to the feature holds every other's address; when a contract it shares with one of them is settled or changes — to that session only; when a step another waits on lands; on a blocker only one of them can clear. The done signal is that message, never `notify_when_idle` — idle fires at every turn end, gates included.
- Plan reviews used individually (`/plan-eng-review` etc.) run via sub-agents — review token burn doesn't belong in main context.
- If work is interrupted mid-step, commit `WIP:` so a resume is clean.
# Parallel multi-agent
For genuinely **parallel, independent** work only; sequential pipelines belong to the feature workflow above. Pick the mechanism by need:
- **Background subagents (DEFAULT):** independent units, contracts known up front. Concurrent writers each need a worktree — spawn them as `team-executor`, which carries `isolation: worktree` in its frontmatter so no spawn call has to remember. Read-only fan-out needs no worktree. Set `worktree.baseRef: "head"` first, or executor worktrees branch from the remote default branch instead of your in-progress work.
- **Workflows:** large (10s+), deterministic/repeatable/resumable fan-outs with cross-checking.
- **Kill delegated agents the moment their unit closes.** Once an agent's output is ingested (commit merged, verdict triaged, report received), stop it in the same turn — agents are per-unit disposables, never kept warm. A result marked partial at `maxTurns` is not an ingested output: that unit is still open, and the agent is resumed, not replaced. Before declaring an arc complete, enumerate live agents and confirm zero remain; the user must never have to kill leftovers by hand. "Zero" also means `pgrep -f 'output\.done'` returns nothing (a leftover marker-file poll is the one shell shape a subagent can orphan; bare `sleep`/`codex` patterns match the owner's own processes and are not criteria) and `ListAgents` shows no subagent still `running`. `TaskStop` is for an agent still running when its unit closes; one whose completion notification has arrived is already gone from the task registry — `ListAgents` no longer shows it and `TaskStop` returns "No task found".
- **When to offer (lead only):** inside a pipeline, the plan's parallel decision settles it and plan approval approves it — no separate question. Outside one, if a task has independent parallel parts AND the user hasn't specified the approach AND the project's CLAUDE.md hasn't set a preference → ask whether to fan out before starting. If you are a worker, never re-ask — just do your assigned task.
- **How:** invoke the `agent-teams` skill for the full playbook (mechanism choice, roles, models, worktree/merge flow, the plan-only approval gate). Don't inline the playbook here.
# Token discipline
Cost ≈ turn-count × context size: every agent turn re-pays its entire context as cache-read, so burn grows quadratically in a long-lived agent. Agent *lifetime* is the lever — not result size or output verbosity.
- **Retirement is mechanical: `maxTurns` in the agent frontmatter, not a prose budget.** `step-executor`/`team-executor` cap at 200 turns, `fixer` at 150, `codex-triage` at 60; the executors' and the fixer's own instructions tell them to commit `WIP:` once they pass ~three-quarters of their cap and keep working. When the cap cuts an agent mid-flight its result comes back marked partial: the master resumes it with `SendMessage` (full history intact, no ramp-up), and only if the resumed agent caps again reads its transcript under `subagents/`, commits any `WIP:` itself, and respawns a fresh agent for the remainder — it never raises the cap, and spawn prompts carry no budget line.
- **The codex run lives in the master, backgrounded; a fresh `codex-triage` agent per round.** A challenge on a real feature range can run up to a 15-minute stall ceiling, equal to the 900 s Bash cap (`BASH_DEFAULT_TIMEOUT_MS`, set by the kit's settings). A subagent cannot wait that out: a foreground compound pipeline is *stopped* at the cap, not moved to the background (only simple commands auto-background), and a subagent's backgrounded call keeps running past its final response — the verdict lands in a context that no longer exists — so the kit's PreToolUse hook `hooks/subagent-no-background.sh` denies `run_in_background` inside any subagent. The master is the one context the harness re-wakes on a background completion, so the run is `codex-challenge.sh` as one `run_in_background` Bash in the master — the script carries `gtimeout 900`, the 3-attempt/5-min retry, the optional pin, and writes the output file. After launching, the master ends its turn or does work that doesn't depend on the verdict. Triage is a fresh `codex-triage` spawn (Sonnet, medium) per round: it reads the round's output file(s) — all slices of a split round go to the one spawn — checks each finding against `git show <head>:<path>`, and returns the ≤2,000-char verdict; a round needs only the range and the file(s), never prior rounds' context. Post-review fixes go to a fresh `fixer` agent that commits its fix on the branch like any executor, never back to the original executor at peak context. A fixer spawn prompt is briefed like an executor's: the plan section (path + line range), the diff range, and the verdict's P0/P1 findings (plus their adjacent P2s) only.
- **Long runs are backgrounded with an explicit `gtimeout`, never unbounded.** A full test suite runs as one `run_in_background` Bash with `gtimeout 3600` ahead of the command. Every such call — the codex run included — passes `timeout: 7200000`, the harness maximum: a background call without its own `timeout` is stopped at 30 min, short of either run's worst case.
- **Build and download logs are pre-filtered before `tail`.** Build tools, platform downloads and similar tools often write progress as `\r`-joined runs, so `tail -n 8` can return one line tens of thousands of characters long. Pipe through `tr '\r' '\n' | tail -n 20 | cut -c1-300`, or `grep` for the lines that matter.
- **An unpinned challenge really is coupled to the working tree — pin it or serialize.** Challenge mode does not hand codex a precomputed diff the way review mode does: it passes a prompt telling codex to work out the diff itself with git, then trace the code, all inside a read-only `codex exec`. So the diff *and* the reads both come from the live tree, and a concurrent fixer corrupts both. `--pin` does the free-space check, the stale-worktree sweep, the detached worktree, and its removal on exit — which is how `codex-challenge.sh` gives an overlapping run its own checkout. Two limits on what that buys: a verdict pinned at sha X says nothing about a commit landing after X, so overlapping a review with unrelated fix work surfaces bugs **earlier** but does not satisfy the gate — stage 5's clean verdict is still one challenge over the final range at a single HEAD — and the pinned sha must stay downstream of the recorded feature base, a history rewrite past that base fails as the script's exit 65. In practice: a stage-4 per-step round always pins (the next executor is writing); a review launched with no writer in flight runs on the live tree, no worktree at all. Every pin is preceded by a free-space check (`df`, ≥2 GB on the scratch volume) that fails loudly instead of burning the launch, and the worktree is removed on exit — never accumulated.
- **Fixers stay serial by default.** `fixer` is single-writer by definition (session branch, no worktree), so writer fan-out is a different agent, not a fixer flag: if a round's finding sets genuinely touch non-intersecting files, that is a pair under stage 4's rules, never wider. Disjoint file lists are the entry condition, not the proof — a fix can reach past its finding's location, and two fixes can collide semantically in files neither list named — so treat an intersection as a hard no and a non-intersection as worth a second look at what each fix actually has to change.
- **Same mechanism twice = stop patching paths.** If a round's findings are instances of one mechanism, or hit the mechanism the previous round just fixed, the loop is chasing instances, not the cause. Say so in the round's report, and make the mechanism the fixer's brief — its spawn prompt names the invariant to establish and the now-redundant per-path patches to remove, so two mechanisms don't end up stacked. If the structural fix is materially larger than the plan's design contract anticipated, that is an AskUserQuestion (structural fix / patch this path and carry the rest), not a judgment call. The fixer runs on Opus here, with a one-line reason stated at the spawn. In stage 5 this is round 1's fixer: a round-2 verdict that hits round 1's mechanism exits the loop under the two-round rule, never a third round.
- **Verdict size contract.** Full challenge output is written to a file in the session scratchpad (never a bare `/tmp/codex-*.md` — two masters in one repo collide); it enters the repo only when a finding is deferred (stage 5 above), and the master shows only the triaged verdict ≤2,000 chars plus that file path. Verdict shape: counts per class on the first line, then findings **grouped by class in priority order — real, regression, test-gap, theoretical** — one `### <class>` header per non-empty class, one `file:line — summary` line per finding beneath it, prefixed `[P0 conf:0.9]`/`[P1 conf:0.8]`/`[P2 conf:0.4]` on real and regression lines and `[conf:0.5]` alone on test-gap and theoretical ones (never an interleaved flat list, and no class tag repeated per line: the header carries it). **One line per finding, always** — a finding that needs a paragraph has the wrong class or confidence. The master **recomputes the per-class counts from the finding lines** and uses its own numbers: the first line is the triage agent's claim, not the record, and a first line that disagrees with the lines beneath it is reported as a mismatch next to the corrected counts. If the ≤2,000-char cap forces findings to be dropped, drop only test-gap and theoretical lines and say so inline on the counts line — `test-gap: 7 (2 dropped)`; real and regression lines are never dropped, so the count that decides clean is never silently short. The actor is explicit: the master's background `codex-challenge.sh` call writes the full output to the verdict file (`--out`), and the `codex-triage` spawn prompt names that round's file(s), the range and the head sha. Never paste a verdict in full. The master NEVER reads challenge-output files — not with Read, and not with `head`/`tail`/`cat`/`grep` in Bash, and that includes `$out.log` and `$out.msg` alongside `$out` itself; the triage agent's report is the only channel. The `.log`/`.msg` sidecars next to `--out` are review scratch and never enter the repo.