Summary
Add Discord as a new channel alongside the existing Telegram and Slack integrations. The current architecture already anticipates Discord — types.ts references Discord in both the acknowledge method comment (line 19: "Discord: typing indicator") and the Destination interface (line 52: "Discord thread"), so this would be a natural next step.
Motivation
Discord is one of the most widely used community/team platforms, especially in developer and AI communities. Adding it as a channel would significantly expand Utah's reach and make it usable in many more contexts.
Proposed implementation
The channel-agnostic design of the agent loop, reply dispatch, and acknowledgment means no changes are needed outside src/channels/ (except registering the handler in index.ts).
New files to create in src/channels/discord/
| File |
Purpose |
Complexity |
api.ts |
Discord REST API client — send messages (POST /channels/{id}/messages) and typing indicators (POST /channels/{id}/typing). Could use @discordjs/rest or raw fetch. |
Low |
handler.ts |
Implements ChannelHandler with sendReply, acknowledge, and setup |
Low |
transform.ts |
Maps Discord webhook payloads to AgentMessageData — e.g. d.channel_id → chatId, d.author.id → senderId, d.content → text |
Medium |
setup.ts |
Webhook/bot registration + Ed25519 signature verification for incoming requests |
Medium–High |
format.ts |
Markdown conversion — mostly pass-through since Discord supports standard MD, but needs 2000-char message chunking |
Low |
File to modify
src/channels/index.ts — register the new DiscordHandler in the channel registry
Environment variables
DISCORD_BOT_TOKEN=...
DISCORD_APPLICATION_ID=...
DISCORD_PUBLIC_KEY=... # for Ed25519 webhook signature verification
Discord-specific considerations
-
Signature verification (Ed25519): Discord requires verifying X-Signature-Ed25519 and X-Signature-Timestamp headers on every incoming webhook request. This is stricter than Telegram and should be handled in the transform or a middleware layer.
-
Interaction acknowledgment: Discord's Interactions Endpoint requires responding to PING events with an immediate PONG, which needs handling in the transform or an edge function.
-
Message length limit: Discord caps messages at 2000 characters, so format.ts needs chunking logic for longer agent replies.
-
Bot vs. Webhook approach: A bot-based approach (connecting to the Gateway) is more flexible for receiving messages than a pure webhook setup. Worth deciding which path to take.
Estimated effort
For a TypeScript dev familiar with Discord's API, roughly half a day to a full day of work. The hardest part is the Ed25519 signature verification and interaction acknowledgment — the rest maps cleanly onto the existing channel abstractions.
Happy to take a stab at this if the team is open to contributions!
Summary
Add Discord as a new channel alongside the existing Telegram and Slack integrations. The current architecture already anticipates Discord —
types.tsreferences Discord in both theacknowledgemethod comment (line 19: "Discord: typing indicator") and theDestinationinterface (line 52: "Discord thread"), so this would be a natural next step.Motivation
Discord is one of the most widely used community/team platforms, especially in developer and AI communities. Adding it as a channel would significantly expand Utah's reach and make it usable in many more contexts.
Proposed implementation
The channel-agnostic design of the agent loop, reply dispatch, and acknowledgment means no changes are needed outside
src/channels/(except registering the handler inindex.ts).New files to create in
src/channels/discord/api.tsPOST /channels/{id}/messages) and typing indicators (POST /channels/{id}/typing). Could use@discordjs/restor raw fetch.handler.tsChannelHandlerwithsendReply,acknowledge, andsetuptransform.tsAgentMessageData— e.g.d.channel_id→chatId,d.author.id→senderId,d.content→textsetup.tsformat.tsFile to modify
src/channels/index.ts— register the newDiscordHandlerin the channel registryEnvironment variables
Discord-specific considerations
Signature verification (Ed25519): Discord requires verifying
X-Signature-Ed25519andX-Signature-Timestampheaders on every incoming webhook request. This is stricter than Telegram and should be handled in the transform or a middleware layer.Interaction acknowledgment: Discord's Interactions Endpoint requires responding to
PINGevents with an immediatePONG, which needs handling in the transform or an edge function.Message length limit: Discord caps messages at 2000 characters, so
format.tsneeds chunking logic for longer agent replies.Bot vs. Webhook approach: A bot-based approach (connecting to the Gateway) is more flexible for receiving messages than a pure webhook setup. Worth deciding which path to take.
Estimated effort
For a TypeScript dev familiar with Discord's API, roughly half a day to a full day of work. The hardest part is the Ed25519 signature verification and interaction acknowledgment — the rest maps cleanly onto the existing channel abstractions.
Happy to take a stab at this if the team is open to contributions!