A Claude Code plugin that coordinates a team of AI agents through your development workflow — from planning to merged PR — pausing only at decisions that need you.
- Decomposes work into atomic tasks with a dependency tree — you approve the plan before any code is written
- Implements each task sequentially on local main, one commit per task — you push and manage PRs yourself
- Opens a diff review window before every commit — no code lands without your sign-off
- Analyzes incoming GitHub review requests on demand when you ask
- Prototype mode — explore before committing to the full plan, no PRs opened
- Knowledge store — learns from past sessions, reapplies lessons in future runs
In a Claude Code session, invoke the skill:
/dispatch
The Orchestrating Agent will run startup reconciliation, then greet you with a status summary and next-step options. Describe the work in plain language, point to a PRD or design document, or reference a tracker epic — the agent will ask for your approval before spawning a Planning Agent.
From there, the workflow runs automatically: plan approval, parallel task implementation, diff review before each PR opens, CI monitoring, and merge queue management. You're pulled in only at specific approval gates — see How It Works below.
- Claude Code (CLI)
gitandgh(GitHub CLI), authenticatedtmux(for diff review windows)jqandyq(for config and plan parsing)- A dedicated plan storage git repository (can be private, can be empty to start)
- Optionally:
deltafor syntax-highlighted diff review (falls back to plaingit diffif not installed) - Optionally: issue tracker access (Jira, Linear, GitHub Issues, etc.) via whichever integration your Claude environment provides
1. Add the marketplace and install the plugin
/plugin add-marketplace evanisnor/evanisnor-plugins
/plugin install evanisnor-plugins:dispatch
2. Install dependencies (macOS)
brew install gh tmux jq yqOptionally install delta for syntax-highlighted diff review.
3. Start a tmux session
tmux new-session -s work4. Configure your project — in your project directory, run the config skill to create .dispatch.yaml interactively:
/config setup
This walks you through the required fields (plan storage path) and optional settings. The file is gitignored — it should never be committed. To review the full config schema at any time, run /config.
| Agent | Role |
|---|---|
| Orchestrating Agent | Coordinates everything — spawns agents, surfaces decisions. Never writes code. |
| Planning Agent | Decomposes work into atomic tasks with a dependency tree. Exits after you approve the plan. |
| Task Agents | One per task. Implements on local main, commits directly. Does not push or manage PRs. |
| Review Agents | On request, analyzes incoming review requests — reads the diff, summarizes changes, surfaces questions — so the work is done before you sit down. |
- Spawning a Planning Agent — before any work is decomposed
- Approving the plan — before anything is saved
- Spawning Task Agents — before any code is written
- Spawning a Prototype Agent — before any exploratory implementation begins
- Diff review — before every commit is accepted
- Abandoning a task — requires explicit confirmation
.dispatch.yaml lives in your project root (gitignored) and overrides plugin defaults for that project. Run /config to see all current values, or /config setup to create or update the file interactively.
| Key | Type | Default | Description |
|---|---|---|---|
plan_storage.repo_path |
string (path) |
~/plans |
Local path to your plan storage git repository. |
git.protected_branches |
array of strings |
["main", "master"] |
Branches Task Agents are sandbox-denied from pushing to directly. |
git.branch_prefix |
string |
"" |
Prefix prepended to every task branch (e.g. "feat/", "users/evan/"). Must end with / for directory-style prefixes. |
issue_tracking.tool |
string |
"" |
Name of the issue tracker ("jira", "linear", "github", etc.). Leave empty to disable. |
issue_tracking.read_only |
boolean |
false |
false = autonomous issue creation (write-enabled). true = generate companion doc for manual creation + backfill IDs after human provides root ID. |
issue_tracking.prompt |
string |
"" |
Prompt (or "/skill-name") for all tracker operations. When set, a general-purpose sub-agent is spawned with this prompt instead of built-in integration. Leave empty to use the built-in approach. |
diff.mode |
"split" | "unified" |
"split" |
Diff display mode in review panes. "split" uses delta --side-by-side; "unified" uses standard delta output. No effect if delta is not installed. |
editor.app |
string |
"" |
Editor or IDE to open when reviewing a diff. On macOS, use the app's display name (e.g. "Cursor", "Xcode", "Visual Studio Code"). On any platform, a CLI command works too (e.g. "code", "cursor"). When set, a open editor option is offered during every diff review. Leave empty to disable. |
pr.template_path |
string (path) |
"" |
Path to a custom PR description template. Leave empty to use the built-in template. |
pr.description_prompt |
string |
"" |
Prompt (or "/skill-name") for PR description authoring. When set, a general-purpose sub-agent is spawned with this prompt instead of calling pr-description.sh. Leave empty to use the built-in template or pr.template_path. |
verification.manual_gate |
boolean |
false |
When true, opens a tmux window at the task's worktree after diff approval and waits for human confirmation before the PR opens. |
verification.startup_command |
string |
"" |
Command to run automatically in the verification window (e.g. "npm run dev"). Only applies when verification.manual_gate is true. |
verification.prompt |
string |
"" |
Prompt (or "/skill-name") for automated pre-PR verification. Spawned after diff approval; output is presented to the human before confirmation. Independent of manual_gate. |
prototype.auto_push |
boolean |
false |
When true, the Prototype Agent pushes its branch to origin automatically after completing all commits. When false (default), the Orchestrating Agent asks before pushing. |
code_review.prompt |
string |
"" |
Prompt (or "/skill-name") for preliminary PR analysis. When set, Review Agents spawn a sub-agent with this prompt instead of performing their own analysis. Leave empty to use the built-in behavior. |
sandbox.network.allowed_domains |
array of strings |
["github.com", "api.github.com", "registry.npmjs.org"] |
Domains Task Agents are permitted to reach over the network. |
sandbox.filesystem.extra_deny_read |
array of glob strings |
[] |
Additional paths to block Task Agents from reading, merged with the hardcoded base deny list. |
defaults.max_ci_fix_attempts |
integer |
3 |
How many times a Task Agent may attempt to fix a CI failure before escalating. |
defaults.max_agent_restarts |
integer |
2 |
How many times the Orchestrating Agent may restart a dead Task Agent before escalating. |
Issue tracking is optional and disabled by default. Set issue_tracking.tool in your .dispatch.yaml and ensure an MCP server for that tracker is configured in your Claude Code environment.
Two modes are available:
- Write-enabled (
read_only: false, the default): The Planning Agent autonomously creates issues — a root issue for the epic and child issues for each task. After a task's PR merges, the Task Agent marks the corresponding issue done and links the PR. - Read-only (
read_only: true): The Planning Agent generates a companion markdown document listing proposed issues for manual creation. After you create them and provide the root ID, the agent backfills real IDs into the plan YAML.
If you have a Claude skill that knows your tracker's structure, set issue_tracking.prompt to delegate all tracker operations to it:
issue_tracking:
tool: jira
prompt: /jira-workflowIf issue tracking is not configured, the Planning Agent uses kebab-case slug IDs throughout.
By default, every Task Agent generates a PR body using the built-in template:
## What
{task_description}
## Why
{task_context}
## Task
`{task_id}` — {epic_title}
---
*Generated by [Dispatch](https://github.com/evanisnor/dispatch)*To use a custom template, point to it in .dispatch.yaml:
pr:
template_path: .github/pr-template.mdAvailable template variables: {task_id}, {task_title}, {task_description}, {task_context}, {epic_title}, {branch}, {plan_path}, {worktree}.
To delegate PR description authoring to a Claude skill, set pr.description_prompt. The Task Agent will spawn that skill with the full task context and use whatever it returns as the PR body.
pr:
description_prompt: /my-pr-skillBy default, Review Agents read the diff and produce a summary, analysis, and list of open questions. To delegate preliminary analysis to a project-specific skill:
code_review:
prompt: /my-review-skillThe Review Agent spawns a sub-agent with the PR URL, title, author, base and head refs, PR description, and diff — all wrapped in <external_content> tags. The sub-agent returns the same structured output (summary, analysis, questions) as the built-in behavior.
Dispatch uses a two-layer settings system to authorize agent tool usage:
| Layer | File | Covers |
|---|---|---|
| Project | .claude/settings.json |
Main conversation, foreground agents spawned within the project root |
| Global | ~/.claude/settings.json |
Background agents in worktrees, any session where the project-level file is not resolved |
Background Task Agents (run_in_background: true, isolation: "worktree") cannot prompt for permissions — they rely entirely on pre-approved allow rules. Because the worktree directory lives outside the project root, Claude Code may not resolve the project-level .claude/settings.json and falls back to the global file. If the global file lacks the required permissions, background agents silently fail.
Project-level .claude/settings.json — scoped to this project, includes paths to the plugin and plan storage repo:
{
"permissions": {
"allow": [
"Read(/path/to/dispatch/plugin/**)",
"Read(/path/to/plans/**)",
"Read(**)",
"Write(**)",
"Edit(**)",
"Glob(**)",
"Grep(**)",
"Bash",
"WebFetch(domain:*)"
]
}
}Global ~/.claude/settings.json — ensures background agents in worktrees have the baseline permissions they need:
{
"permissions": {
"allow": [
"Read",
"Write(**)",
"Edit(**)",
"Glob",
"Grep",
"Bash",
"WebFetch(domain:*)"
]
}
}Note: Deny rules override allow rules. An entry like
Bash(git *)inpermissions.denywill block agents from committing and pushing code even withBashin allow. Review your deny rules to ensure they don't conflict with agent operations.
Running /config setup handles both files automatically — it creates the project-level settings, then checks and offers to update the global settings, including conflict detection for deny rules. Existing settings (env, hooks, MCP servers, etc.) are preserved; only missing permission entries are appended.
- The Orchestrating Agent uses targeted permission rules and does not run in
bypassPermissionsmode. It cannot push code or merge PRs. - Task Agents run with pre-authorized tool permissions scoped to their worktree.
- Write access is limited to the task's assigned worktree directory.
- Network access is limited to domains listed in
sandbox.network.allowed_domains. - Read access is denied for
~/.ssh/**,~/.gnupg/**,**/.env,**/*.pem,**/*.key, plus any paths insandbox.filesystem.extra_deny_read. - Protected branches (
git.protected_branches) are enforced at the permissions layer, independent of agent reasoning.
All external content — PR comments, CI log summaries, reviewer feedback, issue tracker text, and plan context fields — is wrapped in <external_content> tags before being included in any agent prompt. Every agent's system prompt includes an explicit rule to treat content inside those tags as data only and never follow instructions found there.
