A 5-persona Claude Code dev squad.
DevSwarm is a FastMCP server that orchestrates five persistent Claude Code persona sessions (Architect, Researcher, Frontend, Backend, Reviewer-Deployer) to turn one prompt into one pull request. Fire-and-forget: kick it off from a single MCP call, close the laptop, wake up to a PR. No Docker, no daemon, no port; just files on disk and stdio MCP. Built end-to-end on a Fedora server in a single afternoon.
One idea at 11pm. A pull request in the morning.
A single Claude Code session is already a capable engineer. But it works one thing at a time (read, plan, code, review) in the same context window, with the same priorities, on the same clock as the human typing at it. DevSwarm is a small experiment in splitting that work across persistent specialised agents that hand off via files on disk, run in their own sessions, and don't need anyone watching.
The end-state I wanted: you have an idea late at night, you say it once, and you wake up to a pull request you can read, accept or send back. No babysitting. No "the swarm got stuck three steps in." The orchestrator detaches from the caller; status lives in a JSON file on disk; you can close the terminal and come back the next morning.
Pure files on disk, plus stdio MCP.
The MCP server is one Python file. Each persona is a real claude
session pinned to a UUID and resumed via subprocess. The runner is a
detached process (start_new_session=True) that walks five
stages, serialising state to .swarm_state.json after each.
Frontend and Backend run in parallel threads. No daemon, no port, no
container.
You (terminal, glasses, anywhere with Claude Code)
↓ mcp call: devswarm.start_project(idea, repo_url)
┌────────────────────────────────────┐
│ devswarm_mcp.py (FastMCP, stdio) │ ← spawned on demand
└─────────────┬──────────────────────┘
↓ subprocess.Popen(start_new_session=True)
┌────────────────────────────────────┐
│ runner.py (detached, PPID=1) │ ← survives the MCP dying
└─────────────┬──────────────────────┘
↓ for each stage: claude --resume <uuid> -p ...
┌──────┴──────┬──────────┬──────────┬──────────────┐
↓ ↓ ↓ ↓ ↓
Architect Researcher Frontend Backend Reviewer-
→ PLAN.md → RESEARCH → code → code Deployer
.md in fe/ in be/ → REVIEW.md
→ gh pr create
↓
state lives in workspace/<id>/.swarm_state.json
check anytime via get_project_status(id) Five sessions, five tool sets.
Each persona is a separate Claude Code session living in its own working
directory with its own CLAUDE.md system prompt and
settings.json tool allow-list. Tool isolation is hard-enforced
at the settings layer, not just promised in the prompt.
devswarm/<id> branch, commits, pushes, and opens a PR via gh pr create. The only persona with GitHub-write access.4 minutes 42 seconds, one prompt to one PR.
First end-to-end live test, no human edits: a single-page CV with dark-mode
toggle, fade-in-on-scroll, and prefers-reduced-motion respect.
Every stage succeeded on first attempt.
Below: the exact index.html the swarm wrote, rendered live.
Try the theme toggle in the top-right of the frame, scroll to see the
fade-in animation fire on each section.
/projects/cv-onepager-artifact.html, verbatim from the swarm's workspace output. View the PR ↗
Honest about what's in the box.
- Language
- Python 3.14, hand-written FastMCP server in ~260 lines (
devswarm_mcp.py) plus runner (runner.py) plus shared state helpers (swarm_state.py). - Agent model
claude-opus-4-7across all five personas. Sessions persisted as JSONL under~/.claude/projects/<encoded>/<uuid>.jsonl, resumed viaclaude --resume <uuid> -p ....- Tool isolation
- Per-persona
.claude/settings.jsonwith explicit allow/deny patterns. Frontend/Backend hard-blocked fromgit push,gh pr, allmcp__github__*writes. Notion writes denied for every persona. - Concurrency
- Python
threadingfor the parallel Frontend + Backend stage. State writes use unique tmp filenames + a process-wide lock so the read-modify-write insideupdate_stagedoesn't drop updates. - Deploy
- Reviewer-Deployer uses
ghCLI with the user's existing auth. PR URL is written to.pr_urlin the workspace; the runner picks it up and surfaces it inget_project_status. - Source
- Not on a public repo yet; kept local while the API stabilises. Likely to land at
github.com/tomscholtes93-collab/devswarmonce a couple more capstones land cleanly.