Skip to main content

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 + appToken are required for Socket Mode.
  • HTTP mode requires botToken + signingSecret.
  • Config tokens override env fallback.
  • SLACK_BOT_TOKEN / SLACK_APP_TOKEN env 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.customize if you want outgoing messages to use the active agent identity (custom username and icon). icon_emoji uses :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: false and bot token is unavailable.

Access control and routing

channels.slack.dmPolicy controls DM access (legacy: channels.slack.dm.policy):

  • pairing (default)
  • allowlist
  • open (requires channels.slack.allowFrom to 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.allowFrom applies only to the default account.
  • Named accounts inherit channels.slack.allowFrom when their own allowFrom is 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:

  • open
  • allowlist
  • disabled

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, fallback messages.groupChat.mentionPatterns)
  • implicit reply-to-bot thread behavior

Per-channel controls (channels.slack.channels.<id|name>):

  • requireMention
  • users (allowlist)
  • allowBots
  • skills
  • systemPrompt
  • tools, toolsBySender
  • toolsBySender key format: id:, e164:, username:, name:, or "*" wildcard (legacy unprefixed keys still map to id: 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 global commands.native: true).
  • When native commands are enabled, register matching slash commands in Slack (/ names), with one exception:
    • register /agentstatus for the status command (Slack reserves /status)
  • 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: false
  • name: "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 as channel; MPIMs as group.
  • 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.historyScope default is thread; thread.inheritParent default is false.
  • channels.slack.thread.initialHistoryLimit controls how many existing thread messages are fetched when a new thread session starts (default 20; set 0 to disable).

Reply threading controls:

  • channels.slack.replyToMode: off|first|all (default off)
  • channels.slack.replyToModeByChatType: per direct|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.mediaMaxMb when configured; otherwise channel sends use MIME-kind defaults from media pipeline

Preferred explicit targets:

  • user: for DMs
  • channel: 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:

GroupDefault
messagesenabled
reactionsenabled
pinsenabled
memberInfoenabled
emojiListenabled

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.setStatus and require bot scope assistant:write.
  • channel_id_changed can migrate channel config keys when configWrites is 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_submission and view_closed events with routed channel metadata and form inputs

Ack reactions

ackReaction sends an acknowledgement emoji while OpenClaw is processing an inbound message. Resolution order:

  • channels.slack.accounts..ackReaction
  • channels.slack.ackReaction
  • messages.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..typingReaction
  • channels.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:history
  • channels:read, groups:read, im:read, mpim:read
  • users:read
  • reactions:read
  • pins:read
  • emoji:read
  • search:read (if you depend on Slack search reads)

Troubleshooting

Check, in order:

  • groupPolicy
  • channel allowlist (channels.slack.channels)
  • requireMention
  • per-channel users allowlist

Useful commands:

openclaw channels status --probe
openclaw logs --follow
openclaw doctor

Check:

  • channels.slack.dm.enabled
  • channels.slack.dmPolicy (or legacy channels.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 webhookPath per 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 to channels.slack.streaming.
  • boolean channels.slack.streaming is auto-migrated to channels.slack.nativeStreaming.

Requirements

  1. Enable Agents and AI Apps in your Slack app settings.
  2. Ensure the app has the assistant:write scope.
  3. 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

Synology ChatTelegram