Pragmatic Single Agent Configuration

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
        }
      }
    }
  }
}
Last updated on