Slack access control
DM policy, channel allowlists, mention gating, and action gates
Who may reach OpenClaw through Slack, and which Slack actions it may take.
Linked requester identity
Direct Socket Mode events and HTTP Request URLs that pass Slack signing-secret
verification carry verified native Slack user IDs, including the
team:<team-id>:user:<user-id> form. Relay events remain asserted because the
Gateway authenticates the relay peer rather than the Slack sender. Display names
never establish identity, and sender IDs derived from app-controlled message
metadata remain asserted.
For ordinary messages and app mentions from a verified Slack sender linked to an
active user profile, OpenClaw includes that profile's canonical ID and current
display name in host-generated, per-turn conversation info. A linked profile with operator.admin authority can ask
"Assign this session to me"; the agent uses that profile ID with the sessions
tool's assign_owner action for sessions visible to that administrator, including
sessions the agent spawned. The turn carries the linked administrator's existing
operator authority and checks the original link, role, and channel lifecycle before
each privileged action. Unlinking, removing administrator access, or restarting the
channel invalidates that turn; send a new request after access is restored.
The tool remains owner-only: linking an ordinary member identifies the requester without granting assignment access. Unlinked or asserted senders receive no requester profile or operator authority. Configured command owners without a linked administrator profile keep their existing command access. See Channel identity links.
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 |
Current Slack message actions include send, conversation-open, upload-file, download-file, read, edit, delete, pin, unpin, list-pins, member-info, and emoji-list. download-file accepts Slack file IDs shown in inbound file placeholders and returns image previews for images or local file metadata for other file types.
Interactive message actions retain their caller authority through target and permission lookups and recheck it before each Slack request. If that authority closes, remaining requests stop while an already accepted mutation keeps its result.
In a Slack conversation, delegated member-info reads only the current requester
on the same account; omitting userId selects that requester. emoji-list uses
the trusted current workspace. Both metadata actions work without a channel target
with the bundled plugin and verified official npm or ClawHub installations. Existing
action gates and Enterprise workspace requirements still apply.
Use emoji-list to discover workspace custom emoji and aliases:
{ "action": "emoji-list", "channel": "slack", "limit": 25 }Results are sorted by shortcode name. limit defaults to and cannot exceed 100:
{
"ok": true,
"emojis": [
{ "name": "celebrate", "identifier": "celebrate", "aliasOf": "party" },
{ "name": "party", "identifier": "party" }
]
}Use an entry's identifier directly as the react emoji; surrounding colons are optional. channels.slack.actions.emojiList controls discovery separately from the reactions gate, and the app needs the emoji:read scope.
Live policy changes
DM access, allowlists, group policy, mention rules, and existing channel policy fields apply to new messages, commands, and system events without reconnecting Slack. Root settings and account overrides keep their normal precedence. Each admitted turn keeps one resolved policy snapshot; a change does not rewrite a reply already in progress. Workspace name resolution runs once per new snapshot and never appends identities from an older policy. Presence targets learned under an older config snapshot retire before another background wake; fresh admitted activity creates new targets.
Transport credentials, account enablement, adding or removing accounts or channel entries, name-matching mode, presence settings, and native command/approval registration still restart the Slack monitor. The Gateway remains running.
Access control and routing
DM policy
channels.slack.dmPolicy controls DM access. channels.slack.allowFrom is the canonical DM allowlist.
pairing(default)allowlistopen(requireschannels.slack.allowFromto include"*")disabled
DM flags:
dm.enabled(default true)channels.slack.allowFromdm.allowFrom(legacy)dm.groupEnabled(group DMs default false)dm.groupChannels(optional MPIM allowlist)
dm.groupEnabled and dm.groupChannels only filter group DMs Slack already delivers to the app. They cannot make the app see a group DM it never joined. Convert the group DM to a private channel and invite the app, or have the app open a new MPDM with conversations.open. See Group DMs (MPDMs) and bots.
Multi-account precedence:
- Omitted account
dmPolicyandgroupPolicyinherit the channel root. Explicit account policies win; with neither scope set, defaults remainpairingandallowlistrespectively. userTokenReadOnlyalso inherits the channel setting when omitted; its default remainstrue.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.
Legacy channels.slack.dm.policy and channels.slack.dm.allowFrom still read for compatibility. openclaw doctor --fix migrates them to dmPolicy and allowFrom when it can do so without changing access.
Pairing in DMs uses openclaw pairing approve slack <code>.
Channel policy
channels.slack.groupPolicy controls channel handling:
openallowlistdisabled
Channel allowlist lives under channels.slack.channels and must use stable Slack channel IDs (for example C12345678) as config keys. Enterprise Grid org installs require team:<team-id>:channel:<channel-id> so policies cannot cross workspace boundaries.
When invited into an allowed channel, OpenClaw posts one short introduction grounded in the channel name, purpose or topic, and available recent messages. Set channels.slack.joinIntro: false to disable these introductions; channels.slack.accounts.<accountId>.joinIntro overrides the channel-wide setting. Introductions are enabled by default and do not require a mention, but they never bypass channel access policy or run in direct messages.
Without a channels.slack block, the Gateway does not auto-start Slack from SLACK_* environment variables. Once the block exists, those variables remain default-account credential fallbacks. Passing --ambient-channels opts into env-only auto-configuration; that path uses 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 and when a new policy snapshot is first used, when token access allows
- unresolved channel-name entries are kept as configured but ignored for routing by default
- inbound authorization and channel routing are ID-first by default; direct username/slug matching requires
channels.slack.dangerouslyAllowNameMatching: true
Name-based keys (#channel-name or channel-name) depend on successful Slack lookup to resolve a stable channel ID. Under groupPolicy: "allowlist", unresolved names are denied unless dangerouslyAllowNameMatching explicitly enables direct name matching.
Prefer the Slack channel ID as the key to avoid that lookup dependency. To find it: right-click the channel in Slack → Copy link — the ID (C...) appears at the end of the URL.
Recommended stable ID:
{
channels: {
slack: {
groupPolicy: "allowlist",
channels: {
C12345678: { enabled: true, requireMention: true },
},
},
},
}Name-based input (requires successful lookup with the default matching policy):
{
channels: {
slack: {
groupPolicy: "allowlist",
channels: {
"#eng-my-channel": { enabled: true, requireMention: true },
},
},
},
}Mentions and channel users
Channel messages are mention-gated by default.
Mention sources:
- explicit app mention (
<@botId>) - Slack user-group mention (
<!subteam^S...>) when the bot user is a member of that user group; requiresusergroups:read - mention regex patterns (
agents.entries.*.groupChat.mentionPatterns, fallbackmessages.groupChat.mentionPatterns) - replies to the bot's own Slack message (
implicitMentions.replyToBot) - follow-ups in threads where the bot participated (
implicitMentions.threadParticipation)
Per-channel controls (channels.slack.channels.<id>; names only via startup resolution or dangerouslyAllowNameMatching):
requireMentionrequireMentionInBotThreadsignoreOtherMentionsreplyToMode(off|first|all|batched; overrides account/chat-type reply mode for this channel)users(allowlist)allowBotsskillssystemPrompttools,toolsBySendertoolsBySenderkey format:channel:,id:,e164:,username:,name:, or"*"wildcard (runopenclaw doctor --fixto migrate retired unprefixed keys toid:entries)
Add the setting to an existing allowed channel entry:
{
channels: {
slack: {
channels: {
C12345678: {
enabled: true,
requireMention: true,
requireMentionInBotThreads: false,
},
},
},
},
}The setting resolves from the channel entry, then the "*" entry, then the account, then channels.slack.requireMentionInBotThreads. Omit it to preserve existing behavior, including implicitMentions.replyToBot and implicitMentions.threadParticipation. Slack's native parent author identifies the root; when that field is absent, OpenClaw uses accessible thread history. Unknown ownership retains the normal mention policy. Channel and sender access, bot-message restrictions, and ignoreOtherMentions still apply.
Invite the app to the channel and subscribe to message.channels for public channels or message.groups for private channels, with the matching history scope. Subscribing only to app_mention cannot deliver unmentioned follow-ups. Both setup manifests include these subscriptions; see Manifest and scope checklist. To verify, have the bot post a new top-level message, then reply in that message's thread without mentioning it. Replies to a human-created root keep their existing implicit-mention policy even if the bot participates later.
ignoreOtherMentions (default false) drops channel messages that mention another user or user group but not this bot. DMs and group DMs (MPIMs) are unaffected. The filter requires a resolved bot user ID from auth.test; if that identity is unavailable (for example a user-token-only identity), the gate fails open and messages pass through unchanged.
allowBots defaults to true. Bot-authored messages follow the same channel access and mention rules as other messages; messages from this bot are always ignored. Set allowBots: false to prevent other bots from triggering turns, or allowBots: "mentions" to require a mention even in rooms with requireMention: false. Room settings override account settings, which override channels.slack.allowBots. Existing explicit false values remain disabled after an update.
Bot-authored room messages also require either the sending bot to be explicitly listed in that room's users allowlist, or at least one explicit Slack owner ID from channels.slack.allowFrom to be a current room member. Wildcards and display-name owner entries do not satisfy owner presence. Owner presence uses Slack conversations.members; make sure the app has the matching read scope for the room type (channels:read for public channels, groups:read for private channels). If the member lookup fails, OpenClaw drops the bot-authored room message.
allowBots controls incoming turns, not context visibility. A human request can still include accessible bot-authored room history and thread context when allowBots: false; the configured contextVisibility and sender allowlist rules still apply.
Accepted bot-authored Slack messages use shared bot loop protection. Configure channels.defaults.botLoopProtection for the default budget, then override with channels.slack.botLoopProtection or channels.slack.channels.<id>.botLoopProtection when a workspace or channel needs a different limit.
Group DMs (MPDMs) and bots
Slack group DMs, also called multi-person direct messages or MPDMs, are not channels an app can join by being mentioned. Typing @YourBot in an existing group DM does not add the app or make the conversation visible to it.
- If the app was included when the group DM was created, Slack delivers
message.mpimevents and OpenClaw can respond when DM policy allows it. - If the app is mentioned in an existing group DM where it is not a member, the bot token cannot see the conversation at all. Slack Web API calls such as
conversations.info,conversations.members, andconversations.historyfail with method- and context-dependent access or not-found errors, the MPDM does not appear inconversations.list?types=mpim, and no event is delivered to OpenClaw. - OpenClaw wakes in MPDMs through delivered
message.mpimevents.app_mentionevents do not add the app to DM or MPDM contexts. dm.groupEnabledanddm.groupChannelsonly filter MPDMs Slack already delivers to the app. They cannot grant membership or visibility into a group DM the app was never part of. There is no OpenClaw config setting that makes the app see a group DM it never joined.
To bring the app into a group DM, use one of these Slack-supported paths:
- Convert the group DM to a private channel, then ask a current member to invite the app with
/invite @YourBot. An API-based invite must callconversations.invitewith a token whose actor is already a member and allowed to invite the app. - Ask the app to use the message tool's
conversation-openaction with the human recipients inuserIds. It callsconversations.openusing the configured write identity; bot accounts needmpim:write. Slack includes the calling account automatically.
{
"action": "conversation-open",
"channel": "slack",
"userIds": ["U12345678", "U23456789"]
}Provide 1-8 distinct member IDs, excluding the calling account. One recipient opens a 1:1 DM (requiring im:write); multiple recipients open or reuse a group DM with that exact audience. The result contains channelId and a routable target. Send the message with action: "send" and that exact target.
Use accountId to select a configured Slack account and teamId for an explicit workspace. The current workspace is inherited only for the same originating account; detached Enterprise operations require teamId. Opening is controlled by the messages action gate. It does not change DM/read policy, grant history access, or send a message by itself.