Multi-Agent Sandbox and Tool Restrictions: Configuration and Precedence

Learn how to configure per-agent sandbox and tool policies in multi-agent environments, including rule precedence and practical examples. Essential for developers managing agent isolation and security.

Each agent within a multi-agent environment has the ability to override the sandbox and tool policies that apply globally. This document explains how to configure these settings on a per-agent basis, the order in which rules take effect, and provides practical examples.

Warning

Authentication is tied to each agent individually: every agent maintains its own agentDir auth store located in ~/.openclaw/agents/<agentId>/agent/openclaw-agent.sqlite. Do not share agentDir between agents. When an agent lacks a local auth profile, it can fall back to the default or main agent's profiles, but OAuth refresh tokens are never copied into secondary agent stores. If you transfer credentials by hand, only portable static api_key or token profiles should be duplicated.


Configuration examples

Example 1: Personal + restricted family agent

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

Outcome:

  • The main agent executes on the host machine with unrestricted tool access.
  • The family agent runs inside the designated container sandbox backend, with one container created per agent, and is limited to read plus message sends within the current conversation.

Example 2: Work agent with shared sandbox

{
  "agents": {
    "entries": {
      "personal": {
        "default": true,
        "workspace": "~/.openclaw/workspace-personal",
        "sandbox": { "mode": "off" }
      },
      "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"]
        }
      }
    }
  }
}

Example 2b: Global coding profile + messaging-only agent

{
  "tools": { "profile": "coding" },
  "agents": {
    "entries": {
      "main": {
        "default": true
      },
      "support": {
        "tools": { "profile": "messaging", "allow": ["slack"] }
      }
    }
  }
}

Outcome:

  • Default agents are given coding tools.
  • The support agent only handles messaging, along with the Slack tool.

Example 3: Different sandbox modes per agent

{
  "agents": {
    "defaults": {
      "sandbox": {
        "mode": "non-main",
        "scope": "session"
      }
    },
    "entries": {
      "main": {
        "default": true,
        "workspace": "~/.openclaw/workspace",
        "sandbox": {
          "mode": "off"
        }
      },
      "public": {
        "workspace": "~/.openclaw/workspace-public",
        "sandbox": {
          "mode": "all",
          "scope": "agent"
        },
        "tools": {
          "allow": ["read"],
          "deny": ["exec", "write", "edit", "apply_patch"]
        }
      }
    }
  }
}

Configuration precedence

When both a global configuration (agents.defaults.*) and an agent-specific one (agents.entries.*.*) are present:

Sandbox config

Agent-specific settings take priority over global ones:

agents.entries.*.sandbox.mode > agents.defaults.sandbox.mode
agents.entries.*.sandbox.scope > agents.defaults.sandbox.scope
agents.entries.*.sandbox.workspaceRoot > agents.defaults.sandbox.workspaceRoot
agents.entries.*.sandbox.workspaceAccess > agents.defaults.sandbox.workspaceAccess
agents.entries.*.sandbox.docker.* > agents.defaults.sandbox.docker.*
agents.entries.*.sandbox.browser.* > agents.defaults.sandbox.browser.*
agents.entries.*.sandbox.prune.* > agents.defaults.sandbox.prune.*

Note

For that particular agent, agents.entries.*.sandbox.{docker,browser,prune}.* takes precedence over agents.defaults.sandbox.{docker,browser,prune}.* and is disregarded when the sandbox scope resolves to "shared". The docker block is responsible for configuring both built-in container backends.

Tool restrictions

The sequence of filtering is:

Tool profile

Either tools.profile or agents.entries.*.tools.profile.

Provider tool profile

Either tools.byProvider[provider].profile or agents.entries.*.tools.byProvider[provider].profile.

Global tool policy

tools.allow or tools.deny.

Provider tool policy

tools.byProvider[provider].allow/deny.

Agent-specific tool policy

agents.entries.*.tools.allow/deny.

Agent provider policy

agents.entries.*.tools.byProvider[provider].allow/deny.

Sandbox tool policy

Either tools.sandbox.tools or agents.entries.*.tools.sandbox.tools.

Subagent tool policy

tools.subagents.tools, when it applies.

Precedence rules

  • Each level is allowed to further restrict tools, but cannot restore tools that were denied at an earlier level.
  • When agents.entries.*.tools.sandbox.tools is configured, it replaces tools.sandbox.tools for that agent.
  • When agents.entries.*.tools.profile is configured, it takes precedence over tools.profile for that agent.
  • Provider tool keys accept either provider (for example, anthropic) or provider/model (for example, openai/gpt-5.4).

Empty allowlist behavior

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.entries.*.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 for the full list.

Per-agent elevated overrides (agents.entries.*.tools.elevated) can further restrict elevated exec for specific agents. See Elevated mode for details.


Migration from single agent

Before (single agent)

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

After (multi-agent)

{
  "agents": {
    "entries": {
      "main": {
        "default": true,
        "workspace": "~/.openclaw/workspace",
        "sandbox": { "mode": "off" }
      }
    }
  }
}

Note

Legacy agents.list rosters and retired per-agent keys (such as sandbox.perSession, agentRuntime, and embeddedPi) are migrated by openclaw doctor; prefer agents.defaults + agents.entries going forward.


Tool restriction examples

Read-only agent

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

Shell execution with filesystem tools disabled

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

Warning

This policy disables OpenClaw filesystem tools, but exec is still a shell and can write files wherever the selected host or sandbox filesystem allows. For a read-only agent, deny exec and process, or combine shell access with sandbox filesystem controls such as agents.defaults.sandbox.workspaceAccess: "ro" or "none".

Communication-only

{
  "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, <relevant-memories> scaffolding, plain-text tool-call XML payloads (including <tool_call>...</tool_call>, <function_call>...</function_call>, <tool_calls>...</tool_calls>, <function_calls>...</function_calls>, 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"

Warning

agents.defaults.sandbox.mode: "non-main" checks the session key against the main session key (always "main"; session.mainKey is not user-configurable, and OpenClaw warns and ignores any other value), 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.entries.*.sandbox.mode: "off".


Testing

After configuring multi-agent sandbox and tools:

Check agent resolution

openclaw agents list --bindings

Verify sandbox containers

docker ps --filter "name=openclaw-sbx-"

Test tool restrictions

  • Send a message requiring restricted tools.
  • Verify the agent cannot use denied tools.

Monitor logs

openclaw logs --follow | 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.entries.*.sandbox.mode: "all".

Tools still available despite deny list

  • Check the full filtering order: profile → provider profile → global policy → provider policy → agent policy → agent provider policy → sandbox → subagent.
  • Each level can only further restrict, not grant back.
  • See Sandbox vs tool policy vs elevated for step-by-step debugging.

Container not isolated per agent

  • Default scope is "agent" (one container per agent id).
  • Set scope: "session" for one container per session, or scope: "shared" to reuse one container across agents.

1,312 words · updated Aug 6, 2026