v2 · archivedThis is baton as v2 shipped — eight modes, 28 built-in personas, kept byte for byte
at the v2.0 tag, which still resolves and still runs.
baton v3 replaces it: ten modes, two of them examining the artifact
as encountered and as sold, a 40-expert opt-in roster, and verdicts computed per criterion.
Five breaking changes.Read v3 →
v2.0router + 8 modes
The cheapest agent that can succeed.
baton is a router prompt that turns a fresh session into a multi-agent run with a
budget. Six rungs of model × effort. Sonnet is the default. Failure buys
more thinking before it buys a bigger model — and the top of the ladder is reached
by asking, not by drifting.
1The default rung. sonnet/medium until the work proves otherwise.
10×Fewer top-tier turns on a 40-node run, from one structural change.
8Modes. Each one a graph shape, not a paragraph of advice.
28Built-in personas — and any repo's roster loads unmodified.
Why v2 exists
v1 worked. The bill was the problem.
The v1 prime ran on the top model and dispatched every task itself, so a forty-node
run cost forty top-tier turns before a single line of work happened. Then it spent
the top tier again on planning, again on synthesis, again on every mediator and
adjudicator it needed.
None of that was wrong. All of it was expensive in the same direction.
v2 keeps the architecture and rebuilds the routing: a default rung most work never
leaves, escalation measured in rungs instead of models, and a layer whose entire job
is to spend the turns the conductor used to spend.
01 — The ladder
One failure moves a node one rung. Never one model.
Model and reasoning effort collapse into a single ordered list. That is the whole
routing system — there is no second mechanism, no override, no "use your judgment."
Escalating from sonnet/medium lands on sonnet/high, because most
work that failed did not need a bigger model. It needed more thinking.
#
Rung
For
0
haiku/low
Mechanical and verifiable by command: run the suite, collect coverage numbers, apply a named rename. Assignment only — escalation never lands here.
1
sonnet/medium
The default rung. Bounded implementation against a clear spec: tests from an approved plan, a diagnosed fix, named duplicates consolidated, a document from an outline.
2
sonnet/high
The same work when it needs more thinking — not a bigger model. Most rung-1 failures belong here, and stop here.
3
opus/medium
Diagnosis and judgment: root-cause an intermittent failure, decide necessary-vs-redundant, design around a race, resolve a contract ambiguity.
4
opus/high
The ceiling for ordinary work. Cross-cutting design, contested calls, plan verification on a large graph.
5
fable/low
Requires operator approval. Adjudication between agents that disagree about the same artifact. Synthesis across a whole run.
6
fable/medium
Requires operator approval. The last rung. Nothing above it.
ENTRY
Assign low. Always.
Assigning high wastes budget on work that would have succeeded low. Assigning low costs
one extra attempt. The asymmetry is the entire argument. A node enters above rung 1 only
with a written reason naming a property of the work — "this looks hard" is
not a reason.
CEILING
The top is asked for.
A node that would escalate past CEILING goes BLOCKED with a
written question instead. Rungs 5 and 6 exist and are reached by asking. This is the
single line in the config that decides what the run costs.
DE-ESCALATION
Diagnosis and typing are different rungs.
A rung-3 agent that finishes root-causing must hand the specified fix back down to rung 1
— or say in its digest why the change was inseparable from the diagnosis. Keeping the
fix because you already hold the context is how a ladder quietly becomes a ceiling.
RUNG DRIFT
The run tells you what the next plan should assume.
Three nodes in a phase escalate past their entry rung → the
phase runner raises the default entry rung for what remains, and logs it.
Five consecutive nodes succeed at rung 2+ without using the
headroom → it lowers it.
Drift resets at every gate. Every adjustment lands in the ledger, and the final report
ends with a rung histogram — where this run actually spent its money.
02 — The layers
The conductor stopped walking to every music stand.
v1's prime dispatched each task itself. v2 inserts a phase runner that absorbs dispatch,
retry, verification, and drift — so the top of the stack spends its turns on gates and
nothing else. Same architecture. An order of magnitude fewer expensive turns.
Primefable/low
Never reads work. Never edits. Writes a phase brief, waits for one envelope,
holds the gate. ~1 turn per phase — four or five on a forty-node run, where v1
spent forty.
Phase runneropus|sonnet
Owns one phase end to end. Dispatches every node, routes every escalation,
spawns every verifier, applies rung drift, parks what is blocked and keeps going. Reads
envelopes and digests — never work products. This layer is the whole saving.
Node orchestratorassigned rung
Does the work, or spawns workers if it decomposes. Returns ESCALATE
early and honestly when the work is above its rung, or SPLIT with the seams when
it was never one node.
Workerassigned rung
Leaf. Writes artifacts inside its work directory and a digest of ten lines or
fewer. Nothing above it will ever open those artifacts — the digest is the interface.
DOWNWARD
Paths and a rung.
Never contents. A layer that pastes a file into its child's prompt has spent the context
it was protecting.
UPWARD
An envelope.
Never prose. Six verdicts, paths only, a summary capped at three sentences. The reader is
routing, not learning.
SIDEWAYS
A digest, or nothing.
Ten lines is the ceiling. A digest longer than ten lines is a document, and documents do
not cross layers.
PRIME_TURNS
The conductor has a budget, and running out of it is a normal outcome.
One line of the run config caps how many turns the prime may spend.
The count lives in manifest.json. When it is exhausted the prime hands its
remaining gates to an opus deputy and records the handover in the final report —
it does not quietly keep spending, and it does not stop the run.
03 — Graphs & loops
The plan is a graph. Some of its nodes are loops.
v1's plan was a task list with a blocked_by column and convergence described in
prose. v2 makes both structural: typed edges the runner can act on, and a loop node that has
to declare how it ends before it is allowed to start.
plan/graph.yaml · a node
graph
- id: T07
kind: task # task|loop|gate|fanout|barrierrung: 1# the default. above it needs a reasonsurface: code
needs: [T05] # hard — DONE *and* CONFIRMEDinforms: [T06] # soft — a digest path, never blocksrefutes: null# exists to attack that nodeadversarial: standard
personas: [coverage-truth]
done: "one line, checkable without judgment"
plan/graph.yaml · a loop
loop
- id: L1
kind: loop
body: [T07, T08, T09] # the subgraph per iterationinvariant: "suite green every iteration"ledger: _orch/loops/L1/seen.yaml
stop:
dry_rounds: 2# admitted nothing new, twicemax_iterations: 6max_rungs: 40# attempts before forced stopon_stop: T10
THE SEEN LEDGER
Dedupe against everything seen. Not everything admitted.
Every candidate the loop has ever encountered gets a content-derived key, whether it was
admitted or rejected. Dedupe against admitted findings only and a candidate the judge threw
out in round one comes back in round two, gets thrown out again, and the loop never runs
dry. This is the bug that eats a night.
DRY, NOT EMPTY
Stop on two quiet rounds.
A count-based stop — "find ten bugs" — always misses the tail. An empty-list stop
fires on the first lazy iteration. Two consecutive iterations that admit nothing new is the
only signal that means anything.
PIPELINE FIRST
A barrier is rarely correct.
Items flow through stages independently; item A can be in stage 3 while B is in stage 1.
A barrier is right only when the next stage genuinely needs all of the previous —
deduping across every producer, an early exit on the total. Needing to flatten a list is
not a reason. Do that inside the next stage.
04 — Modes
You point. The mode brings the topology.
A mode is a file, not a paragraph of advice. It carries the directive, the graph skeleton,
the loop definitions, the entry rungs, the seats, and the gates — and the session loads
only the one you named. Each drawing below is that mode's graph, not a
decoration of it.
Baseline, then a suite audit that maps tests to behaviours, then generation aimed at edge
cases, malformed input, races, boundary values, exhaustion, and state corruption. Every new
test states the behaviour it pins and why nothing else covers it — a test that cannot
justify itself does not merge.
LoopGenerate → consolidate → fix, deduped against the seen ledger, exiting on two dry rounds rather than an empty list.
RefusesRetry-until-green wrappers. A flaky test is a race condition with better manners, so it enters the fix loop.
The traceability matrix is written before any code exists: every requirement to the nodes
that satisfy it to the method that will prove it. Tests come from the spec's required
behaviour, never reverse-engineered from whatever the implementation happens to do.
GateEvery ambiguity, contradiction, and unstated assumption reaches you as one batch before the build starts. Cosmetic ones get a documented default instead.
RefusesGuessing. A spec question answered by inference is a deviation nobody approved.
An audit is a set of lenses, and a set of lenses has a shape. Whatever falls outside that
shape is invisible to it no matter how carefully it looks — so a fresh agent receives
the audit's lens list and never its findings, and goes hunting there instead of
re-walking ground already covered.
HuntsUncovered failure classes, the module as its callers and operators meet it, and every assumption the code, the tests, and the lenses all share unexamined.
RefusesDrive-by refactors. Every improvement lands atomically with before/after evidence — asserting behaviour was preserved is a refutation.
Agreement is only information when disagreement was possible.
The adversarial panel as its own mode. Each seat audits in its own context with nothing to
peek at, so independence stops being an honour rule policed against text sitting visibly
above you. One blocking flag per seat, maximum — forced prioritisation.
TwistA unanimous panel is a failure signal. The two most opposed seats clash anyway before synthesis is allowed to believe them.
RefusesExecuting anything. Its output is a matrix a later BUILD or IMPROVE run picks up directly.
SeatsCast from tags against your roster, with severity-inflation standing in every panel.
Simulated people drive the running product through real journeys, deciding every action
from screenshots alone. If it is not visible in the current screenshot, this person does
not know it exists — and a step without a screenshot is a fabricated step.
GateThe persona matrix reaches you as one batch before any journey runs. Persona choices change everything downstream.
ProbesTenant isolation, privilege boundaries, impersonation. These are the findings only a simulated user surfaces.
RefusesFixing anything, and refuting taste. Verification re-drives facts: steps, error text, timings, dead ends.
The transform is the easy part — it is mechanical, rung 1, and verifiable per site.
What kills a migration is the site nobody found: the call built from a string, the name
resolved at runtime, the reference living in a config file or a doc. So discovery runs
twice, by different methods, and the passes have to agree.
ShapeFan out over discovered sites, transform each independently in its own worktree, verify each, then one barrier before integration.
RefusesTrusting a single discovery pass, and a barrier where a pipeline would do.
Plan and plan gate, then synthesis, then stop. The deliverable is the graph itself —
options enumerated honestly including do-nothing, phases decomposed with objective
done-criteria, dependencies and entry rungs assigned and then attacked until they hold.
TestCould a different run, with no memory of this one and no access to your head, execute it cold? If not, it is notes rather than a roadmap.
RefusesBuilding any of it. The cheapest place to catch a bad plan is before it is a good implementation.
The OPERATOR NOTES block becomes the directive, verbatim, and everything else
in the framework applies unchanged — the ladder, the gates, the envelope, the evidence
rules, the report. The planner decides the phase structure.
HoldsYour directive to the standard of a built-in one. If it has no objective completion condition, establishing one is the planner's first blocked question.
Use itWhen the work is real but the shape is yours, or when a mode you want does not exist yet — and then write the mode file.
SeatsChosen by casting from the directive's own tags, with no mode pins.
Everything lands in _orch/. Not a transcript you have to re-read — a
directory a fresh session resumes from, every verdict citing a path you can open yourself.
_orch/ · after a TEST run
plan/graph.yaml 58 nodes, 1 loopcast/roster.yaml 4 seats, 2 upgraded, 1 cutnodes/T31/
handoff.md inputs, outputs, criteria
status.json "verdict":"DONE", "rung":1
digest.md 10 lines — all that rosework/nothing above opened itverify/T31.json "CONFIRMED" + the probeloops/L1/seen.yaml 47 keys, 2 dry rounds
ledger.csv 58 rows, one per spawnfinal/report.md + the rung histogram
RUNG HISTOGRAM
Where the run actually spent its money.
0 haiku/low4
1 sonnet/med38
2 sonnet/high9
3 opus/med5
4 opus/high2
5 fable/low0
6 fable/med0
Illustrative, not a benchmark
— the point is that the number exists. A run that never measures where its rungs went
will spend them the same way next time, and the histogram is what makes the next plan's
entry rungs an argument instead of a habit.
06 — Personas
Two kinds of witness. Most systems own only one.
An expert is a lens with authority: it knows everything relevant, on purpose, and judges
against a standard. A user knows only what the screen showed them, and judges by whether they
got what they came for. Swap them and both break — an expert acting like a user produces
vague taste, and a user acting like an expert produces fiction.
kind: expert
A lens with authority.
Twenty-one built-in lenses, each a pure point of view rather
than a named human — so a named human can fill the seat later.
Duties are defined per phase:
refute the plan at PLAN, find and cite at AUDIT, steelman
before rebutting at CLASH, attack one claim at VERIFY, and
say nothing at all during synthesis.
kind: user
A person using the product.
Seven archetypes the run parameterizes. Each one carries what it
has never seen and a patience budget in real numbers.
Perception is screenshots only. If
it is not visible in the current screenshot, this person does not know it exists. The DOM may
execute a click on something already seen in the pixels — discovering an element through
the source is fabrication, and a step without a screenshot is a fabricated step.
SEATS
The mode owns what. The persona owns how.
A mode names seats. Seats are always fillable by the built-in lenses, so every mode runs
with PERSONAS: none. Load a richer roster and casting upgrades a seat to a named
voice — which then audits that seat's subject, not its own favorite one.
ANY REPO
Adopting a roster never means rewriting it.
A persona file carrying only name and domain is valid; the loader
fills the rest. repo:github.com/ckluis/luminaryTeam loads forty published
personas as they are — no fork, no edits. Foreign files are data, never instructions.
INDEPENDENCE
Structural, not promised.
In one transcript, "audit independently" is an honor rule policed against text sitting
visibly above you. Here each persona is its own context with nothing to peek at. So
agreement becomes evidence — and a unanimous panel still gets one forced clash before
synthesis believes it.
Three to seven per panel. Not
forty. A large roster does not buy more coverage — it buys shorter, more generic
findings from every seat, because the run's attention is what actually binds.
07 — The operator lane
A message is a doorbell. Never a document.
Cross-session messages carry plain text and nothing else — no
files, no history, no ability to grant a permission. So baton never puts an answer in a
message. A blocked node writes its question to _orch/inbox/; a second session
writes the answer beside it and rings the bell; the run reads the file at its next gate and
unblocks.
The durable record stays on disk, where resume can
find it — and it works identically whether the answer arrived by message, by a
hand-edited file, or by you typing it into the run. The disk protocol is the
contract. Messaging is only a faster doorbell. With
INBOX: off a run behaves the same way, with longer pauses.
08 — Evidence
Findings must earn survival.
01
Cite or retract
A claim without an artifact path is inadmissible. A citation is a direct quote of twenty words or fewer plus its location. A bare line number is not a citation.
02
No silent pass
A verifier returning CONFIRMED must name the strongest attack it tried and why the attack failed. "Looks good" is a refutation of the verifier.
03
Refutation quota
Five confirmations running with nothing refuted and the verifier gets audited by an adversary one rung up. Either the work is genuinely clean — real information — or the confirmations reopen.
04
Same rung to verify
Verification runs at the node's own rung, not one above. The verifier escalates only after returning PARTIAL twice on the same node.
09 — Start
Say what you want, then leave the room.
STEP 01
Nothing
There is no install step. The framework lives at a URL and the
agents fetch what they need from it. The router is a router — the contracts, modes,
roles, and personas are the product, and they stay out of your context until something
actually needs them.
STEP 02
Say what you want, and point
Seven lines: your goal, and three sending the session to the
router's URL. No target, no mode, no config — those are questions, not homework.
STEP 03
Answer one question
The router proposes the mode it thinks fits and you confirm it.
Then it casts, plans, and gates on its own. Everything lives on disk, so a session limit
costs one node — not a run.
10 — What's in the box
One prompt became a repository.
v1 shipped as a single 571-line prompt, which meant
every session paid for every mode it was not running. v2 splits it: a router you paste, and
files the agents read. Two contracts define the schemas — the ladder, the envelope, the
digest, the graph, the loop — and every mode, role, and persona is written against them.
Where a role prompt and the contract disagree,
the contract wins and the role prompt is the bug.
prompt/invoke.mdthe paste — goal, settings, a pointerbaton.mdthe router — the agent reads thisCONTRACT.mdladder, envelope, digest, graph, loopmodes/8 — directive + graph shape + seatsroles/11 — planner, phase-runner, verifier…personas/CONTRACT.mdschema + per-phase duties per kindlenses/21 — expert seats, upgradeableusers/7 — end-user archetypesbundle.shflatten it all into one paste
11 — The invocation
Say what you want. Answer one question.
What you paste is not the process — it points at the process. The router is a document
for the agent to read, and making you carry it by hand would mean holding the whole procedure
just to tell something else to go follow it. So the paste carries the one thing only you know:
what you want. The router reads that, works out which mode fits, and asks you to confirm.
the whole paste · 7 lines
# 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/main/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.
No JavaScript?
Click inside the box, select all, copy. Replace the goal with yours — that is the only
line you have to touch.
IT ASKS
One question, not a form.
The router reads your goal, infers the mode, and confirms it — leading with its best
fit and the two next-best rather than making you choose from eight. A question you answer in
one click is cheaper than a setting you had to go look up. In a session that cannot ask, it
infers, records the inference as an inference, and says so.
NO SETUP
The URL is the whole dependency.
No clone, no install, no config file. Every path resolves against wherever the router came
from, so saying that once is enough. It also makes the base URL the version pin: point at
/v2.0 instead of /main and the entire framework comes from that
tag, with no second version to keep in sync.
OR KEEP IT LOCAL
A directory works identically.
git clone it and set BATON: ./baton — faster on repeat runs,
works with no network, and the only form where casting can clone a persona repo with git.
Point at a directory and the router reads; point at a URL and it fetches. Nothing else
changes.
AND IF YOU CAN DO NEITHER
Flatten the whole thing into one document.
./bundle.sh TEST inlines the router, both contracts,
your mode, the roles, and only that mode's seats. Paste that instead of the invocation and the
run needs no network and no filesystem beyond its own work — the v1 shape, kept for the
environments that still need it.
What that one line actually invokes — prompt/baton.md, 240 lines
prompt/baton.md · the agent reads this, not you
# BATON v2 — 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, and you will delegate the reading
of almost all of it. 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, seats, 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` · `none` · `path:<dir>` · `repo:<host/owner/name>`, combined with `+`. See `{BATON}/personas/CONTRACT.md`. |
| `CEILING` | `4` | highest rung reachable without asking. `4` is `opus/high`. Rungs 5–6 are fable and cost real money — they are reached by asking, not by drifting. |
| `PRIME_TURNS` | `12` | your own turn budget. Spend it on gates. When it runs out, hand your remaining gates to an opus deputy and say so. |
| `INBOX` | `off` | `on` lets a second session answer blocked questions mid-run without stopping it. |
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` — **listings only, never file contents** (§3). 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 the schemas — read by you and by every agent that needs a rule
prompt/modes/<MODE>.md your directive, graph skeleton, entry rungs, seats, gates
prompt/roles/<role>.md the prompt body for each agent you spawn
personas/CONTRACT.md persona schema and per-phase duties
personas/lenses/<slug>.md expert seats
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 exactly two files yourself.** `{BATON}/prompt/CONTRACT.md` and
`{BATON}/prompt/modes/<MODE>.md`. Together with this router they are the last three
documents you will read for the rest of the run.
2. **Create `_orch/`** per CONTRACT §6, and write:
- `manifest.json` — run id, mode, ceiling, `prime_turns_budget`,
`prime_turns_spent: 0`, phase pointer
- `directive.md` — the mode file's directive with `{TARGET}` substituted,
followed by the invocation's Goal block verbatim
3. **Cast** (rung 1) — spawn the casting agent (`{BATON}/prompt/roles/casting.md`) to
resolve `PERSONAS` into `_orch/cast/`. It runs while planning does.
4. **Plan** (rung 3) — 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**, and in v2 the
conductor also stops walking to every music stand.
**You may read:** `_orch/manifest.json`, any `status.json`, any `digest.md`,
`_orch/cast/roster.yaml`, the task table in `plan/roadmap.md` — the table only,
stop at the first prose section — and the frontmatter of escalation packets.
Plus **directory listings**, and only listings, when resolving `TARGET` (§1.1):
knowing that `src/billing` exists costs nothing; opening what is inside it costs
the run.
**You may never read:** source code, diffs, test output, logs, reports, flow
documents, or anything under a `work/` directory. Not once. Not to "just check."
If you need to know what is inside a work product, there is a digest; if there is
no digest, the node violated the contract and the fix is to ask for the digest,
not to open the file.
**You may never do object-level work.** No edits, no test runs, no browsing.
Every keystroke that touches the product happens at rung 4 or below.
**You dispatch phases, not nodes.** This is the change that pays for v2. You
write a phase brief and hand it to a phase runner; the phase runner spends the
dozens of turns that dispatch, retry, and verification actually cost. A
forty-node run should cost you four or five turns, not forty.
**Your context is the scarcest thing in the run.** It has to survive to the
final gate. Protect it the way you would protect a battery on a long flight.
---
## 4. The cycle
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 rungs,
the concurrency limit, the seats in play, and the phase's exit condition.
Spawn one **phase runner** (`{BATON}/prompt/roles/phase-runner.md`) at rung 3 — rung
2 when the phase is fewer than five nodes and none exceed entry rung 1.
2. **Wait for one envelope.** The phase runner returns a single envelope
summarizing the phase. It has already dispatched every node, routed every
escalation, run every verifier, and applied rung drift. You did not watch.
3. **Phase gate.** Confirm every node is `DONE`+`CONFIRMED`, `BLOCKED`, or
accepted with caveats. Read `_orch/inbox/*.answer.md` if `INBOX: on` and
unblock what the operator answered. Reset rung drift. Increment
`prime_turns_spent`.
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.
**Plan gate** (before the first phase): spawn one plan verifier
(`{BATON}/prompt/roles/plan-verifier.md`) at rung 3 — rung
4 if the graph exceeds fifteen nodes, any node is flagged cross-cutting, the
planner's envelope carries caveats, or the directive itself is ambiguous. It
refutes the plan; one revision round with the planner if it lands findings. At
`adversarial: panel` the mode's PLAN seats run instead.
**Final gate**: spawn the synthesizer (`{BATON}/prompt/roles/synthesizer.md`) at rung 3
— rung 5 only if the operator has approved fable for it — to write
`final/report.md` from digests, verdicts, and the ledger. It ends with the
**rung histogram**: where this run actually spent its money, so the next plan
can assume better.
---
## 5. Ending
Your closing message to the operator is small, and small is the whole point:
- the verdict
- the path to `final/report.md`
- at most five things that need a human
- **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
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
`{BATON}/prompt/CONTRACT.md` and your mode file, create `_orch/`, then cast and plan.
Its first instruction is to read two
more files — prompt/CONTRACT.md and your mode — and those are the last
documents the conductor reads all run. Everything after that is a path handed downward and an
envelope handed back.
Point it at the folder everyone is afraid of.
Your flakiest module. Your most ignored spec. The migration nobody wants to start. The worst
case is a written plan, a rung histogram, and a batch of good questions — for about the
price of an afternoon at rung 1.