Dispatch
The job queue. Everything that runs a Claude Code session goes through dispatch. Other parts of toryo push work in; a daemon drains the queue, spawning one worker (a single Claude Code session) per job, up to a concurrency cap.
Dispatch is deliberately not a scheduler (it has no concept of time) and not a sequence engine (it never chains one job to the next). It holds work, picks it in order, runs a bounded number at once, records the outcome, and reports.
How a job gets picked#
Jobs are claimed in priority order, then oldest-first. Priority runs 1 (highest) to 5, defaulting to 4.
Concurrency is capped, two at a time by default, and the cap is re-read every tick, so raising it in board's Settings applies immediately without a restart.
A job can also be deferred: if it would write to files another running job has already claimed in the same directory, dispatch holds it until that claim clears rather than letting two agents edit the same tree. A job that declares no write scope is treated conservatively, as if it locks the whole directory.
Job states#
queued → running → success | error | crashed | cancelled
cancel on a queued job stops it immediately; on a running job it sends a
termination signal on the next sweep. If the daemon itself dies, every job that
was running is marked crashed on the next boot rather than being left to look
live forever.
What you get back#
Each job records its exit status, token usage, cost, duration, and any artifacts the session produced. Two logs are kept per job:
- The event log, the session's full structured output: every tool call and result.
- The stderr log, holding API timeouts, auth failures, and harness panics that never make it into the structured stream. Check this first when a job stalls, as it is usually the only place the real reason appears.
Board's Dispatch screen surfaces both, along with a lifecycle timeline per job and a crash view that groups recent failures so a systemic problem is visible as a pattern rather than a string of one-offs.
Autonomous recovery#
A failed job is not simply dead. Dispatch climbs an escalation ladder (retry, re-probe authentication, refresh git state, and finally park the job for a human) with backoff that respects provider rate limits and a circuit breaker that stops hammering a provider that is failing every request.
This is why a transient API error overnight does not usually cost you a run.
Live output#
The daemon publishes a live event stream, which is how board shows a running session's output as it happens rather than after the fact. A subscriber that falls too far behind is disconnected rather than being allowed to slow the dispatcher down.
Where things go wrong#
- A job sits
queuedforever. Either the concurrency cap is full, or it is deferred behind another job's write claim in the same directory. Board's Dispatch screen shows which. - A job goes straight to
error. Read the stderr log, since auth and API problems land there and nowhere else. - Nothing runs at all. Run
toryo foreman check; the dispatch daemon is probably down.
Full command surface: CLI & contract reference.