Bus and ask
One-way messages between sessions, and the blocking question a worker raises when the decision is not its own.
What it is#
Two ways for sessions to talk, and they are not interchangeable.
The bus is one-way. msg_send needs a body, an identity (from_session / from_agent) and a target. Pick the target that matches what you know:
| Target argument | Reaches |
|---|---|
to_session and/or to_agent |
That exact seat |
to_worker |
A worker id — stable across reap and respawn, unlike a session id |
to_role |
parent (the Chair), child or sibling, within the same project |
to_project |
A registered project id: that project's running Chair |
Bodies are telegraphic; kind is typically note, handoff or alert. The rest of the bus is msg_inbox, msg_ack, msg_stale (alerts nobody picked up), msg_peers and msg_roster. Humans have the same verbs under orch msg.
An ask blocks. When a decision is not yours to make and you cannot go on without it, you raise one instead of guessing:
ask { question, options?, context?, timeout_sec?, to_session?, to_project? }
It holds until someone answers or the timeout expires — timeout_sec defaults to 600. When options[] is given, those strings are the only accepted answers, case-insensitive; anything else is refused rather than recorded. The first answer wins and a second gets a clear refusal.
Raising an ask also drops an alert in the Chair's inbox naming the id and goes through the configured notify fan-out. The Chair may notice it in msg_inbox, but it answers with ask_answer — or a human does, from a terminal:
orch ask list
orch ask answer <id> --answer "…"
An answer to a cross-project "how did you solve X" can carry a symbol_ref — {project, path, line, symbol} — instead of a pasted body. orch validates it against the index before accepting: the symbol must resolve under that project and be shared scope. The asker then fetches the text with code_snippet.
Why it exists#
Because "the agent went quiet" and "the agent decided for itself" are both failures, and a one-way message cannot tell them apart. An ask makes the waiting explicit and, more importantly, makes the timeout explicit: silence is not a state orch will leave you in.
worker ---- ask -----> Chair worker blocks
worker <-- answer ---- Chair first answer wins
worker <-- timeout --- (nobody) row marked "timeout", error names the question
A timed-out ask is recorded, not swallowed: the row's status becomes timeout, the tool returns an error naming the question, and a Chair answering late is told it arrived too late. The worker then decides for itself — and says so in verify_report.
How it relates to the rest#
- Only the Chair may spawn. A worker that needs more hands messages the Chair with
to_role=parent; it does not fan out. See Chair and workers. - Agents coordinate only through this bus. Vendor sockets and side chats are out of bounds — a parallel bus is invisible to the board, the roster and the reaper.
- A
handoffmessage carrying the one-line verdict is part of how a closed session reports back, alongside the board and the session page.
Nothing to run here#
The verbs exist under orch msg and orch ask for a human at a terminal, but the normal path is an agent calling the MCP tool. You will mostly meet the bus as an orch ask list when a worker is waiting on you.