Discord
Discord (Bot API)
Section titled “Discord (Bot API)”Status: ready for DMs and guild channels via the official Discord gateway.
Quick setup
Section titled “Quick setup”You will need to create a new application with a bot, add the bot to your server, and pair it to CoderClaw. We recommend adding your bot to your own private server. If you don’t have one yet, create one first (choose Create My Own > For me and my friends).
Click **Bot** on the sidebar. Set the **Username** to whatever you call your CoderClaw agent.- **Message Content Intent** (required)- **Server Members Intent** (recommended; required for role allowlists and name-to-ID matching)- **Presence Intent** (optional; only needed for presence updates)<Note>Despite the name, this generates your first token — nothing is being "reset."</Note>
Copy the token and save it somewhere. This is your **Bot Token** and you will need it shortly.Scroll down to **OAuth2 URL Generator** and enable:
- `bot`- `applications.commands`
A **Bot Permissions** section will appear below. Enable:
- View Channels- Send Messages- Read Message History- Embed Links- Attach Files- Add Reactions (optional)
Copy the generated URL at the bottom, paste it into your browser, select your server, and click **Continue** to connect. You should now see your bot in the Discord server.1. Click **User Settings** (gear icon next to your avatar) → **Advanced** → toggle on **Developer Mode**2. Right-click your **server icon** in the sidebar → **Copy Server ID**3. Right-click your **own avatar** → **Copy User ID**
Save your **Server ID** and **User ID** alongside your Bot Token — you'll send all three to CoderClaw in the next step.This lets server members (including bots) send you DMs. Keep this enabled if you want to use Discord DMs with CoderClaw. If you only plan to use guild channels, you can disable DMs after pairing.coderclaw config set channels.discord.token '"YOUR_BOT_TOKEN"' --jsoncoderclaw config set channels.discord.enabled true --jsoncoderclaw gatewayIf CoderClaw is already running as a background service, use `coderclaw gateway restart` instead.<Tabs> <Tab title="Ask your agent"> Chat with your CoderClaw agent on any existing channel (e.g. Telegram) and tell it. If Discord is your first channel, use the CLI / config tab instead.
> "I already set my Discord bot token in config. Please finish Discord setup with User ID `<user_id>` and Server ID `<server_id>`." </Tab> <Tab title="CLI / config"> If you prefer file-based config, set:{ channels: { discord: { enabled: true, token: "YOUR_BOT_TOKEN", }, },} Env fallback for the default account:DISCORD_BOT_TOKEN=... </Tab></Tabs><Tabs> <Tab title="Ask your agent"> Send the pairing code to your agent on your existing channel:
> "Approve this Discord pairing code: `<CODE>`" </Tab> <Tab title="CLI">coderclaw pairing list discordcoderclaw pairing approve discord <CODE> </Tab></Tabs>
Pairing codes expire after 1 hour.
You should now be able to chat with your agent in Discord via DM.Recommended: Set up a guild workspace
Section titled “Recommended: Set up a guild workspace”Once DMs are working, you can set up your Discord server as a full workspace where each channel gets its own agent session with its own context. This is recommended for private servers where it’s just you and your bot.
<Tabs> <Tab title="Ask your agent"> > "Add my Discord Server ID `<server_id>` to the guild allowlist" </Tab> <Tab title="Config">{ channels: { discord: { groupPolicy: "allowlist", guilds: { YOUR_SERVER_ID: { requireMention: true, users: ["YOUR_USER_ID"], }, }, }, },} </Tab></Tabs><Tabs> <Tab title="Ask your agent"> > "Allow my agent to respond on this server without having to be @mentioned" </Tab> <Tab title="Config"> Set `requireMention: false` in your guild config:{ channels: { discord: { guilds: { YOUR_SERVER_ID: { requireMention: false, }, }, }, },} </Tab></Tabs><Tabs> <Tab title="Ask your agent"> > "When I ask questions in Discord channels, use memory_search or memory_get if you need long-term context from MEMORY.md." </Tab> <Tab title="Manual"> If you need shared context in every channel, put the stable instructions in `AGENTS.md` or `USER.md` (they are injected for every session). Keep long-term notes in `MEMORY.md` and access them on demand with memory tools. </Tab></Tabs>Now create some channels on your Discord server and start chatting. Your agent can see the channel name, and each channel gets its own isolated session — so you can set up #coding, #home, #research, or whatever fits your workflow.
Runtime model
Section titled “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:<agentId>:discord:channel:<channelId>). - Group DMs are ignored by default (
channels.discord.dm.groupEnabled=false). - Native slash commands run in isolated command sessions (
agent:<agentId>:discord:slash:<userId>), while still carryingCommandTargetSessionKeyto the routed conversation session.
Interactive components
Section titled “Interactive components”CoderClaw supports Discord components v2 containers for agent messages. Use the message tool with a components payload. Interaction results are routed back to the agent as normal inbound messages and follow the existing Discord replyToMode settings.
Supported blocks:
text,section,separator,actions,media-gallery,file- Action rows allow up to 5 buttons or a single select menu
- Select types:
string,user,role,mentionable,channel
By default, components are single use. Set components.reusable=true to allow buttons, selects, and forms to be used multiple times until they expire.
To restrict who can click a button, set allowedUsers on that button (Discord user IDs, tags, or *). When configured, unmatched users receive an ephemeral denial.
File attachments:
fileblocks must point to an attachment reference (attachment://<filename>)- Provide the attachment via
media/path/filePath(single file); usemedia-galleryfor multiple files - Use
filenameto override the upload name when it should match the attachment reference
Modal forms:
- Add
components.modalwith up to 5 fields - Field types:
text,checkbox,radio,select,role-select,user-select - CoderClaw adds a trigger button automatically
Example:
{ channel: "discord", action: "send", to: "channel:123456789012345678", message: "Optional fallback text", components: { reusable: true, text: "Choose a path", blocks: [ { type: "actions", buttons: [ { label: "Approve", style: "success", allowedUsers: ["123456789012345678"], }, { label: "Decline", style: "danger" }, ], }, { type: "actions", select: { type: "string", placeholder: "Pick an option", options: [ { label: "Option A", value: "a" }, { label: "Option B", value: "b" }, ], }, }, ], modal: { title: "Details", triggerLabel: "Open form", fields: [ { type: "text", label: "Requester" }, { type: "select", label: "Priority", options: [ { label: "Low", value: "low" }, { label: "High", value: "high" }, ], }, ], }, },}Access control and routing
Section titled “Access control and routing”- `pairing` (default)- `allowlist`- `open` (requires `channels.discord.allowFrom` to include `"*"`; legacy: `channels.discord.dm.allowFrom`)- `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>`- `<@id>` mention
Bare numeric IDs are ambiguous and rejected unless an explicit user/channel target kind is provided.- `open`- `allowlist`- `disabled`
Secure baseline when `channels.discord` exists is `allowlist`.
`allowlist` behavior:
- guild must match `channels.discord.guilds` (`id` preferred, slug accepted)- optional sender allowlists: `users` (IDs or names) and `roles` (role IDs only); if either is configured, senders are allowed when they match `users` OR `roles`- 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:{ channels: { discord: { groupPolicy: "allowlist", guilds: { "123456789012345678": { requireMention: true, users: ["987654321098765432"], roles: ["123456789012345678"], 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).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)Role-based agent routing
Section titled “Role-based agent routing”Use bindings[].match.roles to route Discord guild members to different agents by role ID. Role-based bindings accept role IDs only and are evaluated after peer or parent-peer bindings and before guild-only bindings. If a binding also sets other match fields (for example peer + guildId + roles), all configured fields must match.
{ bindings: [ { agentId: "opus", match: { channel: "discord", guildId: "123456789012345678", roles: ["111111111111111111"], }, }, { agentId: "sonnet", match: { channel: "discord", guildId: "123456789012345678", }, }, ],}Developer Portal setup
Section titled “Developer Portal setup”1. Discord Developer Portal -> **Applications** -> **New Application**2. **Bot** -> **Add Bot**3. Copy bot token- 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.- 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.- server ID- channel ID- user ID
Prefer numeric IDs in CoderClaw config for reliable audits and probes.Native commands and command auth
Section titled “Native commands and command auth”commands.nativedefaults to"auto"and is enabled for Discord.- Per-channel override:
channels.discord.commands.native. commands.native=falseexplicitly 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 CoderClaw auth and returns “not authorized”.
See Slash commands for command catalog and behavior.
Feature details
Section titled “Feature details”- `[[reply_to_current]]`- `[[reply_to:<id>]]`
Controlled by `channels.discord.replyToMode`:
- `off` (default)- `first`- `all`
Note: `off` disables implicit reply threading. Explicit `[[reply_to_*]]` tags are still honored.
Message IDs are surfaced in context/history so agents can target specific messages.- `channels.discord.historyLimit` default `20`- fallback: `messages.groupChat.historyLimit`- `0` disables
DM history controls:
- `channels.discord.dmHistoryLimit`- `channels.discord.dms["<user_id>"].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).- `off`- `own` (default)- `all`- `allowlist` (uses `guilds.<id>.users`)
Reaction events are turned into system events and attached to the routed Discord session.Resolution order:
- `channels.discord.accounts.<accountId>.ackReaction`- `channels.discord.ackReaction`- `messages.ackReaction`- agent identity emoji fallback (`agents.list[].identity.emoji`, else "👀")
Notes:
- Discord accepts unicode emoji or custom emoji names.- Use `""` to disable the reaction for a channel or account.This affects `/config set|unset` flows (when command features are enabled).
Disable:{ channels: { discord: { configWrites: false, }, },}{ channels: { discord: { proxy: "http://proxy.example:8080", }, },}Per-account override:{ channels: { discord: { accounts: { primary: { proxy: "http://proxy.example:8080", }, }, }, },}{ channels: { discord: { pluralkit: { enabled: true, token: "pk_live_...", // optional; needed for private systems }, }, },}Notes:
- allowlists can use `pk:<memberId>`- 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`Status only example:{ channels: { discord: { status: "idle", }, },}Activity example (custom status is the default activity type):{ channels: { discord: { activity: "Focus time", activityType: 4, }, },}Streaming example:{ channels: { discord: { activity: "Live coding", activityType: 1, activityUrl: "https://twitch.tv/coderclaw", }, },}Activity type map:
- 0: Playing- 1: Streaming (requires `activityUrl`)- 2: Listening- 3: Watching- 4: Custom (uses the activity text as the status state; emoji is optional)- 5: CompetingConfig path:
- `channels.discord.execApprovals.enabled`- `channels.discord.execApprovals.approvers`- `channels.discord.execApprovals.target` (`dm` | `channel` | `both`, default: `dm`)- `agentFilter`, `sessionFilter`, `cleanupAfterResolve`
When `target` is `channel` or `both`, the approval prompt is visible in the channel. Only configured approvers can use the buttons; other users receive an ephemeral denial. Approval prompts include the command text, so only enable channel delivery in trusted channels. If the channel ID cannot be derived from the session key, CoderClaw falls back to DM delivery.
If approvals fail with unknown approval IDs, verify approver list and feature enablement.
Related docs: [Exec approvals](/tools/exec-approvals)Tools and action gates
Section titled “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 |
Components v2 UI
Section titled “Components v2 UI”CoderClaw uses Discord components v2 for exec approvals and cross-context markers. Discord message actions can also accept components for custom UI (advanced; requires Carbon component instances), while legacy embeds remain available but are not recommended.
channels.discord.ui.components.accentColorsets the accent color used by Discord component containers (hex).- Set per account with
channels.discord.accounts.<id>.ui.components.accentColor. embedsare ignored when components v2 are present.
Example:
{ channels: { discord: { ui: { components: { accentColor: "#5865F2", }, }, }, },}Voice messages
Section titled “Voice messages”Discord voice messages show a waveform preview and require OGG/Opus audio plus metadata. CoderClaw generates the waveform automatically, but it needs ffmpeg and ffprobe available on the gateway host to inspect and convert audio files.
Requirements and constraints:
- Provide a local file path (URLs are rejected).
- Omit text content (Discord does not allow text + voice message in the same payload).
- Any audio format is accepted; CoderClaw converts to OGG/Opus when needed.
Example:
message(action="send", channel="discord", target="channel:123", path="/path/to/audio.mp3", asVoice=true)Troubleshooting
Section titled “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:coderclaw doctorcoderclaw channels status --probecoderclaw logs --follow- `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` allowlistIf 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.dmPolicy="disabled"` (legacy: `channels.discord.dm.policy`)- awaiting pairing approval in `pairing` modeIf you set `channels.discord.allowBots=true`, use strict mention and allowlist rules to avoid loop behavior.Configuration reference pointers
Section titled “Configuration reference pointers”Primary reference:
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.* - presence:
activity,status,activityType,activityUrl - UI:
ui.components.accentColor - features:
pluralkit,execApprovals,intents,agentComponents,heartbeat,responsePrefix
Safety and operations
Section titled “Safety and operations”- Treat bot tokens as secrets (
DISCORD_BOT_TOKENpreferred in supervised environments). - Grant least-privilege Discord permissions.
- If command deploy/state is stale, restart gateway and re-check with
coderclaw channels status --probe.