The queue drains itself now, and the morning note fits in a minute
One directory is the task manager my agents share was the most-read thing I have published, and it left out the part that matters most: who works the queue. For the first month the honest answer was mostly me. The nightly run drained a few entries, and every mechanical finding, a drifted git hook, a dependency advisory, a stale path, still waited for me to notice it and route it. I counted one day’s commits: 68 across eight repos, about 48 of them the fleet maintaining itself with me as the router. The queue routed work. Nothing routed time.
So the fleet maintains itself now, in four moves.
Detection files its own work. Every night the deterministic lenses sweep every repo and file an allowlisted set of finding classes straight into the queue, through the same atomic door a session uses. The allowlist is the whole design: a stale gate, a test that runs only in CI, a dead path, a tool behind its pack. Judgment classes stay out. A file over budget is an editorial call, a missing contract gets authored, anything the sweep marks as risk is a ruling. A wrong work order costs more than a report line.
Progress is measured on the contract, never on commits. The first version of the night loop counted a round as productive when the child committed. The benchmark night showed why that is the wrong delta: eleven of fifteen spawns committed, six of them the same appended paragraph, while the entry each was spawned for never moved. A round is fruitless per entry now: workable at child start, still pending and workable at child exit. An entry that takes fruitless rounds on three distinct nights is parked as needing me, with a note, through the door’s own verb. A lease a dead child left behind is reaped at the start of the next run. The night converges on queue state instead of spinning on it.
night 1 pending ──child──▶ pending fruitless: 1
night 2 pending ──child──▶ pending fruitless: 2
night 3 pending ──child──▶ pending fruitless: 3 ──▶ needs: owner
one line in the brief,
one batched decision
The morning report is a PA’s note. Every report I used to get was accurate and none was ever actionable: fifteen lines of “Started work” in time order, the same errors again and again. I wrote the spec in one sentence, a PA reporting to their boss the next morning, read on a phone, before coffee. The brief is compiled from the run’s one fact stream, a JSON-lines trace every producer writes into, so there is one account of the night rather than three reconciled by nobody. It leads with the shape of the night, keeps four states apart (fixed itself, handled, needs you, still stuck), links merge requests by URL, and counts recurrence in nights from the entries’ own attempt lines. The voice test governs everything: if it cannot be read aloud in under a minute, it is wrong. The benchmark night’s 4.6 KB message became 680 characters.
Morning. The night worked 4 projects; 3 merge requests are ready
for your review.
Needs you:
* tooling: merge request ready to review (link)
* site: merge request ready to review (link)
* 3 decisions waiting in the queue (oldest 14 days); your next
sitting presents them in one batch.
* 6 entries have sat "in progress" for over a week, likely
orphaned by closed sessions; the board lists them.
Full detail: the dated report, one step down.
That is a real one, names changed. No model writes it. A model on the one surface whose truthfulness is the product is a new way to be wrong, and the brief’s own framing is that models are an optimisation, not the topic.
The fourth move came from a failure this week. The drain filed a proposal, escalated it to me when it stalled, and the commit gate refused the whole night’s batch, because a proposal has no business being parked on me: its only door is a rank on the board. Sixteen status flips sat staged, and the brief said nothing, because the commit’s output went to /dev/null. Now any write a job makes that the gate refuses is a line under “needs you”, with the gate’s reason, and the escalate verb refuses proposals at the door.
- A refused write is a morning line, never a silent stage.
One rule for the humans, from the same week. Before a session files a queue entry for another project, it checks whether that project has a live session and sends the request there directly, with the acceptance test, asking for a reply. The queue exists for collision safety and durability, not latency, and a live session already holds the target’s claim. Silence by the end of the task turns into an entry, so nothing is lost to a message nobody read. The first time it ran, a direct message settled a superseded merge request in minutes where the queue would have waited for the night.
The numbers, three weeks in: 54 entries were parked as needing me. 29 of them were repeat classes I had resolved the same way every time. That number is the next thing I am building against.
The queue still has no database. It just stopped needing me to be one.