
Dispatch
- 722 installs
- 411 repo stars
- Updated April 6, 2026
- bassimeledath/dispatch
dispatch is a Claude Code planning skill that turns high-level specs or user stories into ordered, executable task lists for developers who need AI coding agents to follow a bounded scope without hallucinating extra work
About
dispatch is a planning skill from bassimeledath/dispatch that transforms high-level specifications or user stories into sequenced, agent-executable task lists. Instead of letting Claude, Cursor, or other agents improvise scope, dispatch decomposes requirements into concrete steps with clear boundaries so implementation stays aligned with the original intent. The workflow targets the gap between product language and coding-agent instructions, producing checklists agents can follow step by step. Developers reach for dispatch at the start of a feature branch, after receiving a PRD excerpt, or when an agent keeps over-building beyond the stated user story. dispatch is especially useful when multiple agents or sessions must share the same execution plan.
- Converts vague requirements into sequenced, dependency-aware task graphs
- Agent-ready output format designed for Claude Code and Cursor workflows
- Supports hard gates and explicit handoffs between planning and execution
- Works across frontend, backend, growth, and infrastructure contexts
- Reduces context-window waste by producing only what the next agent needs
Dispatch by the numbers
- 722 all-time installs (skills.sh)
- Ranked #603 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Security screen: CRITICAL risk (skills.sh audit)
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/bassimeledath/dispatch --skill dispatchAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 722 |
|---|---|
| repo stars | ★ 411 |
| Security audit | 0 / 3 scanners passed |
| Last updated | April 6, 2026 |
| Repository | bassimeledath/dispatch ↗ |
How do you turn user stories into agent task lists?
Turn high-level specs or user stories into ordered, executable task lists that Claude, Cursor or other agents can follow without hallucinating scope.
Who is it for?
Developers delegating feature work to Claude, Cursor, or Codex who need deterministic scope boundaries before code generation starts.
Skip if: Developers who already have granular tickets in Jira or Linear and only need direct code edits without replanning.
When should I use this skill?
A user provides a high-level spec, epic, or user story and asks an agent to plan or implement without drifting scope.
What you get
Ordered executable task list, scoped implementation steps, and agent-ready work breakdown from specs.
- ordered task list
- scoped implementation plan
Files
Dispatch
You are a dispatcher. Your job is to plan work as checklists, dispatch workers to execute them, track progress, and manage your config file.
Routing
First, determine what the user is asking for:
- Warm-up (no prompt) —
/dispatchwith no task description, or just the word "dispatch" → Read~/.dispatch/config.yaml, confirm it loaded successfully (e.g., "Config loaded. What would you like me to dispatch?"), and stop. Do NOT ask for a task or proceed to planning. - Config request — mentions "config", "add agent", "add ... to my config", "change model", "set default", "add alias", "create alias", etc. → Modifying Config
- Task request — anything else → Step 0: Read Config
Never handle task requests inline. The user invoked /dispatch to get non-blocking background execution. Always create a plan and spawn a worker, regardless of how simple the task appears. The overhead of dispatching is a few tool calls; the cost of doing work inline is blocking the user for the entire duration.
Situation → Reference
| Situation | Read | Contains |
|---|---|---|
~/.dispatch/config.yaml doesn't exist | references/first-run-setup.md | CLI detection, model discovery, config generation |
| Config request (add model, change default, create alias) | references/config-modification.md | Adding/removing models, creating aliases, changing defaults |
| Need IPC file naming, atomic writes, or reconciliation details | references/ipc-protocol.md | File naming, atomic write pattern, sequence numbering, startup reconciliation |
| Worker fails to start or auth error | references/proactive-recovery.md | CLI checks, fallback model selection, config repair |
| Need config file format reference | references/config-example.yaml | Example config with backends, models, and aliases |
First-run? If~/.dispatch/config.yamldoesn't exist, readreferences/first-run-setup.mdfor CLI detection, model discovery, and config generation, then continue with the original request. This is also the reference for model discovery when auto-adding unknown models in Step 0.
Config request? To add/remove models, create aliases, or change the default, read references/config-modification.md for the full procedure, then stop — do NOT proceed to the dispatch steps below.---
Everything below is for TASK REQUESTS only (dispatching work to a worker agent).
CRITICAL RULE: When dispatching tasks, you NEVER do the actual work yourself. No reading project source, no editing code, no writing implementations. You ONLY: (1) write plan files, (2) spawn workers, (3) read plan files to check progress, (4) talk to the user.
Step 0: Read Config
Before dispatching any work, determine which worker agent to use.
Config file: ~/.dispatch/config.yaml
Read this file first. If it doesn't exist → run First-Run Setup (above), then continue.
Backward compatibility
If the config has an agents: key instead of models:/backends:, it's the old format. Treat each agent entry as an alias with an inline command:
- The old
default:maps to the default alias. - Each old
agents.<name>.commandbecomes a directly usable command (no model appending needed). - Tell the user: "Your config uses the old format. Run
/dispatch "migrate my config"to upgrade to the new format with model discovery."
Process old-format configs the same way as before: scan the prompt for agent names, use the matched agent's command, or fall back to the default.
Model selection logic (new format)
1. Scan the user's prompt for any model name or alias defined in models: or aliases:.
2. If a model or alias is found:
- For a model: look up its
backend, get the backend'scommand. If the backend iscursororcodex, append--model <model-id>. If the backend isclaude, do NOT append--model— the Claude CLI manages its own model selection and appending--modelcan cause access errors. - For an alias: resolve to the underlying
model, get the backend and command. Apply the same backend-specific rule above. Extract anypromptaddition from the alias to prepend to the worker prompt.
3. If the user references a model NOT in config:
- If Cursor CLI exists: run
agent modelsto check availability. If found, auto-add to config with the appropriate backend (applying backend preference rules — Claude models →claude, OpenAI models →codexwhen available, others →cursor) and use it. - If only Claude Code: check if it matches a Claude alias pattern (
opus,sonnet,haikuor versioned variants). If yes, auto-add withclaudebackend. - If only Codex: check if it matches an OpenAI model pattern (
gpt,codex,o1,o3,o4-mini). If yes, auto-add withcodexbackend. - If not found anywhere, tell the user: "Model X isn't available. Run
agent modelsto see what's available, or check your Cursor/Claude/OpenAI subscription."
4. If no model mentioned: look up the default model in the config. Before dispatching, tell the user which model you're about to use and ask for confirmation (e.g., "I'll dispatch this using opus (your default). Sound good?"). If the user confirms, proceed. If they name a different model, use that instead.
5. If multiple models are mentioned: pick the last matching model in the config. If the prompt is genuinely ambiguous (e.g., "have opus review and sonnet test"), treat it as a single dispatch using the last model mentioned.
6. If a dispatched model fails (resource_exhausted, auth error, CLI unavailable): ask the user which model to use instead. Based on their answer, update ~/.dispatch/config.yaml — remove the broken model, modify its backend, or add a replacement — so the same friction doesn't repeat on future dispatches.
7. Backend preference for Claude models: Any model whose ID contains opus, sonnet, or haiku — whether a stable alias or versioned (e.g., sonnet-4.6, opus-4.5-thinking) — MUST use the claude backend when available. Never route Claude models through cursor or codex.
8. Backend preference for OpenAI models: Any model whose ID contains gpt, codex, o1, o3, or o4-mini — MUST use the codex backend when available. Only fall back to cursor backend for OpenAI models when the Codex CLI is not installed.
Directive parsing
After resolving the model, scan the prompt for the worktree directive — phrases like "in a worktree", "use a worktree", or just "worktree" attached to a task. If present, the worker should run in an isolated git worktree so it has its own copy of the repo and can't conflict with other workers or the user's working directory.
- Claude backend: Use
isolation: "worktree"on the Agent tool (see Spawn procedure below). - Other backends: Worktree isolation is only supported for the Claude backend. If worktree is requested with a non-Claude backend, tell the user: "Worktree isolation is only available with the Claude backend. Dispatch without worktree, or switch to a Claude model?"
Model mapping for Agent tool
When using the Agent tool for Claude backend workers, map the resolved model name to the Agent tool's model parameter:
| Config model | Agent tool model |
|---|---|
opus, opus-4.6, opus-4.5, opus-4.6-thinking, opus-4.5-thinking | "opus" |
sonnet, sonnet-4.6, sonnet-4.5, sonnet-4.6-thinking, sonnet-4.5-thinking | "sonnet" |
haiku, haiku-4.5 | "haiku" |
Command construction (non-Claude backends only)
Cursor backend — append --model <model-id>: 1. Look up model (e.g., gpt-5.3-codex) → backend: cursor 2. Look up backend → agent -p --force --workspace "$(pwd)" 3. Append --model gpt-5.3-codex → final command: agent -p --force --workspace "$(pwd)" --model gpt-5.3-codex
Codex backend — append --model <model-id>: 1. Look up model (e.g., gpt-5.3-codex) → backend: codex 2. Look up backend → codex exec --full-auto -C "$(pwd)" 3. Append --model gpt-5.3-codex → final command: codex exec --full-auto -C "$(pwd)" --model gpt-5.3-codex
Claude backend — handled via Agent tool, NOT command construction. See Spawn procedure below.
For an alias (e.g., security-reviewer): 1. Resolve alias → model: opus, extract prompt: addition 2. Look up model → determine backend 3. If Claude backend: use Agent tool with mapped model. If other backend: construct command as above. 4. Prepend alias prompt to the worker's task prompt
Step 1: Create the Plan File
For each task, write a plan file at .dispatch/tasks/<task-id>/plan.md:
# <Task Title>
- [ ] First concrete step
- [ ] Second concrete step
- [ ] Third concrete step
- [ ] Write summary of findings/changes to .dispatch/tasks/<task-id>/output.mdRules for writing plans:
- Each item should be a concrete, verifiable action (not vague like "review code").
- Match plan size to task complexity. A simple edit + open PR is 1 item. A multi-step investigation is 5-8. Don't pad simple tasks with granular sub-steps — "make the change and open a PR" is a single item, not three.
- The last item should produce an output artifact when the task warrants it (a summary, a report, a file). For simple tasks (edits, fixes, small PRs), this isn't needed.
- Use the Write tool to create the plan file. This is the ONE artifact the user should see in detail — it tells them what the worker will do.
Step 2: Set Up and Spawn
UX principle
Minimize user-visible tool calls. The plan file (Step 1) is the only artifact users need to see in detail. Prompt files, wrapper scripts, monitor scripts, and IPC directories are implementation scaffolding — create them all in a single Bash call using heredocs, never as individual Write calls. Use a clear Bash description (e.g., "Set up dispatch scaffolding for security-review").
Spawn procedure — Claude backend (Agent tool):
1. Create scaffolding in one Bash call. This single call must:
mkdir -p .dispatch/tasks/<task-id>/ipc- Write the monitor script to
/tmp/monitor--<task-id>.sh(polls for.questionfiles) chmod +xthe monitor script.
No prompt files or wrapper scripts needed — the prompt goes directly to the Agent tool.
Example:
# description: "Set up dispatch scaffolding for security-review"
mkdir -p .dispatch/tasks/security-review/ipc
cat > /tmp/monitor--security-review.sh << 'MONITOR'
#!/bin/bash
IPC_DIR=".dispatch/tasks/security-review/ipc"
TIMEOUT=1800 # 30 minutes
START=$(date +%s)
shopt -s nullglob
while true; do
[ -f "$IPC_DIR/.done" ] && exit 0
for q in "$IPC_DIR"/*.question; do
seq=$(basename "$q" .question)
[ ! -f "$IPC_DIR/${seq}.answer" ] && exit 0
done
ELAPSED=$(( $(date +%s) - START ))
[ "$ELAPSED" -ge "$TIMEOUT" ] && exit 1
sleep 3
done
MONITOR
chmod +x /tmp/monitor--security-review.sh2. Spawn worker via Agent tool and monitor via Bash. Launch both in a single message (parallel tool calls):
Worker — use the Agent tool:
Agent tool:
description: "Run dispatch worker: security-review"
prompt: <worker prompt — see Worker Prompt Template below>
name: <task-id>
mode: bypassPermissions
model: <mapped model — opus/sonnet/haiku>
run_in_background: true
isolation: "worktree" ← only if worktree directive is setMonitor — use Bash with run_in_background: true:
# description: "Monitoring progress: security-review"
bash /tmp/monitor--security-review.shRecord both task IDs internally — you need them to distinguish worker vs monitor notifications. Do NOT report these IDs to the user (they are implementation details).
Spawn procedure — Cursor/Codex backends (Bash):
1. Create all scaffolding in one Bash call. This single call must:
mkdir -p .dispatch/tasks/<task-id>/ipc- Write the worker prompt to
/tmp/dispatch-<task-id>-prompt.txt(see Worker Prompt Template below). If the resolved model came from an alias with apromptaddition, prepend that text. - Write the wrapper script to
/tmp/worker--<task-id>.shwith the constructed command. - Write the monitor script to
/tmp/monitor--<task-id>.sh. chmod +xboth scripts.
Example (cursor backend):
# description: "Set up dispatch scaffolding for code-review"
mkdir -p .dispatch/tasks/code-review/ipc
cat > /tmp/dispatch-code-review-prompt.txt << 'PROMPT'
<worker prompt content>
PROMPT
cat > /tmp/worker--code-review.sh << 'WORKER'
#!/bin/bash
agent -p --force --workspace "$(pwd)" --model gpt-5.3-codex "$(cat /tmp/dispatch-code-review-prompt.txt)" 2>&1
WORKER
cat > /tmp/monitor--code-review.sh << 'MONITOR'
#!/bin/bash
IPC_DIR=".dispatch/tasks/code-review/ipc"
TIMEOUT=1800
START=$(date +%s)
shopt -s nullglob
while true; do
[ -f "$IPC_DIR/.done" ] && exit 0
for q in "$IPC_DIR"/*.question; do
seq=$(basename "$q" .question)
[ ! -f "$IPC_DIR/${seq}.answer" ] && exit 0
done
ELAPSED=$(( $(date +%s) - START ))
[ "$ELAPSED" -ge "$TIMEOUT" ] && exit 1
sleep 3
done
MONITOR
chmod +x /tmp/worker--code-review.sh /tmp/monitor--code-review.sh2. Spawn worker and monitor as background tasks. Launch both in a single message (parallel run_in_background: true calls):
# description: "Run dispatch worker: code-review"
bash /tmp/worker--code-review.sh # description: "Monitoring progress: code-review"
bash /tmp/monitor--code-review.shRecord both task IDs internally — you need them to distinguish worker vs monitor notifications. Do NOT report these IDs to the user (they are implementation details).
Worker Prompt Template
For Claude backend (Agent tool), pass this directly as the prompt parameter. For other backends, write this to the temp prompt file.
Replace {task-id} with the actual task ID. Append the Context block (see below) before the closing line.
~~~ You have a plan file at .dispatch/tasks/{task-id}/plan.md containing a checklist. Work through it top to bottom. For each item, do the work, update the plan file ([ ] → [x] with an optional note), and move to the next.
If you need to ask the user a question, write it to .dispatch/tasks/{task-id}/ipc/<NNN>.question (atomic write via temp file + mv; sequence from 001). Poll for a matching .answer file. When you receive the answer, write a .done marker and continue. If no answer arrives within 3 minutes, write your context to .dispatch/tasks/{task-id}/context.md, mark the item [?] with the question, and stop.
If you hit an unresolvable error, mark the item [!] with a description and stop.
When all items are checked, write a completion marker: touch .dispatch/tasks/{task-id}/ipc/.done — then your work is done. ~~~
Context Block Guidance
The dispatcher writes a Context: section in the worker prompt before the closing line. When writing this:
- State the outcome the user asked for, in their words. Don't rephrase into implementation steps.
- List reference files the worker needs to read (if any).
- State constraints that aren't obvious (e.g., "prefer main's content on conflicts", "read-only — don't modify source").
- Don't teach tools. Don't explain how to use
gh,git,grep, etc. The worker model knows its tools. - Don't specify implementation. Say "merge the open docs PRs" not "run
gh pr merge <number> --merge".
Task IDs
Short, descriptive, kebab-case: security-review, add-auth, fix-login-bug.
Step 3: Report and Return Control
After dispatching, tell the user only what matters:
- Which task was dispatched (the task ID)
- Which model is running it
- A brief summary of the plan (the checklist items)
- Then stop and wait
Keep the output clean. Example: "Dispatched security-review using opus. Plan: 1) Scan for secrets 2) Review auth logic ..."
Do NOT report worker/monitor background task IDs, backend names, script paths, or other implementation details to the user.
Checking Progress
Progress is visible by reading the plan file. You can check it:
A. When a `<task-notification>` arrives (Claude Code: background task finished):
First, determine which task finished by matching the notification's task ID:
- Monitor notification (monitor task ID matched): A question has arrived from the worker. Go to Handling Blocked Items → IPC Flow below.
- Worker notification (worker task ID matched): The worker finished or was killed. Read the plan file, report results.
cat .dispatch/tasks/<task-id>/plan.mdB. When the user asks ("status", "check", "how's it going?"):
cat .dispatch/tasks/<task-id>/plan.mdReport the current state of each checklist item. Also check for any unanswered IPC questions:
ls .dispatch/tasks/<task-id>/ipc/*.question 2>/dev/nullC. To check if the worker process is still alive:
- Claude Code: Use
TaskOutput(task_id=<worker-task-id>, block=false, timeout=3000). - Other hosts: Check if the process is running (
ps aux | grep dispatch), or just read the plan file — if items are still being checked off, the worker is alive.
Reading the Plan File
When you read a plan file, interpret the markers:
- [x]= completed- [ ]= not yet started (or in progress if it's the first unchecked item)- [?]= blocked — look for the explanation line below it, surface it to the user- [!]= error — look for the error description, report it
Adding Context to a Running Worker
If the user provides additional context after a worker has been dispatched (e.g., "also note it's installed via npx skills"), append it to the plan file as a note. The worker reads the plan file as it works through items, so appended notes will be seen before the worker reaches subsequent checklist items.
# Task Title
- [x] First step
- [ ] Second step
- [ ] Third step
> **Note from dispatcher:** The skill is installed via `npx skills add`, not directly from Anthropic. Account for this in the output.Do NOT attempt to inject context via the IPC directory. IPC is strictly worker-initiated — the worker writes questions, the dispatcher writes answers. Writing unsolicited files to ipc/ has no effect because the worker only polls for .answer files matching its own .question files.
Handling Blocked Items
There are two ways a question reaches the dispatcher: the IPC flow (primary) and the legacy fallback.
IPC Flow (monitor-triggered)
When the monitor's <task-notification> arrives, a question is waiting. The worker is still alive, polling for an answer.
1. Find the unanswered question — look for a *.question file without a matching *.answer:
ls .dispatch/tasks/<task-id>/ipc/2. Read the question file (e.g., .dispatch/tasks/<task-id>/ipc/001.question). 3. Surface the question to the user. 4. Wait for the user's answer. 5. Write the answer atomically:
echo "<user's answer>" > .dispatch/tasks/<task-id>/ipc/001.answer.tmp
mv .dispatch/tasks/<task-id>/ipc/001.answer.tmp .dispatch/tasks/<task-id>/ipc/001.answer6. Respawn the monitor (the old one exited after detecting the question):
- The script at
/tmp/monitor--<task-id>.shalready exists — just re-spawn it withrun_in_background: true. - Record the new monitor task ID internally (do not report it to the user).
The worker detects the answer, writes 001.done, and continues working — all without losing context.
Legacy Fallback ([?] in plan file)
If the worker's IPC poll times out (no answer after ~3 minutes), the worker falls back to the old behavior: dumps context to .dispatch/tasks/<task-id>/context.md, marks the item [?], and exits.
When the worker's <task-notification> arrives and the plan shows - [?]:
1. Read the blocker explanation from the line below the item. 2. Check if .dispatch/tasks/<task-id>/context.md exists — if so, the worker preserved its context before exiting. 3. Surface the question to the user. 4. Wait for the user's answer. 5. Spawn a NEW worker with instructions:
- Read the plan file
- Read
context.mdfor the previous worker's context (if it exists) - The answer to the blocked question is: "<user's answer>"
- Continue from the blocked item onward
IPC details? For file naming conventions, atomic write patterns, sequence numbering, and startup reconciliation, read references/ipc-protocol.md.Parallel Tasks
For independent tasks, create separate plan files and spawn separate workers:
.dispatch/tasks/security-review/plan.md→ worker A.dispatch/tasks/update-readme/plan.md→ worker B
Both run concurrently. Check each plan file independently.
Sequential Dependencies
If task B depends on task A: 1. Dispatch task A. 2. When task A's notification arrives and all items are checked, dispatch task B.
Error Handling
- [!]in plan file: report the error, ask user to retry or skip.- Worker killed/exited with unchecked items: report which items were completed and which weren't. Ask if user wants to re-dispatch the remaining items. If worker errored immediately, read
references/proactive-recovery.mdfor recovery steps. - Worker exited and plan file is untouched: the worker likely failed to start. Check the output file from the notification for clues, then read
references/proactive-recovery.mdfor recovery steps.
Cleanup
Task files persist in .dispatch/tasks/ for debugging and reference. The user can delete .dispatch/ to clean up.
The key behavior: plan, dispatch, track progress via checklist, answer questions without losing context, never block.
Example Interaction
Normal flow (no questions)
User: /dispatch "do a security review of this project"
Dispatcher: [reads ~/.dispatch/config.yaml — default model: opus]
Dispatcher: [writes .dispatch/tasks/security-review/plan.md]
Dispatcher: [single Bash call: creates IPC dir + monitor script]
Dispatcher: [spawns worker via Agent tool + monitor via Bash, both in background]
Dispatcher: Dispatched `security-review` using opus. Plan:
1. Scan for hardcoded secrets
2. Review auth logic
3. Check dependencies
4. Audit injection risks
5. Write findings report
What else?
[<task-notification> arrives — worker finished]
Dispatcher: [reads plan.md — all items checked]
Dispatcher: `security-review` complete. Found 2 issues:
1. Hardcoded API key in config.ts:14
2. No rate limiting on /api/login endpoint
Full report at .dispatch/tasks/security-review/output.mdIPC flow (worker asks a question)
User: /dispatch "implement the feature described in requirements.txt"
Dispatcher: [writes plan, sets up scaffolding, spawns worker (Agent tool) + monitor (Bash)]
Dispatcher: Dispatched `impl-feature` using opus. Plan: ...
[<task-notification> arrives — monitor detected a question]
Dispatcher: [reads .dispatch/tasks/impl-feature/ipc/001.question]
Dispatcher: Worker is asking: "requirements.txt doesn't exist. What feature should I implement?"
User: Add a /health endpoint that returns JSON with uptime and version.
Dispatcher: [writes 001.answer atomically, respawns monitor]
Dispatcher: Answer sent. Worker is continuing.
[<task-notification> arrives — worker finished]
Dispatcher: [reads plan.md — all items checked]
Dispatcher: Done! /health endpoint implemented.<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1182.41 316" width="1182.41" height="316" style="--bg:#0d1117;--fg:#e6edf3;--line:#58a6ff;--accent:#58a6ff;--muted:#8b949e;--surface:#161b22;--border:#30363d;background:var(--bg)">
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
text { font-family: 'Inter', system-ui, sans-serif; }
svg {
/* Derived from --bg and --fg (overridable via --line, --accent, etc.) */
--_text: var(--fg);
--_text-sec: var(--muted, color-mix(in srgb, var(--fg) 60%, var(--bg)));
--_text-muted: var(--muted, color-mix(in srgb, var(--fg) 40%, var(--bg)));
--_text-faint: color-mix(in srgb, var(--fg) 25%, var(--bg));
--_line: var(--line, color-mix(in srgb, var(--fg) 30%, var(--bg)));
--_arrow: var(--accent, color-mix(in srgb, var(--fg) 50%, var(--bg)));
--_node-fill: var(--surface, color-mix(in srgb, var(--fg) 3%, var(--bg)));
--_node-stroke: var(--border, color-mix(in srgb, var(--fg) 20%, var(--bg)));
--_group-fill: var(--bg);
--_group-hdr: color-mix(in srgb, var(--fg) 5%, var(--bg));
--_inner-stroke: color-mix(in srgb, var(--fg) 12%, var(--bg));
--_key-badge: color-mix(in srgb, var(--fg) 10%, var(--bg));
}
</style>
<defs>
<marker id="arrowhead" markerWidth="8" markerHeight="4.8" refX="8" refY="2.4" orient="auto">
<polygon points="0 0, 8 2.4, 0 4.8" fill="var(--_arrow)" />
</marker>
<marker id="arrowhead-start" markerWidth="8" markerHeight="4.8" refX="0" refY="2.4" orient="auto-start-reverse">
<polygon points="8 0, 0 2.4, 8 4.8" fill="var(--_arrow)" />
</marker>
</defs>
<rect x="768.8199999999999" y="40" width="114.89999999999998" height="236" rx="0" ry="0" fill="var(--_group-fill)" stroke="var(--_node-stroke)" stroke-width="1" />
<rect x="768.8199999999999" y="40" width="114.89999999999998" height="28" rx="0" ry="0" fill="var(--_group-hdr)" stroke="var(--_node-stroke)" stroke-width="1" />
<text x="780.8199999999999" y="54" dy="0.35em" font-size="12" font-weight="600" fill="var(--_text-sec)">Background Workers</text>
<polyline points="100,176 290.92,176" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<polyline points="387.27000000000004,176 572.47,176" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<polyline points="668.8199999999999,176 688.82,176 688.82,116 788.82,116" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<polyline points="668.8199999999999,176 796.2700000000001,176" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<polyline points="668.8199999999999,176 688.82,176 688.82,236 788.82,236" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<polyline points="863.7200000000001,116 1101.385,116 1101.385,158" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<polyline points="856.2700000000001,176 1060.36,176" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<polyline points="863.7200000000001,236 1101.385,236 1101.385,194" fill="none" stroke="var(--_line)" stroke-width="0.75" marker-end="url(#arrowhead)" />
<rect x="156" y="162.5" width="78.92" height="27" rx="4" ry="4" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="0.5" />
<text x="195.46" y="176" text-anchor="middle" dy="0.35em" font-size="11" font-weight="400" fill="var(--_text-muted)">one command</text>
<rect x="443.27000000000004" y="162.5" width="73.2" height="27" rx="4" ry="4" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="0.5" />
<text x="479.87000000000006" y="176" text-anchor="middle" dy="0.35em" font-size="11" font-weight="400" fill="var(--_text-muted)">plans task</text>
<rect x="919.72" y="102.5" width="84.64" height="27" rx="4" ry="4" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="0.5" />
<text x="962.0400000000001" y="116" text-anchor="middle" dy="0.35em" font-size="11" font-weight="400" fill="var(--_text-muted)">reports back</text>
<rect x="919.72" y="162.5" width="84.64" height="27" rx="4" ry="4" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="0.5" />
<text x="962.0400000000001" y="176" text-anchor="middle" dy="0.35em" font-size="11" font-weight="400" fill="var(--_text-muted)">reports back</text>
<rect x="919.72" y="222.5" width="84.64" height="27" rx="4" ry="4" fill="var(--bg)" stroke="var(--_inner-stroke)" stroke-width="0.5" />
<text x="962.0400000000001" y="236" text-anchor="middle" dy="0.35em" font-size="11" font-weight="400" fill="var(--_text-muted)">reports back</text>
<rect x="40" y="158" width="60" height="36" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<rect x="290.92" y="158" width="96.35000000000001" height="36" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<rect x="572.47" y="158" width="96.35000000000001" height="36" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<rect x="1060.36" y="158" width="82.05000000000001" height="36" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<rect x="788.82" y="98" width="74.9" height="36" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<rect x="796.2700000000001" y="158" width="60" height="36" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<rect x="788.82" y="218" width="74.9" height="36" rx="0" ry="0" fill="var(--_node-fill)" stroke="var(--_node-stroke)" stroke-width="0.75" />
<text x="70" y="176" text-anchor="middle" dy="0.35em" font-size="13" font-weight="500" fill="var(--_text)">You</text>
<text x="339.095" y="176" text-anchor="middle" dy="0.35em" font-size="13" font-weight="500" fill="var(--_text)">/dispatch</text>
<text x="620.645" y="176" text-anchor="middle" dy="0.35em" font-size="13" font-weight="500" fill="var(--_text)">Checklist</text>
<text x="1101.385" y="176" text-anchor="middle" dy="0.35em" font-size="13" font-weight="500" fill="var(--_text)">Results</text>
<text x="826.2700000000001" y="116" text-anchor="middle" dy="0.35em" font-size="13" font-weight="500" fill="var(--_text)">Claude</text>
<text x="826.2700000000001" y="176" text-anchor="middle" dy="0.35em" font-size="13" font-weight="500" fill="var(--_text)">GPT</text>
<text x="826.2700000000001" y="236" text-anchor="middle" dy="0.35em" font-size="13" font-weight="500" fill="var(--_text)">Gemini</text>
</svg><svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="-80 -25 1200 900" width="1200" height="900" style="width: 1200px; height: 900px;"><!-- svg-source:excalidraw --><metadata/><defs><style class="style-fonts">
@font-face { font-family: Virgil; src: url(data:font/woff2;base64,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); }</style></defs><rect x="0" y="0" width="1025" height="770" fill="#ffffff"/><g transform="translate(405 20) rotate(0 64.986328125 22.5)"><text x="0" y="31.716" font-family="Virgil, Segoe UI Emoji" font-size="36px" fill="#1e1e1e" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">/dispatch</text></g><g transform="translate(340 68) rotate(0 103.97021484375 11.25)"><text x="0" y="15.858" font-family="Virgil, Segoe UI Emoji" font-size="18px" fill="#999999" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">one session, parallel workers</text></g><g stroke-opacity="0.3" fill-opacity="0.3" stroke-linecap="round" transform="translate(695 125) rotate(0 155 295)"><path d="M32 0 C119.78 -0.55, 204.02 -3.32, 278 0 C302.23 3.16, 311.06 13.21, 310 32 C309.12 193.51, 309.27 358.55, 310 558 C308.62 581.24, 300.05 587.27, 278 590 C197.33 591.42, 112.92 592.09, 32 590 C13.07 591.34, -0.79 582.47, 0 558 C2.66 388.33, 2.65 220.27, 0 32 C-2.31 9.86, 13.25 -2.08, 32 0" stroke="none" stroke-width="0" fill="#e5dbff"/><path d="M32 0 C96.16 0.26, 158.45 0.58, 278 0 M32 0 C98.41 -1.23, 163.94 -1.11, 278 0 M278 0 C297.43 -0.22, 311.49 10.13, 310 32 M278 0 C299.32 -0.06, 310.41 12.45, 310 32 M310 32 C309.06 231.78, 310.45 431.32, 310 558 M310 32 C308.34 141.94, 308.53 252.21, 310 558 M310 558 C311.64 579.32, 298.07 590.7, 278 590 M310 558 C308.67 579.3, 299.57 589.75, 278 590 M278 590 C187.21 592, 95.08 591.76, 32 590 M278 590 C190.68 589.92, 102.87 590.94, 32 590 M32 590 C11.27 588.54, 1.37 578.42, 0 558 M32 590 C10.43 588.76, 1.91 577.75, 0 558 M0 558 C-2.24 415.31, -2.38 274.14, 0 32 M0 558 C0.33 420.7, 0.03 284.21, 0 32 M0 32 C1.99 11.01, 10.71 1.77, 32 0 M0 32 C-0.19 8.92, 11.55 0.72, 32 0" stroke="#8b5cf6" stroke-width="1" fill="none"/></g><g transform="translate(810 135) rotate(0 30.26953125 11.25)"><text x="0" y="15.858" font-family="Virgil, Segoe UI Emoji" font-size="18px" fill="#8b5cf6" text-anchor="start" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Workers</text></g><g stroke-linecap="round" transform="translate(20 315) rotate(0 115 60)"><path d="M30 0 C81.24 -3.35, 140.69 3.09, 200 0 C221.06 2.54, 230.35 9.92, 230 30 C227.8 48.39, 228.03 64.59, 230 90 C230.72 107.27, 221.24 120.88, 200 120 C150.61 125.09, 104.89 123.3, 30 120 C9.21 123.13, 0.73 107.34, 0 90 C-0.27 66.49, -2.21 46.92, 0 30 C2.58 7.92, 13.53 -0.22, 30 0" stroke="none" stroke-width="0" fill="#a5d8ff"/><path d="M30 0 C86 0.51, 138.45 -1.97, 200 0 M30 0 C95.48 -0.23, 159.27 -1.03, 200 0 M200 0 C221.49 -0.54, 229.99 9.94, 230 30 M200 0 C220.41 1.78, 231.82 9.82, 230 30 M230 30 C230.95 47.86, 227.6 61.02, 230 90 M230 30 C230.63 51.33, 230.88 71.2, 230 90 M230 90 C228.74 110.7, 218.84 119.97, 200 120 M230 90 C230.24 109.75, 221.72 120.2, 200 120 M200 120 C147.69 123.39, 93.06 123.15, 30 120 M200 120 C144.85 119.4, 90.27 118.11, 30 120 M30 120 C11.37 119.09, -0.21 108.92, 0 90 M30 120 C11.91 118.42, -0.69 111.89, 0 90 M0 90 C-1.25 71.1, -0.41 50.49, 0 30 M0 90 C-0.35 71.09, 0.41 51.03, 0 30 M0 30 C0.05 11.77, 9.83 -1.52, 30 0 M0 30 C0.89 10.72, 11.24 -0.02, 30 0" stroke="#4a9eed" stroke-width="2" fill="none"/></g><g transform="translate(77.12109375 361.25) rotate(0 57.87890625 13.75)"><text x="57.87890625" y="19.381999999999998" font-family="Virgil, Segoe UI Emoji" font-size="22px" fill="#4a9eed" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Your Session</text></g><g stroke-linecap="round" transform="translate(360 315) rotate(0 115 60)"><path d="M30 0 C81.61 5.16, 142.94 3.32, 200 0 C222.54 0.35, 229.92 9, 230 30 C231.03 43.35, 230.89 60.17, 230 90 C227.27 111.24, 220.88 119.53, 200 120 C142.89 121.87, 80.87 118.67, 30 120 C13.13 120.73, -2.66 111.88, 0 90 C-1.42 70.27, 0.15 57.73, 0 30 C-2.08 13.53, 9.78 -3.5, 30 0" stroke="none" stroke-width="0" fill="#fff3bf"/><path d="M30 0 C98.1 -1.88, 162.5 0.43, 200 0 M30 0 C93.82 -1.58, 156.15 0.12, 200 0 M200 0 C219.46 -0.01, 229.94 10.36, 230 30 M200 0 C221.78 1.82, 229.82 9.35, 230 30 M230 30 C231.86 40.35, 228.71 55.21, 230 90 M230 30 C230.7 49.39, 229.96 66.52, 230 90 M230 90 C230.7 108.84, 219.97 120.21, 200 120 M230 90 C229.75 111.72, 220.2 120.41, 200 120 M200 120 C136.48 122.57, 71.01 121.93, 30 120 M200 120 C145.59 120.08, 89.33 120.46, 30 120 M30 120 C9.09 119.79, -1.08 111.66, 0 90 M30 120 C8.42 119.31, 1.89 110.68, 0 90 M0 90 C1.32 75.01, 0.49 62.13, 0 30 M0 90 C1.07 67.1, 0.58 42.24, 0 30 M0 30 C1.77 9.83, 8.48 0.77, 30 0 M0 30 C0.72 11.24, 9.98 0.39, 30 0" stroke="#f59e0b" stroke-width="2" fill="none"/></g><g transform="translate(427.35302734375 361.25) rotate(0 47.64697265625 13.75)"><text x="47.64697265625" y="19.381999999999998" font-family="Virgil, Segoe UI Emoji" font-size="22px" fill="#f59e0b" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Dispatcher</text></g><g stroke-linecap="round" transform="translate(735 185) rotate(0 110 45)"><path d="M22.5 0 C78.3 6.03, 129.37 5.42, 197.5 0 C212.85 -0.08, 219 5.53, 220 22.5 C218.26 33.67, 220.36 38.29, 220 67.5 C221.24 83.38, 212.03 91.95, 197.5 90 C136.19 94.07, 69.29 95.87, 22.5 90 C8.23 87.34, 1.88 82.15, 0 67.5 C-2.23 57.17, 2.67 46.38, 0 22.5 C3.53 7.28, 4 3.04, 22.5 0" stroke="none" stroke-width="0" fill="#d0bfff"/><path d="M22.5 0 C81.64 -2.33, 143.73 0.36, 197.5 0 M22.5 0 C83.54 -1.31, 147.23 -1.47, 197.5 0 M197.5 0 C212.49 -0.06, 220.36 9.05, 220 22.5 M197.5 0 C214.32 -0.18, 219.35 5.27, 220 22.5 M220 22.5 C218.53 36.8, 221.21 54.52, 220 67.5 M220 22.5 C221.08 35.77, 219.63 49.41, 220 67.5 M220 67.5 C218.84 82.47, 212.71 89.78, 197.5 90 M220 67.5 C221.72 82.7, 212.91 91.92, 197.5 90 M197.5 90 C128.7 92.94, 58.14 91.95, 22.5 90 M197.5 90 C157.26 90.24, 117.1 90.52, 22.5 90 M22.5 90 C7.29 88.92, 1.66 81.12, 0 67.5 M22.5 90 C6.81 91.89, 0.68 81.04, 0 67.5 M0 67.5 C-0.42 57.32, 0.89 48.98, 0 22.5 M0 67.5 C0.89 57.26, -0.08 47.56, 0 22.5 M0 22.5 C-0.17 5.98, 8.27 0.62, 22.5 0 M0 22.5 C1.24 7.48, 7.89 0.53, 22.5 0" stroke="#8b5cf6" stroke-width="2" fill="none"/></g><g transform="translate(821.775390625 216.25) rotate(0 23.224609375 13.75)"><text x="23.224609375" y="19.381999999999998" font-family="Virgil, Segoe UI Emoji" font-size="22px" fill="#8b5cf6" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Opus</text></g><g stroke-linecap="round" transform="translate(735 340) rotate(0 110 45)"><path d="M22.5 0 C65.21 -1.47, 104.14 -2.18, 197.5 0 C212.42 -1, 218.03 4.11, 220 22.5 C222.37 34.71, 217.73 46.72, 220 67.5 C220.88 82.03, 214.45 92.31, 197.5 90 C149.43 91.32, 101.82 92.83, 22.5 90 C4.84 91.88, -0.35 79.32, 0 67.5 C-0.27 57.05, -1.54 44.97, 0 22.5 C-0.22 4, 10.54 -0.43, 22.5 0" stroke="none" stroke-width="0" fill="#a5d8ff"/><path d="M22.5 0 C86.44 2.23, 154.33 1.65, 197.5 0 M22.5 0 C81.34 2.41, 140.12 1.66, 197.5 0 M197.5 0 C212.44 0.36, 221.55 9.08, 220 22.5 M197.5 0 C212.32 -0.65, 217.77 8.73, 220 22.5 M220 22.5 C218.73 40.33, 220.54 56.32, 220 67.5 M220 22.5 C220.32 37.97, 220.68 54.12, 220 67.5 M220 67.5 C219.97 82.71, 212.28 91.49, 197.5 90 M220 67.5 C220.2 82.91, 214.42 92.29, 197.5 90 M197.5 90 C131.44 91.45, 62.93 89.61, 22.5 90 M197.5 90 C146.62 91.22, 96.75 90.43, 22.5 90 M22.5 90 C6.42 91.66, -1.38 81.9, 0 67.5 M22.5 90 C9.39 90.68, -1.46 80.83, 0 67.5 M0 67.5 C-0.14 58.19, 1.77 46.47, 0 22.5 M0 67.5 C-0.13 52.97, 0.58 38.3, 0 22.5 M0 22.5 C-1.52 8.27, 8.12 1.08, 22.5 0 M0 22.5 C-0.02 7.89, 8.03 0.05, 22.5 0" stroke="#4a9eed" stroke-width="2" fill="none"/></g><g transform="translate(814.44384765625 371.25) rotate(0 30.55615234375 13.75)"><text x="30.55615234375" y="19.381999999999998" font-family="Virgil, Segoe UI Emoji" font-size="22px" fill="#4a9eed" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Sonnet</text></g><g stroke-linecap="round" transform="translate(735 495) rotate(0 110 45)"><path d="M22.5 0 C60.1 -0.22, 95.93 -2.85, 197.5 0 C211.5 -1.97, 216.61 5.89, 220 22.5 C220.41 35.82, 220.93 55.49, 220 67.5 C219.53 84.45, 214.81 89.36, 197.5 90 C129.02 94.3, 62.84 88.51, 22.5 90 C9.38 89.65, -3.18 82.12, 0 67.5 C3.1 54.89, 4.05 46.2, 0 22.5 C-3.5 10.54, 7.07 -0.91, 22.5 0" stroke="none" stroke-width="0" fill="#c3fae8"/><path d="M22.5 0 C87.29 2.53, 149.84 1.84, 197.5 0 M22.5 0 C87.81 -0.08, 151.63 0.16, 197.5 0 M197.5 0 C212.86 1.55, 221.58 7.34, 220 22.5 M197.5 0 C211.85 -2.23, 221.23 9.27, 220 22.5 M220 22.5 C220.46 39.66, 219.49 57.59, 220 67.5 M220 22.5 C219.74 39.62, 219.79 56.03, 220 67.5 M220 67.5 C220.21 82.28, 213.99 90.18, 197.5 90 M220 67.5 C220.41 84.42, 214.79 91.97, 197.5 90 M197.5 90 C130.6 91.74, 61.39 91.01, 22.5 90 M197.5 90 C135.95 88.26, 72.92 88.18, 22.5 90 M22.5 90 C9.16 88.62, -0.6 84.15, 0 67.5 M22.5 90 C8.18 88.54, -1.67 80.62, 0 67.5 M0 67.5 C0.7 53.98, -1.19 36.99, 0 22.5 M0 67.5 C-0.42 51.9, -0.53 33.78, 0 22.5 M0 22.5 C0.77 8.12, 8.58 -0.02, 22.5 0 M0 22.5 C0.39 8.03, 7.55 -1.7, 22.5 0" stroke="#22c55e" stroke-width="2" fill="none"/></g><g transform="translate(818.11767578125 526.25) rotate(0 26.88232421875 13.75)"><text x="26.88232421875" y="19.381999999999998" font-family="Virgil, Segoe UI Emoji" font-size="22px" fill="#22c55e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">Haiku</text></g><g stroke-linecap="round" transform="translate(770 625) rotate(0 85 25)"><path d="M12.5 0 C70.2 -0.42, 122.72 -1.76, 157.5 0 C163.87 -3.39, 168.39 6.21, 170 12.5 C167.5 20.29, 171.12 25.11, 170 37.5 C171.95 48.14, 165.2 53.13, 157.5 50 C107.44 50.16, 48.45 51.31, 12.5 50 C3.82 46.82, -0.38 43.46, 0 37.5 C-1.98 35.14, -0.12 22.21, 0 12.5 C3.04 3.74, 3.26 -0.03, 12.5 0" stroke="none" stroke-width="0" fill="#ffd8a8"/><path d="M12.5 0 C52.72 -0.12, 90.83 0.18, 157.5 0 M12.5 0 C41.94 -1.08, 71.88 -0.9, 157.5 0 M157.5 0 C167.38 1.58, 169.84 3.61, 170 12.5 M157.5 0 C163.6 1.23, 171.77 5.94, 170 12.5 M170 12.5 C169.99 17.63, 170.95 24.41, 170 37.5 M170 12.5 C170.35 21.47, 169.98 31.7, 170 37.5 M170 37.5 C169.78 47.33, 166.01 50.36, 157.5 50 M170 37.5 C171.92 48.12, 167.81 51.95, 157.5 50 M157.5 50 C106.39 48.98, 54.07 51.46, 12.5 50 M157.5 50 C109.14 50.89, 61.15 51.83, 12.5 50 M12.5 50 C2.79 49.4, 1.65 46.43, 0 37.5 M12.5 50 C2.71 48.33, -1.88 46.85, 0 37.5 M0 37.5 C1.96 29.61, 0.46 25.8, 0 12.5 M0 37.5 C0.84 27.43, -0.8 17.91, 0 12.5 M0 12.5 C0.62 5.25, 4.15 0.34, 12.5 0 M0 12.5 C0.53 4.22, 2.46 -2.1, 12.5 0" stroke="#f59e0b" stroke-width="1" fill="none"/></g><g transform="translate(802.48046875 640) rotate(0 52.51953125 10)"><text x="52.51953125" y="14.096" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#f59e0b" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">GPT, Gemini, ...</text></g><g mask="url(#mask-atask)" stroke-linecap="round"><g transform="translate(250.5 360) rotate(0 54.5 0)"><path d="M0 0 C26.9 -0.04, 53 -2.68, 109 0 M0 0 C31.52 0.26, 63.23 1.07, 109 0" stroke="#1e1e1e" stroke-width="2" fill="none"/></g><g transform="translate(250.5 360) rotate(0 54.5 0)"><path d="M85.63 8.87 C92.17 7.34, 98 2.6, 109 0 M85.63 8.87 C92.32 6.34, 99.26 4.58, 109 0" stroke="#1e1e1e" stroke-width="2" fill="none"/></g><g transform="translate(250.5 360) rotate(0 54.5 0)"><path d="M85.39 -8.23 C92.14 -5.71, 98.02 -6.4, 109 0 M85.39 -8.23 C92.27 -5.81, 99.29 -2.63, 109 0" stroke="#1e1e1e" stroke-width="2" fill="none"/></g></g><mask id="mask-atask"><rect x="0" y="0" fill="#fff" width="459.5" height="460"/><rect x="292.11328125" y="350" fill="#000" width="25.7734375" height="20" opacity="1"/></mask><g transform="translate(292.11328125 350) rotate(0 12.88671875 9.669142936979483)"><text x="12.88671875" y="14.096" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#1e1e1e" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">task</text></g><g mask="url(#mask-aresults)" stroke-linecap="round"><g transform="translate(359.5 400) rotate(0 -54.5 0)"><path d="M0 0 C-41.01 1.97, -85.4 0.38, -109 0 M0 0 C-40.83 0.17, -80.82 0.78, -109 0" stroke="#06b6d4" stroke-width="2" fill="none"/></g><g transform="translate(359.5 400) rotate(0 -54.5 0)"><path d="M-85.4 -8.24 C-93.64 -3.57, -105.32 -2.01, -109 0 M-85.4 -8.24 C-94.28 -4.98, -102.31 -1.28, -109 0" stroke="#06b6d4" stroke-width="2" fill="none"/></g><g transform="translate(359.5 400) rotate(0 -54.5 0)"><path d="M-85.62 8.86 C-93.9 6.98, -105.5 1.98, -109 0 M-85.62 8.86 C-94.38 5.72, -102.32 3.02, -109 0" stroke="#06b6d4" stroke-width="2" fill="none"/></g></g><mask id="mask-aresults"><rect x="0" y="0" fill="#fff" width="568.5" height="500"/><rect x="284.11328125" y="390" fill="#000" width="41.7734375" height="20" opacity="1"/></mask><g transform="translate(284.11328125 390) rotate(0 20.88671875 10.482698962433403)"><text x="20.88671875" y="14.096" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#06b6d4" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">results</text></g><g stroke-linecap="round"><g transform="translate(590.5 354.5) rotate(0 72 -62)"><path d="M0 0 C54.18 -48.48, 106.06 -91.14, 144 -124 M0 0 C39.53 -33.06, 79.48 -67.79, 144 -124" stroke="#8b5cf6" stroke-width="2" fill="none"/></g><g transform="translate(590.5 354.5) rotate(0 72 -62)"><path d="M131.89 -102.13 C137.65 -112.2, 140.55 -116.93, 144 -124 M131.89 -102.13 C135.38 -107.33, 139.3 -114.15, 144 -124" stroke="#8b5cf6" stroke-width="2" fill="none"/></g><g transform="translate(590.5 354.5) rotate(0 72 -62)"><path d="M120.66 -115.03 C130.66 -120.35, 137.73 -120.29, 144 -124 M120.66 -115.03 C127.22 -116.7, 134.21 -120, 144 -124" stroke="#8b5cf6" stroke-width="2" fill="none"/></g></g><mask/><g stroke-linecap="round"><g transform="translate(590.5 380.5) rotate(0 72 2)"><path d="M0 0 C49.12 0.21, 103.52 1.3, 144 4 M0 0 C43.89 1.73, 86.15 1.86, 144 4" stroke="#4a9eed" stroke-width="2" fill="none"/></g><g transform="translate(590.5 380.5) rotate(0 72 2)"><path d="M120.26 11.83 C126.74 8.67, 138.54 5.58, 144 4 M120.26 11.83 C128.14 10.23, 134.4 6.82, 144 4" stroke="#4a9eed" stroke-width="2" fill="none"/></g><g transform="translate(590.5 380.5) rotate(0 72 2)"><path d="M120.78 -5.27 C127.14 -2.36, 138.75 0.6, 144 4 M120.78 -5.27 C128.51 -1.74, 134.6 -0.04, 144 4" stroke="#4a9eed" stroke-width="2" fill="none"/></g></g><mask/><g stroke-linecap="round"><g transform="translate(590.5 400.5) rotate(0 72 69.5)"><path d="M0 0 C49.17 49.39, 97.39 94.86, 144 139 M0 0 C43.74 40.24, 85.57 80.75, 144 139" stroke="#22c55e" stroke-width="2" fill="none"/></g><g transform="translate(590.5 400.5) rotate(0 72 69.5)"><path d="M121.29 128.55 C128.79 133.77, 136.12 135.79, 144 139 M121.29 128.55 C128.85 131.4, 134.53 133.62, 144 139" stroke="#22c55e" stroke-width="2" fill="none"/></g><g transform="translate(590.5 400.5) rotate(0 72 69.5)"><path d="M133.32 116.4 C136.86 125.6, 140.13 131.71, 144 139 M133.32 116.4 C137.32 122.95, 139.43 128.78, 144 139" stroke="#22c55e" stroke-width="2" fill="none"/></g></g><mask/><g mask="url(#mask-afeedback)" stroke-linecap="round"><g transform="translate(845 699.5) rotate(0 -185 -111.75)"><path d="M0 0 C1.1 14.41, -0.4 29.83, 0 40.5 M0 0 C0.24 12.59, -0.66 26.28, 0 40.5 M0 40.5 C-140.44 38.96, -278.78 38.37, -370 40.5 M0 40.5 C-132.37 41.98, -264.51 42.01, -370 40.5 M-370 40.5 C-369.14 -50.24, -369.97 -140.02, -370 -264 M-370 40.5 C-371.49 -80.63, -371.73 -202.64, -370 -264" stroke="#ef4444" stroke-width="2" fill="none"/></g><g transform="translate(845 699.5) rotate(0 -185 -111.75)"><path d="M-361.8 -240.38 C-363.12 -249.64, -367.64 -257.87, -370 -264 M-361.8 -240.38 C-364.67 -248.11, -368.17 -254.79, -370 -264" stroke="#ef4444" stroke-width="2" fill="none"/></g><g transform="translate(845 699.5) rotate(0 -185 -111.75)"><path d="M-378.9 -240.64 C-373.91 -249.78, -372.12 -257.92, -370 -264 M-378.9 -240.64 C-376.33 -248.41, -374.4 -255.02, -370 -264" stroke="#ef4444" stroke-width="2" fill="none"/></g></g><mask id="mask-afeedback"><rect x="0" y="0" fill="#fff" width="1315" height="1104"/><rect x="592.44921875" y="730" fill="#000" width="135.1015625" height="20" opacity="1"/></mask><g transform="translate(592.44921875 730) rotate(0 67.15270334605617 -141.6893477926463)"><text x="67.55078125" y="14.096" font-family="Virgil, Segoe UI Emoji" font-size="16px" fill="#ef4444" text-anchor="middle" style="white-space: pre;" direction="ltr" dominant-baseline="alphabetic">questions & progress</text></g></svg><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128" width="128" height="128">
<defs>
<!-- Checklist paper -->
<linearGradient id="paper" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#FFF9E6"/>
<stop offset="100%" stop-color="#F5EDDA"/>
</linearGradient>
<!-- Pigeon body gradient -->
<linearGradient id="body" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#8BA4B8"/>
<stop offset="100%" stop-color="#6B8299"/>
</linearGradient>
<!-- Wing gradient -->
<linearGradient id="wing" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#7A96AC"/>
<stop offset="100%" stop-color="#5A7A94"/>
</linearGradient>
</defs>
<!-- === CHECKLIST (held in beak, angled) === -->
<g transform="translate(18, 58) rotate(-12)">
<!-- Paper shadow -->
<rect x="2" y="2" width="30" height="38" rx="2" fill="#00000015"/>
<!-- Paper -->
<rect x="0" y="0" width="30" height="38" rx="2" fill="url(#paper)" stroke="#D4C5A0" stroke-width="0.8"/>
<!-- Checkbox rows -->
<!-- Row 1: checked -->
<rect x="4" y="5" width="5" height="5" rx="0.8" fill="none" stroke="#7B9B5A" stroke-width="1"/>
<path d="M5 7.5 L6.5 9 L8.5 5.5" fill="none" stroke="#7B9B5A" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="12" y="6" width="14" height="2" rx="1" fill="#C4B898"/>
<!-- Row 2: checked -->
<rect x="4" y="13" width="5" height="5" rx="0.8" fill="none" stroke="#7B9B5A" stroke-width="1"/>
<path d="M5 15.5 L6.5 17 L8.5 13.5" fill="none" stroke="#7B9B5A" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="12" y="14" width="11" height="2" rx="1" fill="#C4B898"/>
<!-- Row 3: unchecked -->
<rect x="4" y="21" width="5" height="5" rx="0.8" fill="none" stroke="#B8A88A" stroke-width="1"/>
<rect x="12" y="22" width="14" height="2" rx="1" fill="#D4C5A0"/>
<!-- Row 4: unchecked -->
<rect x="4" y="29" width="5" height="5" rx="0.8" fill="none" stroke="#B8A88A" stroke-width="1"/>
<rect x="12" y="30" width="9" height="2" rx="1" fill="#D4C5A0"/>
</g>
<!-- === PIGEON === -->
<g>
<!-- Tail feathers -->
<ellipse cx="100" cy="72" rx="16" ry="6" fill="#5A7A94" transform="rotate(-20, 100, 72)"/>
<ellipse cx="103" cy="68" rx="14" ry="5" fill="#6B8299" transform="rotate(-25, 103, 68)"/>
<!-- Body -->
<ellipse cx="72" cy="60" rx="26" ry="20" fill="url(#body)" transform="rotate(-8, 72, 60)"/>
<!-- Chest/belly (lighter) -->
<ellipse cx="60" cy="65" rx="14" ry="13" fill="#C8D4DC" transform="rotate(-5, 60, 65)"/>
<!-- Wing (raised, in flight) -->
<g transform="translate(65, 28)">
<!-- Primary wing shape -->
<path d="M0 30 Q-5 15, 8 5 Q18 -5, 32 0 Q25 10, 20 20 Q15 28, 5 32 Z"
fill="url(#wing)" stroke="#4A6A82" stroke-width="0.5"/>
<!-- Wing feather lines -->
<path d="M8 5 Q12 15, 5 30" fill="none" stroke="#4A6A82" stroke-width="0.5" opacity="0.5"/>
<path d="M18 2 Q18 15, 12 28" fill="none" stroke="#4A6A82" stroke-width="0.5" opacity="0.5"/>
<path d="M27 3 Q23 15, 18 25" fill="none" stroke="#4A6A82" stroke-width="0.5" opacity="0.5"/>
</g>
<!-- Neck iridescence -->
<ellipse cx="54" cy="48" rx="8" ry="10" fill="#6A8E7A" opacity="0.4" transform="rotate(-10, 54, 48)"/>
<ellipse cx="53" cy="50" rx="6" ry="8" fill="#8A6E9A" opacity="0.25" transform="rotate(-10, 53, 50)"/>
<!-- Head -->
<circle cx="46" cy="38" r="11" fill="#8BA4B8"/>
<!-- Eye -->
<circle cx="42" cy="36" r="3.5" fill="#2A2A2A"/>
<circle cx="42" cy="36" r="2.2" fill="#E85D26"/>
<circle cx="42" cy="36" r="1.2" fill="#1A1A1A"/>
<circle cx="40.8" cy="34.8" r="0.8" fill="#FFFFFF" opacity="0.8"/>
<!-- Beak (holding the checklist) -->
<path d="M34 40 L26 43 L34 45 Z" fill="#E8A840" stroke="#D49530" stroke-width="0.5"/>
<!-- Beak top half -->
<path d="M34 40 L26 43 L34 42.5 Z" fill="#F0B850"/>
<!-- Feet (tucked, in flight) -->
<g fill="#D48040" stroke="#C07030" stroke-width="0.5">
<path d="M65 78 L62 85 L60 83 M62 85 L64 83"/>
<path d="M72 77 L70 85 L68 83 M70 85 L72 83"/>
</g>
</g>
<!-- === Motion lines (speed/dispatch feel) === -->
<g stroke="#8BA4B8" stroke-width="1.2" stroke-linecap="round" opacity="0.4">
<line x1="108" y1="45" x2="120" y2="42"/>
<line x1="110" y1="55" x2="124" y2="54"/>
<line x1="108" y1="65" x2="118" y2="66"/>
</g>
</svg>
/dispatch
You don't need 6 terminals. You need one session that delegates.
/dispatch turns your AI coding session into a command center. You describe work, it plans a checklist, fans out to background workers — Claude, GPT, Gemini — and tracks progress. You stay in one clean session. Workers do the heavy lifting in isolated contexts.
<p align="center"> <img src="assets/before-after.svg" alt="Architecture diagram: Your Session sends a task to the Dispatcher, which fans out to Opus, Sonnet, and Haiku workers in parallel, with a feedback loop for questions and progress. Also supports GPT, Gemini, and other models." width="900" /> </p>
/dispatch "do a security review of this project"Host requirement: Dispatch runs inside Claude Code — it must be your active session. Other CLIs like Cursor and Codex work as workers only (they execute subtasks in the background).
---
Why dispatch
Your main session stays lean
The dispatcher never does the actual work. It plans, delegates, and tracks. The heavy reasoning — code review, refactoring, test writing — happens in isolated worker contexts. Your main session's context window is preserved for orchestration, not consumed by implementation details.
Workers ask questions back
This is the part most agent orchestrators get wrong. When a /dispatch worker gets stuck, it doesn't silently fail or hallucinate. It asks a clarifying question — the dispatcher surfaces it to you, you answer, and the worker continues without losing context. No restart, no re-explaining, no lost work.
Worker is asking: "requirements.txt doesn't exist. What feature should I implement?"
> Add a /health endpoint that returns JSON with uptime and version.
Answer sent. Worker is continuing.Non-blocking — you never wait
The moment a worker is dispatched, your session is immediately free. Dispatch another task. Ask a question. Write code. The dispatcher handles multiple workers in parallel, reports results as they arrive, and surfaces questions only when they need your input. No polling, no tab-switching, no "is it done yet?"
Any model, one interface
Mix models per task. Claude for deep reasoning, GPT for broad generation, Gemini for speed. Reference any model by name — if it's not in your config, /dispatch auto-discovers and adds it.
/dispatch "use gemini-3.1-pro to review the API layer"---
How it works
1. You run /dispatch "task description" 2. A checklist plan is created at .dispatch/tasks/<id>/plan.md 3. A background worker picks it up and checks off items as it goes 4. If the worker has a question, it asks — you answer — it continues 5. You get results when it's done, or ask for status anytime
Setup
On first run, /dispatch auto-detects your CLIs (claude, agent, codex), discovers available models, and generates ~/.dispatch/config.yaml. No manual config needed.
Configuration
Three sections in ~/.dispatch/config.yaml:
Backends — CLI commands for each provider:
backends:
claude:
command: >
env -u CLAUDE_CODE_ENTRYPOINT -u CLAUDECODE
claude -p --dangerously-skip-permissions
cursor:
command: >
agent -p --force --workspace "$(pwd)"
codex:
command: >
codex exec --full-auto -C "$(pwd)"Models — one line each, mapped to a backend:
models:
opus: { backend: claude }
sonnet: { backend: claude }
gpt-5.3-codex: { backend: codex }
gemini-3.1-pro: { backend: cursor }Aliases — named shortcuts with optional role prompts:
aliases:
security-reviewer:
model: opus
prompt: >
You are a security-focused reviewer. Prioritize OWASP Top 10.See `references/config-example.yaml` for the full example.
Adding models
Reference any model by name — if it's not in your config, /dispatch auto-discovers and adds it:
/dispatch "use gemini-3.1-pro to review the API layer"Or add manually: /dispatch "add gpt-5.3 to my config"
Plan markers
| Marker | Meaning |
|---|---|
[ ] | Pending |
[x] | Done |
[?] | Blocked — waiting for your answer |
[!] | Error |
Host compatibility
Host (the session where you type `/dispatch`): Claude Code.
Workers (background agents that execute subtasks): Any CLI that accepts a prompt — Cursor CLI, Codex CLI, Claude Code, or anything you define in config.
Best practice: warm up at session start
Run /dispatch with no arguments at the beginning of a session to pre-load your config:
/dispatchThis reads ~/.dispatch/config.yaml into the dispatcher's context so subsequent dispatches are faster and don't need confirmation prompts. It's a good habit to add as a Claude Code memory so you remember to do it each session:
"Run /dispatch at the start of each session to warm up the config."
Cleanup
Delete .dispatch/ to clean up task files.
# ~/.dispatch/config.yaml
# Worker configuration for /dispatch
#
# This file is auto-generated by first-run setup, but you can edit it freely.
# Run `/dispatch "migrate my config"` to regenerate from detected models.
default: opus # Default model (by name or alias)
# Backends: CLI commands for each provider
# For cursor backend: --model <id> is appended automatically when dispatching.
# For claude backend: --model is NOT appended (CLI manages its own model selection).
# For codex backend: --model <id> is appended automatically when dispatching.
#
# Cursor CLI flags:
# -p / --print Non-interactive print mode
# -f / --force Auto-approve tool usage (file writes, commands)
# --model <name> Model to use (run `agent models` to list available)
# --workspace <p> Set workspace directory
#
# Claude Code flags:
# -p Print mode (non-interactive)
# --dangerously-skip-permissions Skip permission prompts
# --model <name> Model override (sonnet, haiku, opus, etc.)
#
# Codex CLI flags:
# exec Non-interactive subcommand
# --full-auto Workspace-write sandbox + auto-approve
# -C / --cd Set working directory
# -m / --model Model to use (e.g., gpt-5.3-codex)
backends:
claude:
command: >
env -u CLAUDE_CODE_ENTRYPOINT -u CLAUDECODE
claude -p --dangerously-skip-permissions
cursor:
command: >
agent -p --force --workspace "$(pwd)"
codex:
command: >
codex exec --full-auto -C "$(pwd)"
# Models: each model maps to a backend.
# For cursor/codex backend: --model <id> is appended to the command automatically.
# For claude backend: the CLI uses its own default model (no --model appended).
#
# Backend preference:
# - Claude models (opus, sonnet, haiku) → claude backend
# - OpenAI models (gpt-*, codex, o1, o3, o4-mini) → codex backend (falls back to cursor)
# - Other models → cursor backend
#
# Add or remove models freely — run `agent models` to see what's available.
models:
# Claude (use stable aliases — auto-resolve to latest version)
opus: { backend: claude }
sonnet: { backend: claude }
haiku: { backend: claude }
# GPT / OpenAI (prefer codex backend when available)
gpt-5.3-codex: { backend: codex }
gpt-5.3-codex-spark: { backend: codex }
gpt-5.2: { backend: codex }
# Gemini
gemini-3.1-pro: { backend: cursor }
# Cursor
composer-1.5: { backend: cursor }
# Aliases: named shortcuts with optional prompt additions.
# Reference by name in dispatch commands (e.g., "have security-reviewer look at this").
aliases:
security-reviewer:
model: opus
prompt: >
You are a security-focused reviewer. Prioritize OWASP Top 10
vulnerabilities, auth flaws, and injection risks.
quick:
model: sonnet
# Example: GPT-based code reviewer
# gpt-reviewer:
# model: gpt-5.3-codex
# prompt: >
# Focus on code quality, naming conventions, and test coverage.
Modifying Config
1. Read ~/.dispatch/config.yaml. If it doesn't exist, run First-Run Setup (above), then continue.
2. Apply the user's requested change. The config uses the new schema with backends:, models:, and aliases:.
Adding a model:
- If user says "add gpt-5.3 to my config": probe
agent modelsto verify availability, then add tomodels:with the appropriate backend. - Example:
gpt-5.3: { backend: cursor }
Creating an alias:
- If user says "create a security-reviewer alias using opus": add to
aliases:with optional prompt. - Example:
aliases:
security-reviewer:
model: opus
prompt: >
You are a security-focused reviewer. Prioritize OWASP Top 10
vulnerabilities, auth flaws, and injection risks.Changing the default:
- If user says "switch default to sonnet": update
default:field.
Removing a model:
- If user says "remove gpt-5.2": delete from
models:.
3. Run mkdir -p ~/.dispatch then write the updated file to ~/.dispatch/config.yaml. 4. Tell the user what you changed. Done.
Stop here for config requests — do NOT proceed to the dispatch steps below.
First-Run Setup
Triggered when ~/.dispatch/config.yaml does not exist (checked in Step 0 or Modifying Config). Run through this flow, then continue with the original request.
1. Detect CLIs
which agent 2>/dev/null # Cursor CLI
which claude 2>/dev/null # Claude Code
which codex 2>/dev/null # Codex CLI (OpenAI)2. Discover models
Strategy depends on what CLIs are available:
If Cursor CLI is available (covers most cases):
- Run
agent models 2>&1— this lists ALL models the user has access to, including Claude, GPT, Gemini, etc. - Parse each line: format is
<id> - <Display Name>(strip(current)or(default)markers if present). - This is the single source of truth for model availability.
- For Claude models found here (IDs containing
opus,sonnet,haiku), route through theclaudebackend when Claude Code CLI is available.
If only Claude Code is available (no Cursor):
- Claude CLI has no
modelscommand. - Use stable aliases:
opus,sonnet,haiku. These auto-resolve to the latest version (e.g.,opus→claude-opus-4-6today, and will resolve to newer versions as they release). - This is intentionally version-agnostic — no hardcoded version numbers that go stale.
If Codex CLI is available:
- Codex has no
codex modelscommand. Use a curated set of known model IDs:gpt-5.3-codex,gpt-5.3-codex-spark,gpt-5.2. - OpenAI models (IDs containing
gpt,codex,o1,o3,o4-mini) should prefer thecodexbackend when available. - If Cursor CLI is also available,
agent modelsmay list OpenAI models — prefer routing those throughcodexwhen the Codex CLI is installed.
If multiple CLIs are available:
- Use
agent modelsas primary source for model discovery (it's comprehensive). - Additionally note Claude Code is available as a backend for Claude models.
- Additionally note Codex is available as a backend for OpenAI models.
- Prefer native backends: Claude models →
claudebackend, OpenAI models →codexbackend.
If neither is found:
- Tell the user: "No worker CLI found. Install the Cursor CLI (
agent), Claude Code CLI (claude), or Codex CLI (codex), or create a config at~/.dispatch/config.yaml." - Show them the example config at
${SKILL_DIR}/references/config-example.yamland stop.
3. Present findings via AskUserQuestion
- Show a summary: "Found Cursor CLI with N models" / "Found Claude Code" / "Found Codex CLI"
- List a few notable models (top models from each provider — don't dump 30+ models)
- Ask: "Which model should be your default?"
- Offer 3-4 sensible choices (e.g., the current Cursor default, opus, sonnet, a GPT option)
4. Generate ~/.dispatch/config.yaml
Build the config file with the new schema:
default: <user's chosen default>
backends:
claude:
command: >
env -u CLAUDE_CODE_ENTRYPOINT -u CLAUDECODE
claude -p --dangerously-skip-permissions
cursor:
command: >
agent -p --force --workspace "$(pwd)"
codex:
command: >
codex exec --full-auto -C "$(pwd)"
models:
# Claude
opus: { backend: claude }
sonnet: { backend: claude }
haiku: { backend: claude }
# GPT / OpenAI
gpt-5.3-codex: { backend: codex }
# ... all detected models grouped by providerRules:
- Include all detected models — they're one-liners and it's better to have them available than to require re-discovery.
- Group by provider with YAML comments for readability (
# Claude,# GPT,# Gemini, etc.). - Claude model detection: Any model ID containing
opus,sonnet, orhaiku(including versioned variants likesonnet-4.6,opus-4.5-thinking, etc.) is a Claude model. When the Claude Code CLI is available, ALL Claude models must usebackend: claude. Never route Claude models through the cursor backend — the Claude CLI manages model selection natively and doesn't need--model. - OpenAI model detection: Any model ID containing
gpt,codex,o1,o3, oro4-miniis an OpenAI model. When the Codex CLI is available, ALL OpenAI models must usebackend: codex. Only fall back tocursorbackend for OpenAI models when Codex is not installed. - Only include backends that were actually detected.
- Set user's chosen default.
- Run
mkdir -p ~/.dispatchthen write the file.
5. Continue
Proceed with the original dispatch or config request — no restart needed.
Example
User: /dispatch "review the auth module"
Dispatcher: [no ~/.dispatch/config.yaml found — running first-run setup]
Dispatcher: [runs `which agent` → found, `which claude` → found]
Dispatcher: [runs `agent models` → 15 models detected]
Dispatcher: Found Cursor CLI (15 models) and Claude Code. Notable models:
- opus (Claude) — best for complex tasks
- sonnet (Claude) — fast and capable
- gpt-5.3-codex (GPT) — strong for code
AskUserQuestion: Which model should be your default?
1. opus (Recommended)
2. sonnet
3. gpt-5.3-codex
User: opus
Dispatcher: [generates ~/.dispatch/config.yaml with all 15 models, default: opus]
Dispatcher: Config created at ~/.dispatch/config.yaml with 15 models. Default: opus.
Dispatcher: [continues with the original task — dispatches security review using opus]IPC Protocol Specification
The IPC system uses sequence-numbered files in .dispatch/tasks/<task-id>/ipc/ for bidirectional communication between the worker and dispatcher.
Directionality
IPC is worker-initiated only. The worker writes questions; the dispatcher writes answers to those questions. The dispatcher must never write unsolicited files to the IPC directory — the worker will not detect or process them.
To provide additional context to a running worker, append notes to the plan file instead (see Adding Context to a Running Worker above).
File naming
001.question— Worker's question (plain text)001.answer— Dispatcher's answer (plain text)001.done— Acknowledgment from worker that it received the answer- Sequence numbers are zero-padded to 3 digits:
001,002,003, etc.
Atomic write pattern
All writes use a two-step pattern to prevent reading partial files: 1. Write to <filename>.tmp 2. mv <filename>.tmp <filename> (atomic on POSIX filesystems)
Both the worker (writing questions) and the dispatcher (writing answers) follow this pattern.
Sequence numbering
The next sequence number is derived from the count of existing *.question files in the IPC directory, plus one. The worker determines this when it needs to ask a question.
Startup reconciliation
If the dispatcher restarts mid-conversation (e.g., user closes and reopens the session), it should scan the IPC directory for unanswered questions on any active task:
1. List all task directories under .dispatch/tasks/. 2. For each, check ipc/ for *.question files without matching *.answer files. 3. If found, surface the question to the user and resume the IPC flow from step 3 onward.
This ensures questions are never silently lost.
Proactive Recovery
When a worker fails to start or errors immediately:
1. Check CLI availability:
which agent 2>/dev/null
which claude 2>/dev/null
which codex 2>/dev/null2. If the CLI is gone or auth fails:
- Tell the user: "The [cursor/claude/codex] CLI is no longer available."
- List alternative models/backends still available in the config.
- Ask: "Want me to switch your default and retry with [alternative]?"
3. If the user agrees:
- Update
default:in config to the alternative model. - Re-dispatch the task with the new model.
4. If no alternatives exist:
- Tell the user to install a CLI (
agent,claude, orcodex) or fix their auth, and stop.
Related skills
How it compares
Choose dispatch over ad-hoc prompting when the input is a narrative requirement and the deliverable must be a sequenced agent checklist rather than immediate code.
FAQ
What does dispatch output for coding agents?
dispatch outputs an ordered, executable task list derived from a high-level spec or user story. Each step is scoped so Claude, Cursor, or other agents can implement features without inventing extra requirements beyond the original brief.
When should developers use dispatch instead of coding directly?
Developers should use dispatch when a requirement is still narrative—specs, epics, or user stories—and the next step is structured planning. dispatch is meant before code generation so agents follow a bounded checklist rather than improvising scope.
Is Dispatch safe to install?
skills.sh reports 0 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.