Dispatch for agents
An agent works in Dispatch through one shell command, dispatch. The Envoy plugin for the agent’s
host (Oh My Pi, Claude Code, or OpenCode) puts it on the agent’s PATH and tells it which session
it acts for. dispatch --help lists the commands, dispatch <command> --help gives a command’s
flags and an example, and --dry-run prints what a command would send without sending it. The
dispatch skill in this repository, skills/dispatch/SKILL.md, teaches the workflow. The
command reference lists every command’s flags.
Dispatch is a record for the people who decide, not a log of the agent’s work. Progress belongs in
the agent’s own transcript and its pull request. Anything a person must read, answer, or approve
goes through a dispatch command.
Connecting an agent
Section titled “Connecting an agent”-
A person signs in to Dispatch and opens Settings → Agent tokens.
-
They type a label and choose New token. The token is shown once; copy it then.
-
They give it to the agent in the
dispatchsection of itsenvoy.json:{"dispatch": {"enabled": true,"serverUrl": "https://dispatch.internal.example","token": "<token>"}}A session under an Oh My Pi profile other than
default, a Claude CodeCLAUDE_CONFIG_DIRor an OpenCodeOPENCODE_CONFIG_DIRreads theenvoy.jsonin that directory and no other. Any other session reads the fileENVOY_CONFIG_FILEnames when it is set, else~/.config/legion/envoy.json($XDG_CONFIG_HOME/legion/envoy.jsonwhen that is set). Thedispatchcommand reads the file its session’s plugin chose, which the plugin hands it inENVOY_CONFIG_FILE; in a Claude Code shell that gets nothing the plugin hands on, as a subagent’s can, it still reads the session’sCLAUDE_CONFIG_DIR. A token written as!<command>, such as!secrets get DISPATCH_TOKEN, is a command, and what it prints is the token.The environment variables
DISPATCH_URLandDISPATCH_TOKENoverride the file’s other fields, but adispatch.enabled: falsein the file keeps Dispatch off. The file’s token goes only to the server written beside it, so aDISPATCH_URLnaming another server needsDISPATCH_TOKENas well. An agent that reaches Dispatch at an address people cannot open, such as a Legion pod’s in-cluster one, also needsDISPATCH_PUBLIC_URL, Dispatch’s dashboard as people open it: every link thedispatchcommand prints points there, and a pasted dashboard link on either address resolves.
Everything the agent writes is attributed to the person who made the token: Dispatch shows the
agent’s name followed by (for <login>), and an issue the agent creates without naming an
assignee goes to that person. dispatch issue names the assignee Dispatch chose. dispatch whoami
tells the agent who Dispatch takes it for.
The commands
Section titled “The commands”| Area | Commands |
|---|---|
| Issues | dispatch issue creates one; --blocked-by <key>, repeated, names up to 20 issues in the same project it waits on. dispatch issue-update changes status, title, labels, priority, parent, links, blockers, or components; its --blocked-by replaces the list, and --clear-blocked-by empties it. dispatch claim claims an issue before work starts. dispatch issues lists a project’s issues. |
| Projects | dispatch project creates a project from a key and a name; a key that is already taken is refused. dispatch projects lists every project’s key and name. |
| Asks | dispatch ask opens one. dispatch edit-ask rewords an open one. dispatch resolve-ask retracts or resolves one. dispatch follow follows or leaves an ask’s thread. dispatch open-asks lists open asks. |
| Comments | dispatch comment comments on a document or replies in a thread. dispatch suggest proposes replacement text. dispatch resolve-comment resolves a thread. |
| Messages | dispatch message posts a message or replies to one. |
| Documents | dispatch doc-read reads a document, or the text of an uploaded file; with --blocks it lists the document’s block ids, tokens and table rows that dispatch doc-edit addresses. dispatch doc-edit edits one in place. dispatch artifact uploads a file or a new document. dispatch request-approval asks a person to approve a document. |
| Reading | dispatch read reads an issue, ask, comment, message, or document summary. dispatch search searches everything. dispatch whoami reports who Dispatch takes the agent for. |
| Architecture | dispatch architecture-sync imports a project’s architecture model now. |
A command with several problems is refused once, with every problem listed, so the next run can fix them all. It exits 0 when it wrote or read, 1 when Dispatch or the flags refused it, and 2 on a usage error such as an unknown command.
Long text, such as a message body or a document, goes on stdin through a quoted here-document, so the shell expands nothing in it:
dispatch message --issue LEGION-1 --body-file - <<'EOF'Shipped in owner/repo#7.EOFAsk, comment, suggest, or message
Section titled “Ask, comment, suggest, or message”Each kind of write reaches people differently. Pick by what you need from them.
| You need | Use | Where it lands |
|---|---|---|
| A decision only a person can make | An ask (dispatch ask, or a decision block in the spec) |
The assignee’s Inbox, under Waiting on you |
| To point at a passage in a document | A comment with a quote (dispatch comment) |
The document’s margin and the issue’s Conversation |
| To change specific text | A suggestion (dispatch suggest) |
The margin, where a person accepts or rejects it |
| To tell people a deliverable landed, or answer a person’s message | A message (dispatch message) |
The issue’s Conversation |
Never post progress, “starting work”, or status on a timer as a message. If you are blocked on a person, that is an ask, and nothing else reaches their Inbox.
The server holds every write to a size, and refuses rather than truncates:
- an ask’s question is at most 800 characters, with at most eight options;
- a comment or message body is at most 2,000 characters;
- a Markdown document is at most 1 MiB, and any other file at most 25 MiB.
To show a picture inline, pass its local path with --image on dispatch message,
dispatch comment or dispatch ask (PNG, JPEG, GIF or WebP, at most 25 MiB each), once per
picture. The command uploads it to the issue — to the project for a comment or ask on a project
document, and to the agent’s own conversation for a reply to a direct message — and appends one
 line per picture, which counts toward the caps above.
dispatch doc-read and dispatch read write the pictures they return to files and print each
one’s path; dispatch read returns the pictures the messages, asks and comments it shows embed,
newest first, at most eight and 10 MiB per read. A picture over 3,750,000 bytes (5 MB once
base64-encoded, the model providers’ bound), or of another type, is described rather than shown. A
session is shown each picture once: a later dispatch read, or an Inbox delivery on Oh My Pi,
names a picture the session was already shown instead of sending it again, because every request
carries the session’s history and Anthropic refuses one over 32 MB. dispatch doc-read always
shows the picture, which is how an agent gets one back after compaction.
Write every ask for a person reading on a phone who has not read the code. Put the problem, what constrains the answer, and your recommendation in the question, and what each option costs in its description.
Documents
Section titled “Documents”Every issue has one spec, its main document. Read it with dispatch doc-read and change it in
place with dispatch doc-edit. Do not upload a file named spec.md to change it: that replaces the
whole spec with your text. Use dispatch artifact for real files, such as a report, an image, or a
draft to send as-is.
A question the spec needs a person to decide is a decision block: an :::ask block at the end
of the section that discusses it.
:::ask{urgency="high" multiple="false"}Should we ship the migration this week?
- Ship: Release the verified change now.- Hold: Wait for another review.:::The block becomes an ask in the person’s Inbox, and their answer lands next to its context.
When every decision block is settled and the spec proposes something the person has not already
agreed to, run dispatch request-approval with a short --summary of what is new. The person
approves that version, or requests changes with a reason. A later version leaves the approval
stale, with one exception: when the person’s own answer to a decision block is the whole change
since the version they approved, Dispatch records the approval in their name at the new version, so
request nothing for it. When their answer changes text outside the block, rewrite that text and
request approval again with a one-sentence --summary naming what changed since the earlier
approval; the card shows that approval and a Show diff control that carries the detail.
Whose turn it is
Section titled “Whose turn it is”Every open ask is waiting on a person or on an agent, and the Inbox files it by that.
- Opening an ask puts it in the person’s Waiting on you.
- When the person replies without answering (Ask back), the turn is yours. Answer in the same
thread with
dispatch comment --reply-to-ask, or reword the question withdispatch edit-ask. Either puts the ask back in front of them. Do not open a second ask. - A progress note on an ask, such as “checking the release branch, back shortly”, goes with
--turn agent. The ask stays under Waiting on agents and the person is not asked to act.
Close what you opened. When an ask’s answer arrives some other way, or the question no longer
matters, resolve it with dispatch resolve-ask, giving the reason.
What reaches you
Section titled “What reaches you”You follow every ask you open or reply to. Its answer, edits, resolution, and replies reach you
directly. A person’s reply to a comment you started reaches you directly, and so does a person’s
new comment on a document you wrote: on a passage, on the whole document, or as a suggestion. A
new comment on your document that mentions you arrives once, as the mention. Nothing else on an
issue reaches you unless you subscribe to the issue’s Envoy topic,
notifications.dispatch.issue.<KEY>.>. Each write’s result names that topic.
A person can also message you from the Agents page:
- On Oh My Pi, their Send or Aside arrives as their own message in your conversation,
except a message beginning with
/runs as the session’s terminal would run it. A prompt template, file command or skill gives you the resulting prompt; an unknown/namegives you the words themselves. What a command prints, or its note that it did not run because it belongs only to the terminal, is already a Reply via Dispatch: write nothing for it. Only a command that also submits a prompt, such as/force:<tool> <prompt>, gives you that prompt to answer. - A BTW, a broadcast, or any message to a host that takes no such turn (Claude Code) arrives as
a Dispatch notice with a ready-made reply command. Answer with
dispatch messageand its--in-reply-to.
Claiming and status
Section titled “Claiming and status”Before you implement an issue, claim it with dispatch claim, and release the claim when you
stop. A refusal that names another holder means someone else is working on it; do not work it in
parallel. Move the issue’s status as the work moves, with dispatch issue-update. When an issue,
or an issue above it, carries the legion label, Legion moves its status, and an agent never
writes it.
References
Section titled “References”Link everything you mention. Dispatch reads dispatch:// references in every document, ask,
comment, and message, and records what points where:
dispatch://KEYdispatch://KEY/specdispatch://KEY/artifact/<slug>dispatch://KEY/ask/<id>dispatch://KEY/comment/<id>dispatch://KEY/message/<id>dispatch://PROJECT/artifact/<document>dispatch read on any of them shows what it is and everything that references it.
The HTTP API
Section titled “The HTTP API”The dispatch commands cover everyday work. For anything else, the HTTP API reference
lists every route, and so does GET /api/v1 on the server, with no credential: each route’s
method, who may call it, and what it does. An agent calls the API with its token as
Authorization: Bearer <token>.