Multi-Agent Orchestration
OpenCrabs supports spawning specialized sub-agents that run autonomously in isolated sessions. Each child agent gets its own context, tool registry, and cancel token. Introduced in v0.2.97 with a typed agent system and team orchestration.
Agent Types
When spawning an agent, an agent_type parameter selects a specialized role with a curated tool set:
| Type | Role | Tools |
|---|---|---|
general | Full-capability agent (default) | All parent tools minus recursive/dangerous |
explore | Fast codebase navigation (read-only) | read_file, glob, grep, ls |
plan | Architecture planning (read + analysis) | read_file, glob, grep, ls, bash |
code | Implementation (full write access) | All parent tools minus recursive/dangerous |
research | Web search + documentation lookup | read_file, glob, grep, ls, web_search, http_request |
Each type receives a role-specific system prompt that shapes its behavior. Explore agents are fast and lightweight – they only read files. Code agents can modify anything. Research agents can search the web but not touch your filesystem.
Safety: ALWAYS_EXCLUDED Tools
No agent type has access to these tools, preventing dangerous or recursive operations:
spawn_agent– no spawning agents from agentsresume_agent,wait_agent,send_input,close_agent– no managing siblingsrebuild– no building from sourceevolve– no self-updating
Five Orchestration Tools
| Tool | Description |
|---|---|
spawn_agent | Create a typed child agent to handle a sub-task autonomously in the background |
wait_agent | Wait for a spawned agent to complete and return its output (configurable timeout) |
send_input | Send follow-up instructions to a running agent (multi-turn conversation) |
close_agent | Terminate a running agent and clean up its resources |
resume_agent | Resume a completed or failed agent with a new prompt (preserves prior context) |
Spawn an Agent
spawn_agent(
label: "refactor-auth", # Human-readable label
agent_type: "code", # general | explore | plan | code | research
prompt: "Refactor auth..." # Task instruction
)
The agent runs in its own session with auto-approved tools. No blocking – it executes in the background while the parent continues.
Wait for Completion
wait_agent(
agent_id: "abc-123",
timeout_secs: 300 # Max wait time (default: 300s)
)
Multi-Turn with send_input
After spawning, you can send additional instructions without restarting:
send_input(
agent_id: "abc-123",
text: "Also add unit tests for the new module"
)
The child agent processes the input on its next iteration. This enables iterative workflows – review the agent’s output, then ask it to refine or continue.
Resume a Completed Agent
resume_agent(
agent_id: "abc-123",
prompt: "Now port the same changes to the other two files"
)
The agent continues in its original session, preserving all prior context. No need to re-explain the codebase.
Team Orchestration
The TeamManager coordinates named groups of agents for parallel execution. Three team-specific tools:
Create a Team
team_create(
team_name: "backend-refactor",
agents: [
{ label: "auth", agent_type: "code", prompt: "Refactor auth module" },
{ label: "tests", agent_type: "code", prompt: "Write tests for auth" },
{ label: "docs", agent_type: "general", prompt: "Update documentation" }
]
)
All agents spawn simultaneously and run in parallel. Returns the team name and all agent IDs.
Broadcast to a Team
team_broadcast(
team_name: "backend-refactor",
message: "Use the new AuthError enum instead of plain strings"
)
Sends a message to all running agents in the team. Non-running agents are skipped. Useful for sharing context or direction changes.
Delete a Team
team_delete(team_name: "backend-refactor")
Cancels all running agents and cleans up resources. Completed agents are left in the subagent manager for reference.
Subagent Provider/Model Config
By default, every spawned agent inherits the parent session’s provider and model. You can override this globally in config.toml so child agents route to a different (usually cheaper or faster) backend:
[agent]
subagent_provider = "openrouter" # Provider for child agents
subagent_model = "qwen/qwen3-235b" # Model override
# Omit both keys and child agents inherit the parent session's provider
# and run on that provider's default model.
The override applies to spawn_agent, resume_agent, and every member of a team_create team. Changes take effect on next session start; running sessions keep their existing provider.
Per-Call Overrides (v0.3.35)
spawn_agent, resume_agent, and team_create now accept optional provider and model fields that override config defaults for a single call. This enables mixed-model teams:
team_create(
team_name: "mixed-stack",
agents: [
{ label: "planner", provider: "zhipu", model: "glm-5", prompt: "Architect the feature" },
{ label: "coder", provider: "deepseek", model: "deepseek-coder", prompt: "Implement it" },
{ label: "reviewer", provider: "kimi", model: "kimi-k2.5", prompt: "Review the code" }
]
)
Precedence order (highest first): per-call provider/model > [agent] subagent_provider/subagent_model in config > parent session’s provider.
Why It Matters
The common pattern is premium parent, cheap children. Your main conversation stays on a reasoning-capable model (Opus, GPT-5, Gemini 2.5 Pro) while subtasks — file exploration, test writing, web research, bulk refactors — run on a faster, cheaper model. With a 4-agent team running 10 minutes each, the cost delta between Opus and Qwen on the children is roughly 50x.
Concrete Examples
OpenRouter parent, Qwen children — best bang-for-buck on mixed workloads:
[providers.openrouter]
enabled = true
api_key = "sk-or-..."
model = "anthropic/claude-opus-4"
[agent]
subagent_provider = "openrouter"
subagent_model = "qwen/qwen3-235b-a22b-instruct"
Kimi on custom OpenCode provider — fast code generation for code and explore agents:
[providers.opencode-kimi]
enabled = true
base_url = "https://api.kimi.com/v1"
api_key = "..."
model = "kimi-k2.5"
[agent]
subagent_provider = "opencode-kimi"
subagent_model = "kimi-k2.6"
Local Ollama children — zero cost, fully offline, good for explore agents that just read files:
[providers.ollama]
enabled = true
model = "qwen3:14b"
[agent]
subagent_provider = "ollama"
subagent_model = "qwen3:14b"
Gemini parent, Gemini Flash children — single billing account, reasoning on main, flash on team:
[providers.gemini]
enabled = true
model = "gemini-2.5-pro"
[agent]
subagent_provider = "gemini"
subagent_model = "gemini-2.5-flash"
Gotchas
- The subagent provider must be enabled and have a valid API key (or be a CLI/none-auth provider). Missing keys cause the spawn to fail with a provider resolution error.
subagent_modelmust be a model the provider actually serves.qwen/qwen3-235bworks on OpenRouter, not on Anthropic. Check/modelson the target provider to confirm.team_createmembers all share the same subagent config. If you need heterogeneous routing (e.g. a research agent on web-search model, a code agent on code-specialized model), spawn them individually withspawn_agentunder different config profiles.- The CLI model override is surfaced in the
spawn_agent,resume_agent, andteam_createtool descriptions themselves, so the LLM knows to mention these keys to you instead of inventing per-call overrides.
If subagent_provider or subagent_model is not set, the spawned agent loads from the parent session’s provider and runs on that provider’s default model.
Workflow Patterns
Parallel Research + Implementation
team_create("feature-research", [
{ label: "research", agent_type: "research", prompt: "Find best practices for rate limiting in Rust" },
{ label: "explore", agent_type: "explore", prompt: "Find all middleware files in the codebase" }
])
Wait for results, then spawn a code agent with the combined context.
Iterative Code Review
# 1. Spawn a code agent
spawn_agent(label: "impl", agent_type: "code", prompt: "Implement rate limiting middleware")
# 2. Wait for completion
wait_agent(agent_id: "impl-id")
# 3. Resume with refinements
resume_agent(agent_id: "impl-id", prompt: "Add tests for the edge cases we discussed")
Large-Scale Refactoring
team_create("refactor-team", [
{ label: "module-a", agent_type: "code", prompt: "Refactor module A to use the new trait" },
{ label: "module-b", agent_type: "code", prompt: "Refactor module B to use the new trait" },
{ label: "module-c", agent_type: "code", prompt: "Refactor module C to use the new trait" },
{ label: "tests", agent_type: "code", prompt: "Update all tests for the new trait signature" }
])
Testing
84 tests cover the entire multi-agent system:
- Manager state machine (spawn, wait, close lifecycle)
SendInputwiring and input loopCloseAgentcleanupWaitAgenttimeout behaviorAgentTypetool filteringTeamManager,TeamDelete,TeamBroadcast- Registry exclusion (ALWAYS_EXCLUDED enforcement)
Sub-Agent Result Reporting (v0.3.81)
A finished agent reports its result back to the spawning session (#1036): the parent sees the outcome in-turn instead of polling or reading status files. Orphaned sub-agent status files from crashed runs are reconciled at startup (#1038), so the registry never shows ghosts of agents that no longer exist.
Sub-Agent Worktree Isolation (v0.3.83)
Each spawned agent gets its own worktree and branch instead of sharing the parent’s working tree: a fan-out of several agents on one repository can no longer clobber each other’s checkouts or builds. The parent’s tree stays untouched while children work in isolation, and results come back through the normal git flow.