Discord (Bot API)
Status: ready for DM and guild text channels via the official Discord bot gateway.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 asagent:<agentId>:discord:channel:<channelId>(display names usediscord:<guildSlug>#<channelSlug>). - Group DMs are ignored by default; enable via
discord.dm.groupEnabledand optionally restrict bydiscord.dm.groupChannels. - Keep routing deterministic: replies always go back to the provider they arrived on.
How it works
- Create a Discord application → Bot, enable the intents you need (DMs + guild messages + message content), and grab the bot token.
- Invite the bot to your server with the permissions required to read/send messages where you want to use it.
- Configure Clawdbot with
DISCORD_BOT_TOKEN(ordiscord.tokenin~/.clawdbot/clawdbot.json). - Run the gateway; it auto-starts the Discord provider only when a
discordconfig section exists and the token is set (unlessdiscord.enabled = false).- If you prefer env vars, still add
discord: { enabled: true }to~/.clawdbot/clawdbot.jsonand setDISCORD_BOT_TOKEN.
- If you prefer env vars, still add
- Direct chats: use
user:<id>(or a<@id>mention) when delivering; all turns land in the sharedmainsession. - Guild channels: use
channel:<channelId>for delivery. Mentions are required by default and can be set per guild or per channel. - Direct chats: secure by default via
discord.dm.policy(default:"pairing"). Unknown senders get a pairing code (expires after 1 hour); approve viaclawdbot pairing approve --provider discord <code>.- To keep old “open to anyone” behavior: set
discord.dm.policy="open"anddiscord.dm.allowFrom=["*"]. - To hard-allowlist: set
discord.dm.policy="allowlist"and list senders indiscord.dm.allowFrom. - To ignore all DMs: set
discord.dm.enabled=falseordiscord.dm.policy="disabled".
- To keep old “open to anyone” behavior: set
- Group DMs are ignored by default; enable via
discord.dm.groupEnabledand optionally restrict bydiscord.dm.groupChannels. - Optional guild rules: set
discord.guildskeyed by guild id (preferred) or slug, with per-channel rules. - Optional native commands: set
commands.native: trueto register native commands in Discord; setcommands.native: falseto clear previously registered native commands. Text commands are controlled bycommands.textand must be sent as standalone/...messages. Usecommands.useAccessGroups: falseto bypass access-group checks for commands.- Full command list + config: Slash commands
- Optional guild context history: set
discord.historyLimit(default 20) to include the last N guild messages as context when replying to a mention. Set0to disable. - Reactions: the agent can trigger reactions via the
discordtool (gated bydiscord.actions.*).- Reaction removal semantics: see /tools/reactions.
- The
discordtool is only exposed when the current provider is Discord.
- Native commands use isolated session keys (
discord:slash:${userId}) rather than the sharedmainsession.
<@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
- Discord Developer Portal → Applications → New Application
- 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)
3) Generate an invite URL (OAuth2 URL Generator)
In your app: OAuth2 → URL Generator Scopes- ✅
bot - ✅
applications.commands(required for native commands)
- ✅ 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)
4) Get the ids (guild/user/channel)
Discord uses numeric ids everywhere; Clawdbot config prefers ids.- Discord (desktop/web) → User Settings → Advanced → enable Developer Mode
- 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=...
discord.accounts with per-account tokens and optional name. See gateway/configuration for the shared pattern.
Allowlist + channel routing
Example “single server, only allow me, only allow #help”:requireMention: truemeans the bot only replies when mentioned (recommended for shared channels).routing.groupChat.mentionPatternsalso count as mentions for guild messages.- Multi-agent override:
routing.agents.<agentId>.mentionPatternstakes precedence. - If
channelsis present, any channel not listed is denied by default.
6) Verify it works
- Start the gateway.
- In your server channel, send:
@Krill hello(or whatever your bot name is). - If nothing happens: check Troubleshooting below.
Troubleshooting
- First: run
clawdbot doctorandclawdbot 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 asdiscord.guilds.*.channelskeys, 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.replyToModeand reply tags.
Retry policy
Outbound Discord API calls retry on rate limits (429) using Discordretry_after when available, with exponential backoff and jitter. Configure via discord.retry. See Retry policy.
Config
messages.ackReaction +
messages.ackReactionScope.
dm.enabled: setfalseto ignore all DMs (defaulttrue).dm.policy: DM access control (pairingrecommended)."open"requiresdm.allowFrom=["*"].dm.allowFrom: DM allowlist (user ids or names). Used bydm.policy="allowlist"and fordm.policy="open"validation.dm.groupEnabled: enable group DMs (defaultfalse).dm.groupChannels: optional allowlist for group DM channel ids or slugs.groupPolicy: controls guild channel handling (open|disabled|allowlist);allowlistrequires 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.<id>.slug: optional friendly slug used for display names.guilds.<id>.users: optional per-guild user allowlist (ids or names).guilds.<id>.channels.<channel>.allow: allow/deny the channel whengroupPolicy="allowlist".guilds.<id>.channels.<channel>.requireMention: mention gating for the channel.guilds.<id>.channels.<channel>.users: optional per-channel user allowlist.guilds.<id>.channels.<channel>.skills: skill filter (omit = all skills, empty = none).guilds.<id>.channels.<channel>.systemPrompt: extra system prompt for the channel (combined with channel topic).guilds.<id>.channels.<channel>.enabled: setfalseto disable the channel.guilds.<id>.channels: channel rules (keys are channel slugs or ids).guilds.<id>.requireMention: per-guild mention requirement (overridable per channel).guilds.<id>.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,0disables).retry: retry policy for outbound Discord API calls (attempts, minDelayMs, maxDelayMs, jitter).actions: per-action tool gates; omit to allow all (setfalseto disable).reactions(covers react + read reactions)stickers,polls,permissions,messages,threads,pins,searchmemberInfo,roleInfo,channelInfo,voiceStatus,eventsroles(role add/remove, defaultfalse)moderation(timeout/kick/ban, defaultfalse)
guilds.<id>.reactionNotifications:
off: no reaction events.own: reactions on the bot’s own messages (default).all: all reactions on all messages.allowlist: reactions fromguilds.<id>.userson 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, orall. 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:<id>]]— reply to a specific message id from context/history. Current message ids are appended to prompts as[message_id: …]; history entries already include ids.
discord.replyToMode:
off: ignore tags.first: only the first outbound chunk/attachment is a reply.all: every outbound chunk/attachment is a reply.
allowFrom/users/groupChannelsaccept ids, names, tags, or mentions like<@id>.- Prefixes like
discord:/user:(users) andchannel:(group DMs) are supported. - Use
*to allow any sender/channel. - When
guilds.<id>.channelsis present, channels not listed are denied by default.
- 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 calldiscord with actions like:
react/reactions(add or list reactions)sticker,poll,permissionsreadMessages,sendMessage,editMessage,deleteMessagethreadCreate,threadList,threadReplypinMessage,unpinMessage,listPinssearchMessages,memberInfo,roleInfo,roleAdd,roleRemove,emojiListchannelInfo,channelList,voiceStatus,eventList,eventCreatetimeout,kick,ban
[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_TOKENenv 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.