Reference

Reference

Config cheat sheet, tool list, chat commands, gotchas, and useful commands.


Tool List

ToolDescription
execExecute shell commands
bashBash shell access
processProcess management (spawn, kill)
readRead files
writeWrite/create files
editEdit existing files
apply_patchApply unified diffs
web_searchSearch the web (Brave/Perplexity)
web_fetchFetch URL content
browserBrowser automation (Playwright)
canvasInteractive artifact rendering
sessions_listList active sessions
sessions_historyRead session history
sessions_sendDelegate work to another agent’s session (agent-to-agent); NOT for message relay — use message with explicit target instead
sessions_spawnSpawn background sub-agent task
session_statusCheck session status
memory_searchSemantic/hybrid search across memory files. Requires memorySearch config. See Phase 2
memory_getRetrieve a specific memory entry by date or path
messageSend messages to channels. With explicit target (JID/phone/channel ID), sends directly to any chat regardless of current session — the right tool for proactive group delivery
cronSchedule recurring tasks
gatewayGateway control (restart, config, status)
nodesRemote node operations
generate_imageGenerate images from text prompts (image-gen plugin)
vm_screenshotCapture VM screen as PNG image (computer-use plugin)
vm_execRun shell command inside Lume VM (computer-use plugin)
vm_clickClick at screen coordinates in VM (computer-use plugin)
vm_typeType text into focused VM application (computer-use plugin)
vm_keyPress key or key combination in VM (computer-use plugin)
vm_launchLaunch macOS application in VM (computer-use plugin)
vm_scrollScroll screen up or down in VM (computer-use plugin)

Tool Groups

GroupTools
group:runtimeexec, bash, process
group:fsread, write, edit, apply_patch
group:sessionssessions_list, sessions_history, sessions_send, sessions_spawn, subagents, session_status
group:memorymemory_search, memory_get
group:webweb_search, web_fetch
group:uibrowser, canvas
group:automationcron, gateway — can be used individually: deny gateway while keeping cron for conversational job management
group:messagingmessage
group:nodesnodes
group:openclawAll built-in tools

Version note: group:memory is not recognized by the gateway in v2026.2.15. Use individual tools (memory_search, memory_get) in tool allow/deny lists until this is fixed upstream.


Config Quick Reference

Most Important Keys

{
  // Agent definitions
  agents: {
    defaults: {
      sandbox: { mode: "off|non-main|all" },
      memorySearch: {
        enabled: true, provider: "local",
        // fallback: "none",              // Don't fall back to remote on local failure
        query: {
          hybrid: {
            enabled: true, vectorWeight: 0.7, textWeight: 0.3,
            // mmr: { enabled: true, lambda: 0.7 }  // Deduplicate similar results
          },
        },
        // temporalDecay: { enabled: true, halfLifeDays: 30 },
        cache: { enabled: true, maxEntries: 50000 }
      },
      compaction: {
        memoryFlush: { enabled: true, softThresholdTokens: 4000 },
        // reserveTokens: 8000,        // Reserve tokens for post-compaction response (added 2026.2.21)
        // keepRecentTokens: 8000,     // Preserve recent context across compaction (added 2026.2.21)
      },
      subagents: {
        maxConcurrent: 8,
        // maxSpawnDepth: 2,           // Max nesting depth for nested sub-agents; default 2 as of 2026.2.21 (added 2026.2.16)
        // maxChildrenPerAgent: 10,    // Max concurrent children per parent agent (added 2026.2.16)
        // announceTimeoutMs: 60000,   // Announce call timeout in ms (added 2026.2.22)
      }
    },
    list: [{
      id: "main", default: true, workspace: "...",
      tools: { deny: [] },
      subagents: { allowAgents: ["search"] }
    }]
  },

  // Channel routing
  bindings: [{ agentId: "...", match: { channel: "..." } }],

  // Chat commands
  commands: { bash: false, config: false, debug: false, restart: false },

  // Tool restrictions
  tools: {
    profile: "full",   // Shorthand: "minimal" | "coding" | "messaging" | "full"
    deny: [],
    elevated: { enabled: false },
    exec: {
      host: "sandbox",  // Route exec to sandbox container (when sandbox.mode: "all")
      // safeBinTrustedDirs: ["/usr/local/bin"],  // Trusted dirs for safeBins path resolution (added 2026.2.22)
    },
    web: { search: { enabled: true, provider: "brave", apiKey: "..." } },
    agentToAgent: { enabled: false, allow: [], maxPingPongTurns: 2 }
  },

  // Skills
  skills: { allowBundled: ["coding-agent", "github", "healthcheck"] },

  // Session isolation
  session: { dmScope: "per-channel-peer" },

  // Channel config
  channels: {
    // modelByChannel: { "whatsapp": "claude-sonnet-4-5", "signal": "..." },  // Per-channel model overrides (added 2026.2.21)
    whatsapp: { dmPolicy: "pairing", allowFrom: [], groupPolicy: "allowlist", groups: { "*": { requireMention: true } } },
    signal: { enabled: true, account: "+...", cliPath: "signal-cli", dmPolicy: "pairing" },
    googlechat: { enabled: true, serviceAccountFile: "...", audienceType: "app-url", audience: "https://..." }
  },

  // Gateway (mode: "local" required for startup)
  gateway: { mode: "local", bind: "loopback", port: 18789, auth: { mode: "token", token: "..." }, reload: { mode: "auto" } },

  // Network discovery
  discovery: { mdns: { mode: "minimal" } },

  // Plugin allowlist
  plugins: { allow: ["whatsapp", "channel-guard", "content-guard"] },

  // Logging
  logging: {
    redactSensitive: "tools",
    // maxFileBytes: 524288000,        // Log file size cap before writes suppressed; default 500 MB (added 2026.2.22)
  },

  // Cron — scheduled tasks (added 2026.2.16: webhookToken, notify)
  cron: {
    // webhookToken: "...",          // Auth token for external cron webhook triggers
    // notify: { channel: "whatsapp", peer: "+..." },  // Deliver cron output to a channel
    jobs: [/* ... */]
  }
}

DM Policy Options

ValueBehavior
pairingUnknown senders get 8-char code (expires 1hr)
allowlistOnly pre-approved senders
openAnyone (requires allowFrom: ["*"])
disabledIgnore all DMs

Group Policy & Mention Gating

Group messages are evaluated in three layers:

  1. groupPolicy — top-level gate at channel root
  2. Group allowlistsgroups keys, groupAllowFrom
  3. Mention gatingrequireMention inside groups, /activation command
groupPolicyBehavior
allowlistOnly groups listed in groups or groupAllowFrom (default)
openAll groups allowed; mention gating still applies
disabledBlock all group messages

The groups object

Keys are group IDs (or "*" for all groups). Values configure per-group behavior. Keys double as an allowlist — a group ID present as a key is implicitly allowed.

requireMention must be inside the groups object — see gotcha #14 for details and per-channel notes.

{
  channels: {
    whatsapp: {
      groupPolicy: "allowlist",
      groups: {
        "*": { requireMention: true },                        // Default: all groups, mention-gated
        "120363XXX@g.us": { requireMention: false },          // Specific group: always respond
        "120363YYY@g.us": { tools: { deny: ["exec"] } }      // Per-group tool restrictions
      }
    }
  }
}

Mention patterns

WhatsApp uses native @mention data (mentionedJids). Google Chat uses native @mention data (when botUser is configured). Signal and other channels without native mentions need regex patterns:

{
  agents: {
    list: [{
      id: "signal",
      groupChat: {
        mentionPatterns: ["@openclaw", "hey openclaw"]  // Case-insensitive regexes
      }
    }]
  }
}

Global fallback (all agents/channels): messages.groupChat.mentionPatterns.

Replying to a bot message counts as an implicit mention on WhatsApp, Google Chat, Telegram, Slack, Discord, and Teams.

Common patterns

GoalConfig
All groups, mention-gatedgroups: { "*": { requireMention: true } }
Specific groups onlygroups: { "<jid>": { requireMention: true } } (no "*" key)
Disable all groupsgroupPolicy: "disabled"
All groups, always respondgroups: { "*": { requireMention: false } }
Sender allowlist in groupsgroupAllowFrom: ["+1555..."]

Session Scope Options

See Session Management for the full deep-dive on session keys, lifecycle, compaction, and pruning.

ValueBehavior
mainAll DMs share one session
per-peerOne session per sender (across channels)
per-channel-peerOne session per sender per channel (recommended)
per-account-channel-peerMost isolated

Sandbox Modes

ModeBehavior
offNo sandboxing — all sessions run on host
non-mainOnly the agent:<id>:main session runs unsandboxed; all other sessions sandboxed
allEvery session sandboxed

Any other value (e.g. "tools") is invalid — causes config validation failure and a gateway crash loop.

What counts as “non-main”: WhatsApp DMs, group sessions, cron runs, and subagent sessions all have session keys that don’t match agent:<id>:main. They are all sandboxed with mode: "non-main". Only the Control UI / CLI main session runs unsandboxed.

Default Sandbox Tool Allow List

When a session is sandboxed, a separate tool policy applies — distinct from and in addition to the agent-level tool policy.

Default allow: exec, process, read, write, edit, apply_patch, image, sessions_list, sessions_history, sessions_send, sessions_spawn, subagents, session_status

Implicitly denied (not in default allow): message, browser, memory_search, memory_get, web_search, web_fetch, agents_list

The default allow list is a closed set — a tool not listed is denied in sandboxed sessions, even if the agent-level policy allows it.

To add message, browser, or memory tools to sandboxed sessions (e.g., so a WhatsApp DM session can send to groups or access memory), override the allow list. This config goes at the global tools level (applies to all agents) or per-agent under agents.list[].tools.sandbox.tools:

{
  "tools": {
    "sandbox": {
      "tools": {
        "allow": [
          "exec", "process", "read", "write", "edit", "apply_patch", "image",
          "sessions_list", "sessions_history", "sessions_send", "sessions_spawn",
          "subagents", "session_status",
          "message", "browser",
          "memory_search", "memory_get"
        ]
      }
    }
  }
}

Gotchas:

  • tools.sandbox.tools.alsoAllow does not work with the default policy (mergeAlsoAllowPolicy() requires an explicit base allow array). Must use allow with the full list.
  • sandbox.tools at agent level is invalid config. Correct path: agents.list[].tools.sandbox.tools (under the agent’s tools key).
  • Verify with: openclaw sandbox explain --agent <id> --session "<session-key>"

For sandbox architecture, container lifecycle, and config options, see Architecture — Docker Sandbox Architecture .

Sandbox Scope & Access Guide

Different agents need different sandbox configurations. Here’s when to use each combination:

Use CasescopeworkspaceAccessmodeRationale
Channel agents (whatsapp, signal)agentrwnon-mainNeed workspace for memory writes; sandbox provides network isolation
Search agentoffNo filesystem tools; tool policy provides isolation. Unsandboxed to avoid #9857
Main agent (recommended )agentrwnon-mainChannel sessions sandboxed on network: "openclaw-egress"; Control UI session on host (operator trusted). See egress allowlisting
Main agent (unsandboxed)offOperator interface; full host access (no Docker isolation)
Computer (optional hardened variant )agentrwallSeparate exec + browser agent, network: "openclaw-egress"
Ephemeral taskssessionnoneallContainer destroyed when session ends; no persistent state

Config Includes ($include)

Split large configs into multiple files — useful for multi-agent setups:

{
  gateway: { port: 18789 },
  agents: { $include: "./agents.json5" },           // Single file: replaces
  broadcast: { $include: ["./a.json5", "./b.json5"] } // Array: deep-merged in order
}

Paths are relative to the including file. Nested includes supported (up to 10 levels).

Config Validation

Config is strictly validated — unknown keys, malformed types, or invalid values cause the gateway to refuse to start. Run openclaw doctor to diagnose, openclaw doctor --fix to auto-repair.

Use openclaw config validate (added in 2026.3.2) to check the config file before starting the gateway:

openclaw config validate              # Human-readable output
openclaw config validate --json       # Machine-readable JSON with error details

Use openclaw config file (added in 2026.3.1) to print the active config file path:

openclaw config file                  # Prints e.g. /Users/openclaw/.openclaw/openclaw.json

Environment Files

OpenClaw reads .env files (non-overriding) from: CWD .env~/.openclaw/.env → config env block. Alternative to putting secrets in plist/systemd env vars.


Tool Policy Precedence

OpenClaw applies tool restrictions in an 8-layer cascade:

LayerSourceExample
1Tool profiletools.profile: "coding"
2Provider tool profiletools.byProvider.anthropic.profile
3Global tool policytools.deny: ["gateway"]
4Provider tool policytools.byProvider.anthropic.deny
5Agent tool policyagents.list[].tools.deny: ["exec"]
6Agent provider policyagents.list[].tools.byProvider.anthropic.deny
7Sandbox tool policytools.sandbox.tools
8Subagent tool policytools.subagents.tools

Critical: Global deny (layer 3) overrides agent-level allow (layer 5). A tool in tools.deny cannot be re-enabled by an agent’s tools.allow. For tools needed by some agents but not others (e.g., web_search for a search agent), deny per-agent instead of globally. See Phase 5 for the correct isolation pattern.

HTTP API tool restrictions: When sessions are created via the HTTP API (/api/v1/chat/completions), OpenClaw additionally denies sessions_spawn, sessions_send, gateway, and whatsapp_login — regardless of agent tool policy. This is a platform-level safety fence for external API callers. It does not apply to embedded agent sessions (session key agent:<id>:main). Override with gateway.tools.allow if needed.


Cron Jobs

sessionTarget

Controls how the cron job executes.

ValueBehavior
"isolated"Fresh throwaway session per run. Agent receives a prompt, executes it, returns a response. Supports channel delivery via delivery.
"main"Injects a short event into the agent’s existing main session (agent:<id>:main). Appended to the ongoing conversation — agent has full prior context. Only supports delivery.mode: "webhook".

Use "isolated" for tasks (“search for news and write a report”) — each run starts clean. Session key: agent:main:cron:<job-id>:run:<uuid>.

Use "main" for reminders and nudges (“you have a meeting in 10 minutes”) — the event lands in the agent’s running session with full context. Requires payload.kind: "systemEvent" with a text field.

wakeMode

ValueBehavior
"now"Triggers an immediate heartbeat — job runs right away
"next-heartbeat"Queues for the agent’s next scheduled heartbeat cycle

With heartbeat.every: "30m", "next-heartbeat" can delay up to 30 minutes. Use "now" for time-sensitive jobs; "next-heartbeat" for jobs where a delay is acceptable.

delivery

ModeBehavior
"announce"Agent’s final response delivered to a channel. Requires delivery.to (e.g. WhatsApp group JID). Agent can reply ANNOUNCE_SKIP to suppress.
"none"Job runs silently — no delivery.
"webhook"POST result to an HTTP URL. Works with both isolated and main.

When delivery is configured on isolated jobs, the runtime appends delivery instructions and disables the message tool (disableMessageTool: true) to prevent duplicate sends. The agent should not call message directly — the runtime delivers the final response automatically.

delivery.bestEffort: true — suppresses errors if delivery fails (e.g. WhatsApp disconnected).

Cron and group:automation

group:automation expands to ["cron", "gateway"]. These can be allowed/denied individually:

{ "deny": ["gateway"] }          // deny gateway only — keeps cron for conversational job management
{ "allow": [..., "cron"] }       // allow cron explicitly in an allowlist config

Alternatives to the cron tool for job management: Control UI (web), openclaw cron create/list/edit CLI, or direct edit of cron/jobs.json.


Chat Commands

Users can send / commands directly in WhatsApp or Signal chats. Commands must be sent as standalone messages (not inline with other text).

Core Commands

CommandWhat it doesAccess
/helpList available commandsAll authorized senders
/reset (/new [model])Fresh session; optionally switch modelAll authorized
/statusSession info (model, tokens, cost)All in DMs; owner-only in groups
/whoamiShow sender identityAll authorized
/compactCompact message historyAll authorized
/stopAbort current operationAll authorized
/activation mention|alwaysToggle group mention gatingOwner-only

Directives (Session Modifiers)

Directives change session behavior. Standalone = persists to session. Inline in a normal message = one-shot hint, stripped before the model sees it.

DirectiveControls
/think off|low|medium|highThinking/reasoning depth
/elevated off|on|ask|fullHost execution mode (escapes sandbox)
/model <name>Switch model mid-session

Dangerous Commands (Disabled by Default)

CommandConfig gateRisk
/bash <cmd> or ! <cmd>commands.bash: trueHost shell access
/configcommands.config: trueRuntime config changes
/debugcommands.debug: trueRuntime overrides
/restartcommands.restart: trueService disruption

These are owner-only even when enabled. Tool policy still applies — /elevated can’t override tools in tools.deny.

Full command reference: docs.openclaw.ai/tools/slash-commands

Google Chat: Slash commands work in Google Chat DMs and spaces. For Google Chat setup and known issues (e.g., DM routing), see Google Chat Channel Setup .


Gotchas & Non-Obvious Behaviors

Tool Policy

  1. deny always beats allow at the same level. If a tool is in both lists, it’s denied.

  2. allow is exclusive — if allow is non-empty, everything not listed is blocked. An empty allow list means “allow everything not denied.”

  3. Tool policy is a hard stop — chat commands like /exec cannot override denied tools.

  4. Global deny overrides agent-level allow — a tool in tools.deny cannot be re-enabled at the agent level. For tools needed by some agents (e.g., web_search), deny per-agent instead of globally.

  5. profile: "full" means no restrictionstools.profile: "full" expands to an empty allow/deny set, bypassing all profile-level filtering entirely. Unlike "coding" (which includes a curated allow list), "full" is a footgun: every tool is reachable unless explicitly denied. Prefer explicit tools.allow lists over "full" when you need broad access.

  6. group:ui deny includes browser — if an agent allows browser but denies group:ui, browser is silently disabled. Deny canvas individually instead when browser should remain available.

  7. exec allowlists don’t catch shell builtins — allowlists match resolved binary paths only. Shell builtins (cd, export, source) bypass the check entirely. echo is both a shell builtin and a standalone binary (/bin/echo) — behavior differs between them, and the builtin version varies by shell. If this matters, deny exec at the agent level.

Agents & Sessions

  1. Never share agentDir between agents — causes auth collisions and session corruption.

  2. MEMORY.md loads in main sessions only (not groups or shared contexts) — don’t put security-critical instructions there.

  3. Binding precedence is most-specific wins — a peer-level binding beats a channel-level one.

  4. elevated mode is per-session, not permanent — but tools.elevated.enabled: false blocks it globally.

  5. Session transcripts contain full message history and tool output — treat them as sensitive. Prune regularly if retention isn’t needed.

Channels

  1. Signal linked devices see everything — the primary phone gets all bot messages. No filtering possible.

  2. pairing codes expire after 1 hour with max 3 pending per channel.

  3. requireMention must be inside the groups object, not at channel root — placing it at channels.whatsapp.requireMention causes a Zod validation error. Correct: channels.whatsapp.groups: { "*": { requireMention: true } }. On Signal, also configure mentionPatterns in agents.list[].groupChat.mentionPatterns (no native @mention support). On Google Chat, set botUser in the channel config for reliable mention detection in spaces.

  4. Google Chat requires both channel config and plugin — missing either channels.googlechat or plugins.entries.googlechat.enabled: true causes a 405 error on the webhook endpoint.

  5. Google Chat per-space rate limit is 60/min (1 write/sec) — the 600/min figure in some documentation applies only to data import operations, not normal messaging.

  6. Placeholder allowFrom values cause silent message dropsallowFrom: ["+46XXXXXXXXX"] or any non-matching number silently drops all incoming messages with no error or log warning. Always replace placeholders with real phone numbers.

  7. Empty env vars cause config validation failure${BRAVE_API_KEY} as an empty string triggers EX_CONFIG (exit 78). Use a non-empty placeholder like "not-configured" for optional keys not yet provisioned.

Sandbox & Docker

  1. Sandbox tool policy is a separate layer from agent tool policy — even if an agent allows message or browser, those tools are blocked in sandboxed sessions unless explicitly listed in tools.sandbox.tools.allow. The default sandbox allow list does not include message, browser, memory_search, memory_get, or web_fetch. WhatsApp DM sessions (and all non-main sessions) are sandboxed with mode: "non-main" or "all". Use tools.sandbox.tools.allow with the full list including any tools your sandboxed sessions need. alsoAllow does not work with the default policy — must specify the complete allow list.

  2. Sandbox image must be built before use — the default openclaw-sandbox:bookworm-slim is raw debian:bookworm-slim with no packages. Run cd $(npm root -g)/openclaw && ./scripts/sandbox-setup.sh before enabling Docker sandboxing. Without this, all exec calls inside the sandbox fail (sh: 1: git: not found).

  3. exec host not allowed when sandboxed — exec calls targeting the gateway host fail with exec host not allowed (requested gateway; configure tools.exec.host=sandbox to allow). Add "tools": { "exec": { "host": "sandbox" } } to route exec to the sandbox container by default. With mode: "non-main" (recommended), this only affects sandboxed sessions (channel DMs/groups/cron) — the Control UI session runs on host and exec goes to host naturally. With mode: "all", the Control UI session is also sandboxed and all exec calls hit this. Prefer mode: "non-main" — the operator’s Control UI session should run on host.

  4. Sandbox network: "none" blocks package installssetupCommand requires network: "bridge" and readOnlyRoot: false, which weakens sandbox isolation. Prefer custom images for production — tools are pre-installed, so secure defaults are preserved.

  5. Bind mounts pierce sandbox filesystem — always use :ro suffix. Never bind docker.sock.

Cron

  1. delivery.to not delivery.target — the cron delivery destination field is delivery.to (e.g. a WhatsApp group JID). The field delivery.target does not exist — using it silently delivers to the wrong destination (DM instead of group). Always use delivery.to.

  2. --announce (delivery mode) requires a channel — creating a cron job with openclaw cron add --announce but no --channel succeeds at creation time, but every run fails at the delivery step with cron delivery target is missing. The error repeats every run and clutters logs. Always pair --announce with --channel <whatsapp|signal> (and a peer if required by your dmPolicy). If there is nothing to report, have the agent reply ANNOUNCE_SKIP to suppress delivery.

  3. Cron jobs can no longer notify via ad hoc agent sends (2026.3.11+) — isolated cron delivery was tightened so cron jobs can no longer notify through the message tool or fallback main-session summaries outside the official delivery mechanism. If you have legacy cron jobs that relied on the agent calling message directly to report results, migrate them to delivery.mode: "announce" with an explicit delivery.to target. Run openclaw doctor --fix to auto-migrate legacy cron storage and delivery metadata.

Config & Gateway

  1. gateway.mode is required — the gateway refuses to start unless gateway.mode: "local" is set in config. Use --allow-unconfigured for ad-hoc/dev runs.

  2. Config validation is strict — unknown keys, malformed types, or invalid values cause the gateway to refuse to start. Run openclaw doctor to diagnose.

  3. Environment variable substitution only matches [A-Z_][A-Z0-9_]* — lowercase vars won’t resolve. Missing vars throw errors at config load.

  4. openclaw gateway stop/restart works with LaunchAgent but not LaunchDaemon — OpenClaw’s built-in gateway commands (openclaw gateway stop, openclaw gateway restart) manage LaunchAgents (gui/<uid> domain) and systemd user services. The default LaunchAgent setup works with these commands. If you use the hardened LaunchDaemon alternative (system domain) or systemd system service, these commands won’t find it — use launchctl bootout/bootstrap or systemctl restart directly. Additionally, KeepAlive: true (launchd) or Restart=always (systemd) causes the service manager to immediately respawn a killed process, which can race with OpenClaw’s own restart logic.

Plugins

  1. Plugin changes require a gateway restart — plugin source files (.ts) are loaded at startup. Config hot-reload does NOT reload plugins. After updating a plugin in ~/.openclaw/extensions/, restart the gateway.

  2. Broken tool results poison session history — if a plugin returns malformed content blocks (wrong format, missing fields), the broken entry persists in the session .jsonl file. Every subsequent message replays it, causing the same error even after the plugin is fixed. Fix: delete the affected session file. Identify it by grepping for the error pattern, then remove:

    # Find sessions with broken image blocks (example)
    grep -l 'media_type' ~/.openclaw/agents/*/sessions/*.jsonl
    # Delete the affected session file — next message creates a fresh one
  3. Image content blocks are model-visible only — tool result image blocks let the LLM see the image but are NOT forwarded as media to channels. To deliver images via WhatsApp/Signal/Google Chat, include a MEDIA:<path> directive in a text content block. OpenClaw’s splitMediaFromOutput() scans text for these directives and attaches matching files as media.

  4. OpenClaw uses a flat image content block format{type: "image", data: "<base64>", mimeType: "image/png"}. This differs from the Anthropic API format ({type: "image", source: {type: "base64", media_type, data}}). Plugins must use the flat format; OpenClaw converts to API format before sending to the LLM.

  5. plugins.allow and enabled: false are independent checks — both must pass for a plugin to load. A plugin in plugins.allow with "enabled": false is fully blocked: the file is never imported, register() is never called. Check precedence: denyallowenabled. You can safely pre-populate plugins.allow with trusted plugin IDs and control which ones actually load via enabled.

  6. Plugin tools are available by default — enabling a plugin that registers tools (image-gen → generate_image, computer-use → vm_*) makes those tools callable by any agent not blocking them. Agents using tools.allow are safe (unlisted tools are blocked). Agents using only tools.deny must explicitly deny plugin tools they shouldn’t have.

  7. Plugin-generated temp files accumulate — plugins that save images via MEDIA: pattern write to $TMPDIR. macOS clears /tmp on reboot, but long-running servers accumulate files. Consider a cron job: find /tmp/openclaw-image-gen -mtime +1 -delete.

Memory

  1. Remote memory search providers need a separate API key — the embedding key (e.g., OPENAI_API_KEY for OpenAI embeddings) is not the same as your AI provider key (ANTHROPIC_API_KEY). Both must be set.

  2. Local memory search requires native build approval — run npx pnpm approve-builds then npx pnpm rebuild node-llama-cpp (from the OpenClaw install directory). Without this, memory_search falls back to a remote provider (if configured) or returns no results.

  3. Memory search auto-reindexes on provider/model change — OpenClaw tracks the embedding provider, model, and chunking params in the index. Changing any of these triggers an automatic reindex. Run openclaw memory index to force an immediate rebuild.

  4. Daily memory files are auto-loaded for today + yesterday only — older files are only accessible via memory_search. If search isn’t configured, the agent can’t recall anything beyond yesterday.


Version Compatibility

Features below require the listed version or later. Check yours with openclaw --version.

VersionFeatureDetails
2026.1.29Control UI token fixSecurity vulnerability (CVSS 8.8) patched — update immediately. See Phase 3
2026.2.1before_tool_call hookRequired for content-guard and network-guard plugins
2026.2.3-1Security audit baselineVersion used in the worked audit example
2026.2.9xAI (Grok) providerNew search provider option
2026.2.12Channel bindings regression#15176 — bindings to non-default agents broken. Not relevant for recommended 2-agent config (all channels route to main)
2026.2.15sessions_spawn sandbox bug#9857sessions_spawn breaks when both agents are sandboxed with per-agent tools. Workaround: run search agent unsandboxed
2026.2.16Security hardening + plugin hooks + subagent limitsCSP enforcement, workspace path sanitization, web_fetch response size cap (tools.web.fetch.maxResponseBytes, default 5 MB), dangerous Docker config rejection, llm_input/llm_output plugin hooks, maxSpawnDepth/maxChildrenPerAgent for nested subagents, Unicode-aware FTS, timezone-aware memory dates, per-agent QMD scoping, Telegram token auto-redaction
2026.2.19Gateway auth auto-generation, hook/plugin path containment, SSRF hardeningSee Phase 3 version note
2026.2.21Shell exec env injection blocking, sandbox browser hardening, Tailscale auth scopingSee Phase 3 version note
2026.2.22Exec safeBin path pinning, openclaw config get redaction, group policy fail-closedSee Phase 3 version note
2026.2.23browser.ssrfPolicy.dangerouslyAllowPrivateNetwork (breaking rename), HSTS support, exec obfuscation detection, openclaw sessions cleanup with disk-budget controlsSee Phase 3 version note
2026.2.26openclaw secrets workflow (audit, configure, apply, reload), openclaw agents bindings/bind/unbindExternal secrets management — see Phase 6
2026.3.1Gateway health endpoints (/health, /healthz, /ready, /readyz), agents.*.heartbeat.lightContextHealth endpoints useful for Docker/Kubernetes health checks
2026.3.2openclaw config validate, tools.profile: "messaging" new default, pdf tool, Telegram streaming defaults to partial, LaunchAgent Umask keySee Phase 3 version note for security details
2026.3.12Workspace plugin auto-load disabled, exec approval Unicode/obfuscation hardening, /config+/debug owner-only, device pairing bootstrap tokens, gateway auth scope fixes, agents.defaults.compaction.postIndexSync, sessions_yield for orchestratorsSee Phase 3 version note; multiple CVEs patched
2026.3.13-1Node.js 22.16.0+ minimum enforced, OPENCLAW_TZ Docker timezone support, Signal groups schema support, Docker build context token leak fix, session key :dm: corrected to :direct:Recovery release (npm version remains 2026.3.13)

Plugins

PluginPurposeRequired env var
whatsappWhatsApp channel (bundled)
signalSignal channel (bundled)
googlechatGoogle Chat channel (bundled)GOOGLE_CHAT_SERVICE_ACCOUNT_FILE
content-guardLLM-based injection scanning at sessions_send boundary (search→main)OPENROUTER_API_KEY
channel-guardInbound message injection scanning for WhatsApp/Signal/Google ChatOPENROUTER_API_KEY
file-guardPath-based file access protection (no_access, read_only, no_delete)— (deterministic)
network-guardApplication-level domain allowlisting for network tool calls— (deterministic, no model)
command-guardRegex-based dangerous command blocking— (no external deps)
image-genGenerate images from text prompts via OpenRouterOPENROUTER_API_KEY
computer-useVM computer interaction (Lume)— (WebSocket to cua-computer-server)

The content-guard plugin intercepts sessions_send calls at the search→main trust boundary, classifying message content for prompt injection using an LLM (claude-haiku-4-5 via OpenRouter). It identifies search-agent traffic by the params.sessionKey of the sessions_send call (sessions targeting agent:search:*); all other sessions_send calls (e.g. proactive group delivery) are skipped without scanning. Note: event.agentId is not populated by the runtime for before_tool_call events — rely on params.sessionKey for caller identification. The channel-guard plugin scans incoming WhatsApp/Signal/Google Chat messages before agent processing using an OpenRouter LLM classifier with warn/block thresholds, fail-closed by default (failOpen: false). Both are included in the recommended configuration .

The file-guard, network-guard, and command-guard plugins provide deterministic enforcement — no ML model, no external dependencies. file-guard enforces path-based file protection with three levels (no_access, read_only, no_delete). network-guard enforces application-level domain allowlisting for web_fetch and exec tool calls. command-guard blocks dangerous shell commands (rm -rf, fork bombs, force push, etc.) via regex. All three are included in the hardened multi-agent configuration and can optionally be added to any deployment. See Phase 5 for overview and the extension docs for full configuration.

Plugin Hooks

Plugins can register handlers for these lifecycle hooks:

HookWhen it firesExample use
before_tool_callBefore a tool executescontent-guard: classify sessions_send content
message_receivedIncoming channel message (WhatsApp/Signal/Google Chat)channel-guard: scan for injection
llm_inputBefore prompt is sent to the model (added 2026.2.16)Input logging, token counting, content filtering
llm_outputAfter model response received (added 2026.2.16)Output logging, response filtering, compliance checks

Note: after_tool_result is not yet wiredbefore_tool_call + pre-fetch is the current workaround for content scanning.

The image-gen plugin registers a generate_image tool that agents can call to create images from text prompts. Uses OpenRouter’s unified API — supports FLUX, Gemini, GPT, and Sourceful models. See extensions/image-gen/ for source.

The computer-use plugin registers 7 vm_* tools for controlling a macOS Lume VM via WebSocket connection to cua-computer-server. Requires Apple Silicon Mac with Lume. See extensions/computer-use/ for setup and Phase 8 for deployment.

Plugin Installation

Plugin directories must be named to match the manifest ID in openclaw.plugin.json (e.g., content-guard/, not openclaw-content-guard/). The name field in package.json should also match the manifest ID.

Manual installation (recommended — openclaw plugins install may fail to resolve dependencies or link manifests correctly; see the OpenClaw changelog for current plugin CLI status):

cp -r extensions/content-guard ~/.openclaw/extensions/content-guard
cp -r extensions/channel-guard ~/.openclaw/extensions/channel-guard

The gateway discovers plugins from ~/.openclaw/extensions/ at startup. Each plugin directory must contain openclaw.plugin.json. Plugin code is loaded once at startup — changes to deployed plugins require a gateway restart (config hot-reload does NOT reload plugins).

Discovery precedence: Plugins are discovered in order: workspace-level (.openclaw/extensions/ in workspace), user-level (~/.openclaw/extensions/), then bundled. First match wins.

CLI installation (when available):

openclaw plugins install --link /path/to/plugin
// openclaw.json — plugins section
{
  plugins: {
    entries: {
      "content-guard": {
        enabled: true,
        config: {
          model: "anthropic/claude-haiku-4-5",
          maxContentLength: 50000, // Truncate content sent to model
          timeoutMs: 15000,      // Classification timeout
        }
      },
      "channel-guard": {
        enabled: true,
        config: {
          model: "anthropic/claude-haiku-4-5",
          maxContentLength: 10000,
          timeoutMs: 10000,
          failOpen: false,       // Block messages if classifier unavailable
          warnThreshold: 0.4,    // Score to inject advisory
          blockThreshold: 0.8    // Score to hard-block message
        }
      },
      "image-gen": {
        enabled: true,
        config: {
          apiKey: "${OPENROUTER_API_KEY}",
          defaultModel: "openai/gpt-5-image-mini",
          defaultAspectRatio: "1:1",
          defaultImageSize: "2K",
          timeoutMs: 60000
        }
      }
    }
  }
}

Useful Commands

# Setup & channels
openclaw setup                              # First-time setup (creates ~/.openclaw/)
openclaw channels login                     # Link a channel (QR code for WhatsApp)
openclaw channels login --account <id>      # Link a specific account
openclaw channels logout                    # Unlink channel

# Gateway management (foreground / LaunchAgent)
openclaw start                              # Start gateway in foreground
openclaw health                             # Gateway health check
openclaw status                             # Gateway status
openclaw dashboard                          # Open browser UI
openclaw logs                               # View logs

# Gateway management — LaunchDaemon (macOS) / systemd (Linux)
# scripts/docker-isolation/gateway.sh wraps these for both platforms + multi-instance
bash scripts/gateway.sh start    [instance]  # Start
bash scripts/gateway.sh stop     [instance]  # Stop
bash scripts/gateway.sh restart  [instance]  # Restart
bash scripts/gateway.sh status   [instance]  # Status
bash scripts/gateway.sh reload   [instance]  # Reload config (SIGUSR1, no restart)
bash scripts/gateway.sh logs     <instance>  # Tail logs (instance required for multi)

# Diagnostics & security
openclaw doctor                             # Diagnose config issues
openclaw doctor --fix                       # Auto-apply config migrations/repairs
openclaw doctor --generate-gateway-token    # Generate a secure token
openclaw security audit                     # Security scan
openclaw security audit --deep              # Deep scan (requires running gateway)
openclaw security audit --fix               # Auto-apply safe guardrails
openclaw config validate                    # Validate config file before startup (2026.3.2+)
openclaw config validate --json             # Machine-readable validation output
openclaw config file                        # Print active config file path (2026.3.1+)

# Memory
openclaw memory status                      # Index size, provider, last indexed
openclaw memory status --deep               # Probe vector + embedding availability
openclaw memory status --deep --index       # Reindex if store is dirty
openclaw memory index                       # Build/rebuild search index
openclaw memory index --agent <id>          # Rebuild index for specific agent
openclaw memory search "<query>"            # Search memory from terminal
openclaw memory search --query "<query>"    # Equivalent long-form (2026.2.24+)

# Session management
openclaw sessions list                      # List active sessions
openclaw sessions reset                     # Reset all sessions
openclaw sessions cleanup                   # Clean up disk + orphaned sessions (2026.2.23+)
openclaw sessions cleanup --fix-missing     # Prune store entries with missing transcripts (2026.2.26+)

# Agent routing
openclaw agents bindings                    # List account-scoped route bindings (2026.2.26+)
openclaw agents bind <agent> <channel>      # Bind an agent to a channel account
openclaw agents unbind <agent> <channel>    # Remove a channel binding

# Secrets management (2026.2.26+)
openclaw secrets audit                      # Find hardcoded secrets in config
openclaw secrets configure                  # Configure secrets provider
openclaw secrets apply                      # Write SecretRefs to config
openclaw secrets reload                     # Activate secrets snapshot without restart

# Pairing
openclaw pairing list <channel>             # List pending pairing requests
openclaw pairing approve <channel> <code>   # Approve a pairing code

# Updates
openclaw update                                # Built-in updater
curl -fsSL https://openclaw.ai/install.sh | bash  # Alternative: install script

Links

Official

Last updated on