Messaging platforms
Slack
Status: production-ready for DMs + channels via Slack app integrations. Default mode is Socket Mode; HTTP Events API mode is also supported.
Quick setup
Token model
botToken+appTokenare required for Socket Mode.- HTTP mode requires
botToken+signingSecret. - Config tokens override env fallback.
SLACK_BOT_TOKEN/SLACK_APP_TOKENenv fallback applies only to the default account.userToken(xoxp-...) is config-only (no env fallback) and defaults to read-only behavior (userTokenReadOnly: true).- Optional: add
chat:write.customizeif you want outgoing messages to use the active agent identity (customusernameand icon).icon_emojiuses:emoji_name:syntax.
💡 For actions/directory reads, user token can be preferred when configured. For writes, bot token remains preferred; user-token writes are only allowed when
userTokenReadOnly: falseand bot token is unavailable.
Access control and routing
channels.slack.dmPolicy controls DM access (legacy: channels.slack.dm.policy):
pairing(default)allowlistopen(requireschannels.slack.allowFromto include"*"; legacy:channels.slack.dm.allowFrom)disabled
DM flags:
dm.enabled(default true)channels.slack.allowFrom(preferred)dm.allowFrom(legacy)dm.groupEnabled(group DMs default false)dm.groupChannels(optional MPIM allowlist)
Multi-account precedence:
channels.slack.accounts.default.allowFromapplies only to thedefaultaccount.- Named accounts inherit
channels.slack.allowFromwhen their ownallowFromis unset. - Named accounts do not inherit
channels.slack.accounts.default.allowFrom.
Pairing in DMs uses openclaw pairing approve slack .
channels.slack.groupPolicy controls channel handling:
openallowlistdisabled
Channel allowlist lives under channels.slack.channels.Runtime note: if channels.slack is completely missing (env-only setup), runtime falls back to groupPolicy="allowlist" and logs a warning (even if channels.defaults.groupPolicy is set).Name/ID resolution:
- channel allowlist entries and DM allowlist entries are resolved at startup when token access allows
- unresolved entries are kept as configured
- inbound authorization matching is ID-first by default; direct username/slug matching requires
channels.slack.dangerouslyAllowNameMatching: true
Channel messages are mention-gated by default.Mention sources:
- explicit app mention (
<@botId>) - mention regex patterns (
agents.list[].groupChat.mentionPatterns, fallbackmessages.groupChat.mentionPatterns) - implicit reply-to-bot thread behavior
Per-channel controls (channels.slack.channels.<id|name>):
requireMentionusers(allowlist)allowBotsskillssystemPrompttools,toolsBySendertoolsBySenderkey format:id:,e164:,username:,name:, or"*"wildcard (legacy unprefixed keys still map toid:only)
Commands and slash behavior
- Native command auto-mode is off for Slack (
commands.native: "auto"does not enable Slack native commands). - Enable native Slack command handlers with
channels.slack.commands.native: true(or globalcommands.native: true). - When native commands are enabled, register matching slash commands in Slack (
/names), with one exception:- register
/agentstatusfor the status command (Slack reserves/status)
- register
- If native commands are not enabled, you can run a single configured slash command via
channels.slack.slashCommand. - Native arg menus now adapt their rendering strategy:
- up to 5 options: button blocks
- 6-100 options: static select menu
- more than 100 options: external select with async option filtering when interactivity options handlers are available
- if encoded option values exceed Slack limits, the flow falls back to buttons
- For long option payloads, Slash command argument menus use a confirm dialog before dispatching a selected value.
Default slash command settings:
enabled: falsename: "openclaw"sessionPrefix: "slack:slash"ephemeral: true
Slash sessions use isolated keys:
agent::slack:slash:
and still route command execution against the target conversation session (CommandTargetSessionKey).
Threading, sessions, and reply tags
- DMs route as
direct; channels aschannel; MPIMs asgroup. - With default
session.dmScope=main, Slack DMs collapse to agent main session. - Channel sessions:
agent::slack:channel:. - Thread replies can create thread session suffixes (
:thread:) when applicable. channels.slack.thread.historyScopedefault isthread;thread.inheritParentdefault isfalse.channels.slack.thread.initialHistoryLimitcontrols how many existing thread messages are fetched when a new thread session starts (default20; set0to disable).
Reply threading controls:
channels.slack.replyToMode:off|first|all(defaultoff)channels.slack.replyToModeByChatType: perdirect|group|channel- legacy fallback for direct chats:
channels.slack.dm.replyToMode
Manual reply tags are supported:
[[reply_to_current]][[reply_to:]]
Note: replyToMode="off" disables all reply threading in Slack, including explicit [[reply_to_*]] tags. This differs from Telegram, where explicit tags are still honored in "off" mode. The difference reflects the platform threading models: Slack threads hide messages from the channel, while Telegram replies remain visible in the main chat flow.
Media, chunking, and delivery
Slack file attachments are downloaded from Slack-hosted private URLs (token-authenticated request flow) and written to the media store when fetch succeeds and size limits permit.Runtime inbound size cap defaults to 20MB unless overridden by channels.slack.mediaMaxMb.
- text chunks use
channels.slack.textChunkLimit(default 4000) channels.slack.chunkMode="newline"enables paragraph-first splitting- file sends use Slack upload APIs and can include thread replies (
thread_ts) - outbound media cap follows
channels.slack.mediaMaxMbwhen configured; otherwise channel sends use MIME-kind defaults from media pipeline
Preferred explicit targets:
user:for DMschannel:for channels
Slack DMs are opened via Slack conversation APIs when sending to user targets.
Actions and gates
Slack actions are controlled by channels.slack.actions.*. Available action groups in current Slack tooling:
| Group | Default |
|---|---|
| messages | enabled |
| reactions | enabled |
| pins | enabled |
| memberInfo | enabled |
| emojiList | enabled |
Events and operational behavior
- Message edits/deletes/thread broadcasts are mapped into system events.
- Reaction add/remove events are mapped into system events.
- Member join/leave, channel created/renamed, and pin add/remove events are mapped into system events.
- Assistant thread status updates (for “is typing…” indicators in threads) use
assistant.threads.setStatusand require bot scopeassistant:write. channel_id_changedcan migrate channel config keys whenconfigWritesis enabled.- Channel topic/purpose metadata is treated as untrusted context and can be injected into routing context.
- Block actions and modal interactions emit structured
Slack interaction: ...system events with rich payload fields:- block actions: selected values, labels, picker values, and
workflow_*metadata - modal
view_submissionandview_closedevents with routed channel metadata and form inputs
- block actions: selected values, labels, picker values, and
Ack reactions
ackReaction sends an acknowledgement emoji while OpenClaw is processing an inbound message. Resolution order:
channels.slack.accounts..ackReactionchannels.slack.ackReactionmessages.ackReaction- agent identity emoji fallback (
agents.list[].identity.emoji, else ”👀”)
Notes:
- Slack expects shortcodes (for example
"eyes"). - Use
""to disable the reaction for the Slack account or globally.
Typing reaction fallback
typingReaction adds a temporary reaction to the inbound Slack message while OpenClaw is processing a reply, then removes it when the run finishes. This is a useful fallback when Slack native assistant typing is unavailable, especially in DMs. Resolution order:
channels.slack.accounts..typingReactionchannels.slack.typingReaction
Notes:
- Slack expects shortcodes (for example
"hourglass_flowing_sand"). - The reaction is best-effort and cleanup is attempted automatically after the reply or failure path completes.
Manifest and scope checklist
{
"display_information": {
"name": "OpenClaw",
"description": "Slack connector for OpenClaw"
},
"features": {
"bot_user": {
"display_name": "OpenClaw",
"always_online": false
},
"app_home": {
"messages_tab_enabled": true,
"messages_tab_read_only_enabled": false
},
"slash_commands": [
{
"command": "/openclaw",
"description": "Send a message to OpenClaw",
"should_escape": false
}
]
},
"oauth_config": {
"scopes": {
"bot": [
"chat:write",
"channels:history",
"channels:read",
"groups:history",
"im:history",
"im:read",
"im:write",
"mpim:history",
"mpim:read",
"mpim:write",
"users:read",
"app_mentions:read",
"assistant:write",
"reactions:read",
"reactions:write",
"pins:read",
"pins:write",
"emoji:read",
"commands",
"files:read",
"files:write"
]
}
},
"settings": {
"socket_mode_enabled": true,
"event_subscriptions": {
"bot_events": [
"app_mention",
"message.channels",
"message.groups",
"message.im",
"message.mpim",
"reaction_added",
"reaction_removed",
"member_joined_channel",
"member_left_channel",
"channel_rename",
"pin_added",
"pin_removed"
]
}
}
}
If you configure channels.slack.userToken, typical read scopes are:
channels:history,groups:history,im:history,mpim:historychannels:read,groups:read,im:read,mpim:readusers:readreactions:readpins:reademoji:readsearch:read(if you depend on Slack search reads)
Troubleshooting
Check, in order:
groupPolicy- channel allowlist (
channels.slack.channels) requireMention- per-channel
usersallowlist
Useful commands:
openclaw channels status --probe
openclaw logs --follow
openclaw doctor
Check:
channels.slack.dm.enabledchannels.slack.dmPolicy(or legacychannels.slack.dm.policy)- pairing approvals / allowlist entries
openclaw pairing list slack
Validate bot + app tokens and Socket Mode enablement in Slack app settings.
Validate:
- signing secret
- webhook path
- Slack Request URLs (Events + Interactivity + Slash Commands)
- unique
webhookPathper HTTP account
Verify whether you intended:
- native command mode (
channels.slack.commands.native: true) with matching slash commands registered in Slack - or single slash command mode (
channels.slack.slashCommand.enabled: true)
Also check commands.useAccessGroups and channel/user allowlists.
Text streaming
OpenClaw supports Slack native text streaming via the Agents and AI Apps API. channels.slack.streaming controls live preview behavior:
off: disable live preview streaming.partial(default): replace preview text with the latest partial output.block: append chunked preview updates.progress: show progress status text while generating, then send final text.
channels.slack.nativeStreaming controls Slack’s native streaming API (chat.startStream / chat.appendStream / chat.stopStream) when streaming is partial (default: true). Disable native Slack streaming (keep draft preview behavior):
channels:
slack:
streaming: partial
nativeStreaming: false
Legacy keys:
channels.slack.streamMode(replace | status_final | append) is auto-migrated tochannels.slack.streaming.- boolean
channels.slack.streamingis auto-migrated tochannels.slack.nativeStreaming.
Requirements
- Enable Agents and AI Apps in your Slack app settings.
- Ensure the app has the
assistant:writescope. - A reply thread must be available for that message. Thread selection still follows
replyToMode.
Behavior
- First text chunk starts a stream (
chat.startStream). - Later text chunks append to the same stream (
chat.appendStream). - End of reply finalizes stream (
chat.stopStream). - Media and non-text payloads fall back to normal delivery.
- If streaming fails mid-reply, OpenClaw falls back to normal delivery for remaining payloads.
Configuration reference pointers
Primary reference:
- Configuration reference - Slack High-signal Slack fields:
- mode/auth:
mode,botToken,appToken,signingSecret,webhookPath,accounts.* - DM access:
dm.enabled,dmPolicy,allowFrom(legacy:dm.policy,dm.allowFrom),dm.groupEnabled,dm.groupChannels - compatibility toggle:
dangerouslyAllowNameMatching(break-glass; keep off unless needed) - channel access:
groupPolicy,channels.*,channels.*.users,channels.*.requireMention - threading/history:
replyToMode,replyToModeByChatType,thread.*,historyLimit,dmHistoryLimit,dms.*.historyLimit - delivery:
textChunkLimit,chunkMode,mediaMaxMb,streaming,nativeStreaming - ops/features:
configWrites,commands.native,slashCommand.*,actions.*,userToken,userTokenReadOnly
- mode/auth: