@mosaicstack/discord-plugin
Official Discord channel adapter for Mosaic Stack.
Behavior
- Runs independently of the bound agent's Claude, Codex, Pi, OpenCode, or future harness.
- Routes authorized untagged messages in configured agent channels and replies in-channel.
- Creates a public Discord thread when the bot is mentioned in a parent channel, or reuses the thread already attached to that same message.
- Keeps follow-ups in existing threads without requiring repeated mentions.
- Keeps
/approveand/stop <approval>on the current durable session. - Applies guild, parent-channel, user, pairing, role, and per-minute abuse limits before thread creation or gateway dispatch.
- Authenticates to the gateway and signs ingress envelopes with the injected service token.
Required configuration
| Variable | Purpose |
|---|---|
DISCORD_BOT_TOKEN |
Discord bot credential |
DISCORD_SERVICE_TOKEN |
High-entropy plugin-to-gateway credential |
DISCORD_SERVICE_USER_ID |
Provisioned Mosaic service principal |
DISCORD_ALLOWED_GUILD_IDS |
Comma-separated guild allowlist |
DISCORD_ALLOWED_CHANNEL_IDS |
Comma-separated parent-channel allowlist |
DISCORD_ALLOWED_USER_IDS |
Comma-separated Discord user allowlist |
DISCORD_INTERACTION_BINDINGS |
JSON channel→logical-agent bindings and paired-user roles |
DISCORD_GATEWAY_URL |
Gateway base URL; defaults to the gateway's local development URL |
DISCORD_MESSAGE_RATE_LIMIT_PER_MINUTE |
Authorized turns per guild/channel/user per minute; default 30 |
DISCORD_THREAD_RATE_LIMIT_PER_MINUTE |
Mention-thread routes per guild/channel/user per minute; default 5 |
Supply credentials through the approved runtime secret mechanism. Never commit tokens or binding data containing secrets.
Example binding shape (identifiers are placeholders):
[
{
"instanceId": "interaction-agent",
"agentConfigId": "agent-config-id",
"guildId": "guild-id",
"channelId": "channel-id",
"pairedUsers": {
"discord-user-id": {
"role": "operator",
"mosaicUserId": "mosaic-user-id"
}
}
}
]
Each binding's trusted agentConfigId must identify a provisioned database agent configuration whose name exactly matches its instanceId. Roles are viewer, operator, and admin. viewer cannot send agent turns. Runtime approval and stop operations require an admin pairing with a provisioned mosaicUserId.
The bot needs Discord permissions to view/send messages in configured channels and create/send in public threads. A channel category is not an authorization boundary; threads inherit authorization only from their configured parent text channel.
Shared contract
The adapter implements OfficialChannelAdapter from @mosaicstack/types. ChannelConversationRouteDto carries only stable logical-agent/channel identity and a response target. Gateway durable-session and provider layers own runtime selection and handoff; Discord code must not import a harness SDK.
Development
pnpm --filter @mosaicstack/types build
pnpm --filter @mosaicstack/discord-plugin typecheck
pnpm --filter @mosaicstack/discord-plugin lint
pnpm --filter @mosaicstack/discord-plugin test
pnpm --filter @mosaicstack/discord-plugin build