agent-a
Scope validate to a tenant
changes validate(token) → validate(ctx, token)
app/auth.py
Dispatch is the local CLI for validating coding-agent changes. Your agents start from a snapshot; while they work, you commit, teammates merge and other agents land. Dispatch checks each agent’s change against the code as it is now, before it lands, and tells you whether to continue, refresh or stop.
rundispatch.sh · github.com/rundispatch/dispatch · binary dispatch · macOS arm64 · Linux x86_64
CONTINUE
Still fits. Your checks run on the merged code first.
REFRESH
Something it relied on changed. Nothing applies; redo it on current code.
STOP
That change already landed. Nothing is applied.
The problem
An agent can do exactly what you asked and still hand back a change that no longer fits the code:
A clean git apply doesn’t mean the change still fits, and every extra agent is one more thing moving the code. The goal isn’t more agent output; it’s more of it landing correctly.
What the agent saw · S0
// src/auth.rs
pub fn validate(token: &Token) -> Result<User, AuthError>
// src/handler.rs, the agent’s patch
+ let user = auth::validate(&token)?;
The code now
// src/auth.rs, changed by a teammate
pub fn validate(ctx: &AuthContext, token: &Token) -> Result<User, AuthError>
The patch still applies. The call no longer compiles.
When to use it
A rebase and your tests tell you whether the merge is clean and the tests pass. Dispatch also keeps the snapshot the Work started from, names the declaration it relied on that changed, and blocks dispatch accept until the Work is redone.
Dispatch judges the local checkout it watches. A teammate’s merge counts once you pull it into that checkout. The verdict gates dispatch accept, which applies Work only when it still holds. Interactions between pieces of Work are advisory and block nothing.
The full list, and how agents should operate Dispatch, is in the agent guide.
How it decides
Every piece of Work carries the code it started from, S0, and the change it produced, Δ. Dispatch asks three questions of Δ against the code as it is now. Each one catches what the one before it can’t see.
The verdict is recomputed from S0, Δ and the code now every time, never trusted from an earlier moment. dispatch check asks the first two, so its CONTINUE is preliminary; accept asks all three.
The agent’s change, kept with the snapshot it started from (S0).
What a clean git apply tells you
Δ against the code as it is now.
Catches: Someone edited the same lines, or the same change already landed.
REFRESHno longer applies
STOPalready there
What Dispatch adds
The declarations Δ edits and the ones its new code calls, compared between S0 and now. By symbol for Rust and Python, by file elsewhere.
Catches: A function the patch calls changed its signature. The patch applies; the call is broken.
REFRESHa fact broke
What Dispatch adds
At accept, when the code moved: your checks.verify on the merged tree, in a scratch copy. Your source is untouched until they pass.
Catches: Behavior changed somewhere the analysis cannot see, and a test now fails.
REFRESHa check failed
CONTINUE
All three hold. The change is ready for your accept, or for auto-apply if you turned it on. A REFRESH or STOP applies nothing and leaves the review pending.
Examples
Same Work. Instead, someone changes the signature of validate in src/auth.rs. The patch still applies cleanly, but it calls the old signature.
Attached Work is redone by running your agent again on current code and attaching it. For a run Dispatch launched, the next step is dispatch refresh, which starts a new run of the same task.
$ dispatch checkRun <id>Coherence: REFRESHAnalysis: symbolsWorld changed files: 1fact_broken: pub fn validate(token: &Token) -> Result<User, AuthError> => pub fn validate(ctx: &AuthContext, token: &Token) -> Result<User, AuthError>Next: run your agent again on the current source and attach it (or dispatch reject <id>)
Two runs started from the same snapshot and made the same change. Run A is accepted. Run B is judged against the code Run A produced.
Accept applies first and records your acceptance after. Work integrates one piece at a time; if Run A had changed something Run B relied on instead, the verdict would be REFRESH.
$ dispatch accept <run-a>Applied Candidate A to ~/my-project (1 file(s) changed).Review recorded (revision 1).$ dispatch check <run-b>Run <run-b>Coherence: STOPAnalysis: files_onlyWorld changed files: 1already_applied: the patch is already present in the sourcealready landed by run <run-a>Next: dispatch reject <run-b>
A teammate changed a retry limit, and nothing the Work relied on moved, so check says CONTINUE. At accept, Dispatch first runs your checks.verify on the merged tree.
Nothing is applied and no acceptance is recorded: the result stays pending review. --despite-refresh cannot override a failed check.
$ dispatch checkRun <id>Coherence: CONTINUEAnalysis: files_onlyWorld changed files: 1Next: dispatch accept <id>$ dispatch accepterror: source has changed; this work is stale (REFRESH): check `python3 -m unittest -q` failed (exit 1): FAIL: test_cap (test_rates.T) / AssertionError: 60 != 30; logs: …/verify-01.stderr.log. The source was left unchanged. Run 'dispatch refresh <id>' to redo the work on the current source, or 'dispatch reject <id>'.
Output from the 0.4.11 CLI · run IDs and paths shortened
Work against Work
Coherence checks each piece of Work against main. While a project is watched, Dispatch also compares the Work still in flight with each other, and names where two pieces already touch.
In flight · nothing has landed yet
agent-a
Scope validate to a tenant
changes validate(token) → validate(ctx, token)
app/auth.py
agent-b
Authenticate in handle
calls validate(token)
app/handler.py
agent-c
Document auth
adds an Auth section
README.md
agent-a changes the signature of validate, which agent-b uses. All three are still CONTINUE against main.
Exact to the declaration for Rust and Python, to the file elsewhere. It’s advisory: a piece of Work can be CONTINUE and still interact, and nothing is blocked, reordered or refreshed. When one piece lands, the rest are judged against the new code as usual. Since 0.4.9, Dispatch also records whether each interaction was followed by an invalid verdict, so you can measure how often it’s right from your own state directory.
dispatch watch · status · accept · check
$ dispatch watch | cat01M4MC7G · isolated agent-a · S0 workspace at start ab027f42 · unmoved · ready · no checks · review pending · interacts with 01M4MC7H01M4MC7H · isolated agent-b · S0 workspace at start 257979f0 · unmoved · ready · no checks · review pending · interacts with 01M4MC7G01M4MC7J · isolated agent-c · S0 workspace at start cad06b0a · unmoved · ready · no checks · review pending$ dispatch status 01M4MC7H…Coherence: CONTINUE — world unchanged…Concurrentwith 01M4MC7G: it changes the signature of validate (app/auth.py), which this Work uses$ dispatch accept 01M4MC7GApplied Candidate A to ~/my-project (1 file(s) changed).Review recorded (revision 1).$ dispatch check 01M4MC7HRun 01M4MC7H…Coherence: REFRESHAnalysis: symbolsWorld changed files: 1fact_broken: def validate(token): => def validate(ctx, token):
How Work reaches Dispatch
dispatch startWatches this project in the background and gives your shell back.
dispatch watchA live table of Work, named by worktree folder or task, with Work that needs you first. Finish, accept, reject or review without copying an ID.
dispatch stopEnds watching. Leaving watch doesn’t.
dispatch attach -- claudeRun any agent CLI from your checkout. Dispatch gives it an isolated workspace and judges the result when it exits.
claude --worktreeWith the hooks from dispatch setup, a session in its own worktree becomes Work by itself. Each one is tracked, pending, or told it isn’t tracked; none is dropped silently. Codex uses attach.
dispatch run "Fix the retry race"Dispatch launches Claude Code or Codex from a frozen snapshot. Needs a profile from dispatch setup, or --agent.
start · attach · watch · stop
$ dispatch start✓ Watching ~/my-projectDispatch is running in the background. See it: dispatch watch · Stop: dispatch stop$ dispatch attach --task "Greet by name" -- ./agent.shWorking in ~/.dispatch/workspaces/<id> on branch dispatch/<id>; your checkout is not touched.Attached work <id> finished; next: dispatch check <id>$ dispatch watch | cat~/my-project · watched in the background since 20:21 (pid <pid>)01M4MC86 · isolated external · S0 workspace at start d180c3aa · unmoved · ready · no checks · review pending$ dispatch stop✓ Dispatch stopped watching ~/my-project.
Checks, review and integration stay separate. Passing tests are evidence; your accept is the decision. Discovered Work is never applied by itself, and auto-apply is a policy you turn on.
All Work shares the same verdicts and lands one piece at a time. Neither watching nor attach needs an agent profile, and Dispatch never scans for agent processes. Details are in the docs.
Built with Dispatch
Releases 0.4.9 and 0.4.10 were each built by parallel coding agents, supervised by the release before. The setup is documented, command by command.
Build with parallel agents4
agents in parallel
Claude Code sessions, each in its own workspace, built 0.4.9 and again 0.4.10. An integrator reviewed their Work and landed it one contribution at a time.
Every landing
re-judged the rest
As each contribution landed, the others were checked against the new code. All stayed CONTINUE, and merged-tree checks ran on the accepts that followed.
2 bugs
found in its own supervision
Building 0.4.9 left two sessions untracked under heavy load. 0.4.10 fixes both causes: now every session ends tracked, pending, or told it isn’t tracked.
Two releases are a small sample. This is how we use it, not a benchmark: no time, token or cost saving is claimed. Each release’s plan in Core records what happened.
Try it
You and an agent, or several agents, on the same repo. Start with a repository you can restore.
cd my-project
dispatch start # watch this project in the background
dispatch attach -- claude # or codex, or any agent CLI
dispatch watch # f finish · a accept · r reject · d review
dispatch stop # stop watching this project