A review of the fleet-control system that ran the 2026-08-10/11 batch merge, written from what actually broke that night rather than from theory.
The shape is right. The seams are wrong. Don't merge the fragments into one process — consolidate three specific primitives that are currently reimplemented differently, badly, in six or more places. Every one of tonight's stalls traces back to one of these three gaps.
The fleet isn't run by one big "operator" program. It's a bunch of tiny scripts — a watcher, a stop-gate, a decision box, an escalation filter — each doing one small job, talking to each other through files and a terminal. That's a good design, the same way a toolbox of screwdrivers beats one tool that tries to do everything. The problem last night wasn't the toolbox. It's that three of the tools each had their own broken way of answering the same question — "is this thing actually gone, or did I just fail to check?" — and each one got it wrong differently.
The "operator" is a constellation of small, single-purpose tools — nudge, drive-gate.py, context-budget.py, fable-decide, blocked, start-operator, the Supervisor — coordinating through the filesystem and tmux panes, with all the actual reasoning living only inside the Claude session itself. That's Unix philosophy applied to an agent fleet, and it earned its keep tonight.
The watchdog bug was cheap to fix because it lived in ~20 lines of bash, not tangled into a reasoning loop. A monolithic "operator brain" would have made the same bug expensive and risky to touch.
The token split is clean. The watchdog — the thing polling and waking sessions all night — spends zero bearer tokens; it's a dumb bash loop. All LLM spend happens only in the session actually doing the work. Cheap surveillance, expensive thinking kept separate.
Everything is inspectable. State lives in plain files and tmux panes, not hidden in a process's memory. Diffing the "live" and "canonical" copies of a script, counting armed watchers, reading a task's state — all of it is a cat or a grep away, which is exactly how tonight's diagnosis happened.
It degrades in pieces. One dead watchdog doesn't take down the session it was watching, and one stalled operator doesn't take down the other nineteen. A monolith fails all-or-nothing; this fails one piece at a time.
Collapsing this into a single process would throw away every one of those properties in exchange for nothing. No monolith.
The tell that something genuinely needs consolidating isn't "there are a lot of small files." It's the same decision getting made in many different places, differently, and each place getting it wrong independently. That is exactly what happened on the night this review is written about.
Three separate tools each reimplemented "is this thing alive, dead, or could-I-just-not-check" — and each one collapsed "could not check" into "dead," which is the wrong answer every time it happens.
| Tool | What it botched | Real-world cost |
|---|---|---|
nudge (the watchdog) |
Unreadable roster read as "target gone" → watcher exits permanently | 7 of 10 operator lanes had no live watchdog while their tasks were active |
blocked adopt --list |
A liveness probe timing out (30s × 104 dirs) read as "not orphaned" | ~50 minutes of serial timeouts ending in a confident, false "no orphaned blocks" |
| roster read (agentflow-relay) | An unreadable question ledger rendered as "0 open blocks" | A session with real open blocks looked idle and safe to ignore |
The fix: one shared alive / dead / unknown result that every tool calls into, with unknown always retrying and never being read as a negative. Killing this class once kills it everywhere at once, instead of three (or six) separate teams independently re-discovering the same bug.
Gera's decisions landed in the docs KV store the instant he answered them. The operators, though, read blocked check — a different store — which was timing out fleet-wide. Result: 40 real, already-given answers sat completely invisible to the sessions that needed them, for the better part of an hour, with nobody lying to anybody — just two ledgers that don't talk to each other.
The fix: one answer store, one reader path. Every "did the human already tell us" check goes through the exact same read — never a race between "the page shows it" and "the session can see it."
Answering "is this operator alive and making progress" required stitching together four different sources by hand, every time: task.json, the tmux pane content, the watcher's PID, and the block ledger. None of them alone told the truth; only the combination did — and that combination isn't written down anywhere, it's re-derived on the spot each time a human (or Smith) asks.
The fix: the fleet-health-tab lane that merged tonight is the right shape — it should become the canonical health read, with every other "is it alive / is it stuck" check routed through it instead of re-deriving the answer from raw sources on each ask.
godloop (canonical), live (running), and loop-canon (reported) — has already caused one fix to be silently reverted by the nightly sweep 3m48s after it landed. Worth collapsing to one source with the other tiers generated from it, not hand-copied.
This is strong architecture with three under-built shared primitives — not a system that needs a rewrite. Add a shared liveness result, one answer store, and one canonical health read; then delete the per-tool reimplementations sitting behind them. Every strength above survives untouched — small tools, inspectability, the token split, graceful degradation — and the one property that hurt every stalled lane tonight (the same wrong assumption, made independently in six places) goes away for good.
Three operators, one per consolidation, each scoped to add the shared primitive and delete the reimplementations it replaces — not just patch the symptom in place.
One alive / dead / unknown read, called by nudge, blocked adopt, and the roster reader — unknown always retries, never reads as a negative.
Collapse the decisions KV store and the blocked ledger into one read path, so an answer landing on the page is immediately visible to the session waiting on it — no more "answered but invisible" hour.
Make fleet-health-tab the one place "is this operator alive and progressing" gets answered, replacing the four-source hand-stitch with a single call.
~/.local/bin/nudge, blocked, and the decisions/ledger split, verified against running code and the merged batch of 2026-08-10/11 — not asserted from memory.