--- summary: "Discord bot support status, capabilities, and configuration" read_when: - Working on Discord channel features title: "Discord" --- # Discord (Bot API) Status: ready for DMs and guild channels via the official Discord gateway. Discord DMs default to pairing mode. Native command behavior and command catalog. Cross-channel diagnostics and repair flow. ## Quick setup Create an application in the Discord Developer Portal, add a bot, then enable: - **Message Content Intent** - **Server Members Intent** (recommended for name-to-ID lookups and allowlist matching) ```json5 { channels: { discord: { enabled: true, token: "YOUR_BOT_TOKEN", }, }, } ``` Env fallback for the default account: ```bash DISCORD_BOT_TOKEN=... ``` Invite the bot to your server with message permissions. ```bash openclaw gateway ``` ```bash openclaw pairing list discord openclaw pairing approve discord ``` Pairing codes expire after 1 hour. Token resolution is account-aware. Config token values win over env fallback. `DISCORD_BOT_TOKEN` is only used for the default account. ## Runtime model - Gateway owns the Discord connection. - Reply routing is deterministic: Discord inbound replies back to Discord. - By default (`session.dmScope=main`), direct chats share the agent main session (`agent:main:main`). - Guild channels are isolated session keys (`agent::discord:channel:`). - Group DMs are ignored by default (`channels.discord.dm.groupEnabled=false`). - Native slash commands run in isolated command sessions (`agent::discord:slash:`), while still carrying `CommandTargetSessionKey` to the routed conversation session. ## Access control and routing `channels.discord.dm.policy` controls DM access: - `pairing` (default) - `allowlist` - `open` (requires `channels.discord.dm.allowFrom` to include `"*"`) - `disabled` If DM policy is not open, unknown users are blocked (or prompted for pairing in `pairing` mode). DM target format for delivery: - `user:` - `<@id>` mention Bare numeric IDs are ambiguous and rejected unless an explicit user/channel target kind is provided. Guild handling is controlled by `channels.discord.groupPolicy`: - `open` - `allowlist` - `disabled` Secure baseline when `channels.discord` exists is `allowlist`. `allowlist` behavior: - guild must match `channels.discord.guilds` (`id` preferred, slug accepted) - if a guild has `channels` configured, non-listed channels are denied - if a guild has no `channels` block, all channels in that allowlisted guild are allowed Example: ```json5 { channels: { discord: { groupPolicy: "allowlist", guilds: { "123456789012345678": { requireMention: true, users: ["987654321098765432"], channels: { general: { allow: true }, help: { allow: true, requireMention: true }, }, }, }, }, }, } ``` If you only set `DISCORD_BOT_TOKEN` and do not create a `channels.discord` block, runtime fallback is `groupPolicy="open"` (with a warning in logs). Guild messages are mention-gated by default. Mention detection includes: - explicit bot mention - configured mention patterns (`agents.list[].groupChat.mentionPatterns`, fallback `messages.groupChat.mentionPatterns`) - implicit reply-to-bot behavior in supported cases `requireMention` is configured per guild/channel (`channels.discord.guilds...`). Group DMs: - default: ignored (`dm.groupEnabled=false`) - optional allowlist via `dm.groupChannels` (channel IDs or slugs) ## Developer Portal setup 1. Discord Developer Portal -> **Applications** -> **New Application** 2. **Bot** -> **Add Bot** 3. Copy bot token In **Bot -> Privileged Gateway Intents**, enable: - Message Content Intent - Server Members Intent (recommended) Presence intent is optional and only required if you want to receive presence updates. Setting bot presence (`setPresence`) does not require enabling presence updates for members. OAuth URL generator: - scopes: `bot`, `applications.commands` Typical baseline permissions: - View Channels - Send Messages - Read Message History - Embed Links - Attach Files - Add Reactions (optional) Avoid `Administrator` unless explicitly needed. Enable Discord Developer Mode, then copy: - server ID - channel ID - user ID Prefer numeric IDs in OpenClaw config for reliable audits and probes. ## Native commands and command auth - `commands.native` defaults to `"auto"` and is enabled for Discord. - Per-channel override: `channels.discord.commands.native`. - `commands.native=false` explicitly clears previously registered Discord native commands. - Native command auth uses the same Discord allowlists/policies as normal message handling. - Commands may still be visible in Discord UI for users who are not authorized; execution still enforces OpenClaw auth and returns "not authorized". See [Slash commands](/tools/slash-commands) for command catalog and behavior. ## Feature details Discord supports reply tags in agent output: - `[[reply_to_current]]` - `[[reply_to:]]` Controlled by `channels.discord.replyToMode`: - `off` (default) - `first` - `all` Message IDs are surfaced in context/history so agents can target specific messages. Guild history context: - `channels.discord.historyLimit` default `20` - fallback: `messages.groupChat.historyLimit` - `0` disables DM history controls: - `channels.discord.dmHistoryLimit` - `channels.discord.dms[""].historyLimit` Thread behavior: - Discord threads are routed as channel sessions - parent thread metadata can be used for parent-session linkage - thread config inherits parent channel config unless a thread-specific entry exists Channel topics are injected as **untrusted** context (not as system prompt). Per-guild reaction notification mode: - `off` - `own` (default) - `all` - `allowlist` (uses `guilds..users`) Reaction events are turned into system events and attached to the routed Discord session. Channel-initiated config writes are enabled by default. This affects `/config set|unset` flows (when command features are enabled). Disable: ```json5 { channels: { discord: { configWrites: false, }, }, } ``` Enable PluralKit resolution to map proxied messages to system member identity: ```json5 { channels: { discord: { pluralkit: { enabled: true, token: "pk_live_...", // optional; needed for private systems }, }, }, } ``` Notes: - allowlists can use `pk:` - member display names are matched by name/slug - lookups use original message ID and are time-window constrained - if lookup fails, proxied messages are treated as bot messages and dropped unless `allowBots=true` Discord supports button-based exec approvals in DMs. Config path: - `channels.discord.execApprovals.enabled` - `channels.discord.execApprovals.approvers` - `agentFilter`, `sessionFilter`, `cleanupAfterResolve` If approvals fail with unknown approval IDs, verify approver list and feature enablement. Related docs: [Exec approvals](/tools/exec-approvals) ## Tools and action gates Discord message actions include messaging, channel admin, moderation, presence, and metadata actions. Core examples: - messaging: `sendMessage`, `readMessages`, `editMessage`, `deleteMessage`, `threadReply` - reactions: `react`, `reactions`, `emojiList` - moderation: `timeout`, `kick`, `ban` - presence: `setPresence` Action gates live under `channels.discord.actions.*`. Default gate behavior: | Action group | Default | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | | reactions, messages, threads, pins, polls, search, memberInfo, roleInfo, channelInfo, channels, voiceStatus, events, stickers, emojiUploads, stickerUploads, permissions | enabled | | roles | disabled | | moderation | disabled | | presence | disabled | ## Troubleshooting - enable Message Content Intent - enable Server Members Intent when you depend on user/member resolution - restart gateway after changing intents - verify `groupPolicy` - verify guild allowlist under `channels.discord.guilds` - if guild `channels` map exists, only listed channels are allowed - verify `requireMention` behavior and mention patterns Useful checks: ```bash openclaw doctor openclaw channels status --probe openclaw logs --follow ``` Common causes: - `groupPolicy="allowlist"` without matching guild/channel allowlist - `requireMention` configured in the wrong place (must be under `channels.discord.guilds` or channel entry) - sender blocked by guild/channel `users` allowlist `channels status --probe` permission checks only work for numeric channel IDs. If you use slug keys, runtime matching can still work, but probe cannot fully verify permissions. - DM disabled: `channels.discord.dm.enabled=false` - DM policy disabled: `channels.discord.dm.policy="disabled"` - awaiting pairing approval in `pairing` mode By default bot-authored messages are ignored. If you set `channels.discord.allowBots=true`, use strict mention and allowlist rules to avoid loop behavior. ## Configuration reference pointers Primary reference: - [Configuration reference - Discord](/gateway/configuration-reference#discord) High-signal Discord fields: - startup/auth: `enabled`, `token`, `accounts.*`, `allowBots` - policy: `groupPolicy`, `dm.*`, `guilds.*`, `guilds.*.channels.*` - command: `commands.native`, `commands.useAccessGroups`, `configWrites` - reply/history: `replyToMode`, `historyLimit`, `dmHistoryLimit`, `dms.*.historyLimit` - delivery: `textChunkLimit`, `chunkMode`, `maxLinesPerMessage` - media/retry: `mediaMaxMb`, `retry` - actions: `actions.*` - features: `pluralkit`, `execApprovals`, `intents`, `agentComponents`, `heartbeat`, `responsePrefix` ## Safety and operations - Treat bot tokens as secrets (`DISCORD_BOT_TOKEN` preferred in supervised environments). - Grant least-privilege Discord permissions. - If command deploy/state is stale, restart gateway and re-check with `openclaw channels status --probe`. ## Related - [Pairing](/channels/pairing) - [Channel routing](/channels/channel-routing) - [Troubleshooting](/channels/troubleshooting) - [Slash commands](/tools/slash-commands)