配置参考
~/.openclaw/openclaw.json 中所有可用字段。面向任务的概览见配置。
配置格式为 JSON5(支持注释和尾逗号)。所有字段都是可选的——省略时 OpenClaw 使用安全默认值。
频道
每个频道在其配置段存在时自动启动(除非 enabled: false)。
私聊和群组访问
所有频道都支持私聊策略和群组策略:
| 私聊策略 | 行为 |
|---|---|
pairing(默认) | 未知发送者获得一次性配对码,需所有者审批 |
allowlist | 仅 allowFrom(或已配对的允许列表)中的发送者 |
open | 允许所有入站私信(需要 allowFrom: ["*"]) |
disabled | 忽略所有入站私信 |
| 群组策略 | 行为 |
|---|---|
allowlist(默认) | 仅匹配已配置白名单的群组 |
open | 绕过群组白名单(提及门控仍然有效) |
disabled | 阻止所有群组/聊天室消息 |
说明:
channels.defaults.groupPolicy在提供商的groupPolicy未设置时作为默认值。 配对码 1 小时后过期。每个频道的待处理私聊配对请求上限为 3 个。 如果提供商配置块完全缺失(channels.<provider>不存在),运行时群组策略回退到allowlist(失败关闭)并在启动时发出警告。
频道模型覆盖
用 channels.modelByChannel 将特定频道 ID 绑定到模型。值接受 provider/model 或已配置的模型别名。频道映射在会话没有已设置的模型覆盖时生效(比如通过 /model 设置的)。
{
channels: {
modelByChannel: {
discord: {
"123456789012345678": "anthropic/claude-opus-4-6",
},
slack: {
C1234567890: "openai/gpt-4.1",
},
telegram: {
"-1001234567890": "openai/gpt-4.1-mini",
"-1001234567890:topic:99": "anthropic/claude-sonnet-4-6",
},
},
},
}
频道默认值和心跳
用 channels.defaults 设置所有提供商共享的群组策略和心跳行为:
{
channels: {
defaults: {
groupPolicy: "allowlist", // open | allowlist | disabled
heartbeat: {
showOk: false,
showAlerts: true,
useIndicator: true,
},
},
},
}
channels.defaults.groupPolicy: fallback group policy when a provider-levelgroupPolicyis unset.channels.defaults.heartbeat.showOk: include healthy channel statuses in heartbeat output.channels.defaults.heartbeat.showAlerts: include degraded/error statuses in heartbeat output.channels.defaults.heartbeat.useIndicator: render compact indicator-style heartbeat output.
WhatsApp 通过 Gateway 的 web 频道(Baileys Web)运行。已有关联会话时自动启动。
{
channels: {
whatsapp: {
dmPolicy: "pairing", // pairing | allowlist | open | disabled
allowFrom: ["+15555550123", "+447700900123"],
textChunkLimit: 4000,
chunkMode: "length", // length | newline
mediaMaxMb: 50,
sendReadReceipts: true, // blue ticks (false in self-chat mode)
groups: {
"*": { requireMention: true },
},
groupPolicy: "allowlist",
groupAllowFrom: ["+15551234567"],
},
},
web: {
enabled: true,
heartbeatSeconds: 60,
reconnect: {
initialMs: 2000,
maxMs: 120000,
factor: 1.4,
jitter: 0.2,
maxAttempts: 0,
},
},
}
多账户 WhatsApp
{
channels: {
whatsapp: {
accounts: {
default: {},
personal: {},
biz: {
// authDir: "~/.openclaw/credentials/whatsapp/biz",
},
},
},
},
}
- 出站命令默认使用
default账户(如果存在),否则使用第一个已配置的账户 id(按排序)。 - 可选的
channels.whatsapp.defaultAccount在匹配已配置账户 id 时覆盖默认账户选择。 - 旧版单账户 Baileys 认证目录由
openclaw doctor迁移到whatsapp/default。 - 按账户覆盖:
channels.whatsapp.accounts.<id>.sendReadReceipts、channels.whatsapp.accounts.<id>.dmPolicy、channels.whatsapp.accounts.<id>.allowFrom。
Telegram
{
channels: {
telegram: {
enabled: true,
botToken: "your-bot-token",
dmPolicy: "pairing",
allowFrom: ["tg:123456789"],
groups: {
"*": { requireMention: true },
"-1001234567890": {
allowFrom: ["@admin"],
systemPrompt: "Keep answers brief.",
topics: {
"99": {
requireMention: false,
skills: ["search"],
systemPrompt: "Stay on topic.",
},
},
},
},
customCommands: [
{ command: "backup", description: "Git backup" },
{ command: "generate", description: "Create an image" },
],
historyLimit: 50,
replyToMode: "first", // off | first | all
linkPreview: true,
streaming: "partial", // off | partial | block | progress (default: off)
actions: { reactions: true, sendMessage: true },
reactionNotifications: "own", // off | own | all
mediaMaxMb: 100,
retry: {
attempts: 3,
minDelayMs: 400,
maxDelayMs: 30000,
jitter: 0.1,
},
network: {
autoSelectFamily: true,
dnsResultOrder: "ipv4first",
},
proxy: "socks5://localhost:9050",
webhookUrl: "https://example.com/telegram-webhook",
webhookSecret: "secret",
webhookPath: "/telegram-webhook",
},
},
}
- Bot token:
channels.telegram.botTokenorchannels.telegram.tokenFile(regular file only; symlinks rejected), withTELEGRAM_BOT_TOKENas fallback for the default account. - Optional
channels.telegram.defaultAccountoverrides default account selection when it matches a configured account id. - In multi-account setups (2+ account ids), set an explicit default (
channels.telegram.defaultAccountorchannels.telegram.accounts.default) to avoid fallback routing;openclaw doctorwarns when this is missing or invalid. configWrites: falseblocks Telegram-initiated config writes (supergroup ID migrations,/config set|unset).- Top-level
bindings[]entries withtype: "acp"configure persistent ACP bindings for forum topics (use canonicalchatId:topic:topicIdinmatch.peer.id). Field semantics are shared in ACP Agents. - Telegram stream previews use
sendMessage+editMessageText(works in direct and group chats). - Retry policy: see Retry policy.
Discord
{
channels: {
discord: {
enabled: true,
token: "your-bot-token",
mediaMaxMb: 8,
allowBots: false,
actions: {
reactions: true,
stickers: true,
polls: true,
permissions: true,
messages: true,
threads: true,
pins: true,
search: true,
memberInfo: true,
roleInfo: true,
roles: false,
channelInfo: true,
voiceStatus: true,
events: true,
moderation: false,
},
replyToMode: "off", // off | first | all
dmPolicy: "pairing",
allowFrom: ["1234567890", "123456789012345678"],
dm: { enabled: true, groupEnabled: false, groupChannels: ["openclaw-dm"] },
guilds: {
"123456789012345678": {
slug: "friends-of-openclaw",
requireMention: false,
ignoreOtherMentions: true,
reactionNotifications: "own",
users: ["987654321098765432"],
channels: {
general: { allow: true },
help: {
allow: true,
requireMention: true,
users: ["987654321098765432"],
skills: ["docs"],
systemPrompt: "Short answers only.",
},
},
},
},
historyLimit: 20,
textChunkLimit: 2000,
chunkMode: "length", // length | newline
streaming: "off", // off | partial | block | progress (progress maps to partial on Discord)
maxLinesPerMessage: 17,
ui: {
components: {
accentColor: "#5865F2",
},
},
threadBindings: {
enabled: true,
idleHours: 24,
maxAgeHours: 0,
spawnSubagentSessions: false, // opt-in for sessions_spawn({ thread: true })
},
voice: {
enabled: true,
autoJoin: [
{
guildId: "123456789012345678",
channelId: "234567890123456789",
},
],
daveEncryption: true,
decryptionFailureTolerance: 24,
tts: {
provider: "openai",
openai: { voice: "alloy" },
},
},
retry: {
attempts: 3,
minDelayMs: 500,
maxDelayMs: 30000,
jitter: 0.1,
},
},
},
}
- Token:
channels.discord.token, withDISCORD_BOT_TOKENas fallback for the default account. - Direct outbound calls that provide an explicit Discord
tokenuse that token for the call; account retry/policy settings still come from the selected account in the active runtime snapshot. - Optional
channels.discord.defaultAccountoverrides default account selection when it matches a configured account id. - Use
user:<id>(DM) orchannel:<id>(guild channel) for delivery targets; bare numeric IDs are rejected. - Guild slugs are lowercase with spaces replaced by
-; channel keys use the slugged name (no#). Prefer guild IDs. - Bot-authored messages are ignored by default.
allowBots: trueenables them; useallowBots: "mentions"to only accept bot messages that mention the bot (own messages still filtered). channels.discord.guilds.<id>.ignoreOtherMentions(and channel overrides) drops messages that mention another user or role but not the bot (excluding @everyone/@here).maxLinesPerMessage(default 17) splits tall messages even when under 2000 chars.channels.discord.threadBindingscontrols Discord thread-bound routing:enabled: Discord override for thread-bound session features (/focus,/unfocus,/agents,/session idle,/session max-age, and bound delivery/routing)idleHours: Discord override for inactivity auto-unfocus in hours (0disables)maxAgeHours: Discord override for hard max age in hours (0disables)spawnSubagentSessions: opt-in switch forsessions_spawn({ thread: true })auto thread creation/binding
- Top-level
bindings[]entries withtype: "acp"configure persistent ACP bindings for channels and threads (use channel/thread id inmatch.peer.id). Field semantics are shared in ACP Agents. channels.discord.ui.components.accentColorsets the accent color for Discord components v2 containers.channels.discord.voiceenables Discord voice channel conversations and optional auto-join + TTS overrides.channels.discord.voice.daveEncryptionandchannels.discord.voice.decryptionFailureTolerancepass through to@discordjs/voiceDAVE options (trueand24by default).- OpenClaw additionally attempts voice receive recovery by leaving/rejoining a voice session after repeated decrypt failures.
channels.discord.streamingis the canonical stream mode key. LegacystreamModeand booleanstreamingvalues are auto-migrated.channels.discord.autoPresencemaps runtime availability to bot presence (healthy => online, degraded => idle, exhausted => dnd) and allows optional status text overrides.channels.discord.dangerouslyAllowNameMatchingre-enables mutable name/tag matching (break-glass compatibility mode).
Reaction notification modes: off (none), own (bot’s messages, default), all (all messages), allowlist (from guilds.<id>.users on all messages).
Google Chat
{
channels: {
googlechat: {
enabled: true,
serviceAccountFile: "/path/to/service-account.json",
audienceType: "app-url", // app-url | project-number
audience: "https://gateway.example.com/googlechat",
webhookPath: "/googlechat",
botUser: "users/1234567890",
dm: {
enabled: true,
policy: "pairing",
allowFrom: ["users/1234567890"],
},
groupPolicy: "allowlist",
groups: {
"spaces/AAAA": { allow: true, requireMention: true },
},
actions: { reactions: true },
typingIndicator: "message",
mediaMaxMb: 20,
},
},
}
- Service account JSON: inline (
serviceAccount) or file-based (serviceAccountFile). - Service account SecretRef is also supported (
serviceAccountRef). - Env fallbacks:
GOOGLE_CHAT_SERVICE_ACCOUNTorGOOGLE_CHAT_SERVICE_ACCOUNT_FILE. - Use
spaces/<spaceId>orusers/<userId>for delivery targets. channels.googlechat.dangerouslyAllowNameMatchingre-enables mutable email principal matching (break-glass compatibility mode).
Slack
{
channels: {
slack: {
enabled: true,
botToken: "xoxb-...",
appToken: "xapp-...",
dmPolicy: "pairing",
allowFrom: ["U123", "U456", "*"],
dm: { enabled: true, groupEnabled: false, groupChannels: ["G123"] },
channels: {
C123: { allow: true, requireMention: true, allowBots: false },
"#general": {
allow: true,
requireMention: true,
allowBots: false,
users: ["U123"],
skills: ["docs"],
systemPrompt: "Short answers only.",
},
},
historyLimit: 50,
allowBots: false,
reactionNotifications: "own",
reactionAllowlist: ["U123"],
replyToMode: "off", // off | first | all
thread: {
historyScope: "thread", // thread | channel
inheritParent: false,
},
actions: {
reactions: true,
messages: true,
pins: true,
memberInfo: true,
emojiList: true,
},
slashCommand: {
enabled: true,
name: "openclaw",
sessionPrefix: "slack:slash",
ephemeral: true,
},
typingReaction: "hourglass_flowing_sand",
textChunkLimit: 4000,
chunkMode: "length",
streaming: "partial", // off | partial | block | progress (preview mode)
nativeStreaming: true, // use Slack native streaming API when streaming=partial
mediaMaxMb: 20,
},
},
}
- Socket mode requires both
botTokenandappToken(SLACK_BOT_TOKEN+SLACK_APP_TOKENfor default account env fallback). - HTTP mode requires
botTokenplussigningSecret(at root or per-account). configWrites: falseblocks Slack-initiated config writes.- Optional
channels.slack.defaultAccountoverrides default account selection when it matches a configured account id. channels.slack.streamingis the canonical stream mode key. LegacystreamModeand booleanstreamingvalues are auto-migrated.- Use
user:<id>(DM) orchannel:<id>for delivery targets.
Reaction notification modes: off, own (default), all, allowlist (from reactionAllowlist).
Thread session isolation: thread.historyScope is per-thread (default) or shared across channel. thread.inheritParent copies parent channel transcript to new threads.
typingReactionadds a temporary reaction to the inbound Slack message while a reply is running, then removes it on completion. Use a Slack emoji shortcode such as"hourglass_flowing_sand".
| Action group | Default | Notes |
|---|---|---|
| reactions | enabled | React + list reactions |
| messages | enabled | Read/send/edit/delete |
| pins | enabled | Pin/unpin/list |
| memberInfo | enabled | Member info |
| emojiList | enabled | Custom emoji list |
Mattermost
Mattermost ships as a plugin: openclaw plugins install @openclaw/mattermost.
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
chatmode: "oncall", // oncall | onmessage | onchar
oncharPrefixes: [">", "!"],
commands: {
native: true, // opt-in
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// Optional explicit URL for reverse-proxy/public deployments
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
textChunkLimit: 4000,
chunkMode: "length",
},
},
}
Chat modes: oncall (respond on @-mention, default), onmessage (every message), onchar (messages starting with trigger prefix).
When Mattermost native commands are enabled:
commands.callbackPathmust be a path (for example/api/channels/mattermost/command), not a full URL.commands.callbackUrlmust resolve to the OpenClaw gateway endpoint and be reachable from the Mattermost server.- For private/tailnet/internal callback hosts, Mattermost may require
ServiceSettings.AllowedUntrustedInternalConnectionsto include the callback host/domain. Use host/domain values, not full URLs. channels.mattermost.configWrites: allow or deny Mattermost-initiated config writes.channels.mattermost.requireMention: require@mentionbefore replying in channels.- Optional
channels.mattermost.defaultAccountoverrides default account selection when it matches a configured account id.
Signal
{
channels: {
signal: {
enabled: true,
account: "+15555550123", // optional account binding
dmPolicy: "pairing",
allowFrom: ["+15551234567", "uuid:123e4567-e89b-12d3-a456-426614174000"],
configWrites: true,
reactionNotifications: "own", // off | own | all | allowlist
reactionAllowlist: ["+15551234567", "uuid:123e4567-e89b-12d3-a456-426614174000"],
historyLimit: 50,
},
},
}
Reaction notification modes: off, own (default), all, allowlist (from reactionAllowlist).
channels.signal.account: pin channel startup to a specific Signal account identity.channels.signal.configWrites: allow or deny Signal-initiated config writes.- Optional
channels.signal.defaultAccountoverrides default account selection when it matches a configured account id.
BlueBubbles
BlueBubbles is the recommended iMessage path (plugin-backed, configured under channels.bluebubbles).
{
channels: {
bluebubbles: {
enabled: true,
dmPolicy: "pairing",
// serverUrl, password, webhookPath, group controls, and advanced actions:
// see /channels/bluebubbles
},
},
}
- Core key paths covered here:
channels.bluebubbles,channels.bluebubbles.dmPolicy. - Optional
channels.bluebubbles.defaultAccountoverrides default account selection when it matches a configured account id. - Full BlueBubbles channel configuration is documented in BlueBubbles.
iMessage
OpenClaw spawns imsg rpc (JSON-RPC over stdio). No daemon or port required.
{
channels: {
imessage: {
enabled: true,
cliPath: "imsg",
dbPath: "~/Library/Messages/chat.db",
remoteHost: "user@gateway-host",
dmPolicy: "pairing",
allowFrom: ["+15555550123", "[email protected]", "chat_id:123"],
historyLimit: 50,
includeAttachments: false,
attachmentRoots: ["/Users/*/Library/Messages/Attachments"],
remoteAttachmentRoots: ["/Users/*/Library/Messages/Attachments"],
mediaMaxMb: 16,
service: "auto",
region: "US",
},
},
}
-
Optional
channels.imessage.defaultAccountoverrides default account selection when it matches a configured account id. -
Requires Full Disk Access to the Messages DB.
-
Prefer
chat_id:<id>targets. Useimsg chats --limit 20to list chats. -
cliPathcan point to an SSH wrapper; setremoteHost(hostoruser@host) for SCP attachment fetching. -
attachmentRootsandremoteAttachmentRootsrestrict inbound attachment paths (default:/Users/*/Library/Messages/Attachments). -
SCP uses strict host-key checking, so ensure the relay host key already exists in
~/.ssh/known_hosts. -
channels.imessage.configWrites: allow or deny iMessage-initiated config writes.
iMessage SSH wrapper example
#!/usr/bin/env bash
exec ssh -T gateway-host imsg "$@"
Microsoft Teams
Microsoft Teams is extension-backed and configured under channels.msteams.
{
channels: {
msteams: {
enabled: true,
configWrites: true,
// appId, appPassword, tenantId, webhook, team/channel policies:
// see /channels/msteams
},
},
}
- Core key paths covered here:
channels.msteams,channels.msteams.configWrites. - Full Teams config (credentials, webhook, DM/group policy, per-team/per-channel overrides) is documented in Microsoft Teams.
IRC
IRC is extension-backed and configured under channels.irc.
{
channels: {
irc: {
enabled: true,
dmPolicy: "pairing",
configWrites: true,
nickserv: {
enabled: true,
service: "NickServ",
password: "${IRC_NICKSERV_PASSWORD}",
register: false,
registerEmail: "[email protected]",
},
},
},
}
- Core key paths covered here:
channels.irc,channels.irc.dmPolicy,channels.irc.configWrites,channels.irc.nickserv.*. - Optional
channels.irc.defaultAccountoverrides default account selection when it matches a configured account id. - Full IRC channel configuration (host/port/TLS/channels/allowlists/mention gating) is documented in IRC.
Multi-account (all channels)
Run multiple accounts per channel (each with its own accountId):
{
channels: {
telegram: {
accounts: {
default: {
name: "Primary bot",
botToken: "123456:ABC...",
},
alerts: {
name: "Alerts bot",
botToken: "987654:XYZ...",
},
},
},
},
}
defaultis used whenaccountIdis omitted (CLI + routing).- Env tokens only apply to the default account.
- Base channel settings apply to all accounts unless overridden per account.
- Use
bindings[].match.accountIdto route each account to a different agent. - If you add a non-default account via
openclaw channels add(or channel onboarding) while still on a single-account top-level channel config, OpenClaw moves account-scoped top-level single-account values intochannels.<channel>.accounts.defaultfirst so the original account keeps working. - Existing channel-only bindings (no
accountId) keep matching the default account; account-scoped bindings remain optional. openclaw doctor --fixalso repairs mixed shapes by moving account-scoped top-level single-account values intoaccounts.defaultwhen named accounts exist butdefaultis missing.
Other extension channels
Many extension channels are configured as channels.<id> and documented in their dedicated channel pages (for example Feishu, Matrix, LINE, Nostr, Zalo, Nextcloud Talk, Synology Chat, and Twitch).
See the full channel index: Channels.
Group chat mention gating
Group messages default to require mention (metadata mention or regex patterns). Applies to WhatsApp, Telegram, Discord, Google Chat, and iMessage group chats.
Mention types:
- Metadata mentions: Native platform @-mentions. Ignored in WhatsApp self-chat mode.
- Text patterns: Regex patterns in
agents.list[].groupChat.mentionPatterns. Always checked. - Mention gating is enforced only when detection is possible (native mentions or at least one pattern).
{
messages: {
groupChat: { historyLimit: 50 },
},
agents: {
list: [{ id: "main", groupChat: { mentionPatterns: ["@openclaw", "openclaw"] } }],
},
}
messages.groupChat.historyLimit sets the global default. Channels can override with channels.<channel>.historyLimit (or per-account). Set 0 to disable.
DM history limits
{
channels: {
telegram: {
dmHistoryLimit: 30,
dms: {
"123456789": { historyLimit: 50 },
},
},
},
}
Resolution: per-DM override → provider default → no limit (all retained).
Supported: telegram, whatsapp, discord, slack, signal, imessage, msteams.
Self-chat mode
Include your own number in allowFrom to enable self-chat mode (ignores native @-mentions, only responds to text patterns):
{
channels: {
whatsapp: {
allowFrom: ["+15555550123"],
groups: { "*": { requireMention: true } },
},
},
agents: {
list: [
{
id: "main",
groupChat: { mentionPatterns: ["reisponde", "@openclaw"] },
},
],
},
}
Commands (chat command handling)
{
commands: {
native: "auto", // register native commands when supported
text: true, // parse /commands in chat messages
bash: false, // allow ! (alias: /bash)
bashForegroundMs: 2000,
config: false, // allow /config
debug: false, // allow /debug
restart: false, // allow /restart + gateway restart tool
allowFrom: {
"*": ["user1"],
discord: ["user:123"],
},
useAccessGroups: true,
},
}
Command details
- Text commands must be standalone messages with leading
/. native: "auto"turns on native commands for Discord/Telegram, leaves Slack off.- Override per channel:
channels.discord.commands.native(bool or"auto").falseclears previously registered commands. channels.telegram.customCommandsadds extra Telegram bot menu entries.bash: trueenables! <cmd>for host shell. Requirestools.elevated.enabledand sender intools.elevated.allowFrom.<channel>.config: trueenables/config(reads/writesopenclaw.json). For gatewaychat.sendclients, persistent/config set|unsetwrites also requireoperator.admin; read-only/config showstays available to normal write-scoped operator clients.channels.<provider>.configWritesgates config mutations per channel (default: true).- For multi-account channels,
channels.<provider>.accounts.<id>.configWritesalso gates writes that target that account (for example/allowlist --config --account <id>or/config set channels.<provider>.accounts.<id>...). allowFromis per-provider. When set, it is the only authorization source (channel allowlists/pairing anduseAccessGroupsare ignored).useAccessGroups: falseallows commands to bypass access-group policies whenallowFromis not set.
Agent 默认值
agents.defaults.workspace
默认值:~/.openclaw/workspace。
{
agents: { defaults: { workspace: "~/.openclaw/workspace" } },
}
agents.defaults.repoRoot
可选的仓库根目录,显示在系统提示的 Runtime 行中。未设置时 OpenClaw 从工作区向上自动检测。
{
agents: { defaults: { repoRoot: "~/Projects/openclaw" } },
}
agents.defaults.skipBootstrap
禁用工作区引导文件的自动创建(AGENTS.md、SOUL.md、TOOLS.md、IDENTITY.md、USER.md、HEARTBEAT.md、BOOTSTRAP.md)。
{
agents: { defaults: { skipBootstrap: true } },
}
agents.defaults.bootstrapMaxChars
每个工作区引导文件在截断前的最大字符数。默认:20000。
{
agents: { defaults: { bootstrapMaxChars: 20000 } },
}
agents.defaults.bootstrapTotalMaxChars
所有工作区引导文件注入的最大总字符数。默认:150000。
{
agents: { defaults: { bootstrapTotalMaxChars: 150000 } },
}
agents.defaults.bootstrapPromptTruncationWarning
控制引导上下文被截断时 Agent 可见的警告文本。
默认:"once"。
"off":不在系统提示中注入警告文本。"once":每个唯一的截断签名只注入一次警告(推荐)。"always":存在截断时每次运行都注入警告。
{
agents: { defaults: { bootstrapPromptTruncationWarning: "once" } }, // off | once | always
}
agents.defaults.imageMaxDimensionPx
发送给提供商之前,转录/工具图片块中最长边的最大像素值。
默认:1200。
较低的值通常能减少截图密集运行的视觉 token 消耗和请求 payload 大小。 较高的值保留更多视觉细节。
{
agents: { defaults: { imageMaxDimensionPx: 1200 } },
}
agents.defaults.userTimezone
系统提示上下文中的时区(不影响消息时间戳)。回退到主机时区。
{
agents: { defaults: { userTimezone: "America/Chicago" } },
}
agents.defaults.timeFormat
系统提示中的时间格式。默认:auto(操作系统偏好)。
{
agents: { defaults: { timeFormat: "auto" } }, // auto | 12 | 24
}
agents.defaults.model
{
agents: {
defaults: {
models: {
"anthropic/claude-opus-4-6": { alias: "opus" },
"minimax/MiniMax-M2.5": { alias: "minimax" },
},
model: {
primary: "anthropic/claude-opus-4-6",
fallbacks: ["minimax/MiniMax-M2.5"],
},
imageModel: {
primary: "openrouter/qwen/qwen-2.5-vl-72b-instruct:free",
fallbacks: ["openrouter/google/gemini-2.0-flash-vision:free"],
},
pdfModel: {
primary: "anthropic/claude-opus-4-6",
fallbacks: ["openai/gpt-5-mini"],
},
pdfMaxBytesMb: 10,
pdfMaxPages: 20,
thinkingDefault: "low",
verboseDefault: "off",
elevatedDefault: "on",
timeoutSeconds: 600,
mediaMaxMb: 5,
contextTokens: 200000,
maxConcurrent: 3,
},
},
}
model: accepts either a string ("provider/model") or an object ({ primary, fallbacks }).- String form sets only the primary model.
- Object form sets primary plus ordered failover models.
imageModel: accepts either a string ("provider/model") or an object ({ primary, fallbacks }).- Used by the
imagetool path as its vision-model config. - Also used as fallback routing when the selected/default model cannot accept image input.
- Used by the
pdfModel: accepts either a string ("provider/model") or an object ({ primary, fallbacks }).- Used by the
pdftool for model routing. - If omitted, the PDF tool falls back to
imageModel, then to best-effort provider defaults.
- Used by the
pdfMaxBytesMb: default PDF size limit for thepdftool whenmaxBytesMbis not passed at call time.pdfMaxPages: default maximum pages considered by extraction fallback mode in thepdftool.model.primary: formatprovider/model(e.g.anthropic/claude-opus-4-6). If you omit the provider, OpenClaw assumesanthropic(deprecated).models: the configured model catalog and allowlist for/model. Each entry can includealias(shortcut) andparams(provider-specific, for exampletemperature,maxTokens,cacheRetention,context1m).paramsmerge precedence (config):agents.defaults.models["provider/model"].paramsis the base, thenagents.list[].params(matching agent id) overrides by key.- Config writers that mutate these fields (for example
/models set,/models set-image, and fallback add/remove commands) save canonical object form and preserve existing fallback lists when possible. maxConcurrent: max parallel agent runs across sessions (each session still serialized). Default: 1.
Built-in alias shorthands (only apply when the model is in agents.defaults.models):
| Alias | Model |
|---|---|
opus | anthropic/claude-opus-4-6 |
sonnet | anthropic/claude-sonnet-4-6 |
gpt | openai/gpt-5.4 |
gpt-mini | openai/gpt-5-mini |
gemini | google/gemini-3.1-pro-preview |
gemini-flash | google/gemini-3-flash-preview |
gemini-flash-lite | google/gemini-3.1-flash-lite-preview |
Your configured aliases always win over defaults.
Z.AI GLM-4.x models automatically enable thinking mode unless you set --thinking off or define agents.defaults.models["zai/<model>"].params.thinking yourself.
Z.AI models enable tool_stream by default for tool call streaming. Set agents.defaults.models["zai/<model>"].params.tool_stream to false to disable it.
Anthropic Claude 4.6 models default to adaptive thinking when no explicit thinking level is set.
agents.defaults.cliBackends
可选的 CLI 后端,用于纯文本回退运行(无工具调用)。API 提供商失败时可作为备用。
{
agents: {
defaults: {
cliBackends: {
"claude-cli": {
command: "/opt/homebrew/bin/claude",
},
"my-cli": {
command: "my-cli",
args: ["--json"],
output: "json",
modelArg: "--model",
sessionArg: "--session",
sessionMode: "existing",
systemPromptArg: "--system",
systemPromptWhen: "first",
imageArg: "--image",
imageMode: "repeat",
},
},
},
},
}
- CLI 后端以文本为主;工具始终禁用。
- 设置
sessionArg时支持会话。 imageArg接受文件路径时支持图片透传。
agents.defaults.heartbeat
周期性心跳运行。
{
agents: {
defaults: {
heartbeat: {
every: "30m", // 0m disables
model: "openai/gpt-5.2-mini",
includeReasoning: false,
lightContext: false, // default: false; true keeps only HEARTBEAT.md from workspace bootstrap files
session: "main",
to: "+15555550123",
directPolicy: "allow", // allow (default) | block
target: "none", // default: none | options: last | whatsapp | telegram | discord | ...
prompt: "Read HEARTBEAT.md if it exists...",
ackMaxChars: 300,
suppressToolErrorWarnings: false,
},
},
},
}
every: duration string (ms/s/m/h). Default:30m.suppressToolErrorWarnings: when true, suppresses tool error warning payloads during heartbeat runs.directPolicy: direct/DM delivery policy.allow(default) permits direct-target delivery.blocksuppresses direct-target delivery and emitsreason=dm-blocked.lightContext: when true, heartbeat runs use lightweight bootstrap context and keep onlyHEARTBEAT.mdfrom workspace bootstrap files.- Per-agent: set
agents.list[].heartbeat. When any agent definesheartbeat, only those agents run heartbeats. - Heartbeats run full agent turns — shorter intervals burn more tokens.
agents.defaults.compaction
{
agents: {
defaults: {
compaction: {
mode: "safeguard", // default | safeguard
reserveTokensFloor: 24000,
identifierPolicy: "strict", // strict | off | custom
identifierInstructions: "Preserve deployment IDs, ticket IDs, and host:port pairs exactly.", // used when identifierPolicy=custom
postCompactionSections: ["Session Startup", "Red Lines"], // [] disables reinjection
model: "openrouter/anthropic/claude-sonnet-4-5", // optional compaction-only model override
memoryFlush: {
enabled: true,
softThresholdTokens: 6000,
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.",
},
},
},
},
}
mode:defaultorsafeguard(chunked summarization for long histories). See Compaction.identifierPolicy:strict(default),off, orcustom.strictprepends built-in opaque identifier retention guidance during compaction summarization.identifierInstructions: optional custom identifier-preservation text used whenidentifierPolicy=custom.postCompactionSections: optional AGENTS.md H2/H3 section names to re-inject after compaction. Defaults to["Session Startup", "Red Lines"]; set[]to disable reinjection. When unset or explicitly set to that default pair, olderEvery Session/Safetyheadings are also accepted as a legacy fallback.model: optionalprovider/model-idoverride for compaction summarization only. Use this when the main session should keep one model but compaction summaries should run on another; when unset, compaction uses the session’s primary model.memoryFlush: silent agentic turn before auto-compaction to store durable memories. Skipped when workspace is read-only.
agents.defaults.contextPruning
Prunes old tool results from in-memory context before sending to the LLM. Does not modify session history on disk.
{
agents: {
defaults: {
contextPruning: {
mode: "cache-ttl", // off | cache-ttl
ttl: "1h", // duration (ms/s/m/h), default unit: minutes
keepLastAssistants: 3,
softTrimRatio: 0.3,
hardClearRatio: 0.5,
minPrunableToolChars: 50000,
softTrim: { maxChars: 4000, headChars: 1500, tailChars: 1500 },
hardClear: { enabled: true, placeholder: "[Old tool result content cleared]" },
tools: { deny: ["browser", "canvas"] },
},
},
},
}
cache-ttl mode behavior
mode: "cache-ttl"enables pruning passes.ttlcontrols how often pruning can run again (after the last cache touch).- Pruning soft-trims oversized tool results first, then hard-clears older tool results if needed.
Soft-trim keeps beginning + end and inserts ... in the middle.
Hard-clear replaces the entire tool result with the placeholder.
Notes:
- Image blocks are never trimmed/cleared.
- Ratios are character-based (approximate), not exact token counts.
- If fewer than
keepLastAssistantsassistant messages exist, pruning is skipped.
See Session Pruning for behavior details.
Block streaming
{
agents: {
defaults: {
blockStreamingDefault: "off", // on | off
blockStreamingBreak: "text_end", // text_end | message_end
blockStreamingChunk: { minChars: 800, maxChars: 1200 },
blockStreamingCoalesce: { idleMs: 1000 },
humanDelay: { mode: "natural" }, // off | natural | custom (use minMs/maxMs)
},
},
}
- Non-Telegram channels require explicit
*.blockStreaming: trueto enable block replies. - Channel overrides:
channels.<channel>.blockStreamingCoalesce(and per-account variants). Signal/Slack/Discord/Google Chat defaultminChars: 1500. humanDelay: randomized pause between block replies.natural= 800–2500ms. Per-agent override:agents.list[].humanDelay.
See Streaming for behavior + chunking details.
Typing indicators
{
agents: {
defaults: {
typingMode: "instant", // never | instant | thinking | message
typingIntervalSeconds: 6,
},
},
}
- Defaults:
instantfor direct chats/mentions,messagefor unmentioned group chats. - Per-session overrides:
session.typingMode,session.typingIntervalSeconds.
See Typing Indicators.
agents.defaults.sandbox
可选的 Docker 沙箱,用于内嵌 Agent。完整指南见 Sandboxing。
{
agents: {
defaults: {
sandbox: {
mode: "non-main", // off | non-main | all
scope: "agent", // session | agent | shared
workspaceAccess: "none", // none | ro | rw
workspaceRoot: "~/.openclaw/sandboxes",
docker: {
image: "openclaw-sandbox:bookworm-slim",
containerPrefix: "openclaw-sbx-",
workdir: "/workspace",
readOnlyRoot: true,
tmpfs: ["/tmp", "/var/tmp", "/run"],
network: "none",
user: "1000:1000",
capDrop: ["ALL"],
env: { LANG: "C.UTF-8" },
setupCommand: "apt-get update && apt-get install -y git curl jq",
pidsLimit: 256,
memory: "1g",
memorySwap: "2g",
cpus: 1,
ulimits: {
nofile: { soft: 1024, hard: 2048 },
nproc: 256,
},
seccompProfile: "/path/to/seccomp.json",
apparmorProfile: "openclaw-sandbox",
dns: ["1.1.1.1", "8.8.8.8"],
extraHosts: ["internal.service:10.0.0.5"],
binds: ["/home/user/source:/source:rw"],
},
browser: {
enabled: false,
image: "openclaw-sandbox-browser:bookworm-slim",
network: "openclaw-sandbox-browser",
cdpPort: 9222,
cdpSourceRange: "172.21.0.1/32",
vncPort: 5900,
noVncPort: 6080,
headless: false,
enableNoVnc: true,
allowHostControl: false,
autoStart: true,
autoStartTimeoutMs: 12000,
},
prune: {
idleHours: 24,
maxAgeDays: 7,
},
},
},
},
tools: {
sandbox: {
tools: {
allow: [
"exec",
"process",
"read",
"write",
"edit",
"apply_patch",
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
],
deny: ["browser", "canvas", "nodes", "cron", "discord", "gateway"],
},
},
},
}
沙箱详情
Workspace access:
none: per-scope sandbox workspace under~/.openclaw/sandboxesro: sandbox workspace at/workspace, agent workspace mounted read-only at/agentrw: agent workspace mounted read/write at/workspace
Scope:
session: per-session container + workspaceagent: one container + workspace per agent (default)shared: shared container and workspace (no cross-session isolation)
setupCommand runs once after container creation (via sh -lc). Needs network egress, writable root, root user.
Containers default to network: "none" — set to "bridge" (or a custom bridge network) if the agent needs outbound access.
"host" is blocked. "container:<id>" is blocked by default unless you explicitly set
sandbox.docker.dangerouslyAllowContainerNamespaceJoin: true (break-glass).
Inbound attachments are staged into media/inbound/* in the active workspace.
docker.binds mounts additional host directories; global and per-agent binds are merged.
Sandboxed browser (sandbox.browser.enabled): Chromium + CDP in a container. noVNC URL injected into system prompt. Does not require browser.enabled in openclaw.json.
noVNC observer access uses VNC auth by default and OpenClaw emits a short-lived token URL (instead of exposing the password in the shared URL).
allowHostControl: false(default) blocks sandboxed sessions from targeting the host browser.networkdefaults toopenclaw-sandbox-browser(dedicated bridge network). Set tobridgeonly when you explicitly want global bridge connectivity.cdpSourceRangeoptionally restricts CDP ingress at the container edge to a CIDR range (for example172.21.0.1/32).sandbox.browser.bindsmounts additional host directories into the sandbox browser container only. When set (including[]), it replacesdocker.bindsfor the browser container.- Launch defaults are defined in
scripts/sandbox-browser-entrypoint.shand tuned for container hosts:--remote-debugging-address=127.0.0.1--remote-debugging-port=<derived from OPENCLAW_BROWSER_CDP_PORT>--user-data-dir=${HOME}/.chrome--no-first-run--no-default-browser-check--disable-3d-apis--disable-gpu--disable-software-rasterizer--disable-dev-shm-usage--disable-background-networking--disable-features=TranslateUI--disable-breakpad--disable-crash-reporter--renderer-process-limit=2--no-zygote--metrics-recording-only--disable-extensions(default enabled)--disable-3d-apis,--disable-software-rasterizer, and--disable-gpuare enabled by default and can be disabled withOPENCLAW_BROWSER_DISABLE_GRAPHICS_FLAGS=0if WebGL/3D usage requires it.OPENCLAW_BROWSER_DISABLE_EXTENSIONS=0re-enables extensions if your workflow depends on them.--renderer-process-limit=2can be changed withOPENCLAW_BROWSER_RENDERER_PROCESS_LIMIT=<N>; set0to use Chromium’s default process limit.- plus
--no-sandboxand--disable-setuid-sandboxwhennoSandboxis enabled. - Defaults are the container image baseline; use a custom browser image with a custom entrypoint to change container defaults.
构建镜像:
scripts/sandbox-setup.sh # main sandbox image
scripts/sandbox-browser-setup.sh # optional browser image
agents.list(按 Agent 覆盖)
{
agents: {
list: [
{
id: "main",
default: true,
name: "Main Agent",
workspace: "~/.openclaw/workspace",
agentDir: "~/.openclaw/agents/main/agent",
model: "anthropic/claude-opus-4-6", // or { primary, fallbacks }
params: { cacheRetention: "none" }, // overrides matching defaults.models params by key
identity: {
name: "Samantha",
theme: "helpful sloth",
emoji: "🦥",
avatar: "avatars/samantha.png",
},
groupChat: { mentionPatterns: ["@openclaw"] },
sandbox: { mode: "off" },
runtime: {
type: "acp",
acp: {
agent: "codex",
backend: "acpx",
mode: "persistent",
cwd: "/workspace/openclaw",
},
},
subagents: { allowAgents: ["*"] },
tools: {
profile: "coding",
allow: ["browser"],
deny: ["canvas"],
elevated: { enabled: true },
},
},
],
},
}
id: stable agent id (required).default: when multiple are set, first wins (warning logged). If none set, first list entry is default.model: string form overridesprimaryonly; object form{ primary, fallbacks }overrides both ([]disables global fallbacks). Cron jobs that only overrideprimarystill inherit default fallbacks unless you setfallbacks: [].params: per-agent stream params merged over the selected model entry inagents.defaults.models. Use this for agent-specific overrides likecacheRetention,temperature, ormaxTokenswithout duplicating the whole model catalog.runtime: optional per-agent runtime descriptor. Usetype: "acp"withruntime.acpdefaults (agent,backend,mode,cwd) when the agent should default to ACP harness sessions.identity.avatar: workspace-relative path,http(s)URL, ordata:URI.identityderives defaults:ackReactionfromemoji,mentionPatternsfromname/emoji.subagents.allowAgents: allowlist of agent ids forsessions_spawn(["*"]= any; default: same agent only).- Sandbox inheritance guard: if the requester session is sandboxed,
sessions_spawnrejects targets that would run unsandboxed.
多 Agent 路由
在一个 Gateway 内运行多个隔离的 Agent。见 Multi-Agent。
{
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" } },
],
}
绑定匹配字段
type(optional):routefor normal routing (missing type defaults to route),acpfor persistent ACP conversation bindings.match.channel(required)match.accountId(optional;*= any account; omitted = default account)match.peer(optional;{ kind: direct|group|channel, id })match.guildId/match.teamId(optional; channel-specific)acp(optional; only fortype: "acp"):{ mode, label, cwd, backend }
Deterministic match order:
match.peermatch.guildIdmatch.teamIdmatch.accountId(exact, no peer/guild/team)match.accountId: "*"(channel-wide)- Default agent
Within each tier, the first matching bindings entry wins.
For type: "acp" entries, OpenClaw resolves by exact conversation identity (match.channel + account + match.peer.id) and does not use the route binding tier order above.
按 Agent 访问配置
完全访问(无沙箱)
{
agents: {
list: [
{
id: "personal",
workspace: "~/.openclaw/workspace-personal",
sandbox: { mode: "off" },
},
],
},
}
只读工具 + 工作区
{
agents: {
list: [
{
id: "family",
workspace: "~/.openclaw/workspace-family",
sandbox: { mode: "all", scope: "agent", workspaceAccess: "ro" },
tools: {
allow: [
"read",
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
],
deny: ["write", "edit", "apply_patch", "exec", "process", "browser"],
},
},
],
},
}
无文件系统访问(仅消息)
{
agents: {
list: [
{
id: "public",
workspace: "~/.openclaw/workspace-public",
sandbox: { mode: "all", scope: "agent", workspaceAccess: "none" },
tools: {
allow: [
"sessions_list",
"sessions_history",
"sessions_send",
"sessions_spawn",
"session_status",
"whatsapp",
"telegram",
"slack",
"discord",
"gateway",
],
deny: [
"read",
"write",
"edit",
"apply_patch",
"exec",
"process",
"browser",
"canvas",
"nodes",
"cron",
"gateway",
"image",
],
},
},
],
},
}
See Multi-Agent Sandbox & Tools for precedence details.
会话
{
session: {
scope: "per-sender",
dmScope: "main", // main | per-peer | per-channel-peer | per-account-channel-peer
identityLinks: {
alice: ["telegram:123456789", "discord:987654321012345678"],
},
reset: {
mode: "daily", // daily | idle
atHour: 4,
idleMinutes: 60,
},
resetByType: {
thread: { mode: "daily", atHour: 4 },
direct: { mode: "idle", idleMinutes: 240 },
group: { mode: "idle", idleMinutes: 120 },
},
resetTriggers: ["/new", "/reset"],
store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
parentForkMaxTokens: 100000, // skip parent-thread fork above this token count (0 disables)
maintenance: {
mode: "warn", // warn | enforce
pruneAfter: "30d",
maxEntries: 500,
rotateBytes: "10mb",
resetArchiveRetention: "30d", // duration or false
maxDiskBytes: "500mb", // optional hard budget
highWaterBytes: "400mb", // optional cleanup target
},
threadBindings: {
enabled: true,
idleHours: 24, // default inactivity auto-unfocus in hours (`0` disables)
maxAgeHours: 0, // default hard max age in hours (`0` disables)
},
mainKey: "main", // legacy (runtime always uses "main")
agentToAgent: { maxPingPongTurns: 5 },
sendPolicy: {
rules: [{ action: "deny", match: { channel: "discord", chatType: "group" } }],
default: "allow",
},
},
}
会话字段详情
dmScope: how DMs are grouped.main: all DMs share the main session.per-peer: isolate by sender id across channels.per-channel-peer: isolate per channel + sender (recommended for multi-user inboxes).per-account-channel-peer: isolate per account + channel + sender (recommended for multi-account).
identityLinks: map canonical ids to provider-prefixed peers for cross-channel session sharing.reset: primary reset policy.dailyresets atatHourlocal time;idleresets afteridleMinutes. When both configured, whichever expires first wins.resetByType: per-type overrides (direct,group,thread). Legacydmaccepted as alias fordirect.parentForkMaxTokens: max parent-sessiontotalTokensallowed when creating a forked thread session (default100000).- If parent
totalTokensis above this value, OpenClaw starts a fresh thread session instead of inheriting parent transcript history. - Set
0to disable this guard and always allow parent forking.
- If parent
mainKey: legacy field. Runtime now always uses"main"for the main direct-chat bucket.sendPolicy: match bychannel,chatType(direct|group|channel, with legacydmalias),keyPrefix, orrawKeyPrefix. First deny wins.maintenance: session-store cleanup + retention controls.mode:warnemits warnings only;enforceapplies cleanup.pruneAfter: age cutoff for stale entries (default30d).maxEntries: maximum number of entries insessions.json(default500).rotateBytes: rotatesessions.jsonwhen it exceeds this size (default10mb).resetArchiveRetention: retention for*.reset.<timestamp>transcript archives. Defaults topruneAfter; setfalseto disable.maxDiskBytes: optional sessions-directory disk budget. Inwarnmode it logs warnings; inenforcemode it removes oldest artifacts/sessions first.highWaterBytes: optional target after budget cleanup. Defaults to80%ofmaxDiskBytes.
threadBindings: global defaults for thread-bound session features.enabled: master default switch (providers can override; Discord useschannels.discord.threadBindings.enabled)idleHours: default inactivity auto-unfocus in hours (0disables; providers can override)maxAgeHours: default hard max age in hours (0disables; providers can override)
消息
{
messages: {
responsePrefix: "🦞", // or "auto"
ackReaction: "👀",
ackReactionScope: "group-mentions", // group-mentions | group-all | direct | all
removeAckAfterReply: false,
queue: {
mode: "collect", // steer | followup | collect | steer-backlog | steer+backlog | queue | interrupt
debounceMs: 1000,
cap: 20,
drop: "summarize", // old | new | summarize
byChannel: {
whatsapp: "collect",
telegram: "collect",
},
},
inbound: {
debounceMs: 2000, // 0 disables
byChannel: {
whatsapp: 5000,
slack: 1500,
},
},
},
}
响应前缀
Per-channel/account overrides: channels.<channel>.responsePrefix, channels.<channel>.accounts.<id>.responsePrefix.
Resolution (most specific wins): account → channel → global. "" disables and stops cascade. "auto" derives [{identity.name}].
Template variables:
| Variable | Description | Example |
|---|---|---|
{model} | Short model name | claude-opus-4-6 |
{modelFull} | Full model identifier | anthropic/claude-opus-4-6 |
{provider} | Provider name | anthropic |
{thinkingLevel} | Current thinking level | high, low, off |
{identity.name} | Agent identity name | (same as "auto") |
Variables are case-insensitive. {think} is an alias for {thinkingLevel}.
确认反应
- Defaults to active agent’s
identity.emoji, otherwise"👀". Set""to disable. - Per-channel overrides:
channels.<channel>.ackReaction,channels.<channel>.accounts.<id>.ackReaction. - Resolution order: account → channel →
messages.ackReaction→ identity fallback. - Scope:
group-mentions(default),group-all,direct,all. removeAckAfterReply: removes ack after reply (Slack/Discord/Telegram/Google Chat only).
入站防抖
将同一发送者的快速纯文本消息合并为单个 Agent 轮次。媒体/附件立即刷新。控制命令绕过防抖。
TTS(文本转语音)
{
messages: {
tts: {
auto: "always", // off | always | inbound | tagged
mode: "final", // final | all
provider: "elevenlabs",
summaryModel: "openai/gpt-4.1-mini",
modelOverrides: { enabled: true },
maxTextLength: 4000,
timeoutMs: 30000,
prefsPath: "~/.openclaw/settings/tts.json",
elevenlabs: {
apiKey: "elevenlabs_api_key",
baseUrl: "https://api.elevenlabs.io",
voiceId: "voice_id",
modelId: "eleven_multilingual_v2",
seed: 42,
applyTextNormalization: "auto",
languageCode: "en",
voiceSettings: {
stability: 0.5,
similarityBoost: 0.75,
style: 0.0,
useSpeakerBoost: true,
speed: 1.0,
},
},
openai: {
apiKey: "openai_api_key",
baseUrl: "https://api.openai.com/v1",
model: "gpt-4o-mini-tts",
voice: "alloy",
},
},
},
}
autocontrols auto-TTS./tts off|always|inbound|taggedoverrides per session.summaryModeloverridesagents.defaults.model.primaryfor auto-summary.modelOverridesis enabled by default;modelOverrides.allowProviderdefaults tofalse(opt-in).- API keys fall back to
ELEVENLABS_API_KEY/XI_API_KEYandOPENAI_API_KEY. openai.baseUrloverrides the OpenAI TTS endpoint. Resolution order is config, thenOPENAI_TTS_BASE_URL, thenhttps://api.openai.com/v1.- When
openai.baseUrlpoints to a non-OpenAI endpoint, OpenClaw treats it as an OpenAI-compatible TTS server and relaxes model/voice validation.
Talk
Defaults for Talk mode (macOS/iOS/Android).
{
talk: {
voiceId: "elevenlabs_voice_id",
voiceAliases: {
Clawd: "EXAVITQu4vr4xnSDxMaL",
Roger: "CwhRBWXzGAHq8TQ4Fs17",
},
modelId: "eleven_v3",
outputFormat: "mp3_44100_128",
apiKey: "elevenlabs_api_key",
silenceTimeoutMs: 1500,
interruptOnSpeech: true,
},
}
- Voice IDs fall back to
ELEVENLABS_VOICE_IDorSAG_VOICE_ID. apiKeyandproviders.*.apiKeyaccept plaintext strings or SecretRef objects.ELEVENLABS_API_KEYfallback applies only when no Talk API key is configured.voiceAliaseslets Talk directives use friendly names.silenceTimeoutMscontrols how long Talk mode waits after user silence before it sends the transcript. Unset keeps the platform default pause window (700 ms on macOS and Android, 900 ms on iOS).
工具
工具配置
tools.profile sets a base allowlist before tools.allow/tools.deny:
Local onboarding defaults new local configs to tools.profile: "coding" when unset (existing explicit profiles are preserved).
| Profile | Includes |
|---|---|
minimal | session_status only |
coding | group:fs, group:runtime, group:sessions, group:memory, image |
messaging | group:messaging, sessions_list, sessions_history, sessions_send, session_status |
full | No restriction (same as unset) |
工具组
| Group | Tools |
|---|---|
group:runtime | exec, process (bash is accepted as an alias for exec) |
group:fs | read, write, edit, apply_patch |
group:sessions | sessions_list, sessions_history, sessions_send, sessions_spawn, session_status |
group:memory | memory_search, memory_get |
group:web | web_search, web_fetch |
group:ui | browser, canvas |
group:automation | cron, gateway |
group:messaging | message |
group:nodes | nodes |
group:openclaw | All built-in tools (excludes provider plugins) |
tools.allow / tools.deny
全局工具允许/拒绝策略(拒绝优先)。不区分大小写,支持 * 通配符。即使 Docker 沙箱关闭也生效。
{
tools: { deny: ["browser", "canvas"] },
}
tools.byProvider
进一步限制特定提供商或模型的工具。顺序:基础配置 → 提供商配置 → allow/deny。
{
tools: {
profile: "coding",
byProvider: {
"google-antigravity": { profile: "minimal" },
"openai/gpt-5.2": { allow: ["group:fs", "sessions_list"] },
},
},
}
tools.elevated
控制提权(宿主机)exec 访问:
{
tools: {
elevated: {
enabled: true,
allowFrom: {
whatsapp: ["+15555550123"],
discord: ["1234567890123", "987654321098765432"],
},
},
},
}
- Per-agent override (
agents.list[].tools.elevated) can only further restrict. /elevated on|off|ask|fullstores state per session; inline directives apply to single message.- Elevated
execruns on the host, bypasses sandboxing.
tools.exec
{
tools: {
exec: {
backgroundMs: 10000,
timeoutSec: 1800,
cleanupMs: 1800000,
notifyOnExit: true,
notifyOnExitEmptySuccess: false,
applyPatch: {
enabled: false,
allowModels: ["gpt-5.2"],
},
},
},
}
tools.loopDetection
Tool-loop safety checks are disabled by default. Set enabled: true to activate detection.
Settings can be defined globally in tools.loopDetection and overridden per-agent at agents.list[].tools.loopDetection.
{
tools: {
loopDetection: {
enabled: true,
historySize: 30,
warningThreshold: 10,
criticalThreshold: 20,
globalCircuitBreakerThreshold: 30,
detectors: {
genericRepeat: true,
knownPollNoProgress: true,
pingPong: true,
},
},
},
}
historySize: max tool-call history retained for loop analysis.warningThreshold: repeating no-progress pattern threshold for warnings.criticalThreshold: higher repeating threshold for blocking critical loops.globalCircuitBreakerThreshold: hard stop threshold for any no-progress run.detectors.genericRepeat: warn on repeated same-tool/same-args calls.detectors.knownPollNoProgress: warn/block on known poll tools (process.poll,command_status, etc.).detectors.pingPong: warn/block on alternating no-progress pair patterns.- If
warningThreshold >= criticalThresholdorcriticalThreshold >= globalCircuitBreakerThreshold, validation fails.
tools.web
{
tools: {
web: {
search: {
enabled: true,
apiKey: "brave_api_key", // or BRAVE_API_KEY env
maxResults: 5,
timeoutSeconds: 30,
cacheTtlMinutes: 15,
},
fetch: {
enabled: true,
maxChars: 50000,
maxCharsCap: 50000,
timeoutSeconds: 30,
cacheTtlMinutes: 15,
userAgent: "custom-ua",
},
},
},
}
tools.media
配置入站媒体理解(图片/音频/视频):
{
tools: {
media: {
concurrency: 2,
audio: {
enabled: true,
maxBytes: 20971520,
scope: {
default: "deny",
rules: [{ action: "allow", match: { chatType: "direct" } }],
},
models: [
{ provider: "openai", model: "gpt-4o-mini-transcribe" },
{ type: "cli", command: "whisper", args: ["--model", "base", "{{MediaPath}}"] },
],
},
video: {
enabled: true,
maxBytes: 52428800,
models: [{ provider: "google", model: "gemini-3-flash-preview" }],
},
},
},
}
媒体模型条目字段
Provider entry (type: "provider" or omitted):
provider: API provider id (openai,anthropic,google/gemini,groq, etc.)model: model id overrideprofile/preferredProfile:auth-profiles.jsonprofile selection
CLI entry (type: "cli"):
command: executable to runargs: templated args (supports{{MediaPath}},{{Prompt}},{{MaxChars}}, etc.)
Common fields:
capabilities: optional list (image,audio,video). Defaults:openai/anthropic/minimax→ image,google→ image+audio+video,groq→ audio.prompt,maxChars,maxBytes,timeoutSeconds,language: per-entry overrides.- Failures fall back to the next entry.
Provider auth follows standard order: auth-profiles.json → env vars → models.providers.*.apiKey.
tools.agentToAgent
{
tools: {
agentToAgent: {
enabled: false,
allow: ["home", "work"],
},
},
}
tools.sessions
Controls which sessions can be targeted by the session tools (sessions_list, sessions_history, sessions_send).
Default: tree (current session + sessions spawned by it, such as subagents).
{
tools: {
sessions: {
// "self" | "tree" | "agent" | "all"
visibility: "tree",
},
},
}
Notes:
self: only the current session key.tree: current session + sessions spawned by the current session (subagents).agent: any session belonging to the current agent id (can include other users if you run per-sender sessions under the same agent id).all: any session. Cross-agent targeting still requirestools.agentToAgent.- Sandbox clamp: when the current session is sandboxed and
agents.defaults.sandbox.sessionToolsVisibility="spawned", visibility is forced totreeeven iftools.sessions.visibility="all".
tools.sessions_spawn
Controls inline attachment support for sessions_spawn.
{
tools: {
sessions_spawn: {
attachments: {
enabled: false, // opt-in: set true to allow inline file attachments
maxTotalBytes: 5242880, // 5 MB total across all files
maxFiles: 50,
maxFileBytes: 1048576, // 1 MB per file
retainOnSessionKeep: false, // keep attachments when cleanup="keep"
},
},
},
}
Notes:
- Attachments are only supported for
runtime: "subagent". ACP runtime rejects them. - Files are materialized into the child workspace at
.openclaw/attachments/<uuid>/with a.manifest.json. - Attachment content is automatically redacted from transcript persistence.
- Base64 inputs are validated with strict alphabet/padding checks and a pre-decode size guard.
- File permissions are
0700for directories and0600for files. - Cleanup follows the
cleanuppolicy:deletealways removes attachments;keepretains them only whenretainOnSessionKeep: true.
tools.subagents
{
agents: {
defaults: {
subagents: {
model: "minimax/MiniMax-M2.5",
maxConcurrent: 1,
runTimeoutSeconds: 900,
archiveAfterMinutes: 60,
},
},
},
}
model: default model for spawned sub-agents. If omitted, sub-agents inherit the caller’s model.runTimeoutSeconds: default timeout (seconds) forsessions_spawnwhen the tool call omitsrunTimeoutSeconds.0means no timeout.- Per-subagent tool policy:
tools.subagents.tools.allow/tools.subagents.tools.deny.
自定义提供商和 base URL
OpenClaw 使用 pi-coding-agent 模型目录。通过配置中的 models.providers 或 ~/.openclaw/agents/<agentId>/agent/models.json 添加自定义提供商。
{
models: {
mode: "merge", // merge (default) | replace
providers: {
"custom-proxy": {
baseUrl: "http://localhost:4000/v1",
apiKey: "LITELLM_KEY",
api: "openai-completions", // openai-completions | openai-responses | anthropic-messages | google-generative-ai
models: [
{
id: "llama-3.1-8b",
name: "Llama 3.1 8B",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 32000,
},
],
},
},
},
}
- Use
authHeader: true+headersfor custom auth needs. - Override agent config root with
OPENCLAW_AGENT_DIR(orPI_CODING_AGENT_DIR). - Merge precedence for matching provider IDs:
- Non-empty agent
models.jsonbaseUrlvalues win. - Non-empty agent
apiKeyvalues win only when that provider is not SecretRef-managed in current config/auth-profile context. - SecretRef-managed provider
apiKeyvalues are refreshed from source markers (ENV_VAR_NAMEfor env refs,secretref-managedfor file/exec refs) instead of persisting resolved secrets. - SecretRef-managed provider header values are refreshed from source markers (
secretref-env:ENV_VAR_NAMEfor env refs,secretref-managedfor file/exec refs). - Empty or missing agent
apiKey/baseUrlfall back tomodels.providersin config. - Matching model
contextWindow/maxTokensuse the higher value between explicit config and implicit catalog values. - Use
models.mode: "replace"when you want config to fully rewritemodels.json. - Marker persistence is source-authoritative: markers are written from the active source config snapshot (pre-resolution), not from resolved runtime secret values.
- Non-empty agent
提供商字段详情
models.mode: provider catalog behavior (mergeorreplace).models.providers: custom provider map keyed by provider id.models.providers.*.api: request adapter (openai-completions,openai-responses,anthropic-messages,google-generative-ai, etc).models.providers.*.apiKey: provider credential (prefer SecretRef/env substitution).models.providers.*.auth: auth strategy (api-key,token,oauth,aws-sdk).models.providers.*.injectNumCtxForOpenAICompat: for Ollama +openai-completions, injectoptions.num_ctxinto requests (default:true).models.providers.*.authHeader: force credential transport in theAuthorizationheader when required.models.providers.*.baseUrl: upstream API base URL.models.providers.*.headers: extra static headers for proxy/tenant routing.models.providers.*.models: explicit provider model catalog entries.models.providers.*.models.*.compat.supportsDeveloperRole: optional compatibility hint. Forapi: "openai-completions"with a non-empty non-nativebaseUrl(host notapi.openai.com), OpenClaw forces this tofalseat runtime. Empty/omittedbaseUrlkeeps default OpenAI behavior.models.bedrockDiscovery: Bedrock auto-discovery settings root.models.bedrockDiscovery.enabled: turn discovery polling on/off.models.bedrockDiscovery.region: AWS region for discovery.models.bedrockDiscovery.providerFilter: optional provider-id filter for targeted discovery.models.bedrockDiscovery.refreshInterval: polling interval for discovery refresh.models.bedrockDiscovery.defaultContextWindow: fallback context window for discovered models.models.bedrockDiscovery.defaultMaxTokens: fallback max output tokens for discovered models.
提供商示例
Cerebras (GLM 4.6 / 4.7)
{
env: { CEREBRAS_API_KEY: "sk-..." },
agents: {
defaults: {
model: {
primary: "cerebras/zai-glm-4.7",
fallbacks: ["cerebras/zai-glm-4.6"],
},
models: {
"cerebras/zai-glm-4.7": { alias: "GLM 4.7 (Cerebras)" },
"cerebras/zai-glm-4.6": { alias: "GLM 4.6 (Cerebras)" },
},
},
},
models: {
mode: "merge",
providers: {
cerebras: {
baseUrl: "https://api.cerebras.ai/v1",
apiKey: "${CEREBRAS_API_KEY}",
api: "openai-completions",
models: [
{ id: "zai-glm-4.7", name: "GLM 4.7 (Cerebras)" },
{ id: "zai-glm-4.6", name: "GLM 4.6 (Cerebras)" },
],
},
},
},
}
Use cerebras/zai-glm-4.7 for Cerebras; zai/glm-4.7 for Z.AI direct.
OpenCode
{
agents: {
defaults: {
model: { primary: "opencode/claude-opus-4-6" },
models: { "opencode/claude-opus-4-6": { alias: "Opus" } },
},
},
}
Set OPENCODE_API_KEY (or OPENCODE_ZEN_API_KEY). Use opencode/... refs for the Zen catalog or opencode-go/... refs for the Go catalog. Shortcut: openclaw onboard --auth-choice opencode-zen or openclaw onboard --auth-choice opencode-go.
Z.AI (GLM-4.7)
{
agents: {
defaults: {
model: { primary: "zai/glm-4.7" },
models: { "zai/glm-4.7": {} },
},
},
}
Set ZAI_API_KEY. z.ai/* and z-ai/* are accepted aliases. Shortcut: openclaw onboard --auth-choice zai-api-key.
- General endpoint:
https://api.z.ai/api/paas/v4 - Coding endpoint (default):
https://api.z.ai/api/coding/paas/v4 - For the general endpoint, define a custom provider with the base URL override.
Moonshot AI (Kimi)
{
env: { MOONSHOT_API_KEY: "sk-..." },
agents: {
defaults: {
model: { primary: "moonshot/kimi-k2.5" },
models: { "moonshot/kimi-k2.5": { alias: "Kimi K2.5" } },
},
},
models: {
mode: "merge",
providers: {
moonshot: {
baseUrl: "https://api.moonshot.ai/v1",
apiKey: "${MOONSHOT_API_KEY}",
api: "openai-completions",
models: [
{
id: "kimi-k2.5",
name: "Kimi K2.5",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 256000,
maxTokens: 8192,
},
],
},
},
},
}
For the China endpoint: baseUrl: "https://api.moonshot.cn/v1" or openclaw onboard --auth-choice moonshot-api-key-cn.
Kimi Coding
{
env: { KIMI_API_KEY: "sk-..." },
agents: {
defaults: {
model: { primary: "kimi-coding/k2p5" },
models: { "kimi-coding/k2p5": { alias: "Kimi K2.5" } },
},
},
}
Anthropic-compatible, built-in provider. Shortcut: openclaw onboard --auth-choice kimi-code-api-key.
Synthetic (Anthropic-compatible)
{
env: { SYNTHETIC_API_KEY: "sk-..." },
agents: {
defaults: {
model: { primary: "synthetic/hf:MiniMaxAI/MiniMax-M2.5" },
models: { "synthetic/hf:MiniMaxAI/MiniMax-M2.5": { alias: "MiniMax M2.5" } },
},
},
models: {
mode: "merge",
providers: {
synthetic: {
baseUrl: "https://api.synthetic.new/anthropic",
apiKey: "${SYNTHETIC_API_KEY}",
api: "anthropic-messages",
models: [
{
id: "hf:MiniMaxAI/MiniMax-M2.5",
name: "MiniMax M2.5",
reasoning: true,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 192000,
maxTokens: 65536,
},
],
},
},
},
}
Base URL should omit /v1 (Anthropic client appends it). Shortcut: openclaw onboard --auth-choice synthetic-api-key.
MiniMax M2.5 (direct)
{
agents: {
defaults: {
model: { primary: "minimax/MiniMax-M2.5" },
models: {
"minimax/MiniMax-M2.5": { alias: "Minimax" },
},
},
},
models: {
mode: "merge",
providers: {
minimax: {
baseUrl: "https://api.minimax.io/anthropic",
apiKey: "${MINIMAX_API_KEY}",
api: "anthropic-messages",
models: [
{
id: "MiniMax-M2.5",
name: "MiniMax M2.5",
reasoning: true,
input: ["text"],
cost: { input: 15, output: 60, cacheRead: 2, cacheWrite: 10 },
contextWindow: 200000,
maxTokens: 8192,
},
],
},
},
},
}
Set MINIMAX_API_KEY. Shortcut: openclaw onboard --auth-choice minimax-api.
Local models (LM Studio)
See Local Models. TL;DR: run MiniMax M2.5 via LM Studio Responses API on serious hardware; keep hosted models merged for fallback.
技能
{
skills: {
allowBundled: ["gemini", "peekaboo"],
load: {
extraDirs: ["~/Projects/agent-scripts/skills"],
},
install: {
preferBrew: true,
nodeManager: "npm", // npm | pnpm | yarn
},
entries: {
"nano-banana-pro": {
apiKey: { source: "env", provider: "default", id: "GEMINI_API_KEY" }, // or plaintext string
env: { GEMINI_API_KEY: "GEMINI_KEY_HERE" },
},
peekaboo: { enabled: true },
sag: { enabled: false },
},
},
}
allowBundled: optional allowlist for bundled skills only (managed/workspace skills unaffected).entries.<skillKey>.enabled: falsedisables a skill even if bundled/installed.entries.<skillKey>.apiKey: convenience for skills declaring a primary env var (plaintext string or SecretRef object).
插件
{
plugins: {
enabled: true,
allow: ["voice-call"],
deny: [],
load: {
paths: ["~/Projects/oss/voice-call-extension"],
},
entries: {
"voice-call": {
enabled: true,
hooks: {
allowPromptInjection: false,
},
config: { provider: "twilio" },
},
},
},
}
- Loaded from
~/.openclaw/extensions,<workspace>/.openclaw/extensions, plusplugins.load.paths. - Config changes require a gateway restart.
allow: optional allowlist (only listed plugins load).denywins.plugins.entries.<id>.apiKey: plugin-level API key convenience field (when supported by the plugin).plugins.entries.<id>.env: plugin-scoped env var map.plugins.entries.<id>.hooks.allowPromptInjection: whenfalse, core blocksbefore_prompt_buildand ignores prompt-mutating fields from legacybefore_agent_start, while preserving legacymodelOverrideandproviderOverride.plugins.entries.<id>.config: plugin-defined config object (validated by plugin schema).plugins.slots.memory: pick the active memory plugin id, or"none"to disable memory plugins.plugins.slots.contextEngine: pick the active context engine plugin id; defaults to"legacy"unless you install and select another engine.plugins.installs: CLI-managed install metadata used byopenclaw plugins update.- Includes
source,spec,sourcePath,installPath,version,resolvedName,resolvedVersion,resolvedSpec,integrity,shasum,resolvedAt,installedAt. - Treat
plugins.installs.*as managed state; prefer CLI commands over manual edits.
- Includes
See Plugins.
浏览器
{
browser: {
enabled: true,
evaluateEnabled: true,
defaultProfile: "chrome",
ssrfPolicy: {
dangerouslyAllowPrivateNetwork: true, // default trusted-network mode
// allowPrivateNetwork: true, // legacy alias
// hostnameAllowlist: ["*.example.com", "example.com"],
// allowedHostnames: ["localhost"],
},
profiles: {
openclaw: { cdpPort: 18800, color: "#FF4500" },
work: { cdpPort: 18801, color: "#0066CC" },
remote: { cdpUrl: "http://10.0.0.42:9222", color: "#00AA00" },
},
color: "#FF4500",
// headless: false,
// noSandbox: false,
// extraArgs: [],
// relayBindHost: "0.0.0.0", // only when the extension relay must be reachable across namespaces (for example WSL2)
// executablePath: "/Applications/Brave Browser.app/Contents/MacOS/Brave Browser",
// attachOnly: false,
},
}
evaluateEnabled: falsedisablesact:evaluateandwait --fn.ssrfPolicy.dangerouslyAllowPrivateNetworkdefaults totruewhen unset (trusted-network model).- Set
ssrfPolicy.dangerouslyAllowPrivateNetwork: falsefor strict public-only browser navigation. ssrfPolicy.allowPrivateNetworkremains supported as a legacy alias.- In strict mode, use
ssrfPolicy.hostnameAllowlistandssrfPolicy.allowedHostnamesfor explicit exceptions. - Remote profiles are attach-only (start/stop/reset disabled).
- Auto-detect order: default browser if Chromium-based → Chrome → Brave → Edge → Chromium → Chrome Canary.
- Control service: loopback only (port derived from
gateway.port, default18791). extraArgsappends extra launch flags to local Chromium startup (for example--disable-gpu, window sizing, or debug flags).relayBindHostchanges where the Chrome extension relay listens. Leave unset for loopback-only access; set an explicit non-loopback bind address such as0.0.0.0only when the relay must cross a namespace boundary (for example WSL2) and the host network is already trusted.
UI
{
ui: {
seamColor: "#FF4500",
assistant: {
name: "OpenClaw",
avatar: "CB", // emoji, short text, image URL, or data URI
},
},
}
seamColor: accent color for native app UI chrome (Talk Mode bubble tint, etc.).assistant: Control UI identity override. Falls back to active agent identity.
Gateway 网关
{
gateway: {
mode: "local", // local | remote
port: 18789,
bind: "loopback",
auth: {
mode: "token", // none | token | password | trusted-proxy
token: "your-token",
// password: "your-password", // or OPENCLAW_GATEWAY_PASSWORD
// trustedProxy: { userHeader: "x-forwarded-user" }, // for mode=trusted-proxy; see /gateway/trusted-proxy-auth
allowTailscale: true,
rateLimit: {
maxAttempts: 10,
windowMs: 60000,
lockoutMs: 300000,
exemptLoopback: true,
},
},
tailscale: {
mode: "off", // off | serve | funnel
resetOnExit: false,
},
controlUi: {
enabled: true,
basePath: "/openclaw",
// root: "dist/control-ui",
// allowedOrigins: ["https://control.example.com"], // required for non-loopback Control UI
// dangerouslyAllowHostHeaderOriginFallback: false, // dangerous Host-header origin fallback mode
// allowInsecureAuth: false,
// dangerouslyDisableDeviceAuth: false,
},
remote: {
url: "ws://gateway.tailnet:18789",
transport: "ssh", // ssh | direct
token: "your-token",
// password: "your-password",
},
trustedProxies: ["10.0.0.1"],
// Optional. Default false.
allowRealIpFallback: false,
tools: {
// Additional /tools/invoke HTTP denies
deny: ["browser"],
// Remove tools from the default HTTP deny list
allow: ["gateway"],
},
push: {
apns: {
relay: {
baseUrl: "https://relay.example.com",
timeoutMs: 10000,
},
},
},
},
}
Gateway 字段详情
mode:local(run gateway) orremote(connect to remote gateway). Gateway refuses to start unlesslocal.port: single multiplexed port for WS + HTTP. Precedence:--port>OPENCLAW_GATEWAY_PORT>gateway.port>18789.bind:auto,loopback(default),lan(0.0.0.0),tailnet(Tailscale IP only), orcustom.- Legacy bind aliases: use bind mode values in
gateway.bind(auto,loopback,lan,tailnet,custom), not host aliases (0.0.0.0,127.0.0.1,localhost,::,::1). - Docker note: the default
loopbackbind listens on127.0.0.1inside the container. With Docker bridge networking (-p 18789:18789), traffic arrives oneth0, so the gateway is unreachable. Use--network host, or setbind: "lan"(orbind: "custom"withcustomBindHost: "0.0.0.0") to listen on all interfaces. - Auth: required by default. Non-loopback binds require a shared token/password. Onboarding wizard generates a token by default.
- If both
gateway.auth.tokenandgateway.auth.passwordare configured (including SecretRefs), setgateway.auth.modeexplicitly totokenorpassword. Startup and service install/repair flows fail when both are configured and mode is unset. gateway.auth.mode: "none": explicit no-auth mode. Use only for trusted local loopback setups; this is intentionally not offered by onboarding prompts.gateway.auth.mode: "trusted-proxy": delegate auth to an identity-aware reverse proxy and trust identity headers fromgateway.trustedProxies(see Trusted Proxy Auth).gateway.auth.allowTailscale: whentrue, Tailscale Serve identity headers can satisfy Control UI/WebSocket auth (verified viatailscale whois); HTTP API endpoints still require token/password auth. This tokenless flow assumes the gateway host is trusted. Defaults totruewhentailscale.mode = "serve".gateway.auth.rateLimit: optional failed-auth limiter. Applies per client IP and per auth scope (shared-secret and device-token are tracked independently). Blocked attempts return429+Retry-After.gateway.auth.rateLimit.exemptLoopbackdefaults totrue; setfalsewhen you intentionally want localhost traffic rate-limited too (for test setups or strict proxy deployments).
- Browser-origin WS auth attempts are always throttled with loopback exemption disabled (defense-in-depth against browser-based localhost brute force).
tailscale.mode:serve(tailnet only, loopback bind) orfunnel(public, requires auth).controlUi.allowedOrigins: explicit browser-origin allowlist for Gateway WebSocket connects. Required when browser clients are expected from non-loopback origins.controlUi.dangerouslyAllowHostHeaderOriginFallback: dangerous mode that enables Host-header origin fallback for deployments that intentionally rely on Host-header origin policy.remote.transport:ssh(default) ordirect(ws/wss). Fordirect,remote.urlmust bews://orwss://.OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1: client-side break-glass override that allows plaintextws://to trusted private-network IPs; default remains loopback-only for plaintext.gateway.remote.token/.passwordare remote-client credential fields. They do not configure gateway auth by themselves.gateway.push.apns.relay.baseUrl: base HTTPS URL for the external APNs relay used by official/TestFlight iOS builds after they publish relay-backed registrations to the gateway. This URL must match the relay URL compiled into the iOS build.gateway.push.apns.relay.timeoutMs: gateway-to-relay send timeout in milliseconds. Defaults to10000.- Relay-backed registrations are delegated to a specific gateway identity. The paired iOS app fetches
gateway.identity.get, includes that identity in the relay registration, and forwards a registration-scoped send grant to the gateway. Another gateway cannot reuse that stored registration. OPENCLAW_APNS_RELAY_BASE_URL/OPENCLAW_APNS_RELAY_TIMEOUT_MS: temporary env overrides for the relay config above.OPENCLAW_APNS_RELAY_ALLOW_HTTP=true: development-only escape hatch for loopback HTTP relay URLs. Production relay URLs should stay on HTTPS.- Local gateway call paths can use
gateway.remote.*as fallback only whengateway.auth.*is unset. - If
gateway.auth.token/gateway.auth.passwordis explicitly configured via SecretRef and unresolved, resolution fails closed (no remote fallback masking). trustedProxies: reverse proxy IPs that terminate TLS. Only list proxies you control.allowRealIpFallback: whentrue, the gateway acceptsX-Real-IPifX-Forwarded-Foris missing. Defaultfalsefor fail-closed behavior.gateway.tools.deny: extra tool names blocked for HTTPPOST /tools/invoke(extends default deny list).gateway.tools.allow: remove tool names from the default HTTP deny list.
OpenAI 兼容端点
- Chat Completions: disabled by default. Enable with
gateway.http.endpoints.chatCompletions.enabled: true. - Responses API:
gateway.http.endpoints.responses.enabled. - Responses URL-input hardening:
gateway.http.endpoints.responses.maxUrlPartsgateway.http.endpoints.responses.files.urlAllowlistgateway.http.endpoints.responses.images.urlAllowlist
- Optional response hardening header:
gateway.http.securityHeaders.strictTransportSecurity(set only for HTTPS origins you control; see Trusted Proxy Auth)
多实例隔离
在一台主机上用独立端口和状态目录运行多个 Gateway:
OPENCLAW_CONFIG_PATH=~/.openclaw/a.json \
OPENCLAW_STATE_DIR=~/.openclaw-a \
openclaw gateway --port 19001
Convenience flags: --dev (uses ~/.openclaw-dev + port 19001), --profile <name> (uses ~/.openclaw-<name>).
See Multiple Gateways.
Hooks(Webhook)
{
hooks: {
enabled: true,
token: "shared-secret",
path: "/hooks",
maxBodyBytes: 262144,
defaultSessionKey: "hook:ingress",
allowRequestSessionKey: false,
allowedSessionKeyPrefixes: ["hook:"],
allowedAgentIds: ["hooks", "main"],
presets: ["gmail"],
transformsDir: "~/.openclaw/hooks/transforms",
mappings: [
{
match: { path: "gmail" },
action: "agent",
agentId: "hooks",
wakeMode: "now",
name: "Gmail",
sessionKey: "hook:gmail:{{messages[0].id}}",
messageTemplate: "From: {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}",
deliver: true,
channel: "last",
model: "openai/gpt-5.2-mini",
},
],
},
}
Auth: Authorization: Bearer <token> or x-openclaw-token: <token>.
Endpoints:
POST /hooks/wake→{ text, mode?: "now"|"next-heartbeat" }POST /hooks/agent→{ message, name?, agentId?, sessionKey?, wakeMode?, deliver?, channel?, to?, model?, thinking?, timeoutSeconds? }sessionKeyfrom request payload is accepted only whenhooks.allowRequestSessionKey=true(default:false).
POST /hooks/<name>→ resolved viahooks.mappings
映射详情
match.pathmatches sub-path after/hooks(e.g./hooks/gmail→gmail).match.sourcematches a payload field for generic paths.- Templates like
{{messages[0].subject}}read from the payload. transformcan point to a JS/TS module returning a hook action.transform.modulemust be a relative path and stays withinhooks.transformsDir(absolute paths and traversal are rejected).
agentIdroutes to a specific agent; unknown IDs fall back to default.allowedAgentIds: restricts explicit routing (*or omitted = allow all,[]= deny all).defaultSessionKey: optional fixed session key for hook agent runs without explicitsessionKey.allowRequestSessionKey: allow/hooks/agentcallers to setsessionKey(default:false).allowedSessionKeyPrefixes: optional prefix allowlist for explicitsessionKeyvalues (request + mapping), e.g.["hook:"].deliver: truesends final reply to a channel;channeldefaults tolast.modeloverrides LLM for this hook run (must be allowed if model catalog is set).
Gmail 集成
{
hooks: {
gmail: {
account: "[email protected]",
topic: "projects/<project-id>/topics/gog-gmail-watch",
subscription: "gog-gmail-watch-push",
pushToken: "shared-push-token",
hookUrl: "http://127.0.0.1:18789/hooks/gmail",
includeBody: true,
maxBytes: 20000,
renewEveryMinutes: 720,
serve: { bind: "127.0.0.1", port: 8788, path: "/" },
tailscale: { mode: "funnel", path: "/gmail-pubsub" },
model: "openrouter/meta-llama/llama-3.3-70b-instruct:free",
thinking: "off",
},
},
}
- Gateway auto-starts
gog gmail watch serveon boot when configured. SetOPENCLAW_SKIP_GMAIL_WATCHER=1to disable. - Don’t run a separate
gog gmail watch servealongside the Gateway.
Canvas 主机
{
canvasHost: {
root: "~/.openclaw/workspace/canvas",
liveReload: true,
// enabled: false, // or OPENCLAW_SKIP_CANVAS_HOST=1
},
}
- Serves agent-editable HTML/CSS/JS and A2UI over HTTP under the Gateway port:
http://<gateway-host>:<gateway.port>/__openclaw__/canvas/http://<gateway-host>:<gateway.port>/__openclaw__/a2ui/
- Local-only: keep
gateway.bind: "loopback"(default). - Non-loopback binds: canvas routes require Gateway auth (token/password/trusted-proxy), same as other Gateway HTTP surfaces.
- Node WebViews typically don’t send auth headers; after a node is paired and connected, the Gateway advertises node-scoped capability URLs for canvas/A2UI access.
- Capability URLs are bound to the active node WS session and expire quickly. IP-based fallback is not used.
- Injects live-reload client into served HTML.
- Auto-creates starter
index.htmlwhen empty. - Also serves A2UI at
/__openclaw__/a2ui/. - Changes require a gateway restart.
- Disable live reload for large directories or
EMFILEerrors.
发现
mDNS(Bonjour)
{
discovery: {
mdns: {
mode: "minimal", // minimal | full | off
},
},
}
minimal(default): omitcliPath+sshPortfrom TXT records.full: includecliPath+sshPort.- Hostname defaults to
openclaw. Override withOPENCLAW_MDNS_HOSTNAME.
广域(DNS-SD)
{
discovery: {
wideArea: { enabled: true },
},
}
Writes a unicast DNS-SD zone under ~/.openclaw/dns/. For cross-network discovery, pair with a DNS server (CoreDNS recommended) + Tailscale split DNS.
Setup: openclaw dns setup --apply.
环境变量
env(内联环境变量)
{
env: {
OPENROUTER_API_KEY: "sk-or-...",
vars: {
GROQ_API_KEY: "gsk-...",
},
shellEnv: {
enabled: true,
timeoutMs: 15000,
},
},
}
- Inline env vars are only applied if the process env is missing the key.
.envfiles: CWD.env+~/.openclaw/.env(neither overrides existing vars).shellEnv: imports missing expected keys from your login shell profile.- See Environment for full precedence.
环境变量替换
在任何配置字符串中用 ${VAR_NAME} 引用环境变量:
{
gateway: {
auth: { token: "${OPENCLAW_GATEWAY_TOKEN}" },
},
}
- Only uppercase names matched:
[A-Z_][A-Z0-9_]*. - Missing/empty vars throw an error at config load.
- Escape with
$${VAR}for a literal${VAR}. - Works with
$include.
密钥
Secret refs 是增量的:明文值仍然有效。
SecretRef
使用以下对象格式:
{ source: "env" | "file" | "exec", provider: "default", id: "..." }
Validation:
providerpattern:^[a-z][a-z0-9_-]{0,63}$source: "env"id pattern:^[A-Z][A-Z0-9_]{0,127}$source: "file"id: absolute JSON pointer (for example"/providers/openai/apiKey")source: "exec"id pattern:^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$source: "exec"ids must not contain.or..slash-delimited path segments (for examplea/../bis rejected)
支持的凭证路径
- Canonical matrix: SecretRef Credential Surface
secrets applytargets supportedopenclaw.jsoncredential paths.auth-profiles.jsonrefs are included in runtime resolution and audit coverage.
密钥提供者配置
{
secrets: {
providers: {
default: { source: "env" }, // optional explicit env provider
filemain: {
source: "file",
path: "~/.openclaw/secrets.json",
mode: "json",
timeoutMs: 5000,
},
vault: {
source: "exec",
command: "/usr/local/bin/openclaw-vault-resolver",
passEnv: ["PATH", "VAULT_ADDR"],
},
},
defaults: {
env: "default",
file: "filemain",
exec: "vault",
},
},
}
Notes:
fileprovider supportsmode: "json"andmode: "singleValue"(idmust be"value"in singleValue mode).execprovider requires an absolutecommandpath and uses protocol payloads on stdin/stdout.- By default, symlink command paths are rejected. Set
allowSymlinkCommand: trueto allow symlink paths while validating the resolved target path. - If
trustedDirsis configured, the trusted-dir check applies to the resolved target path. execchild environment is minimal by default; pass required variables explicitly withpassEnv.- Secret refs are resolved at activation time into an in-memory snapshot, then request paths read the snapshot only.
- Active-surface filtering applies during activation: unresolved refs on enabled surfaces fail startup/reload, while inactive surfaces are skipped with diagnostics.
认证存储
{
auth: {
profiles: {
"anthropic:[email protected]": { provider: "anthropic", mode: "oauth", email: "[email protected]" },
"anthropic:work": { provider: "anthropic", mode: "api_key" },
},
order: {
anthropic: ["anthropic:[email protected]", "anthropic:work"],
},
},
}
- Per-agent profiles are stored at
<agentDir>/auth-profiles.json. auth-profiles.jsonsupports value-level refs (keyRefforapi_key,tokenReffortoken).- Static runtime credentials come from in-memory resolved snapshots; legacy static
auth.jsonentries are scrubbed when discovered. - Legacy OAuth imports from
~/.openclaw/credentials/oauth.json. - See OAuth.
- Secrets runtime behavior and
audit/configure/applytooling: Secrets Management.
日志
{
logging: {
level: "info",
file: "/tmp/openclaw/openclaw.log",
consoleLevel: "info",
consoleStyle: "pretty", // pretty | compact | json
redactSensitive: "tools", // off | tools
redactPatterns: ["\\bTOKEN\\b\\s*[=:]\\s*([\"']?)([^\\s\"']+)\\1"],
},
}
- Default log file:
/tmp/openclaw/openclaw-YYYY-MM-DD.log. - Set
logging.filefor a stable path. consoleLevelbumps todebugwhen--verbose.
CLI
{
cli: {
banner: {
taglineMode: "off", // random | default | off
},
},
}
cli.banner.taglineModecontrols banner tagline style:"random"(default): rotating funny/seasonal taglines."default": fixed neutral tagline (All your chats, one OpenClaw.)."off": no tagline text (banner title/version still shown).
- To hide the entire banner (not just taglines), set env
OPENCLAW_HIDE_BANNER=1.
向导
CLI 向导(onboard、configure、doctor)写入的元数据:
{
wizard: {
lastRunAt: "2026-01-01T00:00:00.000Z",
lastRunVersion: "2026.1.4",
lastRunCommit: "abc1234",
lastRunCommand: "configure",
lastRunMode: "local",
},
}
身份
{
agents: {
list: [
{
id: "main",
identity: {
name: "Samantha",
theme: "helpful sloth",
emoji: "🦥",
avatar: "avatars/samantha.png",
},
},
],
},
}
由 macOS 引导助手写入。派生默认值:
messages.ackReactionfromidentity.emoji(falls back to 👀)mentionPatternsfromidentity.name/identity.emojiavataraccepts: workspace-relative path,http(s)URL, ordata:URI
Bridge(旧版,已移除)
当前版本不再包含 TCP bridge。节点通过 Gateway WebSocket 连接。bridge.* 键已不属于配置 schema(移除前校验会失败;openclaw doctor --fix 可以清除未知键)。
旧版 bridge 配置(历史参考)
{
"bridge": {
"enabled": true,
"port": 18790,
"bind": "tailnet",
"tls": {
"enabled": true,
"autoGenerate": true
}
}
}
定时任务
{
cron: {
enabled: true,
maxConcurrentRuns: 2,
webhook: "https://example.invalid/legacy", // deprecated fallback for stored notify:true jobs
webhookToken: "replace-with-dedicated-token", // optional bearer token for outbound webhook auth
sessionRetention: "24h", // duration string or false
runLog: {
maxBytes: "2mb", // default 2_000_000 bytes
keepLines: 2000, // default 2000
},
},
}
sessionRetention: how long to keep completed isolated cron run sessions before pruning fromsessions.json. Also controls cleanup of archived deleted cron transcripts. Default:24h; setfalseto disable.runLog.maxBytes: max size per run log file (cron/runs/<jobId>.jsonl) before pruning. Default:2_000_000bytes.runLog.keepLines: newest lines retained when run-log pruning is triggered. Default:2000.webhookToken: bearer token used for cron webhook POST delivery (delivery.mode = "webhook"), if omitted no auth header is sent.webhook: deprecated legacy fallback webhook URL (http/https) used only for stored jobs that still havenotify: true.
See Cron Jobs.
媒体模型模板变量
在 tools.media.models[].args 中展开的模板占位符:
| Variable | Description |
|---|---|
{{Body}} | Full inbound message body |
{{RawBody}} | Raw body (no history/sender wrappers) |
{{BodyStripped}} | Body with group mentions stripped |
{{From}} | Sender identifier |
{{To}} | Destination identifier |
{{MessageSid}} | Channel message id |
{{SessionId}} | Current session UUID |
{{IsNewSession}} | "true" when new session created |
{{MediaUrl}} | Inbound media pseudo-URL |
{{MediaPath}} | Local media path |
{{MediaType}} | Media type (image/audio/document/…) |
{{Transcript}} | Audio transcript |
{{Prompt}} | Resolved media prompt for CLI entries |
{{MaxChars}} | Resolved max output chars for CLI entries |
{{ChatType}} | "direct" or "group" |
{{GroupSubject}} | Group subject (best effort) |
{{GroupMembers}} | Group members preview (best effort) |
{{SenderName}} | Sender display name (best effort) |
{{SenderE164}} | Sender phone number (best effort) |
{{Provider}} | Provider hint (whatsapp, telegram, discord, etc.) |
配置包含($include)
将配置拆分为多个文件:
// ~/.openclaw/openclaw.json
{
gateway: { port: 18789 },
agents: { $include: "./agents.json5" },
broadcast: {
$include: ["./clients/mueller.json5", "./clients/schmidt.json5"],
},
}
合并行为:
- 单个文件:替换包含它的对象。
- 文件数组:按顺序深度合并(后面的覆盖前面的)。
- 同级键:在 include 之后合并(覆盖 include 的值)。
- 嵌套 include:最多 10 层深度。
- 路径:相对于包含文件解析,但必须在顶层配置目录(
openclaw.json的dirname)内。绝对路径和../形式仅在仍解析到该边界内时允许。 - 错误:对缺失文件、解析错误和循环 include 给出清晰的错误信息。