Skip to content

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"]
FieldRequiredDefaultDescription
tokenYes—Bot token from the Discord Developer Portal.
ownerIdYes—Discord user ID of the bot operator (numeric snowflake).
timeoutNo60000REST request timeout in milliseconds.
gatewaySilenceTimeoutNo600Seconds the gateway may stay silent before the runtime reconnects; minimum 60.
accessNodisabledGuild channel access restriction.
directMessagesNoownerDirect-message access mode.
trustedUsersNo[]Users allowed to run specific commands.

Access modes ​

access controls who can interact with the agent in guild channels.

ModeBehavior
disabledAnyone can interact (default).
allowlistOnly users in users can interact, plus the owner.
denylistEveryone 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.

ModeBehavior
ownerOnly the owner can DM (default).
publicAnyone can DM.
allowlistOnly users in users can DM, plus the owner.
denylistEveryone can DM except users in users.

Trusted users ​

trustedUsers grants specific users permission to run specific slash commands without being the owner.

FieldRequiredDescription
idsYesArray of Discord user IDs (numeric snowflakes) that share this permission set.
allowedCommandsYesArray 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.

CommandSubcommandsDescription
/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.
/mem-usage—Report current process, agent, and session memory use.
/modeloverride, clear, clear-all, querySwitch 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.

/mem-usage returns an ephemeral snapshot: process working set, managed heap, committed and fragmented bytes, allocations since start, and generation collection counts; one line per agent with its live and indexed session counts, retained payload, and message totals; and the largest live sessions, capped so the answer fits one message.

Session figures approximate what a live session keeps in memory. Media bytes are counted exactly, while text and tool payloads are measured by size; object headers and collection overhead are not included, so the totals compare sessions but understate real heap cost. Only sessions hydrated in this process are listed, because a persisted session that has not been used in this process holds no memory to report.

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.

CommandBehavior
Delete MessageDelete the message from Discord and remove it from session history.
Reroll ResponseDelete 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_MESSAGES
  • DIRECT_MESSAGES
  • MESSAGE_CONTENT
  • GUILD_MESSAGE_REACTIONS
  • DIRECT_MESSAGE_REACTIONS
  • GUILD_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 thread context. Already ingested message IDs are retained durably, including fetched context that is not saved in the transcript, so pruning or restarting does not bring those messages back into the prompt. Existing messages still in the prompt can be refreshed after edits. Long responses are split at sensible boundaries to stay under Discord's 2000-character limit; splits keep code fences open across chunks.

Incoming message IDs are claimed durably before history loading, media downloads, typing, or a model turn. Duplicate gateway deliveries are ignored, including after reconnects and restarts. This is at-most-once processing, not guaranteed response delivery: a crash or failure after the claim can leave the message unanswered, and replaying the same ID will not retry it. Send a new message to retry. Identity records survive session clear and close operations so replay cannot rerun an old turn.

Message edits update stored text and images in place after fetching the complete Discord message. Each turn also checks edit timestamps on existing messages encountered in recent history and reply chains, so missed edit events are reconciled when those messages are fetched again. This does not scan older messages outside the fetched history and reply chains. Edit and delete events wait for an incoming turn in the same session to finish before mutating history. Message deletions remove the original message from internal history, but do not delete independently downloaded files or images injected by separate tool reads.

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. Images and videos sent to a model are stored in the session media cache for later session hydration. 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.

/repair refreshes every supported attachment and sticker image in each repairable user message rather than duplicating its first image. Images no longer present on the Discord message are removed from the repaired image set. If any image download or conversion fails for a message, its previous image set is retained and that refresh is reported as failed; other messages can still be repaired.

Images injected by tools remain historical context until superseded or pruned. For new tool reads, reading the same path again supersedes both the old tool result and its associated visual before the next inference request. Reading a different filename does not supersede the previous path, and older sessions may contain visuals recorded before tool-call associations were available. Use the per-model maxImagesPerRequest setting to cap outgoing image history for models that mishandle multiple images.

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.

Are you an agent? Prefer this page's raw Markdown document: follow its text/markdown alternate link, use its .md URL, or add ?md=1 to the page URL.