Last updated: 2026-04-06

OpenClaw Configuration Reference

OpenClaw stores all configuration in ~/.openclaw/openclaw.json using JSON5 format (comments allowed, trailing commas OK). The gateway validates strictly on startup — unknown keys or wrong types prevent it from starting. This is the complete reference for every top-level object.

Quick commands

openclaw onboard — interactive first-time setup wizard
openclaw config get agents.defaults.model — read a specific key
openclaw config set agents.defaults.heartbeat.every "2h" — set a value
openclaw config schema — view full JSON Schema
openclaw doctor — diagnose config problems
openclaw doctor --fix — auto-repair common issues

Top-Level Structure

The config file is a single JSON5 object. All top-level keys are optional — OpenClaw applies defaults for anything missing.

KeyPurpose
agentsAgent defaults, model list, skills, sandbox settings, heartbeat
channelsChannel integrations: WhatsApp, Telegram, Discord, Slack, email, etc.
sessionConversation scope, thread bindings, daily reset behaviour
gatewayServer port, auth token, health monitoring, hot-reload mode
cronScheduled job settings, concurrency, session retention, run logs
hooksWebhook endpoints, routing mappings, security tokens
envEnvironment variables, secrets, shell imports
uiWeb UI customisation
broadcastMulti-client configuration

agents — Model, Skills & Sandbox

{
  agents: {
    defaults: {
      workspace: "~/.openclaw/workspace",

      // Primary model + fallbacks
      model: {
        primary: "anthropic/claude-sonnet-4-6",
        fallbacks: ["openai/gpt-4.1"]
      },

      // Model allowlist — defines which models users can switch to
      models: {
        "anthropic/claude-sonnet-4-6": { alias: "Sonnet" },
        "anthropic/claude-haiku-4-5":  { alias: "Haiku"  },
        "openai/gpt-4.1":              { alias: "GPT4"   }
      },

      // Skills enabled by default for all agents
      skills: ["github", "weather", "daily-brief"],

      // Sandbox controls which tools run in isolation
      sandbox: {
        mode: "non-main",  // off | non-main | all
        scope: "agent"     // session | agent | shared
      },

      // Heartbeat: proactive check-ins on a schedule
      heartbeat: {
        every: "30m",   // cron or duration string. "0" = disabled
        target: "last"  // "last" = most recent session
      }
    },

    // Multiple named agents
    list: [
      {
        id: "main",
        default: true,
        workspace: "~/.openclaw/workspace",
        skills: ["github", "daily-brief"],
        groupChat: {
          mentionPatterns: ["@openclaw", "openclaw"]
        }
      },
      {
        id: "work",
        workspace: "~/.openclaw/workspace-work",
        skills: ["github", "jira"]
      }
    ]
  }
}

Sandbox Modes

ModeBehaviour
offNo sandboxing — all skills run with full host access
non-mainNon-primary agents run sandboxed; main agent runs direct (recommended)
allAll agents sandboxed — most secure, slowest startup

channels — All Integrations

Every channel uses the same DM access pattern. The key config fields are consistent across all providers:

{
  channels: {
    <provider>: {
      enabled: true,
      dmPolicy:    "pairing",    // pairing | allowlist | open | disabled
      allowFrom:   ["+15555550123"],  // phone numbers, user IDs, or "*"
      groupPolicy: "mention",    // open | allowlist | disabled
      groups: {
        "*": { requireMention: true }
      }
    }
  }
}

dmPolicy Values

ValueBehaviourUse case
pairingNew users send /start, get a code, you approve it on the serverPersonal use — most secure default
allowlistOnly user IDs in allowFrom can DM the agentFamily/team where you know all IDs upfront
openAnyone who discovers the bot can message itPublic bots only — not recommended for personal agents
disabledDMs completely blocked; group-only accessGroup-only deployments

Telegram

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "${TELEGRAM_BOT_TOKEN}",
      dmPolicy: "pairing",
      allowFrom: ["8734062810"],   // your numeric Telegram user ID
      groupPolicy: "allowlist",
      groups: {
        "-1001234567890": {        // group chat ID (negative number)
          requireMention: true,
          allowFrom: ["8734062810", "745123456"]
        }
      }
    }
  }
}

WhatsApp

{
  channels: {
    whatsapp: {
      enabled: true,
      dmPolicy: "allowlist",
      allowFrom: ["+15555550123"],   // E.164 format
      groupPolicy: "mention"
    }
  }
}

Discord

{
  channels: {
    discord: {
      enabled: true,
      botToken: "${DISCORD_BOT_TOKEN}",
      applicationId: "123456789012345678",
      dmPolicy: "allowlist",
      allowFrom: ["your-discord-user-id"]
    }
  }
}

session — Scope & Reset

{
  session: {
    // How conversation history is scoped
    dmScope: "per-channel-peer",
    // Options:
    //   main                — one global session for all DMs
    //   per-peer            — one session per sender (across channels)
    //   per-channel-peer    — one session per sender per channel (recommended)
    //   per-account-channel-peer — adds account-level isolation

    threadBindings: {
      enabled:    true,
      idleHours:  24,   // thread expires after 24h of inactivity
      maxAgeHours: 0    // 0 = no hard limit
    },

    reset: {
      mode:        "daily",  // daily | idle | off
      atHour:      4,        // 4 AM local time
      idleMinutes: 120       // reset after 2h of no messages
    }
  }
}

gateway — Server Settings

{
  gateway: {
    port: 18789,
    bind: "127.0.0.1",   // NEVER change to 0.0.0.0 on a public VPS

    auth: {
      token: "${OPENCLAW_GATEWAY_TOKEN}"
    },

    reload: {
      mode:       "hybrid",  // hybrid | hot | restart | off
      debounceMs: 300
    },

    // Health monitoring
    channelHealthCheckMinutes:          5,
    channelStaleEventThresholdMinutes: 30,
    channelMaxRestartsPerHour:         10
  }
}

Reload Modes

ModeBehaviour
hybridMost changes apply live; gateway changes queue for next restart (recommended)
hotAll changes apply immediately — some instability possible
restartFull restart on any config change
offManual restart required for all changes

cron — Scheduled Jobs

The cron block controls the scheduler's global behaviour. Individual jobs are defined inside the agent's workspace HEARTBEAT.md file (see SOUL.md & Agent Personas).

{
  cron: {
    enabled:           true,
    maxConcurrentRuns: 2,        // max simultaneous job runs
    sessionRetention:  "24h",    // how long cron session logs are kept

    runLog: {
      maxBytes:  "2mb",
      keepLines: 2000
    }
  }
}

Individual cron jobs are scheduled inside your agent's workspace. Typical example in HEARTBEAT.md:

# HEARTBEAT TASKS

## Daily Morning Brief — 7:00 AM
Schedule: 0 7 * * *
Action: Run the daily-brief skill and send result to Telegram

## Disk Check — Every 30 Minutes
Schedule: */30 * * * *
Action: Check disk usage. If any partition > 85%, alert immediately.

## Weekly Security Audit — Monday 9 AM
Schedule: 0 9 * * 1
Action: Run healthcheck skill and summarise results to my DM.

env — Secrets & Environment Variables

{
  env: {
    // Direct values (less secure — prefer shellEnv below)
    OPENROUTER_API_KEY: "sk-or-...",

    // Nested vars object — same behaviour
    vars: {
      GROQ_API_KEY: "gsk-..."
    },

    // Import from shell environment (most secure)
    shellEnv: {
      enabled:   true,
      timeoutMs: 15000
    }
  }
}

Reference env vars anywhere in the config with "${VAR_NAME}". Only uppercase names are supported. Missing variables cause a startup error — use openclaw doctor to diagnose.

Keep secrets out of the config file

The best practice is to use shellEnv: { enabled: true } and export your API keys in your shell profile (~/.zshrc or ~/.bashrc). This way the config file itself contains no secrets and can be safely version-controlled.

Multi-Agent Routing

Route different channels or accounts to different agents using bindings:

{
  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"      } },
    { agentId: "work", match: { channel: "telegram"                         } }
  ]
}

Config Includes — Split Into Multiple Files

Large configs can be split across files using $include:

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

Single files replace the object they're assigned to. Arrays deep-merge in order. This lets you keep Telegram credentials in a separate file with tighter filesystem permissions.

← Back to OpenClaw hub · See also: Telegram Setup · Security Hardening · Cost Optimisation