--- summary: "Discord bot support status, capabilities, and configuration" read_when: - Working on Discord provider features --- # Discord (Bot API) Status: ready for DM and guild text channels via the official Discord bot gateway. ## Quick setup (beginner) 1) Create a Discord bot and copy the bot token. 2) Set the token for Clawdbot: - Env: `DISCORD_BOT_TOKEN=...` - Or config: `discord.token: "..."`. 3) Invite the bot to your server with message permissions. 4) Start the gateway. 5) DM access is pairing by default; approve the pairing code on first contact. Minimal config: ```json5 { discord: { enabled: true, token: "YOUR_BOT_TOKEN" } } ``` ## Goals - Talk to Clawdbot via Discord DMs or guild channels. - Direct chats collapse into the agent's main session (default `agent:main:main`); guild channels stay isolated as `agent::discord:channel:` (display names use `discord:#`). - Group DMs are ignored by default; enable via `discord.dm.groupEnabled` and optionally restrict by `discord.dm.groupChannels`. - Keep routing deterministic: replies always go back to the provider they arrived on. ## How it works 1. Create a Discord application → Bot, enable the intents you need (DMs + guild messages + message content), and grab the bot token. 2. Invite the bot to your server with the permissions required to read/send messages where you want to use it. 3. Configure Clawdbot with `DISCORD_BOT_TOKEN` (or `discord.token` in `~/.clawdbot/clawdbot.json`). 4. Run the gateway; it auto-starts the Discord provider when a token is available (env or config) and `discord.enabled` is not `false`. - If you prefer env vars, set `DISCORD_BOT_TOKEN` (a config block is optional). 5. Direct chats: use `user:` (or a `<@id>` mention) when delivering; all turns land in the shared `main` session. Bare numeric IDs are ambiguous and rejected. 6. Guild channels: use `channel:` for delivery. Mentions are required by default and can be set per guild or per channel. 7. Direct chats: secure by default via `discord.dm.policy` (default: `"pairing"`). Unknown senders get a pairing code (expires after 1 hour); approve via `clawdbot pairing approve discord `. - To keep old “open to anyone” behavior: set `discord.dm.policy="open"` and `discord.dm.allowFrom=["*"]`. - To hard-allowlist: set `discord.dm.policy="allowlist"` and list senders in `discord.dm.allowFrom`. - To ignore all DMs: set `discord.dm.enabled=false` or `discord.dm.policy="disabled"`. 8. Group DMs are ignored by default; enable via `discord.dm.groupEnabled` and optionally restrict by `discord.dm.groupChannels`. 9. Optional guild rules: set `discord.guilds` keyed by guild id (preferred) or slug, with per-channel rules. 10. Optional native commands: set `commands.native: true` to register native commands in Discord; set `commands.native: false` to clear previously registered native commands. Text commands are controlled by `commands.text` and must be sent as standalone `/...` messages. Use `commands.useAccessGroups: false` to bypass access-group checks for commands. - Full command list + config: [Slash commands](/tools/slash-commands) 11. Optional guild context history: set `discord.historyLimit` (default 20, falls back to `messages.groupChat.historyLimit`) to include the last N guild messages as context when replying to a mention. Set `0` to disable. 12. Reactions: the agent can trigger reactions via the `discord` tool (gated by `discord.actions.*`). - Reaction removal semantics: see [/tools/reactions](/tools/reactions). - The `discord` tool is only exposed when the current provider is Discord. 13. Native commands use isolated session keys (`agent::discord:slash:`) rather than the shared `main` session. Note: Discord does not provide a simple username → id lookup without extra guild context, so prefer ids or `<@id>` mentions for DM delivery targets. Note: Slugs are lowercase with spaces replaced by `-`. Channel names are slugged without the leading `#`. Note: Guild context `[from:]` lines include `author.tag` + `id` to make ping-ready replies easy. ## How to create your own bot This is the “Discord Developer Portal” setup for running Clawdbot in a server (guild) channel like `#help`. ### 1) Create the Discord app + bot user 1. Discord Developer Portal → **Applications** → **New Application** 2. In your app: - **Bot** → **Add Bot** - Copy the **Bot Token** (this is what you put in `DISCORD_BOT_TOKEN`) ### 2) Enable the gateway intents Clawdbot needs Discord blocks “privileged intents” unless you explicitly enable them. In **Bot** → **Privileged Gateway Intents**, enable: - **Message Content Intent** (required to read message text in most guilds; without it you’ll see “Used disallowed intents” or the bot will connect but not react to messages) - **Server Members Intent** (recommended; required for some member/user lookups and allowlist matching in guilds) You usually do **not** need **Presence Intent**. ### 3) Generate an invite URL (OAuth2 URL Generator) In your app: **OAuth2** → **URL Generator** **Scopes** - ✅ `bot` - ✅ `applications.commands` (required for native commands) **Bot Permissions** (minimal baseline) - ✅ View Channels - ✅ Send Messages - ✅ Read Message History - ✅ Embed Links - ✅ Attach Files - ✅ Add Reactions (optional but recommended) - ✅ Use External Emojis / Stickers (optional; only if you want them) Avoid **Administrator** unless you’re debugging and fully trust the bot. Copy the generated URL, open it, pick your server, and install the bot. ### 4) Get the ids (guild/user/channel) Discord uses numeric ids everywhere; Clawdbot config prefers ids. 1. Discord (desktop/web) → **User Settings** → **Advanced** → enable **Developer Mode** 2. Right-click: - Server name → **Copy Server ID** (guild id) - Channel (e.g. `#help`) → **Copy Channel ID** - Your user → **Copy User ID** ### 5) Configure Clawdbot #### Token Set the bot token via env var (recommended on servers): - `DISCORD_BOT_TOKEN=...` Or via config: ```json5 { discord: { enabled: true, token: "YOUR_BOT_TOKEN" } } ``` Multi-account support: use `discord.accounts` with per-account tokens and optional `name`. See [`gateway/configuration`](/gateway/configuration#telegramaccounts--discordaccounts--slackaccounts--signalaccounts--imessageaccounts) for the shared pattern. #### Allowlist + channel routing Example “single server, only allow me, only allow #help”: ```json5 { discord: { enabled: true, dm: { enabled: false }, guilds: { "YOUR_GUILD_ID": { users: ["YOUR_USER_ID"], requireMention: true, channels: { help: { allow: true, requireMention: true } } } }, retry: { attempts: 3, minDelayMs: 500, maxDelayMs: 30000, jitter: 0.1 } } } ``` Notes: - `requireMention: true` means the bot only replies when mentioned (recommended for shared channels). - `agents.list[].groupChat.mentionPatterns` (or `messages.groupChat.mentionPatterns`) also count as mentions for guild messages. - Multi-agent override: set per-agent patterns on `agents.list[].groupChat.mentionPatterns`. - If `channels` is present, any channel not listed is denied by default. ### 6) Verify it works 1. Start the gateway. 2. In your server channel, send: `@Krill hello` (or whatever your bot name is). 3. If nothing happens: check **Troubleshooting** below. ### Troubleshooting - First: run `clawdbot doctor` and `clawdbot providers status --probe` (actionable warnings + quick audits). - **“Used disallowed intents”**: enable **Message Content Intent** (and likely **Server Members Intent**) in the Developer Portal, then restart the gateway. - **Bot connects but never replies in a guild channel**: - Missing **Message Content Intent**, or - The bot lacks channel permissions (View/Send/Read History), or - Your config requires mentions and you didn’t mention it, or - Your guild/channel allowlist denies the channel/user. - **Permission audits** (`providers status --probe`) only check numeric channel IDs. If you use slugs/names as `discord.guilds.*.channels` keys, the audit can’t verify permissions. - **DMs don’t work**: `discord.dm.enabled=false`, `discord.dm.policy="disabled"`, or you haven’t been approved yet (`discord.dm.policy="pairing"`). ## Capabilities & limits - DMs and guild text channels (threads are treated as separate channels; voice not supported). - Typing indicators sent best-effort; message chunking uses `discord.textChunkLimit` (default 2000) and splits tall replies by line count (`discord.maxLinesPerMessage`, default 17). - File uploads supported up to the configured `discord.mediaMaxMb` (default 8 MB). - Mention-gated guild replies by default to avoid noisy bots. - Reply context is injected when a message references another message (quoted content + ids). - Native reply threading is **off by default**; enable with `discord.replyToMode` and reply tags. ## Retry policy Outbound Discord API calls retry on rate limits (429) using Discord `retry_after` when available, with exponential backoff and jitter. Configure via `discord.retry`. See [Retry policy](/concepts/retry). ## Config ```json5 { discord: { enabled: true, token: "abc.123", groupPolicy: "open", mediaMaxMb: 8, actions: { reactions: true, stickers: true, polls: true, permissions: true, messages: true, threads: true, pins: true, search: true, memberInfo: true, roleInfo: true, roles: false, channelInfo: true, voiceStatus: true, events: true, moderation: false }, replyToMode: "off", dm: { enabled: true, policy: "pairing", // pairing | allowlist | open | disabled allowFrom: ["123456789012345678", "steipete"], groupEnabled: false, groupChannels: ["clawd-dm"] }, guilds: { "*": { requireMention: true }, "123456789012345678": { slug: "friends-of-clawd", requireMention: false, reactionNotifications: "own", users: ["987654321098765432", "steipete"], channels: { general: { allow: true }, help: { allow: true, requireMention: true, users: ["987654321098765432"], skills: ["search", "docs"], systemPrompt: "Keep answers short." } } } } } } ``` Ack reactions are controlled globally via `messages.ackReaction` + `messages.ackReactionScope`. Use `messages.removeAckAfterReply` to clear the ack reaction after the bot replies. - `dm.enabled`: set `false` to ignore all DMs (default `true`). - `dm.policy`: DM access control (`pairing` recommended). `"open"` requires `dm.allowFrom=["*"]`. - `dm.allowFrom`: DM allowlist (user ids or names). Used by `dm.policy="allowlist"` and for `dm.policy="open"` validation. - `dm.groupEnabled`: enable group DMs (default `false`). - `dm.groupChannels`: optional allowlist for group DM channel ids or slugs. - `groupPolicy`: controls guild channel handling (`open|disabled|allowlist`); `allowlist` requires channel allowlists. - `guilds`: per-guild rules keyed by guild id (preferred) or slug. - `guilds."*"`: default per-guild settings applied when no explicit entry exists. - `guilds..slug`: optional friendly slug used for display names. - `guilds..users`: optional per-guild user allowlist (ids or names). - `guilds..channels..allow`: allow/deny the channel when `groupPolicy="allowlist"`. - `guilds..channels..requireMention`: mention gating for the channel. - `guilds..channels..users`: optional per-channel user allowlist. - `guilds..channels..skills`: skill filter (omit = all skills, empty = none). - `guilds..channels..systemPrompt`: extra system prompt for the channel (combined with channel topic). - `guilds..channels..enabled`: set `false` to disable the channel. - `guilds..channels`: channel rules (keys are channel slugs or ids). - `guilds..requireMention`: per-guild mention requirement (overridable per channel). - `guilds..reactionNotifications`: reaction system event mode (`off`, `own`, `all`, `allowlist`). - `textChunkLimit`: outbound text chunk size (chars). Default: 2000. - `maxLinesPerMessage`: soft max line count per message. Default: 17. - `mediaMaxMb`: clamp inbound media saved to disk. - `historyLimit`: number of recent guild messages to include as context when replying to a mention (default 20; falls back to `messages.groupChat.historyLimit`; `0` disables). - `retry`: retry policy for outbound Discord API calls (attempts, minDelayMs, maxDelayMs, jitter). - `actions`: per-action tool gates; omit to allow all (set `false` to disable). - `reactions` (covers react + read reactions) - `stickers`, `polls`, `permissions`, `messages`, `threads`, `pins`, `search` - `memberInfo`, `roleInfo`, `channelInfo`, `voiceStatus`, `events` - `roles` (role add/remove, default `false`) - `moderation` (timeout/kick/ban, default `false`) Reaction notifications use `guilds..reactionNotifications`: - `off`: no reaction events. - `own`: reactions on the bot's own messages (default). - `all`: all reactions on all messages. - `allowlist`: reactions from `guilds..users` on all messages (empty list disables). ### Tool action defaults | Action group | Default | Notes | | --- | --- | --- | | reactions | enabled | React + list reactions + emojiList | | stickers | enabled | Send stickers | | polls | enabled | Create polls | | permissions | enabled | Channel permission snapshot | | messages | enabled | Read/send/edit/delete | | threads | enabled | Create/list/reply | | pins | enabled | Pin/unpin/list | | search | enabled | Message search (preview feature) | | memberInfo | enabled | Member info | | roleInfo | enabled | Role list | | channelInfo | enabled | Channel info + list | | voiceStatus | enabled | Voice state lookup | | events | enabled | List/create scheduled events | | roles | disabled | Role add/remove | | moderation | disabled | Timeout/kick/ban | - `replyToMode`: `off` (default), `first`, or `all`. Applies only when the model includes a reply tag. ## Reply tags To request a threaded reply, the model can include one tag in its output: - `[[reply_to_current]]` — reply to the triggering Discord message. - `[[reply_to:]]` — reply to a specific message id from context/history. Current message ids are appended to prompts as `[message_id: …]`; history entries already include ids. Behavior is controlled by `discord.replyToMode`: - `off`: ignore tags. - `first`: only the first outbound chunk/attachment is a reply. - `all`: every outbound chunk/attachment is a reply. Allowlist matching notes: - `allowFrom`/`users`/`groupChannels` accept ids, names, tags, or mentions like `<@id>`. - Prefixes like `discord:`/`user:` (users) and `channel:` (group DMs) are supported. - Use `*` to allow any sender/channel. - When `guilds..channels` is present, channels not listed are denied by default. Native command notes: - The registered commands mirror Clawdbot’s chat commands. - Native commands honor the same allowlists as DMs/guild messages (`discord.dm.allowFrom`, `discord.guilds`, per-channel rules). ## Tool actions The agent can call `discord` with actions like: - `react` / `reactions` (add or list reactions) - `sticker`, `poll`, `permissions` - `readMessages`, `sendMessage`, `editMessage`, `deleteMessage` - `threadCreate`, `threadList`, `threadReply` - `pinMessage`, `unpinMessage`, `listPins` - `searchMessages`, `memberInfo`, `roleInfo`, `roleAdd`, `roleRemove`, `emojiList` - `channelInfo`, `channelList`, `voiceStatus`, `eventList`, `eventCreate` - `timeout`, `kick`, `ban` Discord message ids are surfaced in the injected context (`[discord message id: …]` and history lines) so the agent can target them. Emoji can be unicode (e.g., `✅`) or custom emoji syntax like `<:party_blob:1234567890>`. ## Safety & ops - Treat the bot token like a password; prefer the `DISCORD_BOT_TOKEN` env var on supervised hosts or lock down the config file permissions. - Only grant the bot permissions it needs (typically Read/Send Messages). - If the bot is stuck or rate limited, restart the gateway (`clawdbot gateway --force`) after confirming no other processes own the Discord session.