diff --git a/docs/tools/multi-agent-sandbox-tools.md b/docs/tools/multi-agent-sandbox-tools.md
index a3711ed327e..48a6807854f 100644
--- a/docs/tools/multi-agent-sandbox-tools.md
+++ b/docs/tools/multi-agent-sandbox-tools.md
@@ -1,177 +1,176 @@
---
-summary: “Per-agent sandbox + tool restrictions, precedence, and examples”
-title: Multi-agent sandbox & tools
-read_when: “You want per-agent sandboxing or per-agent tool allow/deny policies in a multi-agent gateway.”
+summary: "Per-agent sandbox + tool restrictions, precedence, and examples"
+title: "Multi-agent sandbox and tools"
+sidebarTitle: "Multi-agent sandbox and tools"
+read_when: "You want per-agent sandboxing or per-agent tool allow/deny policies in a multi-agent gateway."
status: active
---
-# Multi-Agent Sandbox & Tools Configuration
+Each agent in a multi-agent setup can override the global sandbox and tool policy. This page covers per-agent configuration, precedence rules, and examples.
-Each agent in a multi-agent setup can override the global sandbox and tool
-policy. This page covers per-agent configuration, precedence rules, and
-examples.
+
+
+ Backends and modes — full sandbox reference.
+
+
+ Debug "why is this blocked?"
+
+
+ Elevated exec for trusted senders.
+
+
-- **Sandbox backends and modes**: see [Sandboxing](/gateway/sandboxing).
-- **Debugging blocked tools**: see [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) and `openclaw sandbox explain`.
-- **Elevated exec**: see [Elevated Mode](/tools/elevated).
-
-Auth is per-agent: each agent reads from its own `agentDir` auth store at
-`~/.openclaw/agents//agent/auth-profiles.json`.
-Credentials are **not** shared between agents. Never reuse `agentDir` across agents.
-If you want to share creds, copy `auth-profiles.json` into the other agent's `agentDir`.
+
+Auth is per-agent: each agent reads from its own `agentDir` auth store at `~/.openclaw/agents//agent/auth-profiles.json`. Credentials are **not** shared between agents. Never reuse `agentDir` across agents. If you want to share creds, copy `auth-profiles.json` into the other agent's `agentDir`.
+
---
-## Configuration Examples
+## Configuration examples
-### Example 1: Personal + Restricted Family Agent
-
-```json
-{
- "agents": {
- "list": [
- {
- "id": "main",
- "default": true,
- "name": "Personal Assistant",
- "workspace": "~/.openclaw/workspace",
- "sandbox": { "mode": "off" }
- },
- {
- "id": "family",
- "name": "Family Bot",
- "workspace": "~/.openclaw/workspace-family",
- "sandbox": {
- "mode": "all",
- "scope": "agent"
- },
- "tools": {
- "allow": ["read"],
- "deny": ["exec", "write", "edit", "apply_patch", "process", "browser"]
- }
- }
- ]
- },
- "bindings": [
+
+
+ ```json
{
- "agentId": "family",
- "match": {
- "provider": "whatsapp",
- "accountId": "*",
- "peer": {
- "kind": "group",
- "id": "120363424282127706@g.us"
+ "agents": {
+ "list": [
+ {
+ "id": "main",
+ "default": true,
+ "name": "Personal Assistant",
+ "workspace": "~/.openclaw/workspace",
+ "sandbox": { "mode": "off" }
+ },
+ {
+ "id": "family",
+ "name": "Family Bot",
+ "workspace": "~/.openclaw/workspace-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.
+
+
+
+ ```json
+ {
+ "agents": {
+ "list": [
+ {
+ "id": "personal",
+ "workspace": "~/.openclaw/workspace-personal",
+ "sandbox": { "mode": "off" }
+ },
+ {
+ "id": "work",
+ "workspace": "~/.openclaw/workspace-work",
+ "sandbox": {
+ "mode": "all",
+ "scope": "shared",
+ "workspaceRoot": "/tmp/work-sandboxes"
+ },
+ "tools": {
+ "allow": ["read", "write", "apply_patch", "exec"],
+ "deny": ["browser", "gateway", "discord"]
+ }
+ }
+ ]
}
}
- ]
-}
-```
+ ```
+
+
+ ```json
+ {
+ "tools": { "profile": "coding" },
+ "agents": {
+ "list": [
+ {
+ "id": "support",
+ "tools": { "profile": "messaging", "allow": ["slack"] }
+ }
+ ]
+ }
+ }
+ ```
-**Result:**
+ **Result:**
-- `main` agent: Runs on host, full tool access
-- `family` agent: Runs in Docker (one container per agent), only `read` tool
+ - default agents get coding tools.
+ - `support` agent is messaging-only (+ Slack tool).
----
-
-### Example 2: Work Agent with Shared Sandbox
-
-```json
-{
- "agents": {
- "list": [
- {
- "id": "personal",
- "workspace": "~/.openclaw/workspace-personal",
- "sandbox": { "mode": "off" }
- },
- {
- "id": "work",
- "workspace": "~/.openclaw/workspace-work",
- "sandbox": {
- "mode": "all",
- "scope": "shared",
- "workspaceRoot": "/tmp/work-sandboxes"
+
+
+ ```json
+ {
+ "agents": {
+ "defaults": {
+ "sandbox": {
+ "mode": "non-main",
+ "scope": "session"
+ }
},
- "tools": {
- "allow": ["read", "write", "apply_patch", "exec"],
- "deny": ["browser", "gateway", "discord"]
- }
+ "list": [
+ {
+ "id": "main",
+ "workspace": "~/.openclaw/workspace",
+ "sandbox": {
+ "mode": "off"
+ }
+ },
+ {
+ "id": "public",
+ "workspace": "~/.openclaw/workspace-public",
+ "sandbox": {
+ "mode": "all",
+ "scope": "agent"
+ },
+ "tools": {
+ "allow": ["read"],
+ "deny": ["exec", "write", "edit", "apply_patch"]
+ }
+ }
+ ]
}
- ]
- }
-}
-```
+ }
+ ```
+
+
---
-### Example 2b: Global coding profile + messaging-only agent
-
-```json
-{
- "tools": { "profile": "coding" },
- "agents": {
- "list": [
- {
- "id": "support",
- "tools": { "profile": "messaging", "allow": ["slack"] }
- }
- ]
- }
-}
-```
-
-**Result:**
-
-- default agents get coding tools
-- `support` agent is messaging-only (+ Slack tool)
-
----
-
-### Example 3: Different Sandbox Modes per Agent
-
-```json
-{
- "agents": {
- "defaults": {
- "sandbox": {
- "mode": "non-main", // Global default
- "scope": "session"
- }
- },
- "list": [
- {
- "id": "main",
- "workspace": "~/.openclaw/workspace",
- "sandbox": {
- "mode": "off" // Override: main never sandboxed
- }
- },
- {
- "id": "public",
- "workspace": "~/.openclaw/workspace-public",
- "sandbox": {
- "mode": "all", // Override: public always sandboxed
- "scope": "agent"
- },
- "tools": {
- "allow": ["read"],
- "deny": ["exec", "write", "edit", "apply_patch"]
- }
- }
- ]
- }
-}
-```
-
----
-
-## Configuration Precedence
+## Configuration precedence
When both global (`agents.defaults.*`) and agent-specific (`agents.list[].*`) configs exist:
-### Sandbox Config
+### Sandbox config
Agent-specific settings override global:
@@ -185,139 +184,154 @@ 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"`).
+
-- `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
+### Tool restrictions
The filtering order is:
-1. **Tool profile** (`tools.profile` or `agents.list[].tools.profile`)
-2. **Provider tool profile** (`tools.byProvider[provider].profile` or `agents.list[].tools.byProvider[provider].profile`)
-3. **Global tool policy** (`tools.allow` / `tools.deny`)
-4. **Provider tool policy** (`tools.byProvider[provider].allow/deny`)
-5. **Agent-specific tool policy** (`agents.list[].tools.allow/deny`)
-6. **Agent provider policy** (`agents.list[].tools.byProvider[provider].allow/deny`)
-7. **Sandbox tool policy** (`tools.sandbox.tools` or `agents.list[].tools.sandbox.tools`)
-8. **Subagent tool policy** (`tools.subagents.tools`, if applicable)
+
+
+ `tools.profile` or `agents.list[].tools.profile`.
+
+
+ `tools.byProvider[provider].profile` or `agents.list[].tools.byProvider[provider].profile`.
+
+
+ `tools.allow` / `tools.deny`.
+
+
+ `tools.byProvider[provider].allow/deny`.
+
+
+ `agents.list[].tools.allow/deny`.
+
+
+ `agents.list[].tools.byProvider[provider].allow/deny`.
+
+
+ `tools.sandbox.tools` or `agents.list[].tools.sandbox.tools`.
+
+
+ `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.
-If `agents.list[].tools.profile` is set, it overrides `tools.profile` for that agent.
-Provider tool keys accept either `provider` (e.g. `google-antigravity`) or `provider/model` (e.g. `openai/gpt-5.4`).
-
-If any explicit allowlist in that chain leaves the run with no callable tools,
-OpenClaw stops before submitting the prompt to the model. This is intentional:
-an agent configured with a missing tool such as
-`agents.list[].tools.allow: ["query_db"]` should fail loudly until the plugin
-that registers `query_db` is enabled, not continue as a text-only agent.
+
+
+ - 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.
+ - If `agents.list[].tools.profile` is set, it overrides `tools.profile` for that agent.
+ - Provider tool keys accept either `provider` (e.g. `google-antigravity`) or `provider/model` (e.g. `openai/gpt-5.4`).
+
+
+ If any explicit allowlist in that chain leaves the run with no callable tools, OpenClaw stops before submitting the prompt to the model. This is intentional: an agent configured with a missing tool such as `agents.list[].tools.allow: ["query_db"]` should fail loudly until the plugin that registers `query_db` is enabled, not continue as a text-only agent.
+
+
Tool policies support `group:*` shorthands that expand to multiple tools. See [Tool groups](/gateway/sandbox-vs-tool-policy-vs-elevated#tool-groups-shorthands) for the full list.
-Per-agent elevated overrides (`agents.list[].tools.elevated`) can further restrict elevated exec for specific agents. See [Elevated Mode](/tools/elevated) for details.
+Per-agent elevated overrides (`agents.list[].tools.elevated`) can further restrict elevated exec for specific agents. See [Elevated mode](/tools/elevated) for details.
---
-## Migration from Single Agent
+## Migration from single agent
-**Before (single agent):**
-
-```json
-{
- "agents": {
- "defaults": {
- "workspace": "~/.openclaw/workspace",
- "sandbox": {
- "mode": "non-main"
- }
- }
- },
- "tools": {
- "sandbox": {
+
+
+ ```json
+ {
+ "agents": {
+ "defaults": {
+ "workspace": "~/.openclaw/workspace",
+ "sandbox": {
+ "mode": "non-main"
+ }
+ }
+ },
"tools": {
- "allow": ["read", "write", "apply_patch", "exec"],
- "deny": []
+ "sandbox": {
+ "tools": {
+ "allow": ["read", "write", "apply_patch", "exec"],
+ "deny": []
+ }
+ }
}
}
- }
-}
-```
-
-**After (multi-agent with different profiles):**
-
-```json
-{
- "agents": {
- "list": [
- {
- "id": "main",
- "default": true,
- "workspace": "~/.openclaw/workspace",
- "sandbox": { "mode": "off" }
+ ```
+
+
+ ```json
+ {
+ "agents": {
+ "list": [
+ {
+ "id": "main",
+ "default": true,
+ "workspace": "~/.openclaw/workspace",
+ "sandbox": { "mode": "off" }
+ }
+ ]
}
- ]
- }
-}
-```
+ }
+ ```
+
+
+
Legacy `agent.*` configs are migrated by `openclaw doctor`; prefer `agents.defaults` + `agents.list` going forward.
+
---
-## Tool Restriction Examples
+## Tool restriction examples
-### Read-only Agent
+
+
+ ```json
+ {
+ "tools": {
+ "allow": ["read"],
+ "deny": ["exec", "write", "edit", "apply_patch", "process"]
+ }
+ }
+ ```
+
+
+ ```json
+ {
+ "tools": {
+ "allow": ["read", "exec", "process"],
+ "deny": ["write", "edit", "apply_patch", "browser", "gateway"]
+ }
+ }
+ ```
+
+
+ ```json
+ {
+ "tools": {
+ "sessions": { "visibility": "tree" },
+ "allow": ["sessions_list", "sessions_send", "sessions_history", "session_status"],
+ "deny": ["exec", "write", "edit", "apply_patch", "read", "browser"]
+ }
+ }
+ ```
-```json
-{
- "tools": {
- "allow": ["read"],
- "deny": ["exec", "write", "edit", "apply_patch", "process"]
- }
-}
-```
+ `sessions_history` in this profile still returns a bounded, sanitized recall view rather than a raw transcript dump. Assistant recall strips thinking tags, `` scaffolding, plain-text tool-call XML payloads (including `...`, `...`, `...`, `...`, and truncated tool-call blocks), downgraded tool-call scaffolding, leaked ASCII/full-width model control tokens, and malformed MiniMax tool-call XML before redaction/truncation.
-### Safe Execution Agent (no file modifications)
-
-```json
-{
- "tools": {
- "allow": ["read", "exec", "process"],
- "deny": ["write", "edit", "apply_patch", "browser", "gateway"]
- }
-}
-```
-
-### Communication-only Agent
-
-```json
-{
- "tools": {
- "sessions": { "visibility": "tree" },
- "allow": ["sessions_list", "sessions_send", "sessions_history", "session_status"],
- "deny": ["exec", "write", "edit", "apply_patch", "read", "browser"]
- }
-}
-```
-
-`sessions_history` in this profile still returns a bounded, sanitized recall
-view rather than a raw transcript dump. Assistant recall strips thinking tags,
-`` scaffolding, plain-text tool-call XML payloads
-(including `...`,
-`...`, `...`,
-`...`, and truncated tool-call blocks),
-downgraded tool-call scaffolding, leaked ASCII/full-width model control
-tokens, and malformed MiniMax tool-call XML before redaction/truncation.
+
+
---
-## Common Pitfall: "non-main"
+## 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"`.
+
+`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"`.
+
---
@@ -325,55 +339,55 @@ sandbox, set `agents.list[].sandbox.mode: "off"`.
After configuring multi-agent sandbox and tools:
-1. **Check agent resolution:**
-
- ```exec
- openclaw agents list --bindings
- ```
-
-2. **Verify sandbox containers:**
-
- ```exec
- docker ps --filter "name=openclaw-sbx-"
- ```
-
-3. **Test tool restrictions:**
- - Send a message requiring restricted tools
- - Verify the agent cannot use denied tools
-
-4. **Monitor logs:**
-
- ```exec
- tail -f "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/logs/gateway.log" | grep -E "routing|sandbox|tools"
- ```
+
+
+ ```bash
+ openclaw agents list --bindings
+ ```
+
+
+ ```bash
+ docker ps --filter "name=openclaw-sbx-"
+ ```
+
+
+ - Send a message requiring restricted tools.
+ - Verify the agent cannot use denied tools.
+
+
+ ```bash
+ tail -f "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/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
+
+
+ - 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"`.
+
+
+ - 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}`.
+
+
+ - Set `scope: "agent"` in agent-specific sandbox config.
+ - Default is `"session"` which creates one container per session.
+
+
---
## Related
-- [Sandboxing](/gateway/sandboxing) -- full sandbox reference (modes, scopes, backends, images)
-- [Sandbox vs Tool Policy vs Elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) -- debugging "why is this blocked?"
-- [Elevated Mode](/tools/elevated)
-- [Multi-Agent Routing](/concepts/multi-agent)
-- [Sandbox Configuration](/gateway/config-agents#agentsdefaultssandbox)
-- [Session Management](/concepts/session)
+- [Elevated mode](/tools/elevated)
+- [Multi-agent routing](/concepts/multi-agent)
+- [Sandbox configuration](/gateway/config-agents#agentsdefaultssandbox)
+- [Sandbox vs tool policy vs elevated](/gateway/sandbox-vs-tool-policy-vs-elevated) — debugging "why is this blocked?"
+- [Sandboxing](/gateway/sandboxing) — full sandbox reference (modes, scopes, backends, images)
+- [Session management](/concepts/session)