← All Guides

🤖 Sub-Agents & Multi-Agent

Run multiple isolated agents in one gateway — each with its own workspace, tools, memory, and model. Route channels to agents, spawn sub-agents for parallel work, and build orchestrator patterns.

Advancedagents.list + bindingsOrchestrator pattern

🏗️ Why multi-agent?

ReasonHow multi-agent helps
Security isolationPersonal assistant gets exec access; public Discord bot does not. Per-agent tool allow/deny lists.
Cost controlMain agent uses expensive Sonnet; sub-agents use cheaper models for grunt work.
Clean sessionsSub-agent noise stays in its own transcript, keeping your main session clean.
Parallel workSpawn multiple sub-agents to research different topics simultaneously.
Context separationWork agent and personal agent have separate memories — no bleed between contexts.

📋 Define agents

// ~/.openclaw/openclaw.json
{
  "agents": {
    "list": [
      {
        "id": "home",
        "default": true,
        "workspace": "~/.openclaw/workspace-home"
      },
      {
        "id": "work",
        "workspace": "~/.openclaw/workspace-work"
      },
      {
        "id": "coding",
        "workspace": "~/.openclaw/workspace-coding",
        "model": {
          "primary": "anthropic/claude-sonnet-4-5"
        }
      }
    ]
  }
}

Each agent gets its own workspace directory (SOUL.md, IDENTITY.md, etc.), sessions, and optionally its own model config. All fields from agents.defaults can be overridden per-agent.

💡 CLI shortcut: openclaw agents add walks you through creating a new agent interactively. Verify with openclaw agents list --bindings.

🔀 Route with bindings

Bindings determine which agent handles which channel, account, or peer:

{
  "bindings": [
    {
      "match": { "channel": "telegram" },
      "agentId": "home"
    },
    {
      "match": { "channel": "slack" },
      "agentId": "work"
    },
    {
      "match": {
        "channel": "whatsapp",
        "peer": "+40712345678"
      },
      "agentId": "home"
    }
  ]
}

Match on: channel, accountId, chatType, peer. When no binding matches, the default: true agent handles the message.

🚀 Spawn sub-agents

From chat (slash command)

/subagents spawn main "Summarize the last 7 days of changelog entries"

This is non-blocking — returns a run ID immediately. On completion, the sub-agent sends a summary back to your chat.

From the agent (sessions_spawn tool)

The agent itself can decide to spawn workers. This is the orchestrator pattern:

# Tool call parameters:
{
  "message": "Research latest React 19 features",
  "model": "google/gemini-2.5-flash",
  "runTimeoutSeconds": 120,
  "thread": false
}

Key parameters

ParameterDefaultPurpose
modelAgent defaultOverride model for cheaper sub-agent runs
thinkingAgent defaultOverride thinking level
runTimeoutSeconds0 (none)Auto-abort after N seconds
threadfalseBind sub-agent to a Discord thread
agentIdRequesterTarget a specific named agent

🎭 Orchestrator pattern

Main agent spawns specialized workers, each returning results:

# Pattern: main → orchestrator → workers
# maxSpawnDepth controls nesting
{
  "agents": {
    "defaults": {
      "subagents": {
        "maxSpawnDepth": 2,
        "archiveAfterMinutes": 60,
        "runTimeoutSeconds": 300
      }
    }
  }
}
  • Depth 1 (default): main can spawn sub-agents, but sub-agents cannot spawn their own
  • Depth 2: enables main → orchestrator → workers (one level of nesting)
  • Sub-agents deeper than depth 2 are not supported

💡 Auto-archive: Sub-agent sessions are archived after archiveAfterMinutes (default 60). Transcripts are renamed to *.deleted.<timestamp> but preserved. Set cleanup: "delete" for immediate archive after completion.

🧵 Thread-bound sessions (Discord)

Discord is currently the only channel supporting persistent thread-bound sub-agent sessions:

# Spawn a sub-agent bound to a Discord thread
/subagents spawn coding "Review this PR" --thread

# The sub-agent stays in that thread
# Follow-up messages in the thread route to it
/session ttl 24h

# Detach manually
/unfocus

Use /agents to list active runs and binding state. Use /focus <target> to bind a thread to a specific agent.

📊 Managing sub-agents

# List active sub-agents
/subagents list

# View output/logs
/subagents log <run-id>

# Stop a running sub-agent
/subagents kill <run-id>

# List available agents for spawning
# (uses agents_list tool internally)
/agents

Allowlist control

{
  "agents": {
    "list": [
      {
        "id": "main",
        "subagents": {
          "allowAgents": ["coding", "research"]
        }
      }
    ]
  }
}

Set allowAgents: ["*"] to allow spawning any agent. Default: only the requester agent itself.

🔐 Security isolation

  • Per-agent tool deny lists — block exec for public-facing agents while allowing it for trusted ones
  • Separate workspaces — each agent gets its own SOUL.md, skills, and memory
  • Sandbox mode — run sub-agents in Docker sandboxes: sandbox.mode: "non-main"
  • Never share skills directories — a skill in a shared dir becomes available to all agents
  • Review third-party skills — especially important with multiple agents (more surface area)

⚠️ Security first: Multi-agent increases surface area. Lock down tools, lock down channels, and keep an audit trail. See Security Guide.

💼 Real-world patterns

PatternSetup
Home + Work splitTwo agents, routed by channel (Telegram → home, Slack → work). Separate memories.
Coding specialistMain spawns "coding" sub-agent with Sonnet for code reviews, using cheaper model for main.
Research parallelismMain spawns 3 sub-agents simultaneously for different research topics, aggregates results.
Public + PrivatePublic Discord bot (no exec, no fs) + private Telegram agent (full access). Same gateway.
Family hubOne agent per family member, routed by WhatsApp peer ID. Shared grocery list via hooks.

🔧 Troubleshooting

ProblemFix
agents_list only shows "main"Agents must be in agents.list[] array in config. Verify with openclaw agents list.
agentId is not allowedSet subagents.allowAgents to include the target agent ID, or ["*"] to allow any.
Sub-agent never completesSet runTimeoutSeconds to auto-abort. Check /subagents log <id> for errors.
Context bleed between agentsEnsure separate workspace paths per agent. Shared workspace = shared memory.
Sessions lost on restartConfigure session persistence. Sub-agent sessions don't survive gateway restarts by default.
Completion announce not deliveredUpdated in v2026.3.1+: typed task_completion events replace ad-hoc handoff. Update OpenClaw.