Discord
The Discord adapter connects an agent to a Discord bot. It handles message sending and receiving, history, reactions, slash commands, and attachments.
The adapter starts automatically when config/channels/discord.toml exists. The file is not created by init; create it to enable the integration.
Configuration
toml
token = "MTxxxxxxxxxxxxxxxxxxxxxxxx.xxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ownerId = "123456789012345678"
# REST request timeout in ms (default 60000)
timeout = 30000
# Seconds the gateway may stay silent before the runtime reconnects (default 600)
gatewaySilenceTimeout = 600
# Restrict who can interact in guild channels
access = { mode = "allowlist", users = ["123456789012345678"] }
# Restrict who can DM the agent
directMessages = { mode = "owner", users = [] }
# Grant non-owner users permission to run specific slash commands
[[trustedUsers]]
ids = ["987654321098765432"]
allowedCommands = ["stop", "summarize", "model query"]| Field | Required | Default | Description |
|---|---|---|---|
token | Yes | — | Bot token from the Discord Developer Portal. |
ownerId | Yes | — | Discord user ID of the bot operator (numeric snowflake). |
timeout | No | 60000 | REST request timeout in milliseconds. |
gatewaySilenceTimeout | No | 600 | Seconds the gateway may stay silent before the runtime reconnects; minimum 60. |
access | No | disabled | Guild channel access restriction. |
directMessages | No | owner | Direct-message access mode. |
trustedUsers | No | [] | Users allowed to run specific commands. |
Access modes
access controls who can interact with the agent in guild channels.
| Mode | Behavior |
|---|---|
disabled | Anyone can interact (default). |
allowlist | Only users in users can interact, plus the owner. |
denylist | Everyone can interact except users in users. |
The ownerId user always bypasses access control regardless of mode.
Direct message modes
directMessages controls who can DM the agent.
| Mode | Behavior |
|---|---|
owner | Only the owner can DM (default). |
public | Anyone can DM. |
allowlist | Only users in users can DM, plus the owner. |
denylist | Everyone can DM except users in users. |
Trusted users
trustedUsers grants specific users permission to run specific slash commands without being the owner.
| Field | Required | Description |
|---|---|---|
ids | Yes | Array of Discord user IDs (numeric snowflakes) that share this permission set. |
allowedCommands | Yes | Array of slash command names as used internally, e.g. stop, summarize, model query. |
Subcommands use the form "<command> <subcommand>". The owner is always allowed to run every command and subcommand. Message commands and the error-reaction cleanup remain owner-only.
Slash commands
Slash commands and subcommands are restricted to the owner and to trusted users whose allowedCommands includes the command path.
| Command | Subcommands | Description |
|---|---|---|
/clear | — | Reset conversation history for the channel; super keeps a history barrier. |
/close | — | Close an open file in the current session. |
/invite | — | Get an invite link for the bot. |
/model | override, clear, clear-all, query | Switch the provider or model for this session. |
/repair | — | Repair corrupted Discord media attachments. |
/stop | — | Gracefully stop the current generation. |
/summarize | — | Summarize a described portion of the conversation. |
/unsummarize | — | Remove the most recent summary. |
/model override stores a provider and model on the current session. /model clear removes both values instead of storing the current global default, so subsequent turns follow the agent's current global provider and model when engine.toml is reloaded.
Unauthorized users receive an ephemeral "You are not authorized to use this command." response.
Message commands
The owner can use the message Apps menu on bot messages.
| Command | Behavior |
|---|---|
| Delete Message | Delete the message from Discord and remove it from session history. |
| Reroll Response | Delete the message and everything after it, then regenerate a response. |
Owner error-reaction cleanup
The owner can react with ✨ to a bot error message to delete it. This works only on messages starting with ⚠️ Engine error, :warning: Engine error, ⚠️ Discord error, or :warning: Discord error. Reactions from other users or on other messages are ignored.
Required intents
Enable the following gateway intents for the bot in the Discord Developer Portal:
GUILD_MESSAGESDIRECT_MESSAGESMESSAGE_CONTENTGUILD_MESSAGE_REACTIONSDIRECT_MESSAGE_REACTIONSGUILD_MEMBERS
Message processing
Guild messages are processed when the bot is mentioned or when the message replies to a bot message. Direct messages are processed according to the configured DM mode.
Each turn reads the recent channel history and crawls reply chains for full thread context. Long responses are split at sensible boundaries to stay under Discord's 2000-character limit; splits keep code fences open across chunks.
Message edits update the stored history in place, and message deletions remove the deleted message from internal history on the next turn.
Supported content
Images are downloaded and converted to WebP before being sent to the model. Stickers are fetched and converted to WebP; Lottie stickers are skipped. Videos are sent only when the selected model supports video and the attachment is within the size cap. File and text attachments are described with metadata; only images and videos are fetched and sent to the model.
Gateway liveness
Discord answers every heartbeat, so a healthy connection always produces traffic even when no one is talking to the bot. The runtime records that traffic and treats prolonged silence as a dead connection, which is what a half-open TCP socket looks like from userspace: the socket still reports itself as open, but no payload will ever arrive again.
When the gateway has been silent for gatewaySilenceTimeout seconds the runtime aborts the connection so the client reconnects. A blocked read cannot be interrupted by cancellation, but aborting the socket releases it immediately. If payloads still do not resume within two minutes the runtime replaces its gateway client entirely, because a fatal error can stop the client without affecting the rest of the runtime.
Each recovery step is logged at warning or error level. Without this watchdog the failure is invisible: sessions, heartbeats, and REST sends keep working while the bot looks offline in every channel.
Restart requirement
Changes to channels/discord.toml require a full runtime restart.