Work Items, Not Org Charts
The current design organizes around who does what — Fleet Lead over Team Lead over PM over executor over five reviewers. That is an org chart, and org charts exist because humans have persistent identity and expensive specialization. Agents have neither. This proposal organizes around the work itself, makes routing a pure function, and gets something the alternatives don't have: an orchestration policy you can test offline against real history.
Make the pipeline data, not code
Right now the route a change takes is spread across a 1,600-line shell state machine, a phase field, and a set of label gates. Every change walks roughly the same path: implement, code review, security review, acceptance, debate, merge. A README typo and a rewrite of the sandbox rules get the same ceremony.
That uniformity is why gates get bypassed. A gate that costs the same on trivial work as on dangerous work is mostly friction, and friction gets routed around. The fix isn't a stronger gate — it's a gate whose cost tracks the risk. So: one work item, one state, and a router that is a pure function.
route(item, evidence) -> next_capability | done
# risk is computed, not declared
risk = f(
sensitivity # auth · sandbox · state paths · schema
blast_radius # downstream nodes in the import graph
coverage # tested_by edges on the touched files
history # defect density of these paths
size, provenance
)
risk < 0.2 -> [implement, review, merge]
risk < 0.6 -> [implement, review, test, merge]
risk >= 0.6 -> [design, implement, review, security, adversary, accept, merge]
# independent of risk, never skipped:
verify(item) must produce evidence before merge
No model call is involved in routing. It is a function over the item and its evidence, which means you can unit-test it, diff two versions of it, and — the part that matters — replay it over the last two hundred work items and see what would have changed.
Five layers
Three of these already exist in some form. The separation is the point: events flow on the spine, state lives on the Board, actions go through MCP. Blurring those three into agent-to-agent messages is where multi-agent systems usually get into trouble — state passed as messages means every agent needs everyone else's context.
The Board
One append-only, queryable store holding every work item: its state, its risk score, its route so far, every verdict, every piece of evidence. Threads and comments are a view on this, not a separate system. Agents never send each other state — they write to the Board and get notified. That kills the N² message problem and makes an agent's context a query rather than an inbox history.
exists: blackboard.py (has CAS), state.db, discussion_cache.py
The Router
A pure function, under a hundred lines to start. Takes an item plus its
evidence, returns the next capability or done. Owns risk scoring,
escalation and admission. This is where the Fleet Lead lives — not as an
agent, as code. Admission control, concurrency and budget should be
deterministic and auditable, not prompted.
new · replaces ~1,600 lines of shell
Capabilities
A capability is a named bundle: prompt profile, tool allowlist, model,
effort, and the evidence it must produce. implement,
review, security, verify,
adversary, research, design,
document. Eight, not twenty-six. Specialist perspectives become
prompted lenses inside one review run rather than five spawns and a consensus
panel — same coverage, one context, a fifth of the tokens.
exists: .claude/agents/*.md, spawn_templates/ — consolidate
The Pool
Ephemeral processes in tmux panes, work-stealing from the queue. A worker claims an item by compare-and-swap, runs one capability, writes evidence and a verdict, exits. Panes are for watching and durability, not identity. Continuity lives in the Board and in per-capability memory files — never in a long-lived session. No context rot, restartable at any point, and concurrency scales with queue depth instead of being fixed at six.
exists: spawn_queue.py, orchestrate.sh
Evidence
Content-addressed store of everything that could justify a decision: test
output, diffs, tool transcripts, screenshots. Every verdict must cite evidence
IDs. A pass with no evidence is rejected by the Board, not by a
reviewer's conscience. This is what makes the Reality Check unnecessary as a
role, and what makes the dry-run rule enforceable rather than documented
— "which mode produced this evidence" becomes a field, not a habit.
new · the missing half of the AGENT_OUTPUT envelope
Six changes
Most of the current design survives. What changes is whether a thing is an agent, a service, or a row in a table.
-
Fleet Lead becomes code, not an agent
was: a persistent Claude pane doing admission and coordination
Admission, concurrency caps, budget and risk scoring should be deterministic, auditable and instant. Prompting a model to decide whether there is room for another executor is slow, non-reproducible, and costs tokens to compute something
spawn_queue.pyalready computes. Multi-project mode stays — as a config-driven scheduler, not a session. -
The three monitors become one read model
was: Session Monitor, Display Agent, System Monitor as persistent panes
All three ask the same question — what is happening right now — from three angles. On the Board that's one query surface plus a subscription to the event spine. Nobody pays per-token for a chart. The genuinely judgment-shaped part, noticing a run has gone off the rails, becomes a
supervisecapability the router triggers on an anomaly event. -
Reviewers stop being a chain
was: code → security → accept → debate → reality check
A fixed serial chain is the most expensive possible arrangement: every stage pays full context assembly, and stage five learns nothing from stage two except a label. Replace with a risk-selected set, run in parallel where independent, all writing to the same item.
-
Verdicts must cite evidence
was:
verdict: passin the AGENT_OUTPUT envelopeAdd required fields:
evidence[],confidence,unknowns[]. The Board rejects a verdict with no evidence. Theunknownsfield is the cheap win — an executor that says "I could not tell whether this path is reachable" gets routed toresearchfor a few thousand tokens, instead of producing a PR that burns a full review cycle discovering the same thing. -
Agents go stateless; tmux stays
was: six persistent panes with permanent addresses
A long-lived session accumulates stale beliefs about a repo that changes hourly, grows context monotonically, and can't scale when the queue is deep. Make workers ephemeral, put continuity in the Board plus a per-capability memory file. tmux keeps its whole value — you attach, you watch, panes appear and disappear as work flows. It just stops being where identity lives.
-
MCP is the only door
was: MCP facade over scripts, agents keep Bash
Agents get no Bash for project operations. Everything through
af-board,af-repo,af-evidence,af-ci. Every agent action becomes loggable and replayable by construction, and orchestration becomes testable in-process instead of through 454 subprocess spawns. Bash stays for the one thing it's for: running the project's own build and test commands, insideverify.
Order of work — and what it costs
Nothing here is a rewrite. The Board is blackboard.py with a schema;
the router is a function that starts by returning exactly what the current phase
machine returns, and diverges from there. Steps 1 and 2 are the load-bearing
ones and they are both small. Everything after them is a policy change you can
measure instead of argue about.
-
01
Schema the Board
$100Work items, evidence and verdicts as real tables in
state.db. Keep writing the old state files in parallel until the read paths move. -
02
The Router, as a pure function
$200Write it so it reproduces today's behaviour exactly, then test it against recorded history: same inputs, same routes. That gives you a baseline and a replay harness before any policy changes.
-
03
Evidence in the envelope
$100Required
evidence[],confidenceandunknowns[]fields, Board-enforced. Backfill nothing; new items only. -
04
Risk scoring, in shadow mode
$300The inputs already exist — sensitivity from path globs, blast radius from the 1,288
importsand 1,165depends_onedges in the graph, coverage from its 831tested_byedges, history from defect density. Run it in shadow first: log the route it would have chosen next to the one taken. -
05
Collapse 26 roles into 8 capabilities
$175Role cards become capability profiles. The specialist panel becomes lenses in one prompt rather than four spawns and a consensus summary.
-
06
The work-stealing pool
$275Ephemeral workers claiming items via compare-and-swap. This is where tmux and the event spine come in properly.
Fund the whole rework
$1000All six steps. The parts add up to $1,150, so this is $150 less than buying them separately.
Where this design is weaker
- Risk scoring is a model you have to get right. A bad score
sends a dangerous change down the cheap path. Shadow mode helps and the mandatory
verifystep is the backstop, but this is a real new failure mode a uniform pipeline doesn't have. Bias the scorer to escalate on uncertainty. - Stateless workers lose warm context. An executor that has been living in a subsystem for an hour genuinely knows things a fresh one doesn't. Memory files are a weaker substitute. If fix-cycle counts get worse after step 6, that's the signal — and it's reversible.
- A pure router is less adaptable than a smart agent.
Deterministic routing can't handle a situation nobody anticipated the way a
person reading the room can. The escape hatch is an explicit
escalateroute — rare and logged, not the default. - It's a bigger conceptual change than it looks. It reorganizes the loop rather than extending it. The migration is staged and each step stands alone, but it asks more than turning a broker on.
This is the second of three designs. The third, The Ratchet, argues that both of the first two share a deeper assumption — that model judgment is the quality gate — and that execution should be instead. It may go up here later.