# Claude Octopus
One brain, many arms.
An MCP server that wraps the [Claude Agent SDK](https://docs.anthropic.com/en/docs/claude-code/sdk), letting you run multiple specialized Claude Code agents — each with its own model, tools, system prompt, and personality — from any MCP client.
## Why
Claude Code is powerful. But one instance does everything the same way. Sometimes you want a **strict code reviewer** that only reads files. A **test writer** that defaults to TDD. A **cheap quick helper** on Haiku. A **deep thinker** on Opus.
Claude Octopus lets you spin up as many of these as you need. Same binary, different configurations. Each one shows up as a separate tool in your MCP client.
## Prerequisites
- **Node.js** >= 18
- **Claude Code** — the [Claude Agent SDK](https://www.npmjs.com/package/@anthropic-ai/claude-agent-sdk) is bundled as a dependency, but it spawns Claude Code under the hood, so you need a working `claude` CLI installation
- **Anthropic API key** (`ANTHROPIC_API_KEY` env var) or an active Claude Code OAuth session
## Install
Three paths, pick whichever matches your MCP client.
### npm (most direct)
```bash
npm install claude-octopus
```
### npx (no install needed)
Skip the install entirely — reference `claude-octopus@latest` in your `.mcp.json` and the client will fetch on demand (see Quick Start below).
### MCP Registry
The server is published to the [MCP Registry](https://registry.modelcontextprotocol.io) under the name **`io.github.xiaolai/claude-octopus`**. Registry-aware MCP clients can resolve and install it by that name without touching npm directly.
## Quick Start
The fastest way to get started:
```bash
npx claude-octopus init
```
This interactive wizard lets you pick a template, detects your MCP client, and writes the config for you.
Or add to your `.mcp.json` manually:
```json
{
"mcpServers": {
"claude": {
"command": "npx",
"args": ["claude-octopus@latest"],
"env": {
"CLAUDE_PERMISSION_MODE": "bypassPermissions"
}
}
}
}
```
This gives you six tools:
| Tool | Purpose |
|------|---------|
| `claude_code` | Send a task, get a result |
| `claude_code_reply` | Continue a conversation |
| `claude_code_timeline` | Query the workflow timeline |
| `claude_code_transcript` | Read full session transcripts |
| `claude_code_sessions` | List Claude Code session history (this project, or all) |
| `claude_code_report` | Generate HTML reports |
That's it — you have Claude Code as a tool, with full workflow observability built in.
## Multiple Agents
The real power is running several instances with different configurations:
```json
{
"mcpServers": {
"code-reviewer": {
"command": "npx",
"args": ["claude-octopus@latest"],
"env": {
"CLAUDE_TOOL_NAME": "code_reviewer",
"CLAUDE_SERVER_NAME": "code-reviewer",
"CLAUDE_DESCRIPTION": "Strict code reviewer. Finds bugs and security issues. Read-only.",
"CLAUDE_MODEL": "opus",
"CLAUDE_ALLOWED_TOOLS": "Read,Grep,Glob",
"CLAUDE_APPEND_PROMPT": "You are a strict code reviewer. Report real bugs, not style preferences.",
"CLAUDE_EFFORT": "high"
}
},
"test-writer": {
"command": "npx",
"args": ["claude-octopus@latest"],
"env": {
"CLAUDE_TOOL_NAME": "test_writer",
"CLAUDE_SERVER_NAME": "test-writer",
"CLAUDE_DESCRIPTION": "Writes thorough tests with edge case coverage.",
"CLAUDE_MODEL": "sonnet",
"CLAUDE_APPEND_PROMPT": "Write tests first. Cover edge cases. TDD."
}
},
"quick-qa": {
"command": "npx",
"args": ["claude-octopus@latest"],
"env": {
"CLAUDE_TOOL_NAME": "quick_qa",
"CLAUDE_SERVER_NAME": "quick-qa",
"CLAUDE_DESCRIPTION": "Fast answers to quick coding questions.",
"CLAUDE_MODEL": "haiku",
"CLAUDE_MAX_BUDGET_USD": "0.02",
"CLAUDE_EFFORT": "low"
}
}
}
}
```
Your MCP client now sees distinct tools for each agent — `code_reviewer`, `test_writer`, `quick_qa` — each purpose-built.
## Multi-Agent Orchestration
Agents can coordinate through a **coordinator pattern**: one agent has the others as inner MCP tools via `CLAUDE_MCP_SERVERS`, and its system prompt drives the pipeline.
```json
{
"mcpServers": {
"publishing-house": {
"command": "npx",
"args": ["claude-octopus@latest"],
"env": {
"CLAUDE_TOOL_NAME": "publishing_house",
"CLAUDE_SERVER_NAME": "publishing-house",
"CLAUDE_MODEL": "opus",
"CLAUDE_PERMISSION_MODE": "bypassPermissions",
"CLAUDE_APPEND_PROMPT": "You are a publishing house coordinator. Dispatch tasks to your specialist agents and drive the pipeline to completion.",
"CLAUDE_MCP_SERVERS": "{\"researcher\":{\"command\":\"npx\",\"args\":[\"claude-octopus@latest\"],\"env\":{\"CLAUDE_TOOL_NAME\":\"researcher\",\"CLAUDE_SERVER_NAME\":\"researcher\",\"CLAUDE_MODEL\":\"sonnet\",\"CLAUDE_PERMISSION_MODE\":\"bypassPermissions\"}},\"architect\":{\"command\":\"npx\",\"args\":[\"claude-octopus@latest\"],\"env\":{\"CLAUDE_TOOL_NAME\":\"architect\",\"CLAUDE_SERVER_NAME\":\"architect\",\"CLAUDE_MODEL\":\"opus\",\"CLAUDE_PERMISSION_MODE\":\"bypassPermissions\"}}}"
}
}
}
}
```
The coordinator agent autonomously calls `researcher`, `architect`, etc. as MCP tools — fully autonomous, no human in the loop until it finishes. Every invocation is tracked in the shared timeline.
## Agent Factory
Don't want to write configs by hand? Add a factory instance:
```json
{
"mcpServers": {
"agent-factory": {
"command": "npx",
"args": ["claude-octopus@latest"],
"env": {
"CLAUDE_FACTORY_ONLY": "true",
"CLAUDE_SERVER_NAME": "agent-factory"
}
}
}
}
```
This exposes a single `create_claude_code_mcp` tool — an interactive wizard. Tell it what you want ("a strict code reviewer that only reads files") and it generates the `.mcp.json` entry for you, listing all available options you can customize.
In factory-only mode, no query tools are registered — just the wizard. This keeps routing clean: the factory creates agents, the agents do work.
## Init Wizard
Don't want to edit JSON by hand? The init wizard gets you from zero to working in 30 seconds:
```bash
npx claude-octopus init
```
```
Claude Octopus — init wizard
One brain, many arms. Let's set up your agents.
Pick a template (or build your own):
1. Code Review Team — Reviewer + test writer + security auditor
2. Publishing House — Researcher + architect + editor + proofreader
3. Tiered Models — Haiku for quick Q&A, Sonnet for coding, Opus for hard problems
4. Solo Agent — Single Claude Code agent with sensible defaults
5. Agent Factory — Interactive wizard that generates agent configs on demand
6. Custom — describe your own agent(s)
Choice [1-6]:
```
It auto-detects installed MCP clients (Claude Desktop, Claude Code, Cursor, Windsurf), merges with existing config, and warns before overwriting.
### Skip the menu
```bash
npx claude-octopus init --template code-review-team
npx claude-octopus init --template tiered-models
npx claude-octopus init --template publishing-house
```
## Templates
Five built-in templates, battle-tested and ready to use:
| Template | Agents | Purpose |
|----------|--------|---------|
| `code-review-team` | code-reviewer (opus), test-writer (sonnet), security-auditor (opus) | Thorough code review pipeline |
| `publishing-house` | researcher (sonnet), architect (opus), editor (sonnet), proofreader (haiku) | Multi-stage content/code pipeline |
| `tiered-models` | quick-qa (haiku), coder (sonnet), deep-thinker (opus) | Right model for the job |
| `solo-agent` | claude (default) | Single agent, quick setup |
| `factory` | agent-factory | Generates configs on demand |
Each agent comes pre-tuned with appropriate model, tools, effort level, and system prompt.
## Dashboard
Monitor your agents in real time:
```bash
npx claude-octopus dashboard
```
Opens a local web dashboard at `http://localhost:3456` with:
- **Live stats** — total runs, invocations, cost, SDK turns, responses, errors
- **Recent activity** — agent cards for the latest run
- **Run table** — all runs with cost, duration, and status
- **Auto-refresh** — SSE connection pushes updates as agents run
```bash
# Custom port
npx claude-octopus dashboard --port 8080
```
The dashboard reads the same timeline index used by the `_timeline` and `_report` tools. No additional configuration needed.
## Tools
Each non-factory instance exposes:
| Tool | Purpose |
|------|---------|
| `` | Send a task to the agent, get a response + `session_id` + `run_id` |
| `_reply` | Continue a previous conversation by `session_id` |
| `_timeline` | Query the cross-agent workflow timeline |
| `_transcript` | Retrieve full session transcript from Claude Code's storage |
| `_sessions` | List Claude Code session history — this project by default, or all projects with `all_projects: true` |
| `_report` | Generate a self-contained HTML report for a run or all runs |
### Query and reply parameters
| Parameter | Description |
|-----------|-------------|
| `prompt` | The task or question (required) |
| `run_id` | Workflow run ID — groups related agent calls into one timeline. Auto-generated if omitted; returned in every response for propagation. |
| `cwd` | Working directory override |
| `model` | Model override (`sonnet`, `opus`, `haiku`, or full ID) |
| `tools` | Restrict available tools (intersects with server restriction) |
| `disallowedTools` | Block additional tools (unions with server blacklist) |
| `additionalDirs` | Extra directories the agent can access |
| `plugins` | Additional plugin paths to load |
| `effort` | Thinking effort (`low`, `medium`, `high`, `max`) |
| `permissionMode` | Permission mode (can only tighten, never loosen) |
| `maxTurns` | Max agent-loop round trips (see [effort counters](#reading-the-effort-counters)) |
| `maxBudgetUsd` | Max spend in USD |
| `systemPrompt` | Additional prompt (appended to server default) |
## Timeline
Every agent invocation is recorded in a lightweight JSONL index at `~/.claude-octopus/timelines/timeline.jsonl`. This solves the multi-agent correlation problem: when several agents participate in a workflow, the timeline tracks which sessions belong to the same run, in what order they executed, and what role each played.
Full session transcripts stay in Claude Code's own storage (`~/.claude/projects/`). The timeline is just the table of contents — ~200 bytes per entry — that cross-references via `session_id`.
```mermaid
graph TB
subgraph "Timeline Index (~200 bytes/entry)"
TL["~/.claude-octopus/timelines/timeline.jsonl"]
end
subgraph "Claude Code Session Storage (full transcripts)"
S1["~/.claude/projects/.../ses-aaa.jsonl"]
S2["~/.claude/projects/.../ses-bbb.jsonl"]
S3["~/.claude/projects/.../ses-ccc.jsonl"]
end
TL -->|"session_id cross-ref"| S1
TL -->|"session_id cross-ref"| S2
TL -->|"session_id cross-ref"| S3
```
### How it works
1. Every `` and `_reply` call appends one line to the timeline
2. If you pass `run_id`, all agents sharing the same `run_id` are grouped into one run
3. If you omit `run_id`, one is auto-generated and returned in the response — pass it to subsequent agents to keep them grouped
### Querying the timeline
```
# List all runs
_timeline({})
# Show one run's agent sequence
_timeline({ run_id: "abc-123" })
# Look up a specific session
_timeline({ session_id: "ses-xyz" })
# Retrieve full transcript (separate tool)
_transcript({ session_id: "ses-xyz" })
```
### Multi-agent workflow example
```
Host: researcher({ prompt: "Research X", run_id: "pub-001" })
→ { run_id: "pub-001", session_id: "ses-aaa", result: "..." }
Host: architect({ prompt: "Structure based on...", run_id: "pub-001" })
→ { run_id: "pub-001", session_id: "ses-bbb", result: "..." }
Host: verifier({ prompt: "Check this plan", run_id: "pub-001" })
→ { run_id: "pub-001", session_id: "ses-ccc", result: "..." }
Later: researcher_timeline({ run_id: "pub-001" })
→ [
{ agent: "researcher", session_id: "ses-aaa", cost: 0.05, turns: 4, tool_calls: 3, response_groups: 2 },
{ agent: "architect", session_id: "ses-bbb", cost: 0.08, turns: 6, tool_calls: 5, response_groups: 3 },
{ agent: "verifier", session_id: "ses-ccc", cost: 0.03, turns: 3, tool_calls: 2, response_groups: 2 },
]
Later: researcher_transcript({ session_id: "ses-aaa" })
→ full conversation transcript from Claude Code's storage
```
## HTML Reports
Generate self-contained HTML reports with agent sequence visualization, cost breakdown, and collapsible transcripts. Dark theme, no external dependencies — one file, open in any browser.
### Via MCP tool
```
_report({}) # index of all runs
_report({ run_id: "pub-001" }) # detailed report for one run
```
### Via CLI
```bash
# Index of all runs
npx claude-octopus report --out index.html
# Detailed report for one run
npx claude-octopus report pub-001 --out report.html
open report.html
# Without transcripts (faster, smaller file)
npx claude-octopus report pub-001 --no-transcripts --out report.html
# To stdout (pipe-friendly)
npx claude-octopus report pub-001 > report.html
```
### What's in the report
- **Run summary** — agent count, total cost, duration, SDK turns, responses, tool calls
- **Timeline bar** — numbered dots for each agent (green = success, red = error)
- **Agent cards** — timing, cost, effort counters, session ID, prompt excerpt
- **Collapsible transcripts** — full tool calls, reasoning, and results per agent
### Reading the effort counters
Three numbers describe how much work an invocation took. They are not
interchangeable, and the first one is the one that surprises people:
| Metric | What it counts |
|---|---|
| `num_turns` (shown as **SDK turns**) | Raw value from the Agent SDK. Measured against the runtime it tracks `tool_use` blocks plus the final response — **not** API round trips. |
| `response_groups` (**responses**) | Distinct assistant responses in the main agent loop — one per API round trip, no matter how many tools that response called in parallel. |
| `tool_calls` (**tool calls**) | `tool_use` blocks issued across the main agent loop. |
When an agent calls several tools in parallel, `num_turns` climbs faster than
the number of visible responses. A run with 3 assistant responses issuing 4
tool calls reports `num_turns: 5`, `response_groups: 3`, `tool_calls: 4`.
`maxTurns`, meanwhile, is enforced against round trips: that same run
completes under `maxTurns: 3` and aborts under `maxTurns: 2`. So size
`maxTurns` against **responses**, not against SDK turns.
Both new counters cover the main agent loop only — work inside a sub-agent
(`Task`) belongs to its own loop and is excluded. Timeline entries written by
older versions have neither, and render as `—` rather than as a false zero.
## Configuration
All configuration is via environment variables in `.mcp.json`. Every env var is optional.
### Identity
| Env Var | Description | Default |
|---------|-------------|---------|
| `CLAUDE_TOOL_NAME` | Tool name prefix (generates ``, `_reply`, `_timeline`, `_transcript`, `_report`) | `claude_code` |
| `CLAUDE_DESCRIPTION` | Tool description shown to the host AI | generic |
| `CLAUDE_SERVER_NAME` | MCP server name in protocol handshake | `claude-octopus` |
| `CLAUDE_FACTORY_ONLY` | Only expose the factory wizard tool | `false` |
### Agent
| Env Var | Description | Default |
|---------|-------------|---------|
| `CLAUDE_MODEL` | Model (`sonnet`, `opus`, `haiku`, or full ID) | SDK default |
| `CLAUDE_CWD` | Working directory | `process.cwd()` |
| `CLAUDE_PERMISSION_MODE` | `default`, `acceptEdits`, `bypassPermissions`, `plan` | `default` |
| `CLAUDE_ALLOWED_TOOLS` | Comma-separated tool restriction (available tools) | all |
| `CLAUDE_DISALLOWED_TOOLS` | Comma-separated tool blacklist | none |
| `CLAUDE_MAX_TURNS` | Max agent-loop round trips per invocation | unlimited |
| `CLAUDE_MAX_BUDGET_USD` | Max spend per invocation | unlimited |
| `CLAUDE_EFFORT` | `low`, `medium`, `high`, `max` | SDK default |
### Prompts
| Env Var | Description |
|---------|-------------|
| `CLAUDE_SYSTEM_PROMPT` | Replaces the default Claude Code system prompt |
| `CLAUDE_APPEND_PROMPT` | Appended to the default prompt (usually what you want) |
### Advanced
| Env Var | Description |
|---------|-------------|
| `CLAUDE_ADDITIONAL_DIRS` | Extra directories to grant access (comma-separated) |
| `CLAUDE_PLUGINS` | Local plugin paths (comma-separated) |
| `CLAUDE_MCP_SERVERS` | MCP servers for the inner agent (JSON) |
| `CLAUDE_PERSIST_SESSION` | `true`/`false` — enable session resume (default: `true`) |
| `CLAUDE_SETTING_SOURCES` | Settings to load: `user`, `project`, `local` |
| `CLAUDE_SETTINGS` | Path to settings JSON or inline JSON |
| `CLAUDE_BETAS` | Beta features (comma-separated) |
### Timeline
| Env Var | Description | Default |
|---------|-------------|---------|
| `CLAUDE_TIMELINE_DIR` | Directory for the cross-agent timeline index | `~/.claude-octopus/timelines` |
### Authentication
| Env Var | Description | Default |
|---------|-------------|---------|
| `ANTHROPIC_API_KEY` | Anthropic API key for this agent | inherited from parent |
| `CLAUDE_CODE_OAUTH_TOKEN` | Claude Code OAuth token for this agent | inherited from parent |
Leave both unset to inherit auth from the parent process. Set one per agent to use a different account or billing source.
Lists accept JSON arrays when values contain commas: `["path,with,comma", "/normal"]`
## Security
- **Permission mode defaults to `default`** — tool executions prompt for approval unless you explicitly set `bypassPermissions`.
- **`cwd` overrides preserve agent knowledge** — when the host overrides `cwd`, the agent's configured base directory is automatically added to `additionalDirectories` so it retains access to its own context.
- **Tool restrictions narrow, never widen** — per-invocation `tools` intersects with the server restriction (can only remove tools, not add). `disallowedTools` unions (can only block more).
- **`_reply` and `_transcript` tools respect persistence** — not registered when `CLAUDE_PERSIST_SESSION=false`.
- **Timeline writes are best-effort** — a failed timeline append never blocks or fails the primary query.
## Architecture
```mermaid
graph TB
subgraph "MCP Client (Claude Desktop, Cursor, etc.)"
C["Sees: code_reviewer, test_writer, quick_qa"]
end
C -->|"JSON-RPC / stdio"| O1
C -->|"JSON-RPC / stdio"| O2
C -->|"JSON-RPC / stdio"| O3
subgraph "Claude Octopus Instances"
O1["code-reviewer
model=opus, tools=Read,Grep,Glob"]
O2["test-writer
model=sonnet"]
O3["quick-qa
model=haiku, budget=$0.02"]
end
O1 -->|"Agent SDK query()"| SDK["Claude Agent SDK"]
O2 -->|"Agent SDK query()"| SDK
O3 -->|"Agent SDK query()"| SDK
O1 -->|"append"| TL["Timeline Index
~/.claude-octopus/timelines/"]
O2 -->|"append"| TL
O3 -->|"append"| TL
SDK -->|"persist"| SS["Session Storage
~/.claude/projects/"]
TL -.->|"cross-ref"| SS
```
## How It Compares
| Feature | Built-in `claude` | [claude-code-mcp](https://github.com/steipete/claude-code-mcp) | **Claude Octopus** |
|---------|-------------------|----------------------------------------------------------------|--------------------|
| Approach | Built-in | CLI wrapping | Agent SDK |
| Tools per instance | 16 raw tools | 1 prompt tool | 5 (prompt, reply, timeline, transcript, report) |
| Multi-instance | No | No | Yes |
| Per-instance config | No | No | Yes (20 env vars) |
| Init wizard | No | No | Yes (`init` + 5 templates) |
| Factory wizard | No | No | Yes |
| Session continuity | No | No | Yes |
| Cross-agent timeline | No | No | Yes |
| Web dashboard | No | No | Yes (live, SSE) |
| HTML reports | No | No | Yes |
## Development
```bash
pnpm install
pnpm build # compile TypeScript
pnpm test # run tests (vitest)
pnpm test:coverage # coverage report
```
## License
[ISC](https://github.com/xiaolai/claude-octopus/blob/main/LICENSE) - Xiaolai Li