Pragmatic Single Agent Configuration
Complete annotated openclaw.json implementing the pragmatic two-agent architecture: main agent with sandbox.mode: "off" and full tool access (exec, browser, filesystem), paired with a search agent for web delegation, and all five guard plugins enabled. Uses JSON5 comments for inline documentation — OpenClaw supports JSON5 natively.
Two-agent setup (main + search), no Docker. Security comes from guard plugins (channel-guard, content-guard, file-guard, network-guard, command-guard) plus OS-level isolation (non-admin user or VM boundary). See Pragmatic Single Agent for the full deployment guide, security analysis, and deployment target options.
For the recommended 2-agent Docker-sandboxed setup, see Recommended Configuration . For maximum hardening with exec isolation, see Hardened Multi-Agent . For a minimal starting point, see Basic Configuration .
Deploy as a non-admin OS user on a dedicated machine, or inside a Lume VM (macOS) / Multipass VM (Linux). See Pragmatic Single Agent — Deployment Target for setup instructions.
{
// ============================================================
// OpenClaw Configuration — Pragmatic Two-Agent Setup
// ============================================================
// NOTE: This file uses JSON5 comments (//) for documentation.
// OpenClaw supports JSON5 natively — no need to strip comments.
//
// Two-agent architecture (no Docker):
// Main agent — unsandboxed, full OS access (exec, browser, filesystem).
// Delegates web search to search agent.
// Search agent — web_search/web_fetch only, no filesystem, no exec.
//
// Security via guard plugins + OS-level isolation (non-admin user or VM).
// content-guard scans sessions_send messages at the search→main trust boundary.
//
// Prerequisites:
// 1. Guard plugins installed (channel-guard, content-guard, file-guard,
// network-guard, command-guard)
// OPENROUTER_API_KEY required for content-guard
// 2. Non-admin OS user or VM boundary (Lume/Multipass)
//
// See pragmatic-single-agent.md for full deployment guide and security analysis.
//
// DEPLOYMENT OPTIONS:
// Dedicated machine — non-admin OS user, chmod 700 home directory.
// Lume VM (macOS) — macOS VM on macOS host, non-admin user inside VM.
// Multipass VM (Linux) — Linux VM on any host, non-admin user inside VM.
// See pragmatic-single-agent.md for setup instructions.
//
// Replace placeholder values:
// +46XXXXXXXXX → your phone number
// /Users/openclaw → your actual home directory path
//
// Environment variables (set in LaunchAgent plist or systemd EnvironmentFile, or LaunchDaemon for hardened setup):
// OPENCLAW_GATEWAY_TOKEN
// ANTHROPIC_API_KEY
// BRAVE_API_KEY (or OPENROUTER_API_KEY for Perplexity)
// OPENROUTER_API_KEY (required for content-guard)
// See Phase 6 — Deployment > Secrets Management for details.
// ============================================================
// --- Chat Commands ---
// Disable dangerous chat commands. These allow users to
// run shell commands, edit config, or restart the gateway
// from within a chat message.
"commands": {
"native": "auto",
"nativeSkills": "auto",
"bash": false, // Blocks !command shell access
"config": false, // Blocks /config writes
"debug": false, // Blocks /debug runtime overrides
"restart": false // Blocks /restart
},
// --- Global Tool Restrictions ---
"tools": {
// Only deny tools globally that NO agent should ever have.
// web_search and web_fetch are allowed for the search agent, not denied globally.
"deny": ["canvas", "gateway", "nodes"],
// Disable elevated mode — prevents sandbox escape
"elevated": { "enabled": false },
// Web search provider config
"web": {
"search": {
"enabled": true,
"provider": "brave",
"apiKey": "${BRAVE_API_KEY}"
// Alternative: Perplexity via OpenRouter
// "provider": "perplexity",
// "perplexity": {
// "apiKey": "${OPENROUTER_API_KEY}",
// "baseUrl": "https://openrouter.ai/api/v1",
// "model": "perplexity/sonar-pro"
// }
}
}
},
// --- Skills ---
// Only allow known-good bundled skills. No skill installer configured
// means no new skills can be added from ClawHub.
"skills": {
"allowBundled": ["coding-agent", "github", "healthcheck", "weather", "video-frames"]
},
// --- Session Isolation ---
"session": {
// Each sender on each channel gets their own isolated session
"dmScope": "per-channel-peer",
// Inter-agent communication settings
"agentToAgent": {
"maxPingPongTurns": 5
}
},
// --- Agent ---
"agents": {
"defaults": {
// Pre-compaction memory flush — saves important context to memory before compacting.
// Without this, the agent forgets everything from the compacted conversation portion.
"compaction": {
"mode": "safeguard",
"reserveTokensFloor": 20000,
"memoryFlush": {
"enabled": true,
"softThresholdTokens": 4000,
"systemPrompt": "Session nearing compaction. Store durable memories now.",
"prompt": "Write any lasting notes to memory/YYYY-MM-DD.md; reply with NO_REPLY if nothing to store."
}
},
// Memory search — semantic + keyword hybrid search across memory files.
// Local provider: no API key, ~600MB disk, full privacy (nothing leaves your machine).
"memorySearch": {
"enabled": true,
"provider": "local",
"query": {
"hybrid": {
"enabled": true,
"vectorWeight": 0.7,
"textWeight": 0.3
}
},
"cache": {
"enabled": true,
"maxEntries": 50000
}
},
"maxConcurrent": 4,
"subagents": {
"maxConcurrent": 8,
"model": "anthropic/claude-sonnet-4-5",
"thinking": "low"
}
},
"list": [
{
// MAIN — channel-facing, full exec + browser + filesystem, no sandbox.
// Delegates web search to search agent via sessions_send.
// Guard plugins are the safety net for exec/filesystem access.
"id": "main",
"default": true,
"workspace": "/Users/openclaw/.openclaw/workspaces/main",
"tools": {
"allow": ["group:runtime", "group:fs", "group:sessions", "memory_search", "memory_get", "message", "browser", "web_fetch"],
"deny": ["web_search", "canvas", "gateway"]
},
"subagents": { "allowAgents": ["search"] },
"sandbox": { "mode": "off" }
},
{
// SEARCH — isolated web search + content processing.
// Only reachable via sessions_send from main.
// No filesystem tools — nothing to read or exfiltrate.
// Unsandboxed — workaround for #9857 (sessions_spawn broken when both agents sandboxed).
"id": "search",
"workspace": "/Users/openclaw/.openclaw/workspaces/search",
"agentDir": "/Users/openclaw/.openclaw/agents/search/agent",
"model": "anthropic/claude-sonnet-4-5",
"tools": {
"allow": ["web_search", "web_fetch", "sessions_send", "session_status"],
"deny": ["exec", "read", "write", "edit", "apply_patch", "process", "browser", "gateway", "cron"]
},
"subagents": { "allowAgents": [] },
"sandbox": { "mode": "off" }
}
]
},
// --- Channel Configuration ---
// No bindings section — unbound channels auto-route to the default agent (main).
// Add/remove channels as needed.
"channels": {
"whatsapp": {
"dmPolicy": "pairing",
"selfChatMode": false,
"allowFrom": ["+46XXXXXXXXX"], // REPLACE with real number — placeholder causes silent message drops
"groupPolicy": "allowlist",
"groups": { "*": { "requireMention": true } }, // Bug #11758: broken on WhatsApp (LID transition) — use false + mentionPatterns as workaround
"mediaMaxMb": 50,
"debounceMs": 0
}
},
// --- Gateway ---
"gateway": {
"port": 18789,
"mode": "local",
"bind": "loopback",
"auth": {
"mode": "token",
"token": "${OPENCLAW_GATEWAY_TOKEN}"
}
},
// --- Network Discovery ---
"discovery": {
"mdns": { "mode": "minimal" }
},
// --- Logging ---
"logging": {
"redactSensitive": "tools",
"redactPatterns": ["pplx-[A-Za-z0-9]+"]
},
// --- Guard Plugins ---
// Five guards enabled. This is the primary defense layer —
// without Docker sandboxing, these plugins are what stand between
// a compromised agent and full OS access.
//
// All guards default to failOpen: false — if a guard is unavailable,
// access is denied rather than allowed.
"plugins": {
// Only allow these plugins to load. Without this, any plugin dropped into
// ~/.openclaw/extensions/ loads automatically at startup.
"allow": [
"whatsapp",
"channel-guard", "content-guard",
"file-guard", "network-guard", "command-guard"
],
"entries": {
"whatsapp": { "enabled": true },
// LLM-based: scans incoming channel messages for prompt injection.
// Three-tier: pass → warn (advisory injected) → block (message rejected).
"channel-guard": {
"enabled": true,
"config": {
"model": "anthropic/claude-haiku-4-5",
"maxContentLength": 10000,
"timeoutMs": 10000,
"failOpen": false,
"warnThreshold": 0.4,
"blockThreshold": 0.8
}
},
// LLM-based: scans sessions_send content at the search→main trust boundary.
// Prevents poisoned web content from compromising the main agent.
// Fails closed on all errors — no failOpen option.
"content-guard": {
"enabled": true,
"config": {
"model": "anthropic/claude-haiku-4-5",
"maxContentLength": 50000,
"timeoutMs": 15000
}
},
// Deterministic: blocks read/write/delete of sensitive file paths
// (.env, .ssh/*, *.pem, credentials, etc.) via picomatch glob patterns.
"file-guard": {
"enabled": true,
"config": {
"failOpen": false,
"configPath": "./file-guard.json", // Relative to plugin install dir (~/.openclaw/plugins/file-guard/)
"logBlocks": true
}
},
// Deterministic: application-level domain allowlisting for web_fetch
// and exec tool calls. Blocks exfiltration patterns (curl -d, wget | sh).
// NOTE: web_fetch to URLs not in allowedDomains is blocked. web_search
// results come through the provider API and are not affected.
// Add domains as the agent needs them for web_fetch.
// NOTE: application-level only — not kernel-level like Docker egress rules.
"network-guard": {
"enabled": true,
"config": {
"allowedDomains": [
"github.com", "*.github.com",
"npmjs.org", "registry.npmjs.org",
"pypi.org", "*.pypi.org",
"api.anthropic.com",
"openrouter.ai" // Required for content-guard
// Add domains as needed:
// "playwright.azureedge.net", // Browser binary downloads
// "storage.googleapis.com", // Playwright CDN
// "api.openai.com",
// "your-internal-service.example.com"
],
"blockDirectIp": true,
"resolveDns": true,
"failOpen": false,
"logBlocks": true
}
},
// Deterministic: blocks dangerous shell commands (rm -rf, fork bombs,
// git push -f, pipe-to-shell, interpreter escapes) via regex matching.
"command-guard": {
"enabled": true,
"config": {
"guardedTools": ["exec", "bash"],
"failOpen": false,
"logBlocks": true
}
}
}
}
}