Keyboard shortcuts

Press ← or β†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

OpenClaw reads an optional JSON5 config from ~/.openclaw/openclaw.json.

If the file is missing, OpenClaw uses safe defaults. Common reasons to add a config:

  • Connect channels and control who can message the bot
  • Set models, tools, sandboxing, or automation (cron, hooks)
  • Tune sessions, media, networking, or UI

See the full reference for every available field.

πŸ’‘ Tip:

New to configuration? Start with openclaw onboard for interactive setup, or check out the Configuration Examples guide for complete copy-paste configs.

Minimal config

// ~/.openclaw/openclaw.json
{
  agents: { defaults: { workspace: "~/.openclaw/workspace" } },
  channels: { whatsapp: { allowFrom: ["+15555550123"] } },
}

Editing config

Interactive wizard:

    openclaw onboard       # full setup wizard
    openclaw configure     # config wizard
    ```
  **CLI (one-liners):**

```bash
    openclaw config get agents.defaults.workspace
    openclaw config set agents.defaults.heartbeat.every "2h"
    openclaw config unset tools.web.search.apiKey
    ```
  **Control UI:**

Open [http://127.0.0.1:18789](http://127.0.0.1:18789) and use the **Config** tab.
    The Control UI renders a form from the config schema, with a **Raw JSON** editor as an escape hatch.
  **Direct edit:**

Edit `~/.openclaw/openclaw.json` directly. The Gateway watches the file and applies changes automatically (see [hot reload](#config-hot-reload)).

## Strict validation

> **⚠️ Warning:**
>
> OpenClaw only accepts configurations that fully match the schema. Unknown keys, malformed types, or invalid values cause the Gateway to **refuse to start**. The only root-level exception is `$schema` (string), so editors can attach JSON Schema metadata.

When validation fails:

- The Gateway does not boot
- Only diagnostic commands work (`openclaw doctor`, `openclaw logs`, `openclaw health`, `openclaw status`)
- Run `openclaw doctor` to see exact issues
- Run `openclaw doctor --fix` (or `--yes`) to apply repairs

## Common tasks

  <details>
<summary>Set up a channel (WhatsApp, Telegram, Discord, etc.)</summary>

Each channel has its own config section under `channels.<provider>`. See the dedicated channel page for setup steps:

    - [WhatsApp](./channels/whatsapp.md) β€” `channels.whatsapp`
    - [Telegram](./channels/telegram.md) β€” `channels.telegram`
    - [Discord](./channels/discord.md) β€” `channels.discord`
    - [Slack](./channels/slack.md) β€” `channels.slack`
    - [Signal](./channels/signal.md) β€” `channels.signal`
    - [iMessage](./channels/imessage.md) β€” `channels.imessage`
    - [Google Chat](./channels/googlechat.md) β€” `channels.googlechat`
    - [Mattermost](./channels/mattermost.md) β€” `channels.mattermost`
    - [MS Teams](./channels/msteams.md) β€” `channels.msteams`

    All channels share the same DM policy pattern:

    ```json5
    {
      channels: {
        telegram: {
          enabled: true,
          botToken: "123:abc",
          dmPolicy: "pairing",   // pairing | allowlist | open | disabled
          allowFrom: ["tg:123"], // only for allowlist/open
        },
      },
    }
    ```

</details>

  <details>
<summary>Choose and configure models</summary>

Set the primary model and optional fallbacks:

    ```json5
    {
      agents: {
        defaults: {
          model: {
            primary: "anthropic/claude-sonnet-4-5",
            fallbacks: ["openai/gpt-5.2"],
          },
          models: {
            "anthropic/claude-sonnet-4-5": { alias: "Sonnet" },
            "openai/gpt-5.2": { alias: "GPT" },
          },
        },
      },
    }
    ```

    - `agents.defaults.models` defines the model catalog and acts as the allowlist for `/model`.
    - Model refs use `provider/model` format (e.g. `anthropic/claude-opus-4-6`).
    - See [Models CLI](./concepts/models.md) for switching models in chat and [Model Failover](./concepts/model-failover.md) for auth rotation and fallback behavior.
    - For custom/self-hosted providers, see [Custom providers](./gateway/configuration-reference#custom-providers-and-base-urls.md) in the reference.

</details>

  <details>
<summary>Control who can message the bot</summary>

DM access is controlled per channel via `dmPolicy`:

    - `"pairing"` (default): unknown senders get a one-time pairing code to approve
    - `"allowlist"`: only senders in `allowFrom` (or the paired allow store)
    - `"open"`: allow all inbound DMs (requires `allowFrom: ["*"]`)
    - `"disabled"`: ignore all DMs

    For groups, use `groupPolicy` + `groupAllowFrom` or channel-specific allowlists.

    See the [full reference](./gateway/configuration-reference#dm-and-group-access.md) for per-channel details.

</details>

  <details>
<summary>Set up group chat mention gating</summary>

Group messages default to **require mention**. Configure patterns per agent:

    ```json5
    {
      agents: {
        list: [
          {
            id: "main",
            groupChat: {
              mentionPatterns: ["@openclaw", "openclaw"],
            },
          },
        ],
      },
      channels: {
        whatsapp: {
          groups: { "*": { requireMention: true } },
        },
      },
    }
    ```

    - **Metadata mentions**: native @-mentions (WhatsApp tap-to-mention, Telegram @bot, etc.)
    - **Text patterns**: regex patterns in `mentionPatterns`
    - See [full reference](./gateway/configuration-reference#group-chat-mention-gating.md) for per-channel overrides and self-chat mode.

</details>

  <details>
<summary>Configure sessions and resets</summary>

Sessions control conversation continuity and isolation:

    ```json5
    {
      session: {
        dmScope: "per-channel-peer",  // recommended for multi-user
        reset: {
          mode: "daily",
          atHour: 4,
          idleMinutes: 120,
        },
      },
    }
    ```

    - `dmScope`: `main` (shared) | `per-peer` | `per-channel-peer` | `per-account-channel-peer`
    - See [Session Management](./concepts/session.md) for scoping, identity links, and send policy.
    - See [full reference](./gateway/configuration-reference#session.md) for all fields.

</details>

  <details>
<summary>Enable sandboxing</summary>

Run agent sessions in isolated Docker containers:

    ```json5
    {
      agents: {
        defaults: {
          sandbox: {
            mode: "non-main",  // off | non-main | all
            scope: "agent",    // session | agent | shared
          },
        },
      },
    }
    ```

    Build the image first: `scripts/sandbox-setup.sh`

    See [Sandboxing](./gateway/sandboxing.md) for the full guide and [full reference](./gateway/configuration-reference#sandbox.md) for all options.

</details>

  <details>
<summary>Set up heartbeat (periodic check-ins)</summary>

```json5
    {
      agents: {
        defaults: {
          heartbeat: {
            every: "30m",
            target: "last",
          },
        },
      },
    }
    ```

    - `every`: duration string (`30m`, `2h`). Set `0m` to disable.
    - `target`: `last` | `whatsapp` | `telegram` | `discord` | `none`
    - See [Heartbeat](./gateway/heartbeat.md) for the full guide.

</details>

  <details>
<summary>Configure cron jobs</summary>

```json5
    {
      cron: {
        enabled: true,
        maxConcurrentRuns: 2,
        sessionRetention: "24h",
      },
    }
    ```

    See [Cron jobs](./automation/cron-jobs.md) for the feature overview and CLI examples.

</details>

  <details>
<summary>Set up webhooks (hooks)</summary>

Enable HTTP webhook endpoints on the Gateway:

    ```json5
    {
      hooks: {
        enabled: true,
        token: "shared-secret",
        path: "/hooks",
        defaultSessionKey: "hook:ingress",
        allowRequestSessionKey: false,
        allowedSessionKeyPrefixes: ["hook:"],
        mappings: [
          {
            match: { path: "gmail" },
            action: "agent",
            agentId: "main",
            deliver: true,
          },
        ],
      },
    }
    ```

    See [full reference](./gateway/configuration-reference#hooks.md) for all mapping options and Gmail integration.

</details>

  <details>
<summary>Configure multi-agent routing</summary>

Run multiple isolated agents with separate workspaces and sessions:

    ```json5
    {
      agents: {
        list: [
          { id: "home", default: true, workspace: "~/.openclaw/workspace-home" },
          { id: "work", workspace: "~/.openclaw/workspace-work" },
        ],
      },
      bindings: [
        { agentId: "home", match: { channel: "whatsapp", accountId: "personal" } },
        { agentId: "work", match: { channel: "whatsapp", accountId: "biz" } },
      ],
    }
    ```

    See [Multi-Agent](./concepts/multi-agent.md) and [full reference](./gateway/configuration-reference#multi-agent-routing.md) for binding rules and per-agent access profiles.

</details>

  <details>
<summary>Split config into multiple files ($include)</summary>

Use `$include` to organize large configs:

    ```json5
    // ~/.openclaw/openclaw.json
    {
      gateway: { port: 18789 },
      agents: { $include: "./agents.json5" },
      broadcast: {
        $include: ["./clients/a.json5", "./clients/b.json5"],
      },
    }
    ```

    - **Single file**: replaces the containing object
    - **Array of files**: deep-merged in order (later wins)
    - **Sibling keys**: merged after includes (override included values)
    - **Nested includes**: supported up to 10 levels deep
    - **Relative paths**: resolved relative to the including file
    - **Error handling**: clear errors for missing files, parse errors, and circular includes

</details>

## Config hot reload

The Gateway watches `~/.openclaw/openclaw.json` and applies changes automatically β€” no manual restart needed for most settings.

### Reload modes

| Mode                   | Behavior                                                                                |
| ---------------------- | --------------------------------------------------------------------------------------- |
| **`hybrid`** (default) | Hot-applies safe changes instantly. Automatically restarts for critical ones.           |
| **`hot`**              | Hot-applies safe changes only. Logs a warning when a restart is needed β€” you handle it. |
| **`restart`**          | Restarts the Gateway on any config change, safe or not.                                 |
| **`off`**              | Disables file watching. Changes take effect on the next manual restart.                 |

```json5
{
  gateway: {
    reload: { mode: "hybrid", debounceMs: 300 },
  },
}

What hot-applies vs what needs a restart

Most fields hot-apply without downtime. In hybrid mode, restart-required changes are handled automatically.

CategoryFieldsRestart needed?
Channelschannels.*, web (WhatsApp) β€” all built-in and extension channelsNo
Agent & modelsagent, agents, models, routingNo
Automationhooks, cron, agent.heartbeatNo
Sessions & messagessession, messagesNo
Tools & mediatools, browser, skills, audio, talkNo
UI & miscui, logging, identity, bindingsNo
Gateway servergateway.* (port, bind, auth, tailscale, TLS, HTTP)Yes
Infrastructurediscovery, canvasHost, pluginsYes

πŸ“ Note:

gateway.reload and gateway.remote are exceptions β€” changing them does not trigger a restart.

Config RPC (programmatic updates)

config.apply (full replace)

Validates + writes the full config and restarts the Gateway in one step.

> **⚠️ Warning:**

config.apply replaces the entire config. Use config.patch for partial updates, or openclaw config set for single keys.

Params:

- `raw` (string) β€” JSON5 payload for the entire config
- `baseHash` (optional) β€” config hash from `config.get` (required when config exists)
- `sessionKey` (optional) β€” session key for the post-restart wake-up ping
- `note` (optional) β€” note for the restart sentinel
- `restartDelayMs` (optional) β€” delay before restart (default 2000)

```bash
openclaw gateway call config.get --params '{}'  # capture payload.hash
openclaw gateway call config.apply --params '{
  "raw": "{ agents: { defaults: { workspace: \"~/.openclaw/workspace\" } } }",
  "baseHash": "<hash>",
  "sessionKey": "agent:main:whatsapp:dm:+15555550123"
}'
```
config.patch (partial update)

Merges a partial update into the existing config (JSON merge patch semantics):

- Objects merge recursively
- `null` deletes a key
- Arrays replace

Params:

- `raw` (string) β€” JSON5 with just the keys to change
- `baseHash` (required) β€” config hash from `config.get`
- `sessionKey`, `note`, `restartDelayMs` β€” same as `config.apply`

```bash
openclaw gateway call config.patch --params '{
  "raw": "{ channels: { telegram: { groups: { \"*\": { requireMention: false } } } } }",
  "baseHash": "<hash>"
}'
```

Environment variables

OpenClaw reads env vars from the parent process plus:

  • .env from the current working directory (if present)
  • ~/.openclaw/.env (global fallback)

Neither file overrides existing env vars. You can also set inline env vars in config:

{
  env: {
    OPENROUTER_API_KEY: "sk-or-...",
    vars: { GROQ_API_KEY: "gsk-..." },
  },
}
Shell env import (optional)

If enabled and expected keys aren’t set, OpenClaw runs your login shell and imports only the missing keys:

{
  env: {
    shellEnv: { enabled: true, timeoutMs: 15000 },
  },
}

Env var equivalent: OPENCLAW_LOAD_SHELL_ENV=1

Env var substitution in config values

Reference env vars in any config string value with ${VAR_NAME}:

{
  gateway: { auth: { token: "${OPENCLAW_GATEWAY_TOKEN}" } },
  models: { providers: { custom: { apiKey: "${CUSTOM_API_KEY}" } } },
}

Rules:

  • Only uppercase names matched: [A-Z_][A-Z0-9_]*
  • Missing/empty vars throw an error at load time
  • Escape with $${VAR} for literal output
  • Works inside $include files
  • Inline substitution: "${BASE}/v1" β†’ "https://api.example.com/v1"

See Environment for full precedence and sources.

Full reference

For the complete field-by-field reference, see Configuration Reference.


Related: Configuration Examples Β· Configuration Reference Β· Doctor