worktender

Delegating to agents without losing the thread

Past two or three workers, the thing that breaks is not the machines. It is the one head holding all of them.

This is what the coordinator skill encodes, so a session acting as router loads it instead of being told. Most of it is not about worktender at all.

npx skills add steig/worktender --skill coordinator -g

Verify, do not relay

Never read a worker's diff. A file read costs two thousand tokens; the check that settles the same question costs ten.

PASS=$(go test -count=1 -v ./... | grep -cE "^--- PASS")
The question worth the most

“Did you run this, or reason it?” Bugs that survived a careful argument were caught by execution every time. When a worker explains why something must work, ask what it printed.

Reports drift without anyone lying. Test counts, branch names, “fixed” meaning the mechanism exists but was never exercised. Check the thing, not the sentence about the thing.

What to delegate, and what to keep

Delegate bounded authoring work with a mechanical done condition. If you cannot state the command that proves it finished, groom the slice before handing it out.

Keep. These are not preferences:

Check file overlap before a wave goes out. Two tasks touching one file is one worker's job, or two waves — never two workers.

Make the report a shape, not a sentence

A worker's task usually arrived as an issue, and an issue body is written by anyone who can file one. So a report should be fixed slots: a status from a closed set, a machine-checkable artefact, and a capped note treated as data.

Branch on the status and the artefact, never on the note. A predicate over free text hands whoever wrote that issue the decision of when your next agent starts.

A done is a claim. The report proves something well-formed arrived, not who composed it or whether the work exists. Check the artefact it names.

Wait on a signal, not a clock

Never hand-roll a readiness wait. Sleep-polling has failed with agent_not_ready every time it has been tried here — including by a coordinator that knew the readiness event existed and hand-rolled the poll anyway.

A worker reporting blocked is a good outcome. It releases the wait immediately instead of burning the timeout, and you are the only party who can unblock it.

The stall you cannot clear

A delegated agent has no human at its terminal. It stalls on the first permission prompt and stays there — and the agent that dispatched it structurally cannot answer. So a worker needs two things settled before the wave: a way to start without asking, and a way to escalate when it genuinely cannot finish.

Four failure modes

  1. Agents argue instead of proving.
  2. The dangerous thing is not where the caution points. Workers have escalated a read-only probe while the next slice would have armed event hooks in a live session.
  3. Reports drift. The quiet one.
  4. Knowing better does not prevent the old habit. See the sleep-poll above.

Handoffs

Write one before delegating, and before your own context is cleared. A handoff that gets corrected by the agent receiving it is working.

Hold in your own context: decisions, invariants, what has been verified. Nothing else.

What the coordinating agent runs

herdr worktree create --branch feat/12-thing --base main --no-focus --json
worktender dispatch --pane <pane> --name thing --model sonnet
herdr agent prompt <pane> "$(cat brief.md)"
worktender gate --any thing,other,third --until done --timeout 20m

Never pick one worker to block on. Dispatch returns as soon as the brief is typed, so nothing tells the four-minute slice from the forty-minute one. --any waits on all of them and releases on the first to report, naming it — drop that one and gate again on the rest.

Dispatch, then gate — the order matters. The gate ignores whatever the pane already held; that was a previous task's answer. Dispatch has the rest, including the two channels a report travels over and why neither wins.

Worked examples walks five fan-outs through all of this — and one case where you should not fan out at all.