Files
stack/plugins/discord
jason.woltje ba13c08890
Some checks failed
ci/woodpecker/push/ci-image Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/publish Pipeline was canceled
Fixes #756 (#763)
2026-07-14 20:26:15 +00:00
..
2026-07-14 20:26:15 +00:00
2026-07-14 20:26:15 +00:00
2026-07-14 20:26:15 +00:00
2026-07-14 20:26:15 +00:00

@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 /approve and /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