Decision artifactD00152026-08-15Autonomy — the worker contract

Workers that finish into nothing

You said keeping track of a day of agent work now feels close to critical, and that making sure the roadmap keeps up is the Navigator's job. This page proposes the rule that makes that checkable: every worker agent has to finish into one of three things — a pull request for a release you have actually planned, a question for you, or a request for the config work only your hands can do. A worker that closes having produced none of the three has not finished; it has evaporated. Counting the last two days: forty-one agent jobs ended, and three of them left behind nothing any tool can now recover. Nobody noticed at the time. The check proposed here would have named all three by morning — and the by-agent list you asked for is that same check made visible.

Recommendation adopt the three-outcome rule; check it at closeout, report drift, never auto-repair Measured 41 agent jobs over two days Decide W1–W4 below
DECIDED — CLOSED 2026-08-16
@jwildfire · 2026-08-16 · in chat

“D14/15/16 all seem like a mess to me. Close them all. Do a single assessment of readiness to move to a schedule and let me know when it’s ready.”

Closed. The four questions on this page were already answered elsewhere: they were folded into the consolidated Navigator design earlier the same day, and he adopted all eight of that page’s calls, including the worker closeout contract this page proposed. So nothing was lost by closing it — the three-outcome rule, the closeout detection, and the agent-attribution answer are live under the Navigator, and the worker identifiers this page said were needed shipped that afternoon. What is retired is the page, not its findings.

He was right to call it a mess, and the mess is ours. Three pages went up across two days circling one question — whether the machine is ready to run unwatched — and two of them, this one included, had to be folded into a fourth. A reader landing here had to follow two hops to find out where the question actually lived. The replacement is one page: Scheduled sessions: what is ready and what is not (D0019).

Everything below is the page as it stood when it was folded, on 2026-08-16. It was folded into the consolidated Navigator design because @jwildfire asked for "a consolidated design/decision doc explaining how the navigator/coo agent is going to work" rather than several pages each answering part of it; the questions were carried forward there and answered there. Nothing here is withdrawn — the measurements and the argument stand, and the consolidated page cites them. The answers are on The Navigator (D0017).

WHAT IS BEING DECIDED

You chose the enforcement point yourself. The alternative was a gate at spawn time — refuse to start a worker until its roadmap paperwork is in order. You picked the other end:

"I'm actually fine with the navigator reviewing agent's work at closeout instead of at spawn. probably makes more sense that way. Any time a 'worker' sibling or sub agent closes, navigator makes sure that the roadmap is updated appropriately and you make sure that my todo list is current. Most of the time, workers should impact both. They should either prepare a PR for a planned release, ask me questions or ask for config work if there are blockers."

That last sentence is the substance, and it is stronger than it first reads. It is not a description of what workers usually do — it is a definition of done. A worker that ends without producing one of those three things has produced nothing that reaches you, and today that outcome is completely silent: the job stops, and the absence looks exactly like a quiet success.

Outcome one

A pull request for a planned release

Work that is finished and ready for your review — attached to a release that actually exists, not speculative work parked on a branch.

Outcome two

A question for you

A call the agent cannot make. It writes the question up, posts the thread, and moves on to the rest of its work rather than stalling.

Outcome three

A request for config work

It is blocked on something only your hands can do — a permission line, an app install, a credential — and it says so on the blockers list.

Those three are not an arbitrary list. They are exactly the three sections of your Operations Dashboard: release candidates, decisions, and the work only your hands can clear. The dashboard is the output surface of the worker contract — which is why "make sure the roadmap is updated" and "make sure my todo list is current" turn out to be one instruction seen from two ends, and why a worker producing none of the three is, by construction, a worker whose night never reaches your screen.

WHAT THE LAST TWO DAYS ACTUALLY LOOK LIKE

Before proposing a mechanism it is worth knowing how bad the problem is, so this was measured rather than assumed. Every agent job the harness recorded over 14–15 August was read back — forty-one that ended, plus the two still running — and cross-checked against the shared scratchpad where agents log what they did.

QuestionAnswerWhat it means
How many worker jobs ended in the window? 41 Roughly twenty a day, unattended for most of it — and this is before full automation.
How many wrote the close-out line the convention requires? 32 of 41nine did not (22%) The scratchpad is the richest record there is, and it is missing for roughly one worker in five. It is also self-reported: a worker that dies mid-flight writes nothing at all.
How many had their work captured automatically by the harness? 22 of 41nineteen captured nothing (46%) The automatic capture is far less complete than it appears. One agent that merged three pull requests and filed two issues that night was recorded as having touched nothing at all.
How many left no recoverable trace — neither automatic capture nor a close-out line? 7 of 41; setting aside three throwaway probes and the concierge session itself, three were real workers Three nights of work that cannot now be reconstructed from anything. Not "hard to find" — gone.

Three-in-forty-one is the honest headline and it is deliberately not inflated: most agents did log properly, and the convention mostly works. But the failures cluster in exactly the wrong place. An agent that finishes cleanly is the one that writes a good close-out line. An agent that dies, gets killed, or runs out of room is the one that writes nothing — and that is precisely the case you need to hear about.

HOW THE NAVIGATOR WOULD KNOW A WORKER CLOSED

This was the load-bearing unknown. The Navigator is not a session — it is a small scheduled job that wakes every five minutes, checks the review queue against GitHub, and writes a state file. It has no hook into any agent's lifecycle and no way of being told when one ends.

It turns out it does not need one. The harness already keeps a ledger of every background agent — one small record per job holding its name, what it was asked to do, whether it is still running, and a timestamp stamped exactly once at the moment it goes terminal. Forty-four such records exist right now. The Navigator can read them all in a single pass with no network calls and no model involvement, remember the newest terminal timestamp it has seen, and treat anything newer as a fresh closeout on its next tick. Worst-case notice is five minutes.

Three properties make this the right lane rather than merely a workable one:

The alternatives were considered and each fails for a specific reason. The scratchpad close-out line is self-reported and measurably missing 22% of the time. A stop hook fires at the end of every conversational turn rather than at the end of a session, and cannot tell "the agent paused" from "the agent is done" — the workspace already runs two of them and neither could carry this. The agent-listing command and the session dashboard are both views over the very same records, so reading the records directly is the same information with one less moving part.

The honest gap — subagents

A subagent has no record at all, and pretending otherwise would be the failure mode

You named both siblings and subagents. They are not equally tractable. A sibling is its own background session and gets its own ledger record; a subagent runs inside another agent's session and leaves none. There is no timestamp to watch and nothing to watermark.

Two facts make this acceptable rather than a hole. First, measured: across all 134 session transcripts in this workspace, subagents have been used zero times — the lane exists but has never once been taken. Second, by rule: the delegation split you approved earlier this month sends deliverable work to siblings and reserves subagents for answer-only research, so a subagent is not supposed to be producing roadmap changes on its own account anyway.

The proposed rule is therefore that a subagent's output belongs to its parent's closeout. The parent is the accountable unit and the parent is what gets checked. Where a subagent does file something it appears under the parent's name — attributed one level up, not lost. Wherever the ledger is shown it must say so in words, rather than implying a per-subagent precision it does not have.

THE TAB YOU ASKED FOR — AND WHY IT IS HARD

Minutes after setting the closeout contract you added what you want to see:

"I think i almost certainly want a navigator tab in the ops db that tells me what changes each agent made to the dasboard. basically a list of issues/PRs that were created/updated by each agent."

That is not a second feature. It is this check made visible: if the Navigator verifies the roadmap at each worker's closeout, the by-agent list is simply that verification rendered. But it runs straight into a problem worth stating plainly, because it has no free solution.

Every agent write is authored by the same identity. Under the standing rule that agents act as the shared bot account, every issue, pull request, comment and commit any of them creates carries the same name, and always will. GitHub's record of "who did this" cannot distinguish forty agents from one. A straightforward sweep of recent activity produces a single undifferentiated pile and answers nothing.

Five ways to bridge that gap, each measured for what it cannot see — since that is what decides whether the resulting tab can be trusted:

How you would tell agents apartWhat it structurally cannot seeMeasured on the last two days
The GitHub author field Everything. One identity for every agent, permanently, by design. Ruled out by construction
The scratchpad lines agents write — already tagged with each agent's name and carrying its links A worker that died before logging, and anything a live worker chose not to mention. It under-reports exactly when you most want it. Missing entirely for 9 of 41 workers
The harness's automatic link capture — links it notices in a session and attaches to that job's record Most of what the worker actually did. The capture is real but partial, and its gaps are invisible from the outside. Captured nothing for 19 of 41 — including an agent that merged three pull requests and filed two issues that same night
Re-reading the full session transcripts — the harness writes one per agent, so attribution is automatic and perfect The difference between something the agent read and something it changed. Both look identical in a transcript. One agent's transcript mentions 87 distinct issues and pull requests, and its command output mentions 61 — but it made only 2 direct issue-creating calls. Its remaining writes went out through helper scripts and raw API calls that no text pattern reliably catches.
Recording each change as it is made — a small hook firing after every shell command, noting what was created or updated Anything written before it is switched on. It is completely blind to the past. Not yet in place — this is the proposal

The transcript row deserves one more sentence, because it is the option that looks most attractive. Attribution there is perfect — one transcript per agent, no identity collision at all. The problem is entirely on the other side: you cannot tell from a transcript whether a pull request appears because the agent created it or because the agent listed it. Every heuristic tried either over-reported reads or missed writes that went through a helper script, and a ledger that credits an agent with work it merely looked at is worse than no ledger.

Recommendation

Two lanes, honestly labelled. Going forward: record each change at the moment it is made, with a small hook that fires after every shell command and writes one line — time, agent, what it did, the link. It sees the command and its output, so it catches the helper-script and raw-API writes that defeat every after-the-fact approach; the workspace already runs hooks of exactly this shape, so the lane is proven rather than speculative. Crucially it is written by the machinery rather than by the agent, so a worker that dies still has everything up to the moment it died. Retrospectively: reconstruct what can be reconstructed from the job records and the scratchpad, and mark it incomplete on its face — because for three of the last two days' workers the honest answer is "we cannot know", and a tab that renders that as a clean empty row is the same failure as an evidence baseline going stale while the tests stay green.

WHAT HAPPENS WHEN A WORKER FAILS THE CHECK

The Navigator cannot merge anything, cannot file a worker's paperwork for it, and should not try. The temptation is obvious — the check knows what is missing, so why not add the milestone, open the issue, write the missing link? Because a repair that silently completes a broken worker's homework destroys the only evidence that the worker was broken. Next week the same agent fails the same way and the ledger still looks clean. A visible failure is worth more than an invisible fix — the same principle already written into the Navigator's charter, which says it observes and reports and never corrects another agent's work.

So a failed check produces a named drift line in the Navigator's state file, and surfaces to the concierge session, which relays it to you like any other finding. The worker is named. What it was asked to do is in its record. What it left behind, or did not, is stated plainly. You decide whether it needs re-running, whether the requirement was wrong, or whether nothing was owed in the first place.

DOES THIS REPLACE THE AUDIT? NO — AND IT MUST NOT DUPLICATE IT

There is already a roadmap audit: about twenty rules checking the board for exactly the things a closeout check would want — a requirement with no milestone, a pull request with no requirement link, an issue under no goal, a missing assignee, a design never written, work that has stopped moving. It runs over the whole board, sorts findings by confidence, and you granted its mechanical high-confidence findings an auto-accept a day ago. That lane works, and it should not grow a second head.

What the audit structurally cannot do is attribute. It sees a requirement with no milestone; it does not know which agent left it that way, or that an agent closed ten minutes ago having left it that way. It is a photograph of the board, not a record of who moved what.

So the closeout check should be the same rules, aimed differently: when a worker closes, run the existing rules against that worker's blast radius rather than across the whole board, and attribute what they find to the worker. Zero new rule engines. Exactly one genuinely new rule is required — "this worker finished into nothing" — and it has to be new, because the board audit cannot possibly express it: nothing on the board records that a worker ran at all.

One thing this reframes rather than adds. Of the audit's rules, five were found last night to fail the "does this actually need @jwildfire's attention" test — work that stopped moving, designs never written, and so on. Several of those are exactly what a closeout check catches at the moment of closing, with a name attached, instead of surfacing weeks later as an anonymous board finding. Same rule, far more actionable, because it arrives attached to the agent that caused it.

WHAT TO DECIDE
W1

Is the three-outcome rule the definition of done for a worker — and what happens to one that finishes into none of them?

Adopting this means a worker agent is not finished when it stops; it is finished when it has produced a pull request for a planned release, a question written up for you, or a config request on the blockers list. The cost is that genuinely fruitless work now has to say so out loud — an agent that investigated something and found nothing worth doing must write that down as a finding rather than quietly ending.

The alternative is to keep this as guidance and let the check merely report against it. That is softer, but it leaves "finished into nothing" indistinguishable from "quietly succeeded", which is the state we are in now.

Recommendation: adopt it as the definition of done. A worker with none of the three produces a named drift line, not silence — and "I looked, and there is nothing to do here" counts as a valid answer, provided it is written somewhere you can see it.
W2

How should the Navigator learn that a worker closed?

The proposal is to read the harness's own job ledger on the existing five-minute sweep — the one record per background agent that already exists, watermarked on the moment each goes terminal. It is free, needs no new plumbing, and sees dead workers as well as healthy ones, which no self-reported source can.

The thing to accept alongside it: subagents get no such record, so their work is attributed to the parent agent that spawned them. Measured usage of that lane in this workspace is zero, so the practical cost today is nil — but the ledger will say "attributed to parent" rather than claim a precision it does not have.

Recommendation: the job ledger, on the existing sweep. A killed worker counts as closed. Subagents roll up to their parent, stated plainly wherever the ledger is shown.
W3

How do we tell which agent made a change, when every change carries the same bot identity?

This is the hard one, and it has no free answer. Recording changes as they happen is the only approach that is both complete and not self-reported, but it cannot see backwards. Reconstructing from what already exists covers the past but is provably lossy — for three of the last two days' workers it recovers nothing at all.

The real choice is whether the tab is allowed to show gaps. A complete-looking ledger that silently omits dead agents would be actively misleading in exactly the situation you would be using it for.

Recommendation: both lanes, visibly distinguished. Switch on recording-as-it-happens now, so that from tomorrow the ledger is real; reconstruct the past from what survives, and mark every reconstructed row as such — with the gaps shown rather than smoothed over.
W4

Does the closeout check live inside the existing roadmap audit, or beside it?

Inside means reusing the twenty rules that already exist, aimed at one worker's blast radius, with findings flowing into the ledger you already have and under the auto-accept grant you already gave. Beside means a second checker with its own rules, its own findings and its own drift — two things to keep in agreement forever.

Recommendation: inside. The same rules, scoped to the closing worker and attributed to it, plus exactly one new rule for "finished into nothing" that the board audit cannot express. No second engine.
WHAT UNBLOCKS

None of this is started. The requirement exists, the design calls are these four, and the work waits on your answers.