Each agent in a multi-agent setup can now have its own:
agents.list[].sandbox overrides agents.defaults.sandbox)tools.allow / tools.deny, plus agents.list[].tools)This allows you to run multiple agents with different security profiles:
setupCommand belongs under sandbox.docker (global or per-agent) and runs once
when the container is created.
Auth is per-agent: each agent reads from its own agentDir auth store at:
~/.coderclaw/agents/<agentId>/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.
For how sandboxing behaves at runtime, see Sandboxing.
For debugging “why is this blocked?”, see Sandbox vs Tool Policy vs Elevated and coderclaw sandbox explain.
{
"agents": {
"list": [
{
"id": "main",
"default": true,
"name": "Personal Assistant",
"workspace": "~/.coderclaw/workspace",
"sandbox": { "mode": "off" }
},
{
"id": "family",
"name": "Family Bot",
"workspace": "~/.coderclaw/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": "[email protected]"
}
}
}
]
}
Result:
main agent: Runs on host, full tool accessfamily agent: Runs in Docker (one container per agent), only read tool{
"agents": {
"list": [
{
"id": "personal",
"workspace": "~/.coderclaw/workspace-personal",
"sandbox": { "mode": "off" }
},
{
"id": "work",
"workspace": "~/.coderclaw/workspace-work",
"sandbox": {
"mode": "all",
"scope": "shared",
"workspaceRoot": "/tmp/work-sandboxes"
},
"tools": {
"allow": ["read", "write", "apply_patch", "exec"],
"deny": ["browser", "gateway", "discord"]
}
}
]
}
}
{
"tools": { "profile": "coding" },
"agents": {
"list": [
{
"id": "support",
"tools": { "profile": "messaging", "allow": ["slack"] }
}
]
}
}
Result:
support agent is messaging-only (+ Slack tool){
"agents": {
"defaults": {
"sandbox": {
"mode": "non-main", // Global default
"scope": "session"
}
},
"list": [
{
"id": "main",
"workspace": "~/.coderclaw/workspace",
"sandbox": {
"mode": "off" // Override: main never sandboxed
}
},
{
"id": "public",
"workspace": "~/.coderclaw/workspace-public",
"sandbox": {
"mode": "all", // Override: public always sandboxed
"scope": "agent"
},
"tools": {
"allow": ["read"],
"deny": ["exec", "write", "edit", "apply_patch"]
}
}
]
}
}
When both global (agents.defaults.*) and agent-specific (agents.list[].*) configs exist:
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").The filtering order is:
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.2).
Tool policies (global, agent, sandbox) support group:* entries that expand to multiple concrete tools:
group:runtime: exec, bash, processgroup:fs: read, write, edit, apply_patchgroup:sessions: sessions_list, sessions_history, sessions_send, sessions_spawn, session_statusgroup:memory: memory_search, memory_getgroup:ui: browser, canvasgroup:automation: cron, gatewaygroup:messaging: messagegroup:nodes: nodesgroup:coderclaw: all built-in CoderClaw tools (excludes provider plugins)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:
exec for untrusted agents (agents.list[].tools.deny: ["exec"])tools.elevated.enabled: false) if you only want sandboxed executionagents.list[].tools.elevated.enabled: false) for sensitive profilesBefore (single agent):
{
"agents": {
"defaults": {
"workspace": "~/.coderclaw/workspace",
"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": "~/.coderclaw/workspace",
"sandbox": { "mode": "off" }
}
]
}
}
Legacy agent.* configs are migrated by coderclaw doctor; prefer agents.defaults + agents.list going forward.
{
"tools": {
"allow": ["read"],
"deny": ["exec", "write", "edit", "apply_patch", "process"]
}
}
{
"tools": {
"allow": ["read", "exec", "process"],
"deny": ["write", "edit", "apply_patch", "browser", "gateway"]
}
}
{
"tools": {
"sessions": { "visibility": "tree" },
"allow": ["sessions_list", "sessions_send", "sessions_history", "session_status"],
"deny": ["exec", "write", "edit", "apply_patch", "read", "browser"]
}
}
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".
After configuring multi-agent sandbox and tools:
Check agent resolution:
coderclaw agents list --bindings
Verify sandbox containers:
docker ps --filter "name=coderclaw-sbx-"
Monitor logs:
tail -f "${CODERCLAW_STATE_DIR:-$HOME/.coderclaw}/logs/gateway.log" | grep -E "routing|sandbox|tools"
mode: "all"agents.defaults.sandbox.mode that overrides itagents.list[].sandbox.mode: "all"[tools] filtering tools for agent:${agentId}scope: "agent" in agent-specific sandbox config"session" which creates one container per session