From 2c6569a4882c8555c260e56e2d7a0caa5828b52e Mon Sep 17 00:00:00 2001
From: Seb Slight <19554889+sebslight@users.noreply.github.com>
Date: Wed, 11 Feb 2026 12:49:10 -0500
Subject: [PATCH] docs(channels): modernize slack docs page (#14205)
---
docs/channels/slack.md | 743 +++++++++++++++++------------------------
1 file changed, 311 insertions(+), 432 deletions(-)
diff --git a/docs/channels/slack.md b/docs/channels/slack.md
index d692431da..ebe588034 100644
--- a/docs/channels/slack.md
+++ b/docs/channels/slack.md
@@ -1,26 +1,47 @@
---
-summary: "Slack setup for socket or HTTP webhook mode"
-read_when: "Setting up Slack or debugging Slack socket/HTTP mode"
+summary: "Slack setup and runtime behavior (Socket Mode + HTTP Events API)"
+read_when:
+ - Setting up Slack or debugging Slack socket/HTTP mode
title: "Slack"
---
# Slack
-## Socket mode (default)
+Status: production-ready for DMs + channels via Slack app integrations. Default mode is Socket Mode; HTTP Events API mode is also supported.
-### Quick setup (beginner)
+
+
+ Slack DMs default to pairing mode.
+
+
+ Native command behavior and command catalog.
+
+
+ Cross-channel diagnostics and repair playbooks.
+
+
-1. Create a Slack app and enable **Socket Mode**.
-2. Create an **App Token** (`xapp-...`) and **Bot Token** (`xoxb-...`).
-3. Set tokens for OpenClaw and start the gateway.
+## Quick setup
-Minimal config:
+
+
+
+
+ In Slack app settings:
+
+ - enable **Socket Mode**
+ - create **App Token** (`xapp-...`) with `connections:write`
+ - install app and copy **Bot Token** (`xoxb-...`)
+
+
+
```json5
{
channels: {
slack: {
enabled: true,
+ mode: "socket",
appToken: "xapp-...",
botToken: "xoxb-...",
},
@@ -28,121 +49,50 @@ Minimal config:
}
```
-### Setup
+ Env fallback (default account only):
-1. Create a Slack app (From scratch) in [https://api.slack.com/apps](https://api.slack.com/apps).
-2. **Socket Mode** → toggle on. Then go to **Basic Information** → **App-Level Tokens** → **Generate Token and Scopes** with scope `connections:write`. Copy the **App Token** (`xapp-...`).
-3. **OAuth & Permissions** → add bot token scopes (use the manifest below). Click **Install to Workspace**. Copy the **Bot User OAuth Token** (`xoxb-...`).
-4. Optional: **OAuth & Permissions** → add **User Token Scopes** (see the read-only list below). Reinstall the app and copy the **User OAuth Token** (`xoxp-...`).
-5. **Event Subscriptions** → enable events and subscribe to:
- - `message.*` (includes edits/deletes/thread broadcasts)
- - `app_mention`
- - `reaction_added`, `reaction_removed`
- - `member_joined_channel`, `member_left_channel`
- - `channel_rename`
- - `pin_added`, `pin_removed`
-6. Invite the bot to channels you want it to read.
-7. Slash Commands → create `/openclaw` if you use `channels.slack.slashCommand`. If you enable native commands, add one slash command per built-in command (same names as `/help`). Native defaults to off for Slack unless you set `channels.slack.commands.native: true` (global `commands.native` is `"auto"` which leaves Slack off).
-8. App Home → enable the **Messages Tab** so users can DM the bot.
-
-Use the manifest below so scopes and events stay in sync.
-
-Multi-account support: use `channels.slack.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern.
-
-### OpenClaw config (Socket mode)
-
-Set tokens via env vars (recommended):
-
-- `SLACK_APP_TOKEN=xapp-...`
-- `SLACK_BOT_TOKEN=xoxb-...`
-
-Or via config:
-
-```json5
-{
- channels: {
- slack: {
- enabled: true,
- appToken: "xapp-...",
- botToken: "xoxb-...",
- },
- },
-}
+```bash
+SLACK_APP_TOKEN=xapp-...
+SLACK_BOT_TOKEN=xoxb-...
```
-### User token (optional)
+
-OpenClaw can use a Slack user token (`xoxp-...`) for read operations (history,
-pins, reactions, emoji, member info). By default this stays read-only: reads
-prefer the user token when present, and writes still use the bot token unless
-you explicitly opt in. Even with `userTokenReadOnly: false`, the bot token stays
-preferred for writes when it is available.
+
+ Subscribe bot events for:
-User tokens are configured in the config file (no env var support). For
-multi-account, set `channels.slack.accounts..userToken`.
+ - `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`
-Example with bot + app + user tokens:
+ Also enable App Home **Messages Tab** for DMs.
+
-```json5
-{
- channels: {
- slack: {
- enabled: true,
- appToken: "xapp-...",
- botToken: "xoxb-...",
- userToken: "xoxp-...",
- },
- },
-}
+
+
+```bash
+openclaw gateway
```
-Example with userTokenReadOnly explicitly set (allow user token writes):
+
+
-```json5
-{
- channels: {
- slack: {
- enabled: true,
- appToken: "xapp-...",
- botToken: "xoxb-...",
- userToken: "xoxp-...",
- userTokenReadOnly: false,
- },
- },
-}
-```
+
-#### Token usage
+
+
+
-- Read operations (history, reactions list, pins list, emoji list, member info,
- search) prefer the user token when configured, otherwise the bot token.
-- Write operations (send/edit/delete messages, add/remove reactions, pin/unpin,
- file uploads) use the bot token by default. If `userTokenReadOnly: false` and
- no bot token is available, OpenClaw falls back to the user token.
+ - set mode to HTTP (`channels.slack.mode="http"`)
+ - copy Slack **Signing Secret**
+ - set Event Subscriptions + Interactivity + Slash command Request URL to the same webhook path (default `/slack/events`)
-### History context
+
-- `channels.slack.historyLimit` (or `channels.slack.accounts.*.historyLimit`) controls how many recent channel/group messages are wrapped into the prompt.
-- Falls back to `messages.groupChat.historyLimit`. Set `0` to disable (default 50).
-
-## HTTP mode (Events API)
-
-Use HTTP webhook mode when your Gateway is reachable by Slack over HTTPS (typical for server deployments).
-HTTP mode uses the Events API + Interactivity + Slash Commands with a shared request URL.
-
-### Setup (HTTP mode)
-
-1. Create a Slack app and **disable Socket Mode** (optional if you only use HTTP).
-2. **Basic Information** → copy the **Signing Secret**.
-3. **OAuth & Permissions** → install the app and copy the **Bot User OAuth Token** (`xoxb-...`).
-4. **Event Subscriptions** → enable events and set the **Request URL** to your gateway webhook path (default `/slack/events`).
-5. **Interactivity & Shortcuts** → enable and set the same **Request URL**.
-6. **Slash Commands** → set the same **Request URL** for your command(s).
-
-Example request URL:
-`https://gateway-host/slack/events`
-
-### OpenClaw config (minimal)
+
```json5
{
@@ -158,13 +108,184 @@ Example request URL:
}
```
-Multi-account HTTP mode: set `channels.slack.accounts..mode = "http"` and provide a unique
-`webhookPath` per account so each Slack app can point to its own URL.
+
-### Manifest (optional)
+
+ Per-account HTTP mode is supported.
-Use this Slack app manifest to create the app quickly (adjust the name/command if you want). Include the
-user scopes if you plan to configure a user token.
+ Give each account a distinct `webhookPath` so registrations do not collide.
+
+
+
+
+
+
+## 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`).
+
+
+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.dm.policy` controls DM access:
+
+ - `pairing` (default)
+ - `allowlist`
+ - `open` (requires `dm.allowFrom` to include `"*"`)
+ - `disabled`
+
+ DM flags:
+
+ - `dm.enabled` (default true)
+ - `dm.allowFrom`
+ - `dm.groupEnabled` (group DMs default false)
+ - `dm.groupChannels` (optional MPIM allowlist)
+
+ 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) and `channels.defaults.groupPolicy` is unset, runtime falls back to `groupPolicy="open"` and logs a warning.
+
+ Name/ID resolution:
+
+ - channel allowlist entries and DM allowlist entries are resolved at startup when token access allows
+ - unresolved entries are kept as configured
+
+
+
+
+ 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.`):
+
+ - `requireMention`
+ - `users` (allowlist)
+ - `allowBots`
+ - `skills`
+ - `systemPrompt`
+ - `tools`, `toolsBySender`
+
+
+
+
+## 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).
+- If native commands are not enabled, you can run a single configured slash command via `channels.slack.slashCommand`.
+
+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`.
+
+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:]]`
+
+## 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:
+
+| 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.
+- `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.
+
+## Manifest and scope checklist
+
+
+
```json
{
@@ -196,14 +317,8 @@ user scopes if you plan to configure a user token.
"channels:history",
"channels:read",
"groups:history",
- "groups:read",
- "groups:write",
"im:history",
- "im:read",
- "im:write",
"mpim:history",
- "mpim:read",
- "mpim:write",
"users:read",
"app_mentions:read",
"reactions:read",
@@ -214,21 +329,6 @@ user scopes if you plan to configure a user token.
"commands",
"files:read",
"files:write"
- ],
- "user": [
- "channels:history",
- "channels:read",
- "groups:history",
- "groups:read",
- "im:history",
- "im:read",
- "mpim:history",
- "mpim:read",
- "users:read",
- "reactions:read",
- "pins:read",
- "emoji:read",
- "search:read"
]
}
},
@@ -254,321 +354,100 @@ user scopes if you plan to configure a user token.
}
```
-If you enable native commands, add one `slash_commands` entry per command you want to expose (matching the `/help` list). Override with `channels.slack.commands.native`.
+
-## Scopes (current vs optional)
+
+ If you configure `channels.slack.userToken`, typical read scopes are:
-Slack's Conversations API is type-scoped: you only need the scopes for the
-conversation types you actually touch (channels, groups, im, mpim). See
-[https://docs.slack.dev/apis/web-api/using-the-conversations-api/](https://docs.slack.dev/apis/web-api/using-the-conversations-api/) for the overview.
+ - `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)
-### Bot token scopes (required)
-
-- `chat:write` (send/update/delete messages via `chat.postMessage`)
- [https://docs.slack.dev/reference/methods/chat.postMessage](https://docs.slack.dev/reference/methods/chat.postMessage)
-- `im:write` (open DMs via `conversations.open` for user DMs)
- [https://docs.slack.dev/reference/methods/conversations.open](https://docs.slack.dev/reference/methods/conversations.open)
-- `channels:history`, `groups:history`, `im:history`, `mpim:history`
- [https://docs.slack.dev/reference/methods/conversations.history](https://docs.slack.dev/reference/methods/conversations.history)
-- `channels:read`, `groups:read`, `im:read`, `mpim:read`
- [https://docs.slack.dev/reference/methods/conversations.info](https://docs.slack.dev/reference/methods/conversations.info)
-- `users:read` (user lookup)
- [https://docs.slack.dev/reference/methods/users.info](https://docs.slack.dev/reference/methods/users.info)
-- `reactions:read`, `reactions:write` (`reactions.get` / `reactions.add`)
- [https://docs.slack.dev/reference/methods/reactions.get](https://docs.slack.dev/reference/methods/reactions.get)
- [https://docs.slack.dev/reference/methods/reactions.add](https://docs.slack.dev/reference/methods/reactions.add)
-- `pins:read`, `pins:write` (`pins.list` / `pins.add` / `pins.remove`)
- [https://docs.slack.dev/reference/scopes/pins.read](https://docs.slack.dev/reference/scopes/pins.read)
- [https://docs.slack.dev/reference/scopes/pins.write](https://docs.slack.dev/reference/scopes/pins.write)
-- `emoji:read` (`emoji.list`)
- [https://docs.slack.dev/reference/scopes/emoji.read](https://docs.slack.dev/reference/scopes/emoji.read)
-- `files:write` (uploads via `files.uploadV2`)
- [https://docs.slack.dev/messaging/working-with-files/#upload](https://docs.slack.dev/messaging/working-with-files/#upload)
-
-### User token scopes (optional, read-only by default)
-
-Add these under **User Token Scopes** if you configure `channels.slack.userToken`.
-
-- `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`
-
-### Not needed today (but likely future)
-
-- `mpim:write` (only if we add group-DM open/DM start via `conversations.open`)
-- `groups:write` (only if we add private-channel management: create/rename/invite/archive)
-- `chat:write.public` (only if we want to post to channels the bot isn't in)
- [https://docs.slack.dev/reference/scopes/chat.write.public](https://docs.slack.dev/reference/scopes/chat.write.public)
-- `users:read.email` (only if we need email fields from `users.info`)
- [https://docs.slack.dev/changelog/2017-04-narrowing-email-access](https://docs.slack.dev/changelog/2017-04-narrowing-email-access)
-- `files:read` (only if we start listing/reading file metadata)
-
-## Config
-
-Slack uses Socket Mode only (no HTTP webhook server). Provide both tokens:
-
-```json
-{
- "slack": {
- "enabled": true,
- "botToken": "xoxb-...",
- "appToken": "xapp-...",
- "groupPolicy": "allowlist",
- "dm": {
- "enabled": true,
- "policy": "pairing",
- "allowFrom": ["U123", "U456", "*"],
- "groupEnabled": false,
- "groupChannels": ["G123"],
- "replyToMode": "all"
- },
- "channels": {
- "C123": { "allow": true, "requireMention": true },
- "#general": {
- "allow": true,
- "requireMention": true,
- "users": ["U123"],
- "skills": ["search", "docs"],
- "systemPrompt": "Keep answers short."
- }
- },
- "reactionNotifications": "own",
- "reactionAllowlist": ["U123"],
- "replyToMode": "off",
- "actions": {
- "reactions": true,
- "messages": true,
- "pins": true,
- "memberInfo": true,
- "emojiList": true
- },
- "slashCommand": {
- "enabled": true,
- "name": "openclaw",
- "sessionPrefix": "slack:slash",
- "ephemeral": true
- },
- "textChunkLimit": 4000,
- "mediaMaxMb": 20
- }
-}
-```
-
-Tokens can also be supplied via env vars:
-
-- `SLACK_BOT_TOKEN`
-- `SLACK_APP_TOKEN`
-
-Ack reactions are controlled globally via `messages.ackReaction` +
-`messages.ackReactionScope`. Use `messages.removeAckAfterReply` to clear the
-ack reaction after the bot replies.
-
-## Limits
-
-- Outbound text is chunked to `channels.slack.textChunkLimit` (default 4000).
-- Optional newline chunking: set `channels.slack.chunkMode="newline"` to split on blank lines (paragraph boundaries) before length chunking.
-- Media uploads are capped by `channels.slack.mediaMaxMb` (default 20).
-
-## Reply threading
-
-By default, OpenClaw replies in the main channel. Use `channels.slack.replyToMode` to control automatic threading:
-
-| Mode | Behavior |
-| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `off` | **Default.** Reply in main channel. Only thread if the triggering message was already in a thread. |
-| `first` | First reply goes to thread (under the triggering message), subsequent replies go to main channel. Useful for keeping context visible while avoiding thread clutter. |
-| `all` | All replies go to thread. Keeps conversations contained but may reduce visibility. |
-
-The mode applies to both auto-replies and agent tool calls (`slack sendMessage`).
-
-### Per-chat-type threading
-
-You can configure different threading behavior per chat type by setting `channels.slack.replyToModeByChatType`:
-
-```json5
-{
- channels: {
- slack: {
- replyToMode: "off", // default for channels
- replyToModeByChatType: {
- direct: "all", // DMs always thread
- group: "first", // group DMs/MPIM thread first reply
- },
- },
- },
-}
-```
-
-Supported chat types:
-
-- `direct`: 1:1 DMs (Slack `im`)
-- `group`: group DMs / MPIMs (Slack `mpim`)
-- `channel`: standard channels (public/private)
-
-Precedence:
-
-1. `replyToModeByChatType.`
-2. `replyToMode`
-3. Provider default (`off`)
-
-Legacy `channels.slack.dm.replyToMode` is still accepted as a fallback for `direct` when no chat-type override is set.
-
-Examples:
-
-Thread DMs only:
-
-```json5
-{
- channels: {
- slack: {
- replyToMode: "off",
- replyToModeByChatType: { direct: "all" },
- },
- },
-}
-```
-
-Thread group DMs but keep channels in the root:
-
-```json5
-{
- channels: {
- slack: {
- replyToMode: "off",
- replyToModeByChatType: { group: "first" },
- },
- },
-}
-```
-
-Make channels thread, keep DMs in the root:
-
-```json5
-{
- channels: {
- slack: {
- replyToMode: "first",
- replyToModeByChatType: { direct: "off", group: "off" },
- },
- },
-}
-```
-
-### Manual threading tags
-
-For fine-grained control, use these tags in agent responses:
-
-- `[[reply_to_current]]` — reply to the triggering message (start/continue thread).
-- `[[reply_to:]]` — reply to a specific message id.
-
-## Sessions + routing
-
-- DMs share the `main` session (like WhatsApp/Telegram).
-- Channels map to `agent::slack:channel:` sessions.
-- Slash commands use `agent::slack:slash:` sessions (prefix configurable via `channels.slack.slashCommand.sessionPrefix`).
-- If Slack doesn’t provide `channel_type`, OpenClaw infers it from the channel ID prefix (`D`, `C`, `G`) and defaults to `channel` to keep session keys stable.
-- Native command registration uses `commands.native` (global default `"auto"` → Slack off) and can be overridden per-workspace with `channels.slack.commands.native`. Text commands require standalone `/...` messages and can be disabled with `commands.text: false`. Slack slash commands are managed in the Slack app and are not removed automatically. Use `commands.useAccessGroups: false` to bypass access-group checks for commands.
-- Full command list + config: [Slash commands](/tools/slash-commands)
-
-## DM security (pairing)
-
-- Default: `channels.slack.dm.policy="pairing"` — unknown DM senders get a pairing code (expires after 1 hour).
-- Approve via: `openclaw pairing approve slack `.
-- To allow anyone: set `channels.slack.dm.policy="open"` and `channels.slack.dm.allowFrom=["*"]`.
-- `channels.slack.dm.allowFrom` accepts user IDs, @handles, or emails (resolved at startup when tokens allow). The wizard accepts usernames and resolves them to ids during setup when tokens allow.
-
-## Group policy
-
-- `channels.slack.groupPolicy` controls channel handling (`open|disabled|allowlist`).
-- `allowlist` requires channels to be listed in `channels.slack.channels`.
-- If you only set `SLACK_BOT_TOKEN`/`SLACK_APP_TOKEN` and never create a `channels.slack` section,
- the runtime defaults `groupPolicy` to `open`. Add `channels.slack.groupPolicy`,
- `channels.defaults.groupPolicy`, or a channel allowlist to lock it down.
-- The configure wizard accepts `#channel` names and resolves them to IDs when possible
- (public + private); if multiple matches exist, it prefers the active channel.
-- On startup, OpenClaw resolves channel/user names in allowlists to IDs (when tokens allow)
- and logs the mapping; unresolved entries are kept as typed.
-- To allow **no channels**, set `channels.slack.groupPolicy: "disabled"` (or keep an empty allowlist).
-
-Channel options (`channels.slack.channels.` or `channels.slack.channels.`):
-
-- `allow`: allow/deny the channel when `groupPolicy="allowlist"`.
-- `requireMention`: mention gating for the channel.
-- `tools`: optional per-channel tool policy overrides (`allow`/`deny`/`alsoAllow`).
-- `toolsBySender`: optional per-sender tool policy overrides within the channel (keys are sender ids/@handles/emails; `"*"` wildcard supported).
-- `allowBots`: allow bot-authored messages in this channel (default: false).
-- `users`: optional per-channel user allowlist.
-- `skills`: skill filter (omit = all skills, empty = none).
-- `systemPrompt`: extra system prompt for the channel (combined with topic/purpose).
-- `enabled`: set `false` to disable the channel.
-
-## Delivery targets
-
-Use these with cron/CLI sends:
-
-- `user:` for DMs
-- `channel:` for channels
-
-## Tool actions
-
-Slack tool actions can be gated with `channels.slack.actions.*`:
-
-| 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 |
-
-## Security notes
-
-- Writes default to the bot token so state-changing actions stay scoped to the
- app's bot permissions and identity.
-- Setting `userTokenReadOnly: false` allows the user token to be used for write
- operations when a bot token is unavailable, which means actions run with the
- installing user's access. Treat the user token as highly privileged and keep
- action gates and allowlists tight.
-- If you enable user-token writes, make sure the user token includes the write
- scopes you expect (`chat:write`, `reactions:write`, `pins:write`,
- `files:write`) or those operations will fail.
+
+
## Troubleshooting
-Run this ladder first:
+
+
+ Check, in order:
+
+ - `groupPolicy`
+ - channel allowlist (`channels.slack.channels`)
+ - `requireMention`
+ - per-channel `users` allowlist
+
+ Useful commands:
```bash
-openclaw status
-openclaw gateway status
+openclaw channels status --probe
openclaw logs --follow
openclaw doctor
-openclaw channels status --probe
```
-Then confirm DM pairing state if needed:
+
+
+
+ Check:
+
+ - `channels.slack.dm.enabled`
+ - `channels.slack.dm.policy`
+ - pairing approvals / allowlist entries
```bash
openclaw pairing list slack
```
-Common failures:
+
-- Connected but no channel replies: channel blocked by `groupPolicy` or not in `channels.slack.channels` allowlist.
-- DMs ignored: sender not approved when `channels.slack.dm.policy="pairing"`.
-- API errors (`missing_scope`, `not_in_channel`, auth failures): bot/app tokens or Slack scopes are incomplete.
+
+ Validate bot + app tokens and Socket Mode enablement in Slack app settings.
+
-For triage flow: [/channels/troubleshooting](/channels/troubleshooting).
+
+ Validate:
-## Notes
+ - signing secret
+ - webhook path
+ - Slack Request URLs (Events + Interactivity + Slash Commands)
+ - unique `webhookPath` per HTTP account
-- Mention gating is controlled via `channels.slack.channels` (set `requireMention` to `true`); `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) also count as mentions.
-- Multi-agent override: set per-agent patterns on `agents.list[].groupChat.mentionPatterns`.
-- Reaction notifications follow `channels.slack.reactionNotifications` (use `reactionAllowlist` with mode `allowlist`).
-- Bot-authored messages are ignored by default; enable via `channels.slack.allowBots` or `channels.slack.channels..allowBots`.
-- Warning: If you allow replies to other bots (`channels.slack.allowBots=true` or `channels.slack.channels..allowBots=true`), prevent bot-to-bot reply loops with `requireMention`, `channels.slack.channels..users` allowlists, and/or clear guardrails in `AGENTS.md` and `SOUL.md`.
-- For the Slack tool, reaction removal semantics are in [/tools/reactions](/tools/reactions).
-- Attachments are downloaded to the media store when permitted and under the size limit.
+
+
+
+ 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.
+
+
+
+
+## Configuration reference pointers
+
+Primary reference:
+
+- [Configuration reference - Slack](/gateway/configuration-reference#slack)
+
+High-signal Slack fields:
+
+- mode/auth: `mode`, `botToken`, `appToken`, `signingSecret`, `webhookPath`, `accounts.*`
+- DM access: `dm.enabled`, `dm.policy`, `dm.allowFrom`, `dm.groupEnabled`, `dm.groupChannels`
+- channel access: `groupPolicy`, `channels.*`, `channels.*.users`, `channels.*.requireMention`
+- threading/history: `replyToMode`, `replyToModeByChatType`, `thread.*`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit`
+- delivery: `textChunkLimit`, `chunkMode`, `mediaMaxMb`
+- ops/features: `configWrites`, `commands.native`, `slashCommand.*`, `actions.*`, `userToken`, `userTokenReadOnly`
+
+## Related
+
+- [Pairing](/channels/pairing)
+- [Channel routing](/channels/channel-routing)
+- [Troubleshooting](/channels/troubleshooting)
+- [Configuration](/gateway/configuration)
+- [Slash commands](/tools/slash-commands)