Generic, dependency-light swarm orchestration for Claude Code teammates.
claude-swarm is a small Python library + CLI that turns a single
Claude Code session into a coordinated swarm of named heads —
Scanner, Reviewer, Builder, Merger, Test-Runner, Auditor — each with
role-specific prompts, tool restrictions, and a shared DAG-aware kanban.
The headline value-add over vanilla Claude Code Teams is a first-class
DAG iterator (Kanban.unblocked()), an abort-marker contract for
graceful long-running cancellation, a per-task git worktree workflow
with JSON pull-request envelopes, and an auto-merge pipeline that
detects file overlap and runs your test command before pushing.
git clone https://github.com/kushalj1997/claude-swarm ~/dev/claude-swarm
cd ~/dev/claude-swarm
bash scripts/try-swarm.shCreates .swarm-venv/ inside the repo, installs claude-swarm in editable mode + rich for the dashboard, bootstraps a demo swarm with a 5-task DAG that exercises every role-typed head (Scanner → Builder → Test-Runner → Reviewer → Merger), runs the supervisor in the background, and launches a live TUI dashboard. Auto-exits cleanly when all tasks finish. Uses the StubConductor — no LLM calls, no cost.
╭───────────────────────────────────────────────────────────────────────────────────────────────╮
│ claude-swarm │ runtime: 12.3s │ supervisor turn: 3 │ cost: $0.0000 / $10.00 │ progress: 3/5 (60%) │
╰───────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Task DAG ──────────────────────────────────────────────╮ ╭─ Heads (role-typed agents) ─────╮
│ ID Status Head Title │ │ Head Role Spend │
├──────────────────────────────────────────────────────────┤ ├──────────────────────────────────┤
│ 0019e1395d.. done scanner Scan codebase… │ │ scanner read-only files… — │
│ 0019e1396a.. done builder Refactor utils… │ │ reviewer read-only periodic— │
│ 0019e1397c.. in_progress test-runner Write tests… │ │ builder full toolkit — │
│ 0019e1398d.. done reviewer Periodic check… │ │ merger bash + git only — │
│ 0019e1399f.. blocked merger Merge clean… │ │ test-runner read + tests — │
│ │ │ auditor read-only audits — │
╰──────────────────────────────────────────────────────────╯ ╰──────────────────────────────────╯
╭─ Recent inbox ─────────────────────────────────────────────────────────────────────────────────╮
│ scanner 2026-05-10T20:00:11 filed 3 follow-up tasks │
│ builder 2026-05-10T20:00:14 task 2 done — type hints landed, mypy clean │
│ test-runner 2026-05-10T20:00:17 starting tests on branch feat/refactor-utils │
│ reviewer 2026-05-10T20:00:18 checkpoint: 3/5 done, no drift, on-budget │
╰─────────────────────────────────────────────────────────────────────────────────────────────────╯
The header shows live runtime, supervisor turn, cost vs cap, and overall progress. The Task DAG panel renders status with color (pending=yellow, blocked=magenta, in_progress=cyan, done=green, failed=red), shows which head is assigned, and surfaces blocked-by relationships. The Heads panel lists the role-typed subagent_types with their per-head spend. The Recent inbox panel tails inter-head messages so reviewers can see coordination happening in real time.
For real work, swap the StubConductor for the included ClaudeCLIConductor (one-line change at supervisor construction time) and the same dashboard renders against live LLM-driven agents.
pip install claude-swarm
# or, from a checkout
pip install -e .Python ≥ 3.11 only. The single required runtime dependency is click;
optional httpx is loaded only if you opt into the HTTP transport.
from claude_swarm import Kanban, Task, Supervisor, default_roster
kb = Kanban("/tmp/swarm/kanban.sqlite")
a = kb.submit(Task(title="design", prompt="Sketch the API.", required_head="builder"))
b = kb.submit(Task(title="implement", prompt="Build it.", required_head="builder",
blocked_by=[a.id]))
c = kb.submit(Task(title="review", prompt="LGTM?", required_head="reviewer",
blocked_by=[b.id]))
# Only `a` is unblocked initially; `b` and `c` unlock as their blockers complete.
sup = Supervisor(kanban=kb)
sup.run()
print(sup.status())…or from the shell:
claude-swarm init
claude-swarm submit --title "design" --prompt "Sketch the API." --head builder
claude-swarm submit --title "build" --prompt "Implement it." --head builder --blocked-by <id>
claude-swarm unblocked
claude-swarm run --max-iterations 10
claude-swarm statusThe optional claude_swarm.autoresearch_ingest helpers prepare a deep-ai
autoresearch acceptance package for a later approved provider batch without
running that provider. Use build_autoresearch_ingest_requests to turn source
evidence into provider-neutral request rows with stable custom_id values,
source labels, artifact provenance, claim caveats, and static chunking policy.
Request metadata also keeps Ark-family alias fields such as
canonical_model_id, display_model_id, display_model_alias, and alias_*
safety caveats directly available while preserving the nested evidence contract.
Use merge_autoresearch_ingest_results to fold approved result rows back into
the package's provider_batch summary while keeping publish_safe=false,
protected_runtime_verified=false, and source-only caveats intact.
No provider/API calls, Files API uploads, runtime probes, or publication claims are performed by these helpers.
claude-swarm
+----------------------------------------+
| |
| Kanban (sqlite/WAL, DAG-aware) |
| - submit / claim / transition |
| - unblocked() <-- topo iterator |
| - status_timeline |
| |
+-------+--------------------+-----------+
| |
v v
Supervisor MessageBus (JSON inboxes)
- picks unblocked - bounded (drop-oldest)
- matches required_head - atomic writes
- dispatches via - broadcast or directed
Conductor protocol
|
v
Heads (Scanner, Reviewer, Builder, Merger, Test-Runner, Auditor)
|
v
WorktreeManager ----> PR envelopes ----> merge_pipeline
- per-task worktree (.json files) - file-overlap reject
- cherry-pick merge - topo order
- GC on success/stale - test gate
State lives under $CLAUDE_SWARM_HOME (default ./.claude-swarm):
.claude-swarm/
├── state/
│ ├── kanban.sqlite # tasks, dependencies, status timeline
│ ├── inboxes/<name>.json # bounded directed message queues
│ ├── pull_requests/<id>.json
│ ├── worktrees_meta/<id>.json # GC markers
│ └── status.json # mind-page-friendly snapshot
└── worktrees/swarm-<id>/ # per-task git worktrees
| Command | Description |
|---|---|
claude-swarm init |
Create the swarm home directory tree. |
claude-swarm submit --title T --prompt P [--head H] [--blocked-by ID] |
File a task. |
claude-swarm list [--status S] [--tag X] |
List tasks. |
claude-swarm unblocked [--head H] |
Print the topological iterator. |
claude-swarm status |
JSON snapshot of kanban + supervisor; also writes status.json. |
claude-swarm heads |
List the built-in heads. |
claude-swarm inbox send --from A --to B --body '{...}' |
Send a directed message. |
claude-swarm inbox recv NAME [--drain] |
Read messages targeted at NAME. |
claude-swarm merge --repo PATH [--test-cmd "..."] |
Run the auto-merge pipeline. |
claude-swarm abort set --worktree DIR --teammate NAME |
Set an abort marker. |
claude-swarm abort clear --worktree DIR --teammate NAME |
Clear it. |
claude-swarm abort check --worktree DIR --teammate NAME |
Exit 0 if set, 1 if clear. |
claude-swarm run [--max-iterations N] |
Run the supervisor loop with the stub conductor. |
The default roster:
| Name | Role | Allowed tools | Default model |
|---|---|---|---|
scanner |
Read-only; files new tasks. | Read, Grep, Glob, Bash(git log|diff) |
claude-sonnet-4-6 |
reviewer |
Periodic checkpoints, no edits. | Read, Grep, Bash(git log|status) |
claude-sonnet-4-6 |
builder |
Default worker; full toolkit. | Read, Edit, Write, Grep, Glob, Bash |
claude-opus-4-7 |
merger |
Git + bash only. | Bash |
claude-haiku-4-5 |
test-runner |
Read + scoped test commands. | Read, Bash(pytest|npm test|cargo test) |
claude-haiku-4-5 |
auditor |
Read-only; produces audit docs. | Read, Grep, Glob, Write |
claude-sonnet-4-6 |
Override any of these — pass your own roster to Supervisor or use the
constructor functions in claude_swarm.heads to mint a custom head.
A Conductor is the pluggable strategy that actually runs a head against a task. The library ships three:
StubConductor— records dispatches and immediately marks done. Useful for tests + the toy examples inexamples/.SubprocessConductor(command_factory=…)— runs an arbitrary command per task with the prompt on stdin.ClaudeCLIConductor()— convenience wrapper forclaude --print.
A downstream Claude Code plugin can ship its own conductor that spawns subagents directly inside an existing session.
Configure a reviewer-checkpoint to inject a self-review prompt every N turns of a long-running head:
from claude_swarm import ReviewerCheckpoint
cp = ReviewerCheckpoint(interval=3, max_turns=100, cost_cap_usd=5.0)
if cp.should_fire(turn=current_turn):
print(cp.render(turn=current_turn, cost_so_far_usd=spent))The default template forces the worker to (1) list what was accomplished, (2) confirm pending work is committed, (3) surface blockers, (4) account for cost vs. budget, and (5) state the next concrete tool call.
Long-running heads should poll for <worktree>/.claude/abort-<name>
between phases. When set, commit any work-in-progress, push, and exit
cleanly. The AbortMarker helper bundles the contract:
from claude_swarm import AbortMarker, AbortRequested
marker = AbortMarker(worktree_root=Path.cwd(), teammate="builder-1")
try:
marker.raise_if_set()
do_work()
except AbortRequested:
git_commit_wip()
sys.exit(0)from pathlib import Path
from claude_swarm import WorktreeManager
from claude_swarm.merge_pipeline import run_pipeline
mgr = WorktreeManager(repo_root=Path("/path/to/repo"))
report = run_pipeline(
mgr,
test_command=["pytest", "-x", "-q"],
reject_overlap=True,
)
print(report.merged, report.rejected, report.test_failures)Behaviour:
- File-overlap reject — if two open PRs touch the same file, the batch is refused; retry serially.
- Topological order — smallest diffs merge first to minimise rebases.
- Test gate — the configured command runs after each merge; failures
trigger an automatic
git revertof the just-merged commits. - GC on success — the worktree + branch are deleted when the merge lands cleanly.
| Feature | Vanilla Teams | claude-swarm |
|---|---|---|
addBlocks / addBlockedBy |
yes | yes |
| Topological iterator | no | Kanban.unblocked() |
| Auto-unblock cascade | manual | yes (status timeline) |
| Named heads with tool allowlists | manual | default 6-head roster |
| Abort-marker contract | ad-hoc | first-class |
| Per-task worktree + PR envelopes | manual | WorktreeManager |
| Auto-merge with overlap reject | manual | merge_pipeline |
| Reviewer checkpoints | manual | ReviewerCheckpoint |
| Status timeline | n/a | yes |
Why SQLite for the kanban?
WAL mode gives us concurrent reads + a single writer. The schema is small,
the file is portable, and sqlite3 is in the stdlib. No daemon to run.
Why JSON envelopes for PRs instead of GitHub PRs?
Local-first. The operator is the human reviewer of last resort. The
envelope captures everything a merger needs (head sha, diff stat, files
changed, body). Wrap WorktreeManager if you want real GitHub PRs.
Does it work without Claude?
Yes — the StubConductor runs the orchestration end-to-end with no LLM
calls. Ship your own Conductor to plug in any backend.
examples/todo_app— three tasks (design → build → review) with DAG dependencies, all using the stub conductor.examples/doc_writer_team— a roster of scanners + builders feeding directed messages through the inbox.
- Poll latency: < 100 ms (sqlite WAL select)
- Dispatch time: < 5 s including worktree creation
- Inbox round-trip: < 50 ms (atomic JSON write)
Run the benchmarks under tests/benchmarks/ to verify locally.
Apache 2.0. See LICENSE.