docs: normalize Mintlify links
This commit is contained in:
347
docs/discord.md
347
docs/discord.md
@@ -5,100 +5,293 @@ read_when:
|
||||
---
|
||||
# Discord (Bot API)
|
||||
|
||||
Updated: 2026-01-06
|
||||
Updated: 2025-12-07
|
||||
|
||||
Status: production-ready for DMs + guild channels via the Discord gateway.
|
||||
Status: ready for DM and guild text channels via the official Discord bot gateway.
|
||||
|
||||
## What it is
|
||||
- Discord bot provider owned by the Gateway.
|
||||
- Deterministic routing: replies always go back to Discord.
|
||||
- DMs share the agent's main session; guild channels are isolated (`discord:channel:<id>`).
|
||||
## 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:<agentId>:discord:channel:<channelId>` (display names use `discord:<guildSlug>#<channelSlug>`).
|
||||
- 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.
|
||||
|
||||
## Setup (fast path)
|
||||
1) Create a Discord application + bot.
|
||||
2) Enable intents: **Message Content** (required), **Server Members** (recommended).
|
||||
3) Invite the bot to your server with message permissions.
|
||||
4) Configure the token (env or config) and start the gateway.
|
||||
## 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 only when a `discord` config section exists **and** the token is set (unless `discord.enabled = false`).
|
||||
- If you prefer env vars, still add `discord: { enabled: true }` to `~/.clawdbot/clawdbot.json` and set `DISCORD_BOT_TOKEN`.
|
||||
5. Direct chats: use `user:<id>` (or a `<@id>` mention) when delivering; all turns land in the shared `main` session.
|
||||
6. Guild channels: use `channel:<channelId>` 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; approve via `clawdbot pairing approve --provider discord <code>`.
|
||||
- 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](/slash-commands)
|
||||
11. Optional guild context history: set `discord.historyLimit` (default 20) 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.*`).
|
||||
- The `discord` tool is only exposed when the current provider is Discord.
|
||||
13. Native commands use isolated session keys (`discord:slash:${userId}`) 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:
|
||||
|
||||
Example:
|
||||
```json5
|
||||
{
|
||||
discord: {
|
||||
enabled: true,
|
||||
token: "YOUR_BOT_TOKEN",
|
||||
dm: { policy: "pairing" },
|
||||
guilds: { "*": { requireMention: true } }
|
||||
token: "YOUR_BOT_TOKEN"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Access control (DMs + guilds)
|
||||
DMs:
|
||||
- Default: `discord.dm.policy = "pairing"`.
|
||||
- Unknown senders receive a pairing code; messages are ignored until approved.
|
||||
- Approve via:
|
||||
- `clawdbot pairing list --provider discord`
|
||||
- `clawdbot pairing approve --provider discord <CODE>`
|
||||
- Pairing is the default token exchange for Discord DMs. Details: https://docs.clawd.bot/pairing
|
||||
#### Allowlist + channel routing
|
||||
Example “single server, only allow me, only allow #help”:
|
||||
|
||||
Guild channels:
|
||||
- `discord.groupPolicy = open | allowlist | disabled`.
|
||||
- `discord.guilds` (per-guild) + `channels` (per-channel) act as allowlists.
|
||||
- Mentions are required by default; override per guild/channel.
|
||||
```json5
|
||||
{
|
||||
discord: {
|
||||
enabled: true,
|
||||
dm: { enabled: false },
|
||||
guilds: {
|
||||
"YOUR_GUILD_ID": {
|
||||
users: ["YOUR_USER_ID"],
|
||||
requireMention: true,
|
||||
channels: {
|
||||
help: { allow: true, requireMention: true }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## How it works (behavior)
|
||||
- Inbound messages are normalized into the shared provider envelope.
|
||||
- Optional guild context history is injected before the current message.
|
||||
- Replies always route back to the same channel or DM.
|
||||
Notes:
|
||||
- `requireMention: true` means the bot only replies when mentioned (recommended for shared channels).
|
||||
- `routing.groupChat.mentionPatterns` also count as mentions for guild messages.
|
||||
- If `channels` is present, any channel not listed is denied by default.
|
||||
|
||||
## Commands + reply threading
|
||||
- Native commands: `commands.native = true` (registers `/` commands).
|
||||
- Text commands: `commands.text = true` (standalone `/...` messages).
|
||||
- Threaded replies: controlled by `discord.replyToMode` using reply tags.
|
||||
### 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.
|
||||
|
||||
## Media + limits
|
||||
- Files supported up to `discord.mediaMaxMb` (default 8 MB).
|
||||
- Outbound chunking controlled by `discord.textChunkLimit`.
|
||||
### Troubleshooting
|
||||
- **“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.
|
||||
- **DMs don’t work**: `discord.dm.enabled=false`, `discord.dm.policy="disabled"`, or you haven’t been approved yet (`discord.dm.policy="pairing"`).
|
||||
|
||||
## Delivery targets (CLI/cron)
|
||||
- DMs: `user:<id>`
|
||||
- Guild channels: `channel:<channelId>`
|
||||
## Capabilities & limits
|
||||
- DMs and guild text channels (threads are treated as separate channels; voice not supported).
|
||||
- Typing indicators sent best-effort; message chunking honors Discord’s 2k character limit.
|
||||
- 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.
|
||||
|
||||
## Configuration reference (Discord)
|
||||
Full configuration: https://docs.clawd.bot/configuration
|
||||
## Config
|
||||
|
||||
Provider options:
|
||||
- `discord.enabled`: enable/disable provider startup.
|
||||
- `discord.token`: bot token (env: `DISCORD_BOT_TOKEN`).
|
||||
- `discord.groupPolicy`: `open | allowlist | disabled` (default: open).
|
||||
- `discord.textChunkLimit`: outbound chunk size (chars).
|
||||
- `discord.mediaMaxMb`: inbound/outbound media cap (MB).
|
||||
- `discord.historyLimit`: number of recent guild messages injected as context.
|
||||
- `discord.replyToMode`: `off | first | all`.
|
||||
- `discord.actions.reactions`: enable reaction tool actions.
|
||||
- `discord.actions.stickers`: enable sticker actions.
|
||||
- `discord.actions.polls`: enable poll actions.
|
||||
- `discord.actions.permissions`: enable permission inspection actions.
|
||||
- `discord.actions.messages`: enable message read/send/edit/delete actions.
|
||||
- `discord.actions.threads`: enable thread actions.
|
||||
- `discord.actions.pins`: enable pin actions.
|
||||
- `discord.actions.search`: enable search actions.
|
||||
- `discord.actions.memberInfo`: enable member info actions.
|
||||
- `discord.actions.roleInfo`: enable role info actions.
|
||||
- `discord.actions.roles`: enable role management actions.
|
||||
- `discord.actions.channelInfo`: enable channel info actions.
|
||||
- `discord.actions.voiceStatus`: enable voice status actions.
|
||||
- `discord.actions.events`: enable event actions.
|
||||
- `discord.actions.moderation`: enable moderation actions.
|
||||
- `discord.dm.enabled`: enable/disable DMs.
|
||||
- `discord.dm.policy`: `pairing | allowlist | open | disabled` (default: pairing).
|
||||
- `discord.dm.allowFrom`: DM allowlist (ids/usernames). `open` requires `"*"`.
|
||||
- `discord.dm.groupEnabled`: enable group DMs.
|
||||
- `discord.dm.groupChannels`: group DM allowlist.
|
||||
- `discord.guilds`: per-guild rules:
|
||||
- `slug`, `requireMention`, `reactionNotifications`, `users`, `channels.*`.
|
||||
```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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Related global options:
|
||||
- `routing.groupChat.mentionPatterns`.
|
||||
- `commands.native`, `commands.text`, `commands.useAccessGroups`.
|
||||
- `messages.responsePrefix`, `messages.ackReaction`, `messages.ackReactionScope`.
|
||||
Ack reactions are controlled globally via `messages.ackReaction` +
|
||||
`messages.ackReactionScope`.
|
||||
|
||||
- `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.<id>.slug`: optional friendly slug used for display names.
|
||||
- `guilds.<id>.users`: optional per-guild user allowlist (ids or names).
|
||||
- `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`).
|
||||
- `mediaMaxMb`: clamp inbound media saved to disk.
|
||||
- `historyLimit`: number of recent guild messages to include as context when replying to a mention (default 20, `0` disables).
|
||||
- `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.<id>.reactionNotifications`:
|
||||
- `off`: no reaction events.
|
||||
- `own`: reactions on the bot's own messages (default).
|
||||
- `all`: all reactions on all messages.
|
||||
- `allowlist`: reactions from `guilds.<id>.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 spec) |
|
||||
| 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:<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.
|
||||
|
||||
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.<id>.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.
|
||||
|
||||
Reference in New Issue
Block a user