Basic Configuration

Basic Configuration

Minimal secure openclaw.json covering the security baseline (Phase 3), a single WhatsApp channel routing to the main agent (Phase 4), and isolated web search delegation (Phase 5). Two agents only: main + search. Uses JSON5 comments for inline documentation — OpenClaw supports JSON5 natively.

For production deployments with Docker sandboxing, egress allowlisting, multiple channels, and image generation — see Recommended Configuration .

Three deployment postures are covered: Docker isolation (this config), macOS VM isolation (remove sandbox blocks), and Linux VM isolation (keep sandbox blocks). See Phase 3 — Security for the full trade-off analysis.

{
  // ============================================================
  // OpenClaw Configuration — Basic Setup
  // ============================================================
  // NOTE: This file uses JSON5 comments (//) for documentation.
  // OpenClaw supports JSON5 natively — no need to strip comments.
  //
  // Minimal secure setup covering:
  // - Security baseline (Phase 3)
  // - Two agents: main + search (Phases 4-5)
  // - Single channel: WhatsApp (Phase 4)
  // - Web search delegation (Phase 5)
  //
  // NOT included (see recommended example for these):
  // - Docker sandboxing with egress allowlisting (see recommended example)
  // - Dedicated channel agents (defense-in-depth — channels route to main here)
  // - Signal / Google Chat channels
  // - Image generation plugin
  // - Deterministic guard plugins (file-guard, network-guard, command-guard)
  //   — see hardened-multi-agent.md for the maximum-security configuration
  //
  // DEPLOYMENT OPTIONS:
  //   Docker isolation — Dedicated OS user + Docker (this config): stronger
  //                      internal agent isolation via Docker sandboxing.
  //   VM: macOS VMs — Lume / Parallels: stronger host isolation, no Docker inside VM.
  //                   Remove all "sandbox" blocks; tool policy provides internal isolation.
  //   VM: Linux VMs — Multipass / KVM: strongest combined posture (VM boundary + Docker).
  //                   Keep "sandbox" blocks — Docker works inside Linux VMs.
  //   See Phase 3 — Security for the full trade-off analysis.
  //
  // Replace placeholder values:
  //   +46XXXXXXXXX  → your phone number
  //   Workspace paths → your actual paths
  //
  // 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, web_fetch, browser are denied per-agent (not here) —
    // global deny overrides agent-level allow, which would break the search agent.
    "deny": ["canvas", "gateway"],

    // Disable elevated mode — prevents sandbox escape
    "elevated": { "enabled": false },

    // Sandbox tool policy — the default allow list excludes message and memory tools.
    // WhatsApp DMs and all non-main sessions are sandboxed with mode:"non-main".
    // alsoAllow does NOT work with the default policy — must provide the full allow list.
    "sandbox": {
      "tools": {
        "allow": [
          "exec", "process", "read", "write", "edit", "apply_patch", "image",
          "sessions_list", "sessions_history", "sessions_send", "sessions_spawn",
          "subagents", "session_status",
          "message",
          "memory_search", "memory_get"
        ]
      }
    },

    // Web search provider config (accessible only to agents that allow the tool)
    "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"]
  },

  // --- Session Isolation ---
  "session": {
    // Each sender on each channel gets their own isolated session
    "dmScope": "per-channel-peer",

    // Inter-agent communication settings
    "agentToAgent": {
      "maxPingPongTurns": 5
    }
  },

  // --- Agents ---
  "agents": {
    "defaults": {
      // Pre-compaction memory flush — saves important context to memory before compacting.
      // Without this, the agent forgets everything from the compacted conversation portion.
      // Flush triggers silently when token estimate nears the reserve floor.
      "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).
      // Remote alternatives: "openai", "gemini", "voyage" (require separate API keys).
      // See Phase 2 — Memory for full provider comparison.
      "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"
      },
      // Default sandbox (Docker isolation / Linux VMs): non-main sessions run in Docker with no network.
      // macOS VM isolation: remove this block — no Docker available inside macOS VM.
      // Linux VM isolation: keep this block — Docker works inside Linux VMs.
      "sandbox": {
        "mode": "non-main",
        "scope": "agent",
        "workspaceAccess": "rw"
      }
    },
    "list": [
      {
        // MAIN AGENT — operator access via Control UI / CLI
        // Full tool access except web tools. WhatsApp routes here automatically
        // (no bindings needed — main is the default agent).
        // Web access delegated to search agent via sessions_send.
        "id": "main",
        "default": true,
        "workspace": "/Users/openclaw/.openclaw/workspaces/main",
        "tools": {
          "deny": ["web_search", "web_fetch", "browser", "nodes"]
        },
        "subagents": { "allowAgents": ["search"] }
      },
      {
        // SEARCH AGENT — isolated web search + content processing
        // Only reachable via sessions_send from main agent.
        // No channel binding = can't be messaged directly.
        // No filesystem tools — nothing to read or exfiltrate.
        // Tool policy provides isolation — no filesystem tools to abuse.
        // Unsandboxed — workaround for #9857 (sessions_spawn broken when both agents sandboxed + per-agent tools).
        "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).
  // For dedicated channel agents with restricted tools (defense-in-depth),
  // see the recommended example.
  "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]+"]
  },

  // --- Plugins ---
  "plugins": {
    // Only allow these plugins to load. Without this, any plugin dropped into
    // ~/.openclaw/extensions/ loads automatically at startup.
    "allow": ["whatsapp", "content-guard", "channel-guard"],
    "entries": {
      "whatsapp": { "enabled": true },
      "content-guard": {
        // LLM-based injection scanning at the sessions_send trust boundary.
        // Guards search→main: prevents poisoned web content from compromising main.
        // Requires OPENROUTER_API_KEY. Fails closed — no failOpen option.
        "enabled": true,
        "config": {
          "model": "anthropic/claude-haiku-4-5",
          "maxContentLength": 50000,
          "timeoutMs": 15000
        }
      },
      "channel-guard": {
        "enabled": true,
        "config": {
          "model": "anthropic/claude-haiku-4-5",
          "maxContentLength": 10000,
          "timeoutMs": 10000,
          "failOpen": false,
          "warnThreshold": 0.4,
          "blockThreshold": 0.8
        }
      }
    }
  }
}
Last updated on