36 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| Channel configuration: access control, pairing, per-channel keys across Slack, Discord, Telegram, WhatsApp, Matrix, iMessage, and more |
|
Configuration — channels |
Per-channel configuration keys under channels.*. Covers DM and group access,
multi-account setups, mention gating, and per-channel keys for Slack, Discord,
Telegram, WhatsApp, Matrix, iMessage, and the other bundled channel plugins.
For agents, tools, gateway runtime, and other top-level keys, see Configuration reference.
Channels
Each channel starts automatically when its config section exists (unless enabled: false).
DM and group access
All channels support DM policies and group policies:
| DM policy | Behavior |
|---|---|
pairing (default) |
Unknown senders get a one-time pairing code; owner must approve |
allowlist |
Only senders in allowFrom (or paired allow store) |
open |
Allow all inbound DMs (requires allowFrom: ["*"]) |
disabled |
Ignore all inbound DMs |
| Group policy | Behavior |
|---|---|
allowlist (default) |
Only groups matching the configured allowlist |
open |
Bypass group allowlists (mention-gating still applies) |
disabled |
Block all group/room messages |
Channel model overrides
Use channels.modelByChannel to pin specific channel IDs to a model. Values accept provider/model or configured model aliases. The channel mapping applies when a session does not already have a model override (for example, set via /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",
},
},
},
}
Channel defaults and heartbeat
Use channels.defaults for shared group-policy and heartbeat behavior across providers:
{
channels: {
defaults: {
groupPolicy: "allowlist", // open | allowlist | disabled
contextVisibility: "all", // all | allowlist | allowlist_quote
heartbeat: {
showOk: false,
showAlerts: true,
useIndicator: true,
},
},
},
}
channels.defaults.groupPolicy: fallback group policy when a provider-levelgroupPolicyis unset.channels.defaults.contextVisibility: default supplemental context visibility mode for all channels. Values:all(default, include all quoted/thread/history context),allowlist(only include context from allowlisted senders),allowlist_quote(same as allowlist but keep explicit quote/reply context). Per-channel override:channels.<channel>.contextVisibility.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 runs through the gateway's web channel (Baileys Web). It starts automatically when a linked session exists.
{
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,
},
},
}
{
channels: {
whatsapp: {
accounts: {
default: {},
personal: {},
biz: {
// authDir: "~/.openclaw/credentials/whatsapp/biz",
},
},
},
},
}
- Outbound commands default to account
defaultif present; otherwise the first configured account id (sorted). - Optional
channels.whatsapp.defaultAccountoverrides that fallback default account selection when it matches a configured account id. - Legacy single-account Baileys auth dir is migrated by
openclaw doctorintowhatsapp/default. - Per-account overrides:
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 | batched
linkPreview: true,
streaming: "partial", // off | partial | block | progress (default: off; opt in explicitly to avoid preview-edit rate limits)
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: 100,
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 | batched
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" },
},
},
execApprovals: {
enabled: "auto", // true | false | "auto"
approvers: ["987654321098765432"],
agentFilter: ["default"],
sessionFilter: ["discord:"],
target: "dm", // dm | channel | both
cleanupAfterResolve: false,
},
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 + LLM + TTS overrides.channels.discord.voice.modeloptionally overrides the LLM model used for Discord voice channel responses.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).channels.discord.execApprovals: Discord-native exec approval delivery and approver authorization.enabled:true,false, or"auto"(default). In auto mode, exec approvals activate when approvers can be resolved fromapproversorcommands.ownerAllowFrom.approvers: Discord user IDs allowed to approve exec requests. Falls back tocommands.ownerAllowFromwhen omitted.agentFilter: optional agent ID allowlist. Omit to forward approvals for all agents.sessionFilter: optional session key patterns (substring or regex).target: where to send approval prompts."dm"(default) sends to approver DMs,"channel"sends to the originating channel,"both"sends to both. When target includes"channel", buttons are only usable by resolved approvers.cleanupAfterResolve: whentrue, deletes approval DMs after approval, denial, or timeout.
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 | batched
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: {
mode: "partial", // off | partial | block | progress
nativeTransport: true, // use Slack native streaming API when mode=partial
},
mediaMaxMb: 20,
execApprovals: {
enabled: "auto", // true | false | "auto"
approvers: ["U123"],
agentFilter: ["default"],
sessionFilter: ["slack:"],
target: "dm", // dm | channel | both
},
},
},
}
- Socket mode requires both
botTokenandappToken(SLACK_BOT_TOKEN+SLACK_APP_TOKENfor default account env fallback). - HTTP mode requires
botTokenplussigningSecret(at root or per-account). botToken,appToken,signingSecret, anduserTokenaccept plaintext strings or SecretRef objects.- Slack account snapshots expose per-credential source/status fields such as
botTokenSource,botTokenStatus,appTokenStatus, and, in HTTP mode,signingSecretStatus.configured_unavailablemeans the account is configured through SecretRef but the current command/runtime path could not resolve the secret value. configWrites: falseblocks Slack-initiated config writes.- Optional
channels.slack.defaultAccountoverrides default account selection when it matches a configured account id. channels.slack.streaming.modeis the canonical Slack stream mode key.channels.slack.streaming.nativeTransportcontrols Slack's native streaming transport. LegacystreamMode, booleanstreaming, andnativeStreamingvalues 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.
- Slack native streaming plus the Slack assistant-style "is typing..." thread status require a reply thread target. Top-level DMs stay off-thread by default, so they use
typingReactionor normal delivery instead of the thread-style preview. 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".channels.slack.execApprovals: Slack-native exec approval delivery and approver authorization. Same schema as Discord:enabled(true/false/"auto"),approvers(Slack user IDs),agentFilter,sessionFilter, andtarget("dm","channel", or"both").
| 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: [">", "!"],
groups: {
"*": { requireMention: true },
"team-channel-id": { requireMention: false },
},
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.- Native slash callbacks are authenticated with the per-command tokens returned
by Mattermost during slash command registration. If registration fails or no
commands are activated, OpenClaw rejects callbacks with
Unauthorized: invalid command token. - 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.channels.mattermost.groups.<channelId>.requireMention: per-channel mention-gating override ("*"for default).- 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. - Top-level
bindings[]entries withtype: "acp"can bind BlueBubbles conversations to persistent ACP sessions. Use a BlueBubbles handle or target string (chat_id:*,chat_guid:*,chat_identifier:*) inmatch.peer.id. Shared field semantics: ACP Agents. - 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", "user@example.com", "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. -
Top-level
bindings[]entries withtype: "acp"can bind iMessage conversations to persistent ACP sessions. Use a normalized handle or explicit chat target (chat_id:*,chat_guid:*,chat_identifier:*) inmatch.peer.id. Shared field semantics: ACP Agents.
#!/usr/bin/env bash
exec ssh -T gateway-host imsg "$@"
Matrix
Matrix is plugin-backed and configured under channels.matrix.
{
channels: {
matrix: {
enabled: true,
homeserver: "https://matrix.example.org",
accessToken: "syt_bot_xxx",
proxy: "http://127.0.0.1:7890",
encryption: true,
initialSyncLimit: 20,
defaultAccount: "ops",
accounts: {
ops: {
name: "Ops",
userId: "@ops:example.org",
accessToken: "syt_ops_xxx",
},
alerts: {
userId: "@alerts:example.org",
password: "secret",
proxy: "http://127.0.0.1:7891",
},
},
},
},
}
- Token auth uses
accessToken; password auth usesuserId+password. channels.matrix.proxyroutes Matrix HTTP traffic through an explicit HTTP(S) proxy. Named accounts can override it withchannels.matrix.accounts.<id>.proxy.channels.matrix.network.dangerouslyAllowPrivateNetworkallows private/internal homeservers.proxyand this network opt-in are independent controls.channels.matrix.defaultAccountselects the preferred account in multi-account setups.channels.matrix.autoJoindefaults tooff, so invited rooms and fresh DM-style invites are ignored until you setautoJoin: "allowlist"withautoJoinAllowlistorautoJoin: "always".channels.matrix.execApprovals: Matrix-native exec approval delivery and approver authorization.enabled:true,false, or"auto"(default). In auto mode, exec approvals activate when approvers can be resolved fromapproversorcommands.ownerAllowFrom.approvers: Matrix user IDs (e.g.@owner:example.org) allowed to approve exec requests.agentFilter: optional agent ID allowlist. Omit to forward approvals for all agents.sessionFilter: optional session key patterns (substring or regex).target: where to send approval prompts."dm"(default),"channel"(originating room), or"both".- Per-account overrides:
channels.matrix.accounts.<id>.execApprovals.
channels.matrix.dm.sessionScopecontrols how Matrix DMs group into sessions:per-user(default) shares by routed peer, whileper-roomisolates each DM room.- Matrix status probes and live directory lookups use the same proxy policy as runtime traffic.
- Full Matrix configuration, targeting rules, and setup examples are documented in Matrix.
Microsoft Teams
Microsoft Teams is plugin-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 plugin-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: "bot@example.com",
},
},
},
}
- 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 promotes account-scoped top-level single-account values into the channel account map first so the original account keeps working. Most channels move them intochannels.<channel>.accounts.default; Matrix can preserve an existing matching named/default target instead. - 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 into the promoted account chosen for that channel. Most channels useaccounts.default; Matrix can preserve an existing matching named/default target instead.
Other plugin channels
Many plugin 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 safe 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: Safe regex patterns in
agents.list[].groupChat.mentionPatterns. Invalid patterns and unsafe nested repetition are ignored. - 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
nativeSkills: "auto", // register native skill commands when supported
text: true, // parse /commands in chat messages
bash: false, // allow ! (alias: /bash)
bashForegroundMs: 2000,
config: false, // allow /config
mcp: false, // allow /mcp
plugins: false, // allow /plugins
debug: false, // allow /debug
restart: true, // allow /restart + gateway restart tool
ownerAllowFrom: ["discord:123456789012345678"],
ownerDisplay: "raw", // raw | hash
ownerDisplaySecret: "${OWNER_ID_HASH_SECRET}",
allowFrom: {
"*": ["user1"],
discord: ["user:123"],
},
useAccessGroups: true,
},
}
- This block configures command surfaces. For the current built-in + bundled command catalog, see Slash Commands.
- This page is a config-key reference, not the full command catalog. Channel/plugin-owned commands such as QQ Bot
/bot-ping/bot-help/bot-logs, LINE/card, device-pair/pair, memory/dreaming, phone-control/phone, and Talk/voiceare documented in their channel/plugin pages plus Slash Commands. - Text commands must be standalone messages with leading
/. native: "auto"turns on native commands for Discord/Telegram, leaves Slack off.nativeSkills: "auto"turns on native skill commands for Discord/Telegram, leaves Slack off.- Override per channel:
channels.discord.commands.native(bool or"auto").falseclears previously registered commands. - Override native skill registration per channel with
channels.<provider>.commands.nativeSkills. 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.mcp: trueenables/mcpfor OpenClaw-managed MCP server config undermcp.servers.plugins: trueenables/pluginsfor plugin discovery, install, and enable/disable controls.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>...). restart: falsedisables/restartand gateway restart tool actions. Default:true.ownerAllowFromis the explicit owner allowlist for owner-only commands/tools. It is separate fromallowFrom.ownerDisplay: "hash"hashes owner ids in the system prompt. SetownerDisplaySecretto control hashing.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.- Command docs map:
Related
- Configuration reference — top-level keys
- Configuration — agents
- Channels overview