Skip to content

Add Discord as a communication provider#268

Open
mrubens wants to merge 30 commits into
developfrom
codex/discord-communication-provider
Open

Add Discord as a communication provider#268
mrubens wants to merge 30 commits into
developfrom
codex/discord-communication-provider

Conversation

@mrubens

@mrubens mrubens commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add Discord as a first-class communication provider across onboarding, settings, account linking, task entry, follow-ups, attachments, reactions, and completion notifications
  • run the Discord Gateway as a lazy, opt-in subsystem inside the existing BullMQ process: no extra container, process, port, or deployment-template service; Redis still provides leader handoff, resumable sessions, durable delivery, and bounded backpressure
  • launch server-channel tasks in their own Discord thread or forum post, with shared title generation and snapshot resume
  • deliver onboarding setup work, suggestions, and their follow-up to the linked setup user's DM; expose a default-channel picker in settings so proactive posts (automation suggestions, reports) have a configurable destination
  • register /new, /link, and /help, add task controls, and keep guild traffic limited to mentions or bot-owned task threads
  • add diagnostics, database migrations, public docs, a mock Discord API + Gateway-stand-in harness, LLM-judged eval scenarios, a mock-discord-testing skill, and broad regression coverage

Update (2026-07-15): rebased onto develop + Telegram feature parity

The branch was brought up to date with develop (85 commits, including the communication-adapter refactors, the collapsed PR terminal-status notifier, oxfmt/oxlint, and drizzle migration 0010), and Discord was audited feature-by-feature against Telegram, the most complete chat surface, with every gap closed.

Merge adaptations

  • Discord registered in getCommunicationProviderAdapter via a new createDiscordCommunicationProviderFromRuntimeCredentials sdk helper; MCP thread replies, PR review notifications, and the collapsed notifyPullRequestTerminalStatus notifier all reach Discord through it (replacing the pre-merge notifyDiscordPrMerge path)
  • automation destination waterfall (listConnectedCommunicationProviders, resolveAutomationRuntimeDestination, prompt context) extended to Discord, and the six Teams/Telegram-capable background automations now also declare Discord support
  • Discord setup-completion chat notification dropped to match [Improve] Stop sending setup-complete messages that push users to /setup #324 (env setup is non-blocking on develop)
  • Discord schema migration regenerated as 0011 after develop shipped its own 0010

Feature matrix: Discord vs Telegram

Capability Telegram Discord
Inbound
Task entry from DM
Task entry from group/guild (mention-gated)
Follow-ups queued to the active run
New-task command (/new)
Help/welcome command (/start · /help)
Account linking + link codes (/start <code> · /link) ✅ (DM-verified)
Unlinked-sender gating + link nudge
Attachments (images + text documents, size-capped)
Exactly-once inbound dedup (Redis)
Routing confirmation with workspace picker buttons
Cancel-task button
Snapshot resume after completion
Webhook/event authentication ✅ secret header ✅ gateway secret
Outbound
Markdown replies with chunking (4096 / 2000 chars)
Per-task threads (forum topics / threads + forum posts)
Early-title thread rename
Ack reactions (👀) + reaction tool
Typing indicator across reply delivery (added)
Image delivery
Reply anchored to the conversation (quote latest inbound / dedicated task thread)
API base-URL override for testing
Worker tools
send_chat_reply
send_chat_reaction_emoji
Surface-generic post_to_channel (Slack tool suppressed) (added)
Suggestions & onboarding
Setup suggestions with Start buttons
Automation suggestions to default destination
Onboarding follow-up reminder job
Proactive destination (primary chat / default channel) ✅ auto-captured ✅ + settings picker (added)
Automations
Automation work-item launch targets
Destination waterfall + connected-provider listing (added)
Announcer / manager-stats / triage / auditor delivery (added)
Lifecycle notifications
PR terminal status (merged/closed) to linked threads (added)
PR review notifications (idle-gated)
Task failure notification ❌ (pre-existing gap)
PR permalink stamping in workflow
Web UI
Onboarding setup step
Settings provider section + status diagnostics
Account link/unlink UI + hooks
Repair action
Config & persistence
Runtime credentials (env > saved settings, cached)
DB tables + migrations ✅ (0011)
Dev tooling & docs
Mock API harness with /mock/state + /mock/events (added)
Harness runner script + example scenario (added)
LLM-judged eval scenarios + runner (added)
Agent skill (mock-*-testing) (added)
Public docs page

Notes:

  • Telegram's missing task-failure notification is a pre-existing Telegram gap (Discord already covers it); left for a separate change.
  • Forum/media channels that require a tag remain explicitly unsupported (DISCORD_REQUIRED_TAG_FORUM_ERROR), documented behavior.

Reliability and security

  • stay dormant until a Discord token is saved, connect automatically without a restart, and disconnect when Discord is removed
  • persist Gateway resume state and inbound events before acknowledgement
  • make task/thread creation and follow-up delivery idempotent across retries
  • retain events indefinitely during Discord/API infrastructure failures while acknowledging inaccessible resources
  • disable broad mentions, validate attachment limits and forum capabilities, scope cancellation to linked participants, and keep Discord credentials out of task sandboxes

Validation

  • full pre-push gate green: pnpm format:check, oxlint --deny-warnings, residual ESLint (includes a small oxlint/ESLint suppression reconciliation in apps/worker that also fails on origin/develop today), pnpm check-types (26/26), full uncached Vitest suite (26/26 workspaces), pnpm knip (clean)
  • new/updated tests: PR terminal-status Discord fan-out, PR-review Discord adapter route, MCP Discord thread replies with typing, DiscordSetupStatus default-channel picker

@roomote-roomote

roomote-roomote Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

No code issues found. See task

  • apps/docs/providers/communications/discord.mdx:117 — Resolved in 4e4f7ec. The "Verify setup" flow no longer tells operators to select a server and default channel and confirm a permission check; line 12 now says Roomote sends onboarding work to the linked setup user's direct messages, and line 41 replaces "Roomote checks the selected destination for:" with server-task permission guidance. The docs now match the DM-based onboarding behavior.
  • packages/communication/src/discord-provider.ts:1012-1023diagnoseChannelPermissions double-applied the @everyone channel overwrite. Fixed in bdcbfae by excluding overwrite.id === input.guildId from the roleOverwrites filter (lines 1012-1017), so @everyone is now applied only in its dedicated step and no longer OR'd back in during member-role aggregation. A regression test where @everyone allows Send Messages but a member role denies it now correctly reports canUseChannel: false.
  • apps/api/src/handlers/discord/callback-actions.ts:193 — Resolved in 2838738. Direct-message suggestion cards now use their DM channel as the launch target, so the Start action launches a task instead of rejecting the card for lacking parentChannelId.
  • apps/api/src/handlers/tasks/automation-work-items/launch.ts:378 — Resolved in ca5171e. New scans now load reopened fingerprint duplicates without a linked task and include them in the launch set, so transient Discord preparation failures can be retried.
  • apps/api/src/handlers/mcp/communication-channel-posts.ts:234 — Resolved in 2838738. Discord now rejects a caller-provided threadTs unless it is the task's stored thread or launch channel, and posts always use the stored task thread rather than the requested value.
  • apps/api/src/handlers/tasks/__tests__/submitAutomationWorkItems.lifecycle.test.ts:76-80 — Resolved in 5717264. The persistence mock now exports loadRelaunchableDuplicateWorkItems, returning no duplicates for these lifecycle cases; the focused suite passes all 9 tests.

Reviewed 5717264

Comment thread apps/discord-gateway/src/config.ts Fixed
@mrubens

mrubens commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the remaining permission-resolution feedback in bdcbfae. The @everyone overwrite is now applied only in its dedicated step and excluded from member-role aggregation. Added a regression case where @everyone allows Send Messages but the bot role denies it; diagnostics now correctly report the channel unusable. Focused provider tests, lint, types, and pre-push checks pass.

@mrubens

mrubens commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the remaining docs feedback in 4e4f7ec: removed the retired default-destination instructions, clarified the server permissions as task-entry requirements, and updated Gateway troubleshooting for the embedded BullMQ runtime. Also added linked-user DM delivery for the setup task, suggestions, and follow-up in a28f16e. Full pnpm check and the Mintlify validation/broken-link check pass.

@mrubens

mrubens commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Updated the Discord linking flow in bcf72d3: /link is now explicitly performed in a DM with the bot, with guidance to enable Direct Messages in the server privacy settings if Discord blocks it. Public docs and the component regression test were updated; focused test, docs validation, lint, types, and pre-push checks pass.

mrubens added 13 commits July 13, 2026 02:18
Adapts the Discord provider to refactors that landed on develop since the
PR was opened:
- PR terminal-status notifications now go through the collapsed
  notifyPullRequestTerminalStatus notifier (Discord delivery to be wired
  into it) instead of per-provider notifyDiscordPrMerge
- PR review notifications go through getCommunicationProviderAdapter;
  registered a discord adapter backed by resolveDiscordRuntimeCredentials
- MCP thread replies build the Discord provider via the new sdk helper
  createDiscordCommunicationProviderFromRuntimeCredentials
- Setup flow rebased onto the new bootstrap/setup page structure
- Dropped the PR's 0010 drizzle migration (develop also shipped an 0010);
  the Discord migration will be regenerated as 0011
- Register Discord in the automation destination waterfall (connected
  providers list, primary-conversation fallback via the default Discord
  destination, prompt surface label) and in the six automations that
  already support Teams/Telegram
- Add discord/discord_channel to the background-automation provider and
  target-kind unions
- Drop the Discord setup-completion notification: develop removed that
  pattern for all surfaces in #324 (env setup is non-blocking now)
- Remove merge-duplicated CornerDownRight mock and stale import
Fans Discord targets out through the collapsed
notifyPullRequestTerminalStatus notifier via the shared communication
adapter, replacing the pre-merge notifyDiscordPrMerge path.
- Worker tasks launched from Discord now get the surface-generic
  post_to_channel tool (with a Discord channel-post path on the API MCP
  endpoint) instead of the Slack-labeled post tool
- Show a typing indicator across Discord thread-reply delivery,
  mirroring the Telegram typing heartbeat
- Add a default-channel picker to the Discord settings/setup status card
  so the proactive destination (automation suggestions, reports) is
  configurable from the UI; the backing endpoints already existed
- Ship a mock-discord-testing skill plus a runnable harness: mock server
  control endpoints (/mock/state, /mock/events acting as the Gateway),
  run-mock-discord script with example scenario, and LLM-judged eval
  scenarios with an eval:discord-scenario runner
mrubens added 3 commits July 15, 2026 03:14
oxlint enforces @typescript-eslint/no-require-imports and no-explicit-any
here while residual ESLint does not, so eslint-disable comments trip
ESLint's unused-directive check. Use oxlint-disable comments, which
ESLint ignores, so both linters pass.
- DM-delivered setup suggestion cards: the Start button launched only
  from guild threads and threw for DMs, releasing the claim and making
  every DM card unusable. DM cards now launch the task in the DM
  conversation itself, matching direct-message task entry.
- Automation work-item launches: transient Discord failures (429/5xx/
  network) while preparing the task thread reopen the work item under
  its claim instead of terminally failing it, so the retry resumes in
  the persisted thread. Permanent failures stay terminal.
- Discord channel posts: a caller-provided threadTs redirected the post
  to any bot-accessible thread. Only the task's own stored thread (or
  its launch channel) is accepted; anything else is rejected with 403.
@mrubens

mrubens commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the three outstanding review findings in 2838738:

  • DM setup-suggestion Start button (callback-actions.ts): DM-delivered cards no longer throw on Start. Guild cards still launch in the parent channel so the task gets its own thread; DM cards launch in the DM conversation itself, matching direct-message task entry. Regression test covers the DM path end to end.
  • Work-item launch retry (automation-work-items/launch.ts): transient Discord failures (429/5xx/network) while preparing the task thread now reopen the work item under its claim instead of terminally failing it, so the retry resumes in the persisted thread. Permanent failures (permissions, deleted channel) stay terminal. Tests cover both classifications and the reopen write.
  • Discord channel-post thread scoping (communication-channel-posts.ts): a caller-provided threadTs is only accepted when it names the task's own stored thread or launch channel; anything else returns 403 instead of redirecting the post. Tests cover the hijack rejection and the own-thread accept.

Focused suites (28 files / 223 tests across the Discord, MCP, and work-item handlers), typecheck, lint, and the full pre-push gate pass.

mrubens added 3 commits July 15, 2026 06:55
Develop's #375 expanded CI failure triage to Teams/Telegram manager
destinations without updating the capability-badge test, which only
runs on merge refs here. The triage runner is destination-generic, so
declare Discord support too (matching the other multi-provider
automations), teach the triage prompt the Discord surface label, and
update the badge and registry test expectations.
A transient launch failure reopens the work item, but the reopened row
also blocks re-insertion as an active fingerprint duplicate, so nothing
ever launched it again. Scans now load fingerprint-duplicate rows that
are still open (or stale-launching) with no linked task and include
them in the launch set; the claim CAS keeps concurrent launchers safe.
@mrubens

mrubens commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the remaining stranded-work-item finding in ca5171e. Reopening on a transient failure wasn't enough on its own: the reopened row blocks re-insertion as an active fingerprint duplicate, so no later scan would launch it. submitAutoActWorkItems now loads fingerprint-duplicate rows that are still open (or stale-launching) with no linked task and includes them in the launch set, so the next scan that reports the same finding relaunches the stranded item; the existing claim CAS keeps concurrent launchers safe. Real-DB coverage exercises the relaunchable filter (open/stale-launching picked up; launched, failed, and suggestion rows skipped). Focused suites, typecheck, and the full pre-push gate pass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants