The prime only dispatches. It never reads a file, runs a command or holds a work product: a mod refuses it. It hands goals to sub-orchestrators, which dispatch agents or do the work themselves and hand back one line. That line goes into a memory the prime can zoom into, so the thread lasts as long as the work does.
baton always said the conductor never plays a note. v7 makes it mechanical: during a run the main session's tool calls go through a guard, and anything but dispatching, asking you, or using its memory is refused with the route. Context the prime never takes in can't fill it up.
Agent, AskUserQuestion, SendMessage, mcp__baton__*. Nothing else.The mod tells the prime from a subagent by the
agentId on each tool call. If the guard throws, the call is refused. A sub-orchestrator's calls pass
untouched: its context is there to be spent.
Every spawn during a run is bound at
agent.spawn: Opus 5.5 for every role, Sonnet 5.5 for a type or name ending -cheap,
whatever the caller asked for. Merges of the memory run on Sonnet.
Envelopes, per-criterion verdicts,
refutation triage, the ledger, gates and TEAM: github all work as in v6. Sub-orchestrators keep
that record; the prime keeps one line per phase.
A mod is a JavaScript module Claude Code runs inside its own loop. It sees every prompt, model request, tool call, spawn and redraw, and can answer, change or refuse each one. baton’s registers 27 hooks, 16 commands, 11 tools and 16 settings. None of it depends on an agent remembering to do something: each piece runs where its event happens.
session.startReads the engine version. The guard tells the prime from a subagent by agentId, verified on 2.1.287; on any other version it says so and fails closed.
session.startRuns the doctor in the background (node, git, gh and its login, ripgrep, the memory) and checks for a newer baton: a failed check, or an update with 9 to install it, shows in the band.
SessionStart · startup, resumeA new session in a directory with an active run is told it is that run’s prime: wake from the memory first, then dispatch.
session.startRegisters /baton, and in a run directory the seven memory tools. Starts a 150 ms ticker for owed rotations and the kickoff, and the PR poller.
prompt.submitYour words become a run note. In the background, Sonnet reads them for a standing rule; one it finds becomes a ruling in the project memory.
prompt.submitAfter a rotation, the prompt carries the instruction to call memory_wake first.
turn.stepReads the request’s usage and the agent that made it: fresh tokens and cache reads, by role, phase and node, into _orch/spend.json. The response streams on untouched.
tool.callThe prime guard. A call with no agentId is the prime’s: only Agent, AskUserQuestion, SendMessage, ToolSearch, the prime skill and mcp__baton__* pass. Anything else is refused with the route. If the guard throws, the call is refused.
tool.call · mcp__baton__*Serves memory_wake, _note, _zoom, _recall and the three project_* tools from the log and tree on disk. Wake leads with your rulings.
tool.call · BashForbidden files. A git add naming .env, a key or credentials is refused from any agent, run or no run.
tool.call · BashThe command gate. Push, PR create/merge/close, publish, reset --hard and rm -r from any depth wait on a dialog naming the chain. With nobody at the terminal, it is asked on the PR instead.
tool.call · BashCheckpoints. Before reset --hard, clean -f or rm -r runs, the whole tree is snapshotted to a hidden ref; /baton restore puts it back.
tool.call · AgentThe phase gate. After a sub-orchestrator reports DONE, the prime’s next dispatch waits until you approve the phase or send it back with a reason.
tool.check · BashEnforced rulings. After the permission rules decide, a command matching an enforced ruling’s pattern is refused, quoting the ruling.
agent.spawnThe binding. Opus 5.5 for every role, Sonnet 5.5 for a type or name ending -cheap, whatever the caller asked for. The spawn joins the agent tree under its parent.
agent.spawnThe budget. Another review or fix round is refused once the goal has spent tokensPerGoal, with a note at 80%.
agent.spawnLessons that stick. A worker or sub-orchestrator spawned on code an earlier refutation touched gets those lessons in its prompt.
agent.spawn · tool.callPause. While /baton pause holds, every new spawn and every gated command waits.
agent.spawnA clean base first. A PR reviewer on a PR that conflicts with its base is refused: merge the base in, then review.
turn.completeA subagent the prime dispatched: its one-line return becomes a run note, tagged with its role. The prime’s own reply: its first line becomes one too.
turn.completeA sub-orchestrator whose return leads with DONE joins the phase-gate queue, and the band flags it.
turn.completeWrites the spend down and re-reads the record: every computed state that moved becomes a row in _orch/track/.
session.measureThe context gauge. At rotateAtPercent (35%): a one-line handoff from a fork of the prime, then a compaction off the clock.
session.compact · SessionStartEvery compaction in a run counts as a rotation and arms the wake, delivered by whichever comes first: SessionStart, the next prompt, or the next allowed tool result.
$.clock → gh pr viewThe PR as data, no model: state, checks, mergeability, files, closing issues, comments. Merge-ready is computed row by row; the reviewer’s verdict is parsed from its comment.
$.clock → commentsFrom allowed answerers, /approve P3, /send-back P3 … and /approve push act as the gate. Other remarks become one line each, condensed by Haiku 4.5.
$.clock → the issueThe goal’s state as a baton:<state> label, and optionally a Projects board column. One spend comment on the PR, edited in place.
ui.render · PaneOpens by itself, with two tabs: Work (the goal, the PR and its review findings linked to their lines, the agent table with a trend column, the plan one line per phase with p for every node, what waits for you) and Memory (your rulings, then the memory browser). Every agent, phase, node and ruling row opens with ↑/↓ and Enter (b goes back); buttons approve phases and retract rulings; fields search the memory, add a ruling, or message a running agent.
ui.render · AbovePromptOne line: plan usage, the context against its threshold, the cost, the goal and the PR. With a phase waiting, 1 typed into an empty prompt approves it.
ui.render · SpinnerThe spinner names the phase and what the prime is waiting on.
command.run · /batonstart · stop · pause · resume · rotate · status · doctor · watch · next · rule · rulings · retract · enforce · checkpoints · restore. Text where nothing draws, so all of it works under claude -p.
What fires, in order, when you hand it an issue.
/baton start #12 reads the issue with gh, writes the manifest ("prime": true, the run branch), notes the start, and starts the prime’s first turn with the issue verbatim and your rulings.command.runRead the codebase. Refused: dispatch a sub-orchestrator. It dispatches one for the bootstrap.tool.callagent.spawn · turn.stepturn.completebaton:building.turn.complete · $.clockgit push. You get a dialog: prime › P3 › T7 wants to git push. You approve it for the run.tool.callturn.complete · tool.callmemory_wake. Your rulings come first in what it sees.session.measure · session.compactCHANGES, 1 high. The poller notes it, and a steward runs a fix round.agent.spawn · $.clockREADY. Every merge row holds. The PR is marked ready, the label goes baton:ready, and the band says it is waiting for you.$.clockmerged. /baton next archives the run and starts the next issue in the queue.$.clock · command.run| command | does |
|---|---|
| start <MODE> <TARGET|#n> | arm the guard, write the manifest, start the prime |
| stop | close the run; the guard comes off; _orch/ stays |
| pause · resume | hold every new spawn and gated command, then let it go on |
| doctor | check node, git, gh and its login, ripgrep, the version, the memory |
| checkpoints · restore <id> | the snapshots taken before reset/clean/rm, and putting files back |
| rotate | handoff, compaction and wake, now |
| status | run, context, rotations, guard, approvals, the tracker |
| show <P3|T12|agent> | the view Enter opens, as text |
| watch [label] | the issue queue |
| next [#n] | archive a finished run and start the next goal |
| rule <text> | a standing ruling, by hand |
| rulings | list them, newest first |
| retract <#> | withdraw one; the log keeps it |
| enforce <#> <regex> | make one refuse matching commands |
| tool | does |
|---|---|
| memory_wake | the run in a fixed budget of lines, rulings first |
| memory_note | one line, at most 280 bytes |
| memory_zoom | open a block back up to its notes |
| memory_recall | regex over notes and summaries |
| project_wake | the memory that spans runs |
| project_note | what the next run should know |
| project_recall | search it; namespace selects one inside it |
| setting | default |
|---|---|
| rotateAtPercent | 35 |
| wakeBudgetLines | 96 |
| memoryDir | .baton/memory |
| approvals | on |
| phaseGate | on |
| prPollSeconds | 120 |
| tokensPerGoal | 0 (off) |
| labels | on |
| boardProject | 0 (off) |
| boardOwner | you |
| forbiddenFiles | added to the defaults |
BATON_APPROVALS=0 turns both gates off for unattended runs; BATON_AUTOROTATE=0 leaves rotation to /baton rotate.
| path | holds |
|---|---|
| _orch/manifest.json | the run: "prime": true, mode, goal, branch |
| _orch/memory/ | the run memory: the log and the merge tree |
| .baton/memory/ | the project memory; ns/rulings inside it |
| _orch/track/ | one row per state change, measured |
| _orch/spend.json | tokens by role, phase and node |
| _orch/github/pr.json | the goal’s PR, written by the bootstrap |
| .baton/runs/<id>/ | finished runs, archived by /baton next |
Tested: 61 node tests, including two end-to-end fixtures that run the real hooks module and
memory store under a fake mods runtime and a scripted gh. Not yet tested: the live terminal UI and real GitHub. Mods are early access in Claude Code.
The mod’s README →
Every return, every message you send and the first line of every prime reply is a note: one fixed-width record of at most 280 bytes, appended to a log. Pairs of notes merge into a summary, pairs of summaries into another, up a binary tree, compressed by Sonnet in the background.
memory_wake.The log, the tree and the wake view follow OptMem's ideas; the code is baton's own (OptMem ships no license).
Standing rulings, newest first: #3 PRs target main directly; never stack. [enforced] #1 Fan-outs on Sonnet; Opus to synthesize. memory: 214 notes, 213 summaries; 24 blocks #0-127 (128 notes) bootstrap BUILD ./billing; 41 nodes / 6 phases; P1–P3 CONFIRMED; Q-1 vendor key answered #128-191 (64 notes) P4 parser: T14 refuted twice, escalated; a red test passed pre-change and was refuted (9.4) #192-207 (16 notes) P5 export 9/9; approved … #211 [operator] ship P6, hold the migration #212 [prime-reply] P6 dispatched, T31 held #213 [sub] P6 DONE 6/7 · T31 parked on Q-4
When you state a standing rule mid-run ("from now on…", "never…", a change of mind), Sonnet lifts it into the project memory's rulings. Every wake and every kickoff leads with the newest twelve, and the newest wins. Tested on ten real operator messages: five rules found, five one-offs left alone.
On Opus 5.5 we found no context rot to fix: a prime carrying 831K tokens lost nothing. The memory earns its place on cost (a lean prime is cheaper per run) and continuity: runs longer than a window, and rulings that hold across sessions. The numbers.
There is nothing to open. In any Claude Code session with baton loaded, one line above the prompt carries your plan usage (5 hours, the week, Fable), the context against its threshold and the session's cost, and the pane opens by itself as soon as there are agents to show. It has two tabs. Work is everything happening: the goal and its PR, a table of every agent, the plan one line per phase, what waits for you. Memory is everything the run remembers: your rulings, then the memory itself. This is what a run looks like; the tabs are live.
> /baton start #12 baton run build-20261005T0912Z started (MODE BUILD, TARGET issue #12: CSV export). The prime guard is armed. ⏺ I'll start with the bootstrap, then run the phases. ⏺ Agent(baton:sub-orchestrator · bootstrap) ⎿ bootstrap DONE · 6 phases, 41 nodes, plan verified · draft PR #47 opened ⏺ Read(src/export.ts) ⎿ baton: Read is not a prime tool — dispatch a sub-orchestrator ⏺ Agent(baton:sub-orchestrator · P5 export) … ⎿ P5 DONE+CONFIRMED 9/9 · T23 refuted once, fixed ⚑ you approved P5 > ship P6, but hold the migration until I say baton: ruling recorded — Hold the database migration until the operator releases it. ⏺ Agent(baton:sub-orchestrator · P6 import) running ✻ Coordinating… · baton · P6 · P6 import
#12 CSV export ↗ · PR #47 ↗ checks 5/6 · review CHANGES (1 high, 0 med) goal ● queued 2m ─ ● planned 6m ─ ◉ building 1h04 ─ ○ reviewing ─ ○ ready ─ ○ merged · 2.7M · $17.41+? PR ● draft 1h10 ─ ● checks 4m ─ ✗ reviewed 14m (changes) ─ ○ ready ─ ○ merged merge-ready 6/9 · ✗ every check green · ✗ the reviewer’s latest verdict is READY · ✗ no high finding open high src/import/csv.ts:88 ↗ a quoted newline splits the row agent context trend budget model input c.write c.read output cost steps state › ◆ prime 24% ▁▁▂▂▂▂ 35% opus 41k 88k 2.1M 19k $1.43 ●─●─◉─○─○─○ building › ✓ sub-orch P5 export 18% ▁▁▁▂▂ 50% opus 120k 310k 6.4M 88k $5.39 ●─●─●─● approved › ✓ worker T22 31% ▁▁▂▂▃ 50% opus 52k 140k 2.9M 41k $2.43 ●─●─●─● verified › ✗ worker-cheap T23 9% ▁▁▁ 50% sonnet 18k 22k 410k 9k $? ●─✗─○─○ green (refuted) › ● sub-orch P6 import 12% ▁▁▁ 50% opus 36k 90k 1.5M 21k $1.28 ●─◉─○─○ dispatched › ● worker T29 57% ▁▂▃▄▄▅ 50% opus 61k 160k 3.8M 52k $3.05 ●─●─◉─○ blue › ● verifier T27 6% ▁▁ 50% opus 9k 31k 220k 4k $0.32 ●─●─◉─○ blue T29 crossed its 50% budget: the mod told it to finish or split. plan p every node › P5 ● briefed 1m ─ ● dispatched 38m ─ ● verified 4m ─ ● approved 2m · 2/2 verified · 1.4M · $8.12 › T22 ● red 3m ─ ● green 9m ─ ● blue 2m ─ ● verified 4m › T23 ● red 2m ─ ✗ green 5m (refuted) ─ ○ blue ─ ○ verified › P6 ● briefed 1m ─ ◉ dispatched 12m ─ ○ verified ─ ○ approved · 1/5 verified · T31 blocked · 410k · $4.65 › T27 ● red 2m ─ ● green 4m ─ ◉ blue 1m ─ ○ verified › T29 ● red 3m ─ ● green 6m ─ ◉ blue 2m ─ ○ verified › T30 ● red 2m ─ ● green 7m ─ ● blue 1m ─ ● verified 3m › T31 ✗ red 9m (blocked) ─ ○ green ─ ○ blue ─ ○ verified › T32 ○ red ─ ○ green ─ ○ blue ─ ○ verified › P7 ○ briefed ─ ○ dispatched ─ ○ verified ─ ○ approved ? Q-4 Which vendor key does the import use? — blocked by _orch/nodes/T31/handoff.md:"use the vendor API" (explicit: fix the cause) ruling #3 2026-10-05 Hold the database migration until the operator releases it. ↑/↓ then Enter on › opens an agent, a phase or a node · ✉ messages a running one · p shows every node · b goes back
‹ back (b) ● prime prime refresh (r) in the tree prime model opus · running 1h31m · 96 tool calls context 24% of its window · budget 35% · trend ▁▁▂▂▂▂ tokens input 41k · cache write 88k · cache read 2.1M · output 19k · $1.43 its work ● queued 2m ─ ● planned 6m ─ ◉ building 1h04 ─ ○ reviewing ─ ○ ready ─ ○ merged the task it was given /baton start #12 — the goal is GitHub issue #12: "CSV export". Export orders as CSV from the admin; an empty export still has a header row; quoting follows RFC 4180. Hold the database migration until the operator releases it (ruling #3). last tool calls 10:31:41 memory_note P6 dispatched with the migration held (ruling #3) 10:31:44 Agent P6 import 10:39:02 memory_wake 10:41:58 Agent pr-reviewer round 1
‹ back (b) ✓ sub-orch P5 export refresh (r) in the tree prime › P5 export model opus · finished in 41m00s · 212 tool calls · DONE+CONFIRMED context 18% of its window · budget 50% · trend ▁▁▁▂▂ tokens input 120k · cache write 310k · cache read 6.4M · output 88k · $5.39 its work ● briefed 1m ─ ● dispatched 38m ─ ● verified 4m ─ ● approved 2m the task it was given Own phase P5 (export) of run build-20261005T0912Z: write the phase brief from plan/graph.yaml, dispatch each node by §4.1, verify each with a fresh verifier, route escalations, run the phase gate, and return one line. last tool calls 09:52:10 Agent T23 empty export header (retry) 09:58:30 Agent verifier T23 10:00:02 Write _orch/phases/P5/envelope.json returned P5 DONE+CONFIRMED 9/9 · T23 refuted once, fixed · next: P6 import
‹ back (b) ✓ worker T22 refresh (r) in the tree prime › P5 export › T22 model opus · finished in 18m00s · 37 tool calls · DONE context 31% of its window · budget 50% · trend ▁▁▂▂▃ tokens input 52k · cache write 140k · cache read 2.9M · output 41k · $2.43 its work ● red 3m ─ ● green 9m ─ ● blue 2m ─ ● verified 4m the task it was given Node T22: quote fields per RFC 4180 in src/export/csv.ts. Handoff: _orch/nodes/T22/handoff.md. last tool calls 09:33:12 Write test/export/csv.test.ts 09:33:40 Bash npm test -- csv (red: 6 failing) 09:41:02 Edit src/export/csv.ts 09:41:30 Bash npm test (green: 412 passing) returned T22 DONE · quoting per RFC 4180, 6 tests red→green · nothing open
‹ back (b) ✗ worker-cheap T23 refresh (r) in the tree prime › P5 export › T23 model sonnet · finished in 9m00s · 8 tool calls · REFUTED context 9% of its window · budget 50% · trend ▁▁▁ tokens input 18k · cache write 22k · cache read 410k · output 9k · $? its work ● red 2m ─ ✗ green 5m (refuted) ─ ○ blue ─ ○ verified the task it was given Node T23: an empty export has a header row (src/export/csv.ts). last tool calls 09:34:02 Edit src/export/csv.ts 09:35:10 Write test/export/empty.test.ts 09:35:40 Bash npm test -- empty returned T23 DONE · header row on empty export · 1 test
‹ back (b) ● sub-orch P6 import refresh (r) in the tree prime › P6 import model opus · running 12m00s · 64 tool calls context 12% of its window · budget 50% · trend ▁▁▁ tokens input 36k · cache write 90k · cache read 1.5M · output 21k · $1.28 its work ● briefed 1m ─ ◉ dispatched 12m ─ ○ verified ─ ○ approved the task it was given Own phase P6 (import) of run build-20261005T0912Z. The operator holds the database migration (ruling #3): do not dispatch T32 until it is released. last tool calls 10:31:50 Write _orch/phases/P6/brief.md 10:32:05 Agent T29 import parser 10:32:07 Agent T31 vendor key 10:39:20 Agent verifier T27 10:42:12 Bash git status --short
‹ back (b) ● worker T29 refresh (r) in the tree prime › P6 import › T29 model opus · running 11m00s · 19 tool calls context 57% of its window · budget 50% · trend ▁▂▃▄▄▅ tokens input 61k · cache write 160k · cache read 3.8M · output 52k · $3.05 its work ● red 3m ─ ● green 6m ─ ◉ blue 2m ─ ○ verified the task it was given Node T29: parse orders from CSV in src/import/csv.ts; a bad row reports its line number. lessons the mod added to it (from earlier refutations in this code) - T23: "an empty export has a header row" was refuted — the red test passed against the unchanged code last tool calls 10:33:01 code_search parseCsv 10:33:04 code_fetch src/export/csv.ts:12-48 10:34:10 Write test/import/csv.test.ts 10:34:40 Bash npm test -- import (red: 4 failing) 10:40:22 Edit src/import/csv.ts 10:41:05 Bash npm test (green: 418 passing) 10:42:30 Edit src/import/csv.ts
‹ back (b) ● verifier T27 refresh (r) in the tree prime › P6 import › T27 model opus · running 4m00s · 6 tool calls context 6% of its window · budget 50% · trend ▁▁ tokens input 9k · cache write 31k · cache read 220k · output 4k · $0.32 its work ● red 2m ─ ● green 4m ─ ◉ blue 1m ─ ○ verified the task it was given Verify node T27 (import dedupes orders by id). Refute each done-criterion; re-run red against the unchanged code; write _orch/verify/T27-verdict.json. last tool calls 10:39:30 Read _orch/nodes/T27/handoff.md 10:40:02 Bash git worktree add /tmp/verify-T27 <red parent> 10:40:40 Bash npm test -- dedupe (red reproduced: 2 failing)
‹ back (b) P5 · approved refresh (r) steps ● briefed 1m ─ ● dispatched 38m ─ ● verified 4m ─ ● approved 2m nodes 1 of 2 verified · 1.4M · $8.12 the brief P5 — export Nodes: T22 (frontier), T23 (cheap) Concurrency: 2 · exit: every node DONE+CONFIRMED, the gate approved its nodes (Enter on one in Work opens it) T22 ● red 3m ─ ● green 9m ─ ● blue 2m ─ ● verified 4m · 233k · $2.43 T23 ● red 2m ─ ✗ green 5m (refuted) ─ ○ blue ─ ○ verified · 49k · $? its envelope DONE+CONFIRMED — 9/9 criteria confirmed; T23 refuted once (the red test passed pre-change) and redone. risk: exports over 1M rows are untested
‹ back (b) P6 · dispatched refresh (r) steps ● briefed 1m ─ ◉ dispatched 12m ─ ○ verified ─ ○ approved nodes 1 of 5 verified · 410k · $4.65 the brief P6 — import Nodes: T27, T29, T30, T31, T32 (T32 held: ruling #3, the migration) Concurrency: 3 · exit: every node DONE+CONFIRMED or BLOCKED-and-batched its nodes (Enter on one in Work opens it) T27 ● red 2m ─ ● green 4m ─ ◉ blue 1m ─ ○ verified · 44k · $0.32 T29 ● red 3m ─ ● green 6m ─ ◉ blue 2m ─ ○ verified · 273k · $3.05 T30 ● red 2m ─ ● green 7m ─ ● blue 1m ─ ● verified 3m · 120k · $1.10 T31 ✗ red 9m (blocked) ─ ○ green ─ ○ blue ─ ○ verified T32 ○ red ─ ○ green ─ ○ blue ─ ○ verified
‹ back (b) P7 · briefed refresh (r) steps ○ briefed ─ ○ dispatched ─ ○ verified ─ ○ approved nodes 0 of 0 verified the brief P7 — docs and release notes (not started)
‹ back (b) T29 · blue refresh (r) steps ● red 3m ─ ● green 6m ─ ◉ blue 2m ─ ○ verified · 273k · $3.05 done-criteria 1. a CSV of 3 orders imports as 3 orders 2. a bad row reports its line number 3. quoting per RFC 4180 round-trips with the export red · green · blue red npm test -- import 4 failing: imports 3 orders · reports the bad line · round-trips quoting · rejects BOM commit 41c2e0a (tests only) green npm test 418 passing commit 7d10b9f blue not yet
‹ back (b) T31 · red (blocked) refresh (r) steps ✗ red 9m (blocked) ─ ○ green ─ ○ blue ─ ○ verified · 38k · $0.29 done-criteria 1. the import authenticates with the vendor API red · green · blue red npm test -- vendor 1 failing: 401 from the vendor API green not yet blue not yet
‹ back (b) T23 · green (refuted) refresh (r) steps ● red 2m ─ ✗ green 5m (refuted) ─ ○ blue ─ ○ verified done-criteria 1. an empty export has a header row red · green · blue red npm test -- empty 0 failing (!) green npm test 412 passing blue not yet the verifier REFUTED — reverted src/export/csv.ts; the red test still passed ✗ an empty export has a header row the red test passed against the unchanged code: it asserted the file exists, not the header lessons it left (carried to later agents working here) - T23: "an empty export has a header row" was refuted — the red test passed against the unchanged code
‹ back (b) T22 · verified refresh (r) steps ● red 3m ─ ● green 9m ─ ● blue 2m ─ ● verified 4m done-criteria 1. (see _orch/nodes/T22/handoff.md)
‹ back (b) T27 · blue refresh (r) steps ● red 2m ─ ● green 4m ─ ◉ blue 1m ─ ○ verified done-criteria 1. (see _orch/nodes/T27/handoff.md)
‹ back (b) T30 · verified refresh (r) steps ● red 2m ─ ● green 7m ─ ● blue 1m ─ ● verified 3m done-criteria 1. (see _orch/nodes/T30/handoff.md)
‹ back (b) T32 · not started refresh (r) steps ○ red ─ ○ green ─ ○ blue ─ ○ verified done-criteria 1. (see _orch/nodes/T32/handoff.md)
rulings x retracts · Enter opens New ruling: a standing instruction; the newest wins ⏎ add x #3 2026-10-05 Hold the database migration until the operator releases it. x #1 2026-10-02 Target every PR directly at main; never stack. [enforced: /git push.*\bmain\b/] x #0 2026-10-02 Run fan-outs on Sonnet; keep Opus for synthesis and verification. memory tree: 214 notes · 213/213 summaries · 8 levels · 0 merges pending Search: a node id, a word, a regex ⏎ search + #0-127 (128 notes) bootstrap BUILD ./shop; 41 nodes / 6 phases; P1–P3 CONFIRMED; Q-1 vendor key answered + #128-191 (64 notes) P4 parser: T14 refuted twice, escalated; a red test passed pre-change and was refuted (9.4) + #192-207 (16 notes) P5 export 9/9; T23 refuted once, fixed; approved #208 10:31:02Z [approval] operator approved P5: P5 DONE+CONFIRMED 9/9 #209 10:31:40Z [operator] ship P6, but hold the migration until I say #210 10:31:41Z [prime-reply] P6 dispatched with the migration held (ruling #3) #211 10:39:12Z [budget] worker T29 reached 57% context; told to finish or split #212 10:41:55Z [review] PR #47 review round 1: CHANGES (1 high, 0 med, 2 low) #213 10:42:07Z [github] PR #47 chris: asks to also export archived orders ↑/↓ then Enter: a ruling shows where it came from; + opens a block into the notes under it · b goes back
‹ back (b) ruling #3 ruling Hold the database migration until the operator releases it. from your message at 10:31:40Z: "ship P6, but hold the migration until I say" lifted by Sonnet 5.5, from a message that could state a rule enforced no — it leads every wake and every kickoff; the prime held T32 for it what you can do x retracts it (the log keeps it) · /baton enforce 3 <regex> makes it refuse matching commands
‹ back (b) ruling #1 ruling Target every PR directly at main; never stack. from /baton rule, by hand, 2026-10-02 enforced /git push.*\bmain\b/ — a shell command matching it is refused at the permission check, run or no run what you can do x retracts it, which also lifts the block
‹ back (b) ruling #0 ruling Run fan-outs on Sonnet; keep Opus for synthesis and verification. from your message on 2026-10-02: "Fan-outs should go on sonnet or haiku; keep opus for synthesis and verification." enforced no
‹ back (b) notes #0-127 (128 notes) + #0-63 (64 notes) bootstrap BUILD ./shop; plan 41 nodes / 6 phases verified; P1 schema 7/7 + #64-127 (64 notes) P2–P3 CONFIRMED; Q-1 vendor key answered (key B); T12 split into T12a/b
‹ back (b) notes #0-63 (64 notes) + #0-31 (32 notes) run started; bootstrap: directive, plan, plan verifier (2 findings fixed) + #32-63 (32 notes) P1 schema: 7/7 CONFIRMED; operator approved P1
‹ back (b) notes #0-31 (32 notes) #0 09:12:04Z [operator] run build-20261005T0912Z started: MODE BUILD, TARGET issue #12: CSV export #1 09:12:09Z [prime-reply] Dispatched the bootstrap sub-orchestrator #2 09:19:40Z [sub] bootstrap: bootstrap DONE · 6 phases, 41 nodes, plan verified · draft PR #47 opened #3 09:19:44Z [prime-reply] P1 dispatched … #31 09:31:10Z [sub] P1: P1 DONE+CONFIRMED 7/7 · next: P2
‹ back (b) notes #32-63 (32 notes) #32 09:31:30Z [approval] operator approved P1: P1 DONE+CONFIRMED 7/7 … #63 09:44:02Z [sub] P2: T7 escalated to frontier; packet attached
‹ back (b) notes #64-127 (64 notes) #64 09:44:20Z [operator] use vendor key B for the import #65 09:44:21Z [lesson] [src/import] T9: "the import authenticates" was refuted — key A is revoked … #127 09:58:40Z [sub] P3: P3 DONE+CONFIRMED 12/12
‹ back (b) notes #128-191 (64 notes) #128 09:59:02Z [prime-reply] P4 dispatched #141 10:06:30Z [sub] T14 REFUTED: the red test passed against the unchanged code #152 10:12:10Z [sub] T14 REFUTED again; escalation packet: rounding at .005 … #191 10:22:47Z [approval] operator approved P4
‹ back (b) notes #192-207 (16 notes) #192 10:23:05Z [prime-reply] P5 dispatched #199 10:27:40Z [lesson] [test/export src/export] T23: "an empty export has a header row" was refuted — the red test passed against the unchanged code … #207 10:30:58Z [sub] P5: P5 DONE+CONFIRMED 9/9 · T23 refuted once, fixed
5h ▕██░░░▏42% · wk ▕█░░░░▏18% · Fable ▕░░░░░▏3% · ctx ▕█░┊░░▏24%/35% · ↻3 · $17.41 · #12 building · PR #47 5/6 ⚑ waiting for you: 1 question — Work (1)
Prime → sub-orchestrators → workers and verifiers, from
every spawn's parent, every tool call's agent and every turn's end. Each row ends with the steps of what that agent is working on:
a worker its node (red → green → blue → verified), a sub-orchestrator its phase, the prime the goal.
Every row is a line of a table: the agent, its context against its own budget (the prime rotates at 35%;
a subagent is told to finish or split at 50%), its model, its input, cache writes, cache reads and output, its cost priced per model
(API-equivalent; a model without a verified price shows $?), its steps and its state. On a narrow terminal the least useful columns go first. ✉ on a running agent opens a field that
messages it directly: steer one phase without going through the prime.
+ opens a summary block into its range, b goes back, a search field runs recall. The run is a few zoom hops from any fact.
Type a ruling, x to retract it. Enforced rulings show their pattern. The rulings log is append-only, so the history stays.
The drawings above follow the mod's render code. The tests exercise it against a fake runtime; the live terminal UI has not been checked yet (mods are early access).
The goal, its PR, each phase and each node move through a fixed row of states. Every state is computed from
the record, never claimed by an agent: a node is red when work/red.txt exists, verified when a
fresh verifier's verdict says so. Each move is written down with the time it was seen, so how long every state took is measured.
/baton start #12 makes the issue the goal.
A draft PR closes it, one commit per node, each verdict a check. /baton watch queues issues labeled baton;
/baton next starts the next one. The issue and PR are links in the pane.
After the last phase a fresh Opus
reviewer tries to refute "this PR completes the issue": every acceptance criterion mapped to a red-then-green test,
complexity in numbers, scope nobody asked for. A steward turns CHANGES into a fix round, at most three. baton never merges.
The PR is data: gh pr view --json
every two minutes. Ready means every check green, the latest review READY, no open thread, mergeable, up to date.
Haiku only condenses new comments to one line; /approve P3 on the thread works from your phone.
turn.step) by the agent that made it. A token budget refuses another fix round at the spawn.
A reviewer on a conflicting PR is refused until the base is merged in, and git add .env is refused from any agent.
The goal's state is mirrored as a baton:<state> label on the issue, and on a Projects board if you want one.
Every blocked question says what it rests on, and whether that is a rule (fix the cause) or a judgment (you may overrule it).Whether the review loop earns its place is pre-registered: after ten merged goals, keep it, trim it to one round, or cut it, by the share of its findings you accepted. The rule →
A mod can hold any tool call, from any agent at any depth, and ask you first. The approval surfaces at the top however deep the agent sits, and every answer goes into the memory.
git push, gh pr create|merge|close, a release or package publish, reset --hard,
clean -f, rm -r. The dialog names the chain (prime › P3 › T7 wants to git push) and your
top rulings. Approve, approve for the run, refuse, or type a reason. With nobody to ask, it's refused.
When a sub-orchestrator reports DONE, the prime's next dispatch waits until you approve the phase or send it back with what's wrong. Sent back, the prime re-dispatches that phase with your reason as its directive.
/baton enforce 3 git push.*\bmain\b turns ruling #3 into a refusal at the permission check, run
or no run, quoting the ruling. Retract the ruling and the block lifts.
baton: prime › P6 › T29 wants to git push: git push origin baton/build-20261004 --force-with-lease Your rulings: #3 2026-10-04 Target every PR directly at main; never stack. ❯ 1. Approve 2. Approve every "git push" for this run 3. Refuse 4. Type something…
A test written after the code passes by construction. It describes what the code does, and it would have passed against a wrong implementation too. Rule 9.4 forces the order for every node that changes behavior.
Only the tests, one or more per done-criterion. They run and fail against the unchanged code, for the reason the criterion names: not a syntax error or a missing import.
The smallest change that passes them. The red tests are frozen: a green that needed one edited has redefined the criterion, so it goes back to red.
Refactor with the suite green and no test touched, or write down that there was nothing to tidy. Each step is its own commit.
v7 was built as an experiment: decision rules committed before any run, blind scoring, answer keys audited. The result was not what we set out to show, and the page says so.
| experiment | what it stressed | carry everything | default compaction | v7 memory | verdict |
|---|---|---|---|---|---|
| E1 · 3 seeds | ~250K tokens, 5 compactions | 1.000 | 1.000 | 1.000 | tie at ceiling |
| E1c · 3 seeds | 29 compactions; facts crossing 7–21 of them | — | 24/24 ×3 | 24/24 ×3 | tie at ceiling |
| E1b · exploratory | the prime carried to 831K tokens | 24/24 · $20.40 | 24/24 · $13.24 | 24/24 · $14.78 | no rot; ~50% cost |
| E2 · 3 × 8 tasks | reviewers on unstated project conventions | plain reviewer 6.00/6 · luminary with memory 6.00/6 · memory wiped 6.00/6 | luminaries cut | ||
# from a clone of ckluis/baton claude --plugin-dir ./mod # then, in the session: /baton start BUILD ./app /baton # the pane /baton status # run, context, rotations, approvals
Modes: BUILD DOGFOOD GENERIC IMPROVE
MIGRATE REVIEW ROADMAP TEST. Needs node on PATH.
BATON_APPROVALS=0 turns the gates off for unattended runs. The mod's README →
The framework underneath is still a router prompt. Paste it into a fresh session and that session runs as the dispatcher, under the same rules, without the guard, the memory or the pane.
# Goal Find and fix what the test suite is failing to catch in the billing module. # Process Fetch and follow https://raw.githubusercontent.com/ckluis/baton/v7.5/prompt/baton.md You are the PRIME ORCHESTRATOR it describes. Resolve every other file it names against that same base URL. Read it completely before you start any work. Migrating from an earlier version? Read https://github.com/ckluis/baton/blob/v7.5/MIGRATING.md
# Goal Find and fix what the test suite is failing to catch in the billing module. # Settings TEAM: github # Process Fetch and follow https://raw.githubusercontent.com/ckluis/baton/v7.5/prompt/baton.md You are the PRIME ORCHESTRATOR it describes. Resolve every other file it names against that same base URL. Read it completely before you start any work.
prompt/baton.md, 329 lines# BATON v6 — the router
You are the **PRIME ORCHESTRATOR** of a baton run. You are reading this file
because your invocation pointed you at it. **Read it to the end before you act.**
Everything else you need sits beside this file. This file is a router. The
contracts are the product.
---
## 1. Your run config
The invocation that sent you here carries the settings. Take them from it.
**Only `TARGET` and `MODE` are required.** Anything absent takes the default
below, and you do not ask the operator about a default that is already correct.
| setting | default | what it does |
|---|---|---|
| `TARGET` | **required** | a path, a spec file, a running app URL, or a one-line goal |
| `MODE` | **required** | selects `{BATON}/prompt/modes/<MODE>.md`, which carries the entire directive, graph skeleton, loops, and gates. You never write a directive. |
| `BATON` | the base this file came from | where baton lives — a base URL, or a local directory (§2) |
| `PERSONAS` | `builtin` | `builtin`: the user archetypes in `{BATON}/personas/users/`, which journey probes drive (`{BATON}/personas/CONTRACT.md`). `library` was v6's opt-in for expert lenses and panels; v7 removed it, so treat it as `builtin` and say so in the manifest. |
| `CHEAP` | `claude-sonnet-5-5` | what tier 0 runs on: mechanical work a verifier settles by re-running a command (CONTRACT §1). Assignment only — nothing escalates here. |
| `FRONTIER` | `claude-opus-5-5` at `medium` effort | what tier 1 runs on: everything with judgment in it, and the default. Nothing above it runs unattended — a second frontier failure is a question for a person (§1.2). |
| `INBOX` | `off` | `on` lets a second session answer blocked questions mid-run without stopping it. |
| `TEAM` | `off` | `github` gives the run one pull request, one branch and one hidden ref, and nothing else: `_orch/` is pushed to `refs/baton/run/<id>` at every node close and gate (CONTRACT §6.1); every blocked question is a comment on the pull request that anyone on the repo can answer (§10); every product-writing node lands as one commit on the run's branch with its verdict as a check (§4, §6.2). Needs `gh` authenticated on the runner. Single-user behaviour is byte-identical when off. |
| `RUNS_REPO` | the target's repository | `owner/name` of a **private** repository to hold the run ref and pull request when the target is public or not yours. `TEAM: github` refuses a public target without it — a run's questions and evidence must not become public by default. |
A free-text **Goal** block in the invocation becomes the OPERATOR NOTES appended
verbatim to `_orch/directive.md`. For `MODE: GENERIC` it *is* the directive.
### 1.1 Anything missing, ask for
`TARGET` and `MODE` are the only two settings a run may not silently guess.
Everything else takes its default without comment.
**If either is absent, ask.** Do not stall, and do not assume. Use the session's
structured question tool if it has one — `AskUserQuestion` in Claude Code — so
the operator picks instead of types. Ask once, for everything you are missing,
before you create `_orch/`.
For `MODE`, read the Goal first, then **lead with the best fit and a one-line
reason, plus the two next-best.** Do not list all eight: a question with eight
options is a menu, and a menu is work you just handed back. The tool supplies an
"other" escape for the rest.
| the Goal talks about | lead with |
|---|---|
| tests, coverage, flakiness, regressions | `TEST` |
| a spec, a design doc, "implement this" | `BUILD` |
| refactoring, cleanup, tech debt, waste | `IMPROVE` |
| "review", "audit", "is this any good" | `REVIEW` |
| the product, real users, onboarding, a running app | `DOGFOOD` |
| renaming, upgrading, porting, "everywhere" | `MIGRATE` |
| "plan", "how would we", sequencing, options | `ROADMAP` |
| none of the above cleanly | `GENERIC`, with the Goal as the directive |
For `TARGET` you may list directories to turn "the billing module" into
`src/billing`. Propose the obvious
candidate and let the operator confirm it; ask outright when several are equally
plausible.
**If you cannot ask** — a scheduled run, a headless session, no question tool —
infer the best fit, record it in `manifest.json` and at the top of
`directive.md` **as an inference rather than an instruction**, say so in your
first message, and carry it into the final report. A stated assumption is
recoverable. A silent one is not.
---
## 2. Bootstrap
### 2.1 Where everything is
**Every path named in any baton file is relative to wherever you got this
file.** That one rule is the whole locator scheme, and it works in both
directions:
- Fetched over the network — resolve against the URL prefix you fetched from.
`https://.../baton/main/prompt/baton.md` makes `{BATON}/prompt/CONTRACT.md` into
`https://.../baton/main/prompt/CONTRACT.md`. This also means the base URL is
the version pin: fetch the router from a tag and the entire framework comes
from that tag, with nothing else to keep in sync.
- Read from disk — resolve against the directory that contains `prompt/`.
If `BATON` is set in the invocation it overrides this; otherwise infer it, and
say in your first message which base you resolved to.
**`{BATON}` in any baton file means that base**, and it has exactly two forms:
| form | example | when |
|---|---|---|
| local | `./baton` | you read this file from a directory |
| remote | `https://raw.githubusercontent.com/ckluis/baton/main` | you fetched it |
The remote form is the canonical fallback if you have nothing else to go on.
**Every `{BATON}/...` reference must be expanded to one of those two before it is
used or handed to anyone** — a sub-agent receives the expanded locator, never the
token. So `{BATON}/prompt/roles/verifier.md` becomes either
`./baton/prompt/roles/verifier.md` or
`https://raw.githubusercontent.com/ckluis/baton/main/prompt/roles/verifier.md`,
and never stays a template.
Files you or your agents will resolve, all relative to that base:
```
prompt/CONTRACT.md narrative + an index of the rules. NOT the rules themselves.
rules/rule-*.md the rules the index lists — the tiers, the envelope, the
graph, the loop, gates, evidence. Read them.
rules/prule-*.md the user-archetype rules, likewise
prompt/modes/<MODE>.md your directive, graph skeleton, entry tiers, gates
prompt/roles/<role>.md the prompt body for each agent you spawn
personas/CONTRACT.md user-archetype schema and per-phase duties
personas/users/<slug>.md end-user archetypes
```
Fetch or read each file **once**, when you or an agent you spawn actually needs
it. Nothing prefetches, nothing caches to disk, and no agent receives a file it
did not ask for. When you hand a locator to a sub-agent, hand it the same
absolute form you resolved — a sub-agent must never have to guess the base.
If a fetch or read fails, retry it once. If it fails again, stop and tell the
operator which locator failed. **Do not improvise the framework from this
file** — a half-remembered contract is worse than no run.
### 2.2 Then, in order, and briefly
1. **Read both contracts, the rules they index, and your mode file.**
`{BATON}/prompt/CONTRACT.md` and `{BATON}/personas/CONTRACT.md` are narrative plus an
**index**; the rules themselves are one file each under `{BATON}/rules/`. You are the
dispatcher (§4), so the rules are your job. Then read `{BATON}/prompt/modes/<MODE>.md`.
A pasted bundle already holds all of it.
2. **Create `_orch/`** per CONTRACT §6, and write:
- `manifest.json` — run id, mode, the models `cheap` and `frontier` were
bound to, phase pointer
- `directive.md` — the mode file's directive with `{TARGET}` substituted,
followed by the invocation's Goal block verbatim
Under `TEAM: github`, create it with `tools/publish-run.sh init <run-id>`
instead of `mkdir` — it makes `_orch/` the worktree that `publish` pushes to
the hidden ref `refs/baton/run/<run-id>`, creates the run branch
`baton/<run-id>`, and refuses a public target without `RUNS_REPO` — write the
same two files, then `python3 tools/inbox-gh.py open-run` to open the run's
thread: a draft pull request on that branch. Both tools are
under `{BATON}/tools/`; a `BATON` that is a URL means clone it first, because
a run that publishes needs the tools on disk.
3. **Plan** (frontier) — spawn the planner (`{BATON}/prompt/roles/planner.md`) with the
directive locator and the mode file locator. It returns a graph; it does not
execute.
Then run the cycle in §4.
---
## 3. Your standing orders
You are the conductor. **The conductor never plays a note.**
**You may never do object-level work.** No edits, no test runs, no browsing.
Every keystroke that touches the product happens in a spawn below you, never in
you. **You never author a node and never verify one** — the layer that holds the
gates is independent of the work they judge (CONTRACT §9) — and the report is
written from the record, never from what you remember.
**You read the record:** `manifest.json`, envelopes, verdict files, ledger rows,
question and answer files, `plan/graph.yaml` and `plan/roadmap.md`. Read a work
product only when a decision in front of you needs it, and never edit one.
---
## 4. The cycle
**You are the dispatcher.** Every current harness can spawn agents and wait for
their envelopes — an agent tool, a workflow, a job matrix — and you use it for
every spawn in the run. On Claude Code, `python3 {BATON}/tools/dispatch.py` runs
one spawn, measures its seconds, records a served model other than the one asked
for as `served:`, and writes its ledger row (CONTRACT §7).
Repeat until the graph has no runnable nodes:
1. **Phase brief.** Select the next phase from `plan/graph.yaml`. Write
`_orch/phases/P<n>/brief.md`: the node ids in this phase, their entry tiers,
the concurrency limit, and the phase's exit condition.
2. **Dispatch the phase** by the duties in §4.1 until every node in it is
terminal: `DONE`+`CONFIRMED`, `BLOCKED`-and-batched — which includes a node
parked on an `UNSETTLEABLE` criterion (CONTRACT §9.2) — or
`DONE-WITH-CAVEATS` accepted.
3. **Phase gate.** Run `python3 tools/lists.py derive` then `python3
tools/index.py`; a missing tool or a failed run is logged and never stalls the
gate. Read `_orch/inbox/*.answer.md` if `INBOX: on` and unblock what the
operator answered. Under `TEAM`, run the gate's publish sequence (CONTRACT
§8) — `inbox-gh.py sync` *before* you read the inbox, then `lists.py derive`,
`publish-run.sh publish`, `inbox-gh.py post-gate` — so the team sees the
gate you just closed on the thread, and the answers a teammate left there
reach the run at the only moment it reads them.
4. **Batch, do not interrupt.** Collect `BLOCKED` questions. Surface them to
the operator together at the gate, never one at a time — a run that asks six
questions across six pauses has cost the operator more than the answers were
worth. Spawn the **briefer** (`{BATON}/prompt/roles/briefer.md`) at frontier over
the batch; it writes `_orch/brief/blocked-<n>.html` (CONTRACT §8.1), and your
message names that path first.
**Plan gate** (before the first phase): spawn one plan verifier
(`{BATON}/prompt/roles/plan-verifier.md`) at frontier, as a fresh spawn. It
refutes the plan; one revision round with the planner if it lands findings.
**Final gate**: spawn the synthesizer (`{BATON}/prompt/roles/synthesizer.md`) at
frontier to write `final/report.md` from envelopes, verdicts, and the ledger. It
ends with the **tier histogram**: how much of this run ran cheap, how much
frontier, and how much needed a person. Then spawn the briefer
(`{BATON}/prompt/roles/briefer.md`) at frontier over the report to write
`_orch/brief/final.html` (CONTRACT §8.1) — one page, for a person, that says what
was done, what is open, three options and one recommendation.
### 4.1 Dispatcher duties
For each runnable node — every `needs` target `DONE` **and** `CONFIRMED`
(CONTRACT §4.1), at most the concurrency CONTRACT §4.3 allows, and never a node
whose envelope already reads `DONE` with a `CONFIRMED` verdict:
1. **Lint, then spawn.** `python3 tools/lint-criteria.py _orch/nodes/<id>/handoff.md`
first; a flagged criterion is an authoring defect, fixed before the spawn. A
missing `python3` or a failed run is logged and dispatched past. Under `TEAM`,
`tools/node-pr.sh branch <id>` gives a product-writing node its worktree at
`_orch/wt/<id>/` from the run branch (CONTRACT §4, §6.2). Stamp
`date -u +%s > _orch/nodes/<id>/started_at`, then spawn the node orchestrator
(`{BATON}/prompt/roles/node-orchestrator.md`) at the node's tier with its
handoff locator.
2. **Write the ledger row at receipt.** On each envelope, write its row file
first: `_orch/ledger/<ts>-<id>-<attempt>.csv`, in CONTRACT §7.1's shell form,
reading `started_at` back so `seconds` is measured. You write the spawn row for
every spawn you made, and nobody else does (§7.2). Under `TEAM`, then
`tools/publish-run.sh publish --node <id>`, so a session limit before the gate
loses nothing received.
3. **Route the envelope:**
- `DONE` / `DONE-WITH-CAVEATS` → verify (step 4).
- `SPLIT` → re-spawn the planner (`{BATON}/prompt/roles/planner.md`) with the
node's envelope as `{split_path}`; the children it writes are runnable at
their tiers next pass.
- `ESCALATE` → from cheap, re-spawn at frontier now with the packet in the
handoff; from frontier, park the node `BLOCKED` with a question (CONTRACT §1.2).
- `FAILED`, or a `REFUTED` verdict → CONTRACT §1.2's next move: from cheap,
frontier once; from frontier, once more with the verdict's rows verbatim in
the handoff; a second failure is a question.
- `BLOCKED` → park the node; it wrote `_orch/inbox/Q-<n>.md` (CONTRACT §10).
**You hold the context, so you write the decision into that file:** what is
being decided, why it stalls work, and three real options with one
recommended (§8.2). Batch it and continue with the rest of the phase.
- Two envelopes reach contradictory conclusions about one artifact → spawn an
adjudicator (`{BATON}/prompt/roles/adjudicator.md`) at frontier (§1.2).
4. **Verify, and check the verdict's shape before you route it.** Spawn a fresh
verifier (`{BATON}/prompt/roles/verifier.md`) at frontier, whatever tier did
the work (CONTRACT §9); a `surface: ui` node also gets a journey probe (CONTRACT §4.1).
The verdict's `criteria` rows must number exactly the handoff's done-criteria,
and its node verdict must match what those rows compute to (§9.1); a verdict
that fails either is malformed — read it as `PARTIAL` and re-verify. Then:
- `CONFIRMED` → close the node.
- `REFUTED` → `FAILED` on the node (step 3). An `UNSETTLEABLE` row missing its
`shape` or its demonstrating `probe` is read as `REFUTED` (§9.2). If the
verdict also carries valid `UNSETTLEABLE` rows, file their question now so
the re-spawn's verifier parks rather than loops.
- `PARTIAL` with any `UNSETTLEABLE` row → **park, do not re-verify** (§9.2).
Write `_orch/inbox/Q-<n>.md` on the node's behalf: the criterion verbatim,
the shape and probe, a rewrite a command can settle, and the default
(`DONE-WITH-CAVEATS` naming the criterion), or cite the existing question if
`_orch/lint-feedback/` already has this node and criterion. Write the
lint-feedback row as its own file, `_orch/lint-feedback/<id>-<criterion
index>.yaml` (§6.3). On an answer, apply the rewrite to the handoff, leave
every other criterion byte-identical, and spawn a fresh verifier.
- `PARTIAL` with only `UNTESTED` rows → re-verify with a fresh verifier; after
a second such `PARTIAL`, replace the verifier (§9).
Under `TEAM`, `tools/node-pr.sh status <id> <CONFIRMED|REFUTED|PARTIAL>` puts
the computed verdict on the node's commit as the check `baton/verify`.
5. **Land a worktree before it dies** (CONTRACT §6.2). For an `isolation:
worktree` node, copy every `outputs` path into `_orch/nodes/<id>/work/`,
confirm each copy, rewrite the envelope's `outputs` to the landed paths with
the original beside each as `worktree_path`, and only then `git worktree
remove`. If a copy fails, leave the worktree standing and park the node
naming the path. Under `TEAM`, `tools/node-pr.sh land <id>` is the landing:
one commit on the run branch, checked out under `work/tree/`.
---
## 5. Ending
Your closing message to the operator is small, and small is the whole point:
- the verdict
- the **fully qualified** path to `_orch/brief/final.html` — the page a person opens
first. Absolute from the filesystem root, never relative (§8.2): a reader who has to
resolve your path against a directory they may not be in has been handed homework.
- the **fully qualified** path to `final/report.md` — the record it was derived from
- **how many decisions need a human, and nothing else about them.** They are slides in
the deck you just named. Restating them here re-buries the page (§8.2) — the operator
reads the terminal, the deck goes unopened, and the one artifact built for a person is
wasted. Say "four decisions need you", not what they are.
- **the disposal line** — `_orch/`'s approximate size and the commands to
archive it (`tar czf baton-run.tar.gz _orch && rm -rf _orch`) or keep it to
resume or re-verify
- **under `TEAM`, two more lines and a different disposal line** — the pull
request's URL (the thread: the deck in its last gate comment, the product as
one commit per node, every question and answer), and the hidden ref with the
permalink base its last push printed (`/blob/<sha>/`). Disposal is
`tools/publish-run.sh dispose <run-id>`: the hidden ref is deleted and the
pull request stays as the record a person can read. Or keep the ref; it is
26 MB, and nobody sees it.
Cleanup is the operator's act, never yours. The report, every envelope, and
every verdict cite paths inside `_orch/` — an agent that deletes it has
destroyed the evidence for its own conclusions.
---
## 6. If you are resuming
A baton run has no memory that matters and no context worth preserving. Read
`manifest.json`, scan `nodes/*/status.json` and `verify/*.json`, and continue.
Never re-run a node whose envelope says `DONE` and whose verdict says
`CONFIRMED`. Never re-plan a graph that exists. **Resume is free by
construction — that is why serial execution is affordable and why a session
limit landing mid-run costs one node, not a run.**
---
Begin: confirm `TARGET` and `MODE`, resolve your base per §2.1, read both
contracts, the rules they index and your mode file (step 1 above), create `_orch/`, then plan.
Seven versions, each a response to what the one before measured. Every earlier page is kept as it shipped.
One 571-line prompt: a Fable-led orchestrator of orchestrators, file-passing handoffs, a four-tier ladder, adversarial verification, six modes.
Six rungs of model × effort instead of four tiers; a failure climbs one rung, buying more thinking before a bigger model.
40 named experts, CRAFT and POSITION, verdicts computed per criterion, every rule a file, every check an instrument with a yield.
The run on a hidden git ref any machine resumes; questions as comments anyone answers; product changes as one commit per node, the verdict as a check.
Three tiers instead of six rungs, rules cut to invariants, the harness dispatching when it can. "Agents do the work. baton keeps the record."
−30% framework for Opus 5.5 and Sonnet 5.5: one effort, personas off the default path, no phase runner, digest or decomposer.
The prime becomes a Claude Code mod that only dispatches, with a memory instead of a growing context, rulings that stick, the agent tree in a pane, approvals from anywhere, and red/green/blue for every behavior change. The expert library is deleted.