Files
clawdbot/docs/multi-agent-sandbox-tools.md
2026-01-12 22:59:36 +00:00

8.3 KiB

summary, title, read_when, status
summary title read_when status
Per-agent sandbox + tool restrictions, precedence, and examples Multi-Agent Sandbox & Tools You want per-agent sandboxing or per-agent tool allow/deny policies in a multi-agent gateway. active

Multi-Agent Sandbox & Tools Configuration

Overview

Each agent in a multi-agent setup can now have its own:

  • Sandbox configuration (agents.list[].sandbox overrides agents.defaults.sandbox)
  • Tool restrictions (tools.allow / tools.deny, plus agents.list[].tools)

This allows you to run multiple agents with different security profiles:

  • Personal assistant with full access
  • Family/work agents with restricted tools
  • Public-facing agents in sandboxes

For how sandboxing behaves at runtime, see Sandboxing. For debugging “why is this blocked?”, see Sandbox vs Tool Policy vs Elevated and clawdbot sandbox explain.


Configuration Examples

Example 1: Personal + Restricted Family Agent

{
  "agents": {
    "list": [
      {
        "id": "main",
        "default": true,
        "name": "Personal Assistant",
        "workspace": "~/clawd",
        "sandbox": { "mode": "off" }
      },
      {
        "id": "family",
        "name": "Family Bot",
        "workspace": "~/clawd-family",
        "sandbox": {
          "mode": "all",
          "scope": "agent"
        },
        "tools": {
          "allow": ["read"],
          "deny": ["exec", "write", "edit", "apply_patch", "process", "browser"]
        }
      }
    ]
  },
  "bindings": [
    {
      "agentId": "family",
      "match": {
        "provider": "whatsapp",
        "accountId": "*",
        "peer": {
          "kind": "group",
          "id": "120363424282127706@g.us"
        }
      }
    }
  ]
}

Result:

  • main agent: Runs on host, full tool access
  • family agent: Runs in Docker (one container per agent), only read tool

Example 2: Work Agent with Shared Sandbox

{
  "agents": {
    "list": [
      {
        "id": "personal",
        "workspace": "~/clawd-personal",
        "sandbox": { "mode": "off" }
      },
      {
        "id": "work",
        "workspace": "~/clawd-work",
        "sandbox": {
          "mode": "all",
          "scope": "shared",
          "workspaceRoot": "/tmp/work-sandboxes"
        },
        "tools": {
          "allow": ["read", "write", "apply_patch", "exec"],
          "deny": ["browser", "gateway", "discord"]
        }
      }
    ]
  }
}

Example 3: Different Sandbox Modes per Agent

{
  "agents": {
    "defaults": {
      "sandbox": {
        "mode": "non-main",  // Global default
        "scope": "session"
      }
    },
    "list": [
      {
        "id": "main",
        "workspace": "~/clawd",
        "sandbox": {
          "mode": "off"  // Override: main never sandboxed
        }
      },
      {
        "id": "public",
        "workspace": "~/clawd-public",
        "sandbox": {
          "mode": "all",  // Override: public always sandboxed
          "scope": "agent"
        },
        "tools": {
          "allow": ["read"],
          "deny": ["exec", "write", "edit", "apply_patch"]
        }
      }
    ]
  }
}

Configuration Precedence

When both global (agents.defaults.*) and agent-specific (agents.list[].*) configs exist:

Sandbox Config

Agent-specific settings override global:

agents.list[].sandbox.mode > agents.defaults.sandbox.mode
agents.list[].sandbox.scope > agents.defaults.sandbox.scope
agents.list[].sandbox.workspaceRoot > agents.defaults.sandbox.workspaceRoot
agents.list[].sandbox.workspaceAccess > agents.defaults.sandbox.workspaceAccess
agents.list[].sandbox.docker.* > agents.defaults.sandbox.docker.*
agents.list[].sandbox.browser.* > agents.defaults.sandbox.browser.*
agents.list[].sandbox.prune.* > agents.defaults.sandbox.prune.*

Notes:

  • agents.list[].sandbox.{docker,browser,prune}.* overrides agents.defaults.sandbox.{docker,browser,prune}.* for that agent (ignored when sandbox scope resolves to "shared").

Tool Restrictions

The filtering order is:

  1. Global tool policy (tools.allow / tools.deny)
  2. Agent-specific tool policy (agents.list[].tools)
  3. Sandbox tool policy (tools.sandbox.tools or agents.list[].tools.sandbox.tools)
  4. Subagent tool policy (tools.subagents.tools, if applicable)

Each level can further restrict tools, but cannot grant back denied tools from earlier levels. If agents.list[].tools.sandbox.tools is set, it replaces tools.sandbox.tools for that agent.

Tool groups (shorthands)

Sandbox tool policy supports group:* entries that expand to multiple concrete tools:

  • group:runtime: exec, bash, process
  • group:fs: read, write, edit, apply_patch
  • group:sessions: sessions_list, sessions_history, sessions_send, sessions_spawn, session_status
  • group:memory: memory_search, memory_get

Elevated Mode

tools.elevated is the global baseline (sender-based allowlist). agents.list[].tools.elevated can further restrict elevated for specific agents (both must allow).

Mitigation patterns:

  • Deny exec for untrusted agents (agents.list[].tools.deny: ["exec"])
  • Avoid allowlisting senders that route to restricted agents
  • Disable elevated globally (tools.elevated.enabled: false) if you only want sandboxed execution
  • Disable elevated per agent (agents.list[].tools.elevated.enabled: false) for sensitive profiles

Migration from Single Agent

Before (single agent):

{
  "agents": {
    "defaults": {
      "workspace": "~/clawd",
      "sandbox": {
        "mode": "non-main"
      }
    }
  },
  "tools": {
    "sandbox": {
      "tools": {
        "allow": ["read", "write", "apply_patch", "exec"],
        "deny": []
      }
    }
  }
}

After (multi-agent with different profiles):

{
  "agents": {
    "list": [
      {
        "id": "main",
        "default": true,
        "workspace": "~/clawd",
        "sandbox": { "mode": "off" }
      }
    ]
  }
}

Legacy agent.* configs are migrated by clawdbot doctor; prefer agents.defaults + agents.list going forward.


Tool Restriction Examples

Read-only Agent

{
  "tools": {
    "allow": ["read"],
    "deny": ["exec", "write", "edit", "apply_patch", "process"]
  }
}

Safe Execution Agent (no file modifications)

{
  "tools": {
    "allow": ["read", "exec", "process"],
    "deny": ["write", "edit", "apply_patch", "browser", "gateway"]
  }
}

Communication-only Agent

{
  "tools": {
    "allow": ["sessions_list", "sessions_send", "sessions_history", "session_status"],
    "deny": ["exec", "write", "edit", "apply_patch", "read", "browser"]
  }
}

Common Pitfall: "non-main"

agents.defaults.sandbox.mode: "non-main" is based on session.mainKey (default "main"), not the agent id. Group/channel sessions always get their own keys, so they are treated as non-main and will be sandboxed. If you want an agent to never sandbox, set agents.list[].sandbox.mode: "off".


Testing

After configuring multi-agent sandbox and tools:

  1. Check agent resolution:

    clawdbot agents list --bindings
    
  2. Verify sandbox containers:

    docker ps --filter "label=clawdbot.sandbox=1"
    
  3. Test tool restrictions:

    • Send a message requiring restricted tools
    • Verify the agent cannot use denied tools
  4. Monitor logs:

    tail -f "${CLAWDBOT_STATE_DIR:-$HOME/.clawdbot}/logs/gateway.log" | grep -E "routing|sandbox|tools"
    

Troubleshooting

Agent not sandboxed despite mode: "all"

  • Check if there's a global agents.defaults.sandbox.mode that overrides it
  • Agent-specific config takes precedence, so set agents.list[].sandbox.mode: "all"

Tools still available despite deny list

  • Check tool filtering order: global → agent → sandbox → subagent
  • Each level can only further restrict, not grant back
  • Verify with logs: [tools] filtering tools for agent:${agentId}

Container not isolated per agent

  • Set scope: "agent" in agent-specific sandbox config
  • Default is "session" which creates one container per session

See Also