Skip to content

feat: Slack and Discord service integrations#24

Open
joshupadhyay wants to merge 4 commits intohdresearch:mainfrom
joshupadhyay:slack-and-discord-integration
Open

feat: Slack and Discord service integrations#24
joshupadhyay wants to merge 4 commits intohdresearch:mainfrom
joshupadhyay:slack-and-discord-integration

Conversation

@joshupadhyay
Copy link
Copy Markdown

@joshupadhyay joshupadhyay commented Mar 27, 2026

Summary

Adds Slack and Discord as reef service modules — bidirectional messaging, proactive event notifications, and a centralized notifications architecture.

Currently, this creates a new chat in 'reef' for each thread you have with the bot. The bot will start a thread to each message (not each channel). This way, the context from the thread is passed cleanly via a thread id.

@Claude works slightly differently:

Claude Code pulls information contextually, which we can totally adjust to. I just found this as a better MVP. In this implementation, each thread becomes a new chat in the reef. That way the context for the chat -> is the thread.

usage:

message the reef about discord / slack
use the invite code, add the bot
tag the bot @username!
to continue conversations with a certain context, start a thread and keep replying.

  • Discord: Gateway WebSocket for receiving @mentions and DMs, reaction acknowledgment (👀→✅/❌), conversation persistence per channel
  • Slack: Socket Mode for receiving @mentions and DMs, reaction acknowledgment (eyes→check/x), threaded replies, conversation persistence per channel
  • Notifications service: Centralized event filtering and push — subscribes to reef events, applies heuristic (skip <30s tasks, skip bot-originated, always notify errors), emits to all channels
  • Shared modules: services/shared/messaging.ts (reef submit, event bus wait, tag stripping, message splitting) and services/shared/config.ts (cached vers-config resolution, shared across all services)
  • Event bus architecture: Task completion waiting uses the in-process ServiceEventBus instead of HTTP polling — zero network overhead, no timeout, instant notification

What works today

  • Discord bot receives messages via Gateway, submits to reef, replies with full output
  • Slack bot receives messages via Socket Mode, submits to reef, replies in-thread
  • Both bots acknowledge receipt with emoji reactions, swap to ✅/❌ on completion
  • Messages in the same channel continue the same reef conversation (context preserved)
  • Smart notification filtering: only notifies for tasks >30s, errors, or file changes
  • Notification channel configurable per platform via tools or API
  • Bot token resolution: env var (provision time) → vers-config store (runtime)
  • No polling — uses ServiceEventBus for task completion (was 240 HTTP requests per message, now 0)
  • No timeout — tasks wait as long as they take (reef guarantees task_done/task_error on every task)

What still needs to be done

Official Vers bots

Currently uses BYO tokens — each user creates their own Discord app / Slack app. The target state:

  • Discord: Vers creates one bot. Users click an invite link to add it. Token injected at provision time. GET /discord/invite route exists with placeholder DISCORD_APP_ID.
  • Slack: Vers creates one Slack app with OAuth distribution. Users click "Add to Slack." Vers backend needs an OAuth callback endpoint (vers.sh/api/slack/oauth/callback) to store per-workspace tokens.

See DISCORD_INTEGRATION_PLAN.md for the full migration plan.

Slack reactions

Slack reactions (👀→✅/❌) require the reactions:write scope. Need to add to required scopes and verify.

Reef agent instructions

When a user asks for Discord or Slack integration, the reef agent should return an invite/install link for the official Vers bot instead of BYO-token instructions.

Architecture

ServiceEventBus (in-process, no network)
  → Notifications service (filter + format + batch)
    → notification:push event
      → Discord service (forward to channel)
      → Slack service (forward to channel)

Task completion flow (event bus, not polling):
  User messages bot
    → submit to reef
    → eventBus.on("reef:event", { taskId }) — waits for matching task_done
    → reef fires event when agent finishes
    → callback resolves instantly, reply posted

Discord Gateway ← WebSocket → reef
  User @mentions → 👀 react → submit to reef → wait → reply + ✅

Slack Socket Mode ← WebSocket → reef
  User @mentions/DMs → 👀 react → submit to reef → wait → reply in-thread + ✅

New files

File Description
services/discord/index.ts Discord service — Gateway, routes, tools, notification forwarding
services/discord/SETUP.md Setup guide for Discord integration
services/discord/DISCORD_BOT.md Notification heuristic (what to post vs skip)
services/discord/DISCORD_INTEGRATION_PLAN.md Official Vers bot migration plan
services/slack/index.ts Slack service — Socket Mode, routes, tools, notification forwarding
services/slack/SETUP.md Setup guide for Slack integration
services/notifications/index.ts Centralized notification service — event filtering, batching, history
services/notifications/SETUP.md Notifications service documentation
services/shared/messaging.ts Shared helpers — reef submit, event bus wait, tag stripping, message splitting
services/shared/config.ts Shared config — cached vers-config resolution, escapeHtml

Modified files

File Change
services/vers-config/index.ts Allowlist expanded for integration tokens and notification config
src/reef.ts Emit task_done/task_error on ServiceEventBus (was SSE-only) + enriched payloads with duration/trigger

Environment variables

Discord

Variable Required Description
DISCORD_BOT_TOKEN Yes Discord Bot Token
DISCORD_APP_ID No For invite link generation (placeholder until official bot)
DISCORD_NOTIFICATION_CHANNEL_ID No Channel for proactive notifications

Slack

Variable Required Description
SLACK_BOT_TOKEN Yes Bot User OAuth Token (xoxb-...)
SLACK_APP_TOKEN Yes (for receiving messages) App-Level Token with connections:write (xapp-...)
SLACK_NOTIFICATION_CHANNEL No Channel for proactive notifications

Notifications

Variable Description
NOTIFICATION_MUTE "true" to mute all notifications globally
NOTIFICATION_MIN_DURATION_MS Minimum task duration to notify (default: 30000)

Slack bot required scopes

chat:write, chat:write.public, channels:read, channels:history, im:history, im:read, im:write, app_mentions:read, reactions:read, reactions:write, users:read

Slack required event subscriptions

app_mention, message.im

Slack required settings

Socket Mode: ON, App Home > Chat Tab: ON, "Allow users to send Slash commands and messages from the chat tab": checked

🤖 Generated with Claude Code

joshupadhyay and others added 3 commits March 25, 2026 20:15
Extracted loadVersConfigOverride + cache into services/shared/config.ts.
All three services now share one config cache instead of three copies
(Slack had no cache at all — sync disk I/O on every call).

Also extracted resolveConfig() and escapeHtml() into shared module.

Fixes from code review:
- Fixed undefined isNotificationsMuted/reefAuthToken in Discord (crash)
- Fixed dead ternary in formatNotificationForDiscord (all branches identical)
- Fixed notification debounce (was resetting timer, deferring indefinitely)
- Added TTL expiry to externalTaskIds (memory leak on orphaned tasks)
- Replaced magic "hello" fallback with descriptive prompt
- Added SETUP.md documentation for Discord, Slack, and Notifications

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removed the HTTP polling loop (240 requests per message, 4-min
timeout) and replaced with a direct event bus listener. The
ServiceEventBus is required — no fallback polling path.

Reef guarantees every task emits task_done or task_error (even
on crash via child.on close), so no timeout is needed. Tasks
now wait as long as they take.

Also removed dead polling fallback code (~50 lines).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Discord:
- Real invite link with correct permissions (274877975616)
- reef_discord_setup tool returns invite link
- Each @mention gets its own reef conversation (discord-{channel}-{messageId})

Slack:
- Add to Slack link with all required scopes
- reef_slack_setup tool returns install link
- Thread-based conversations: each top-level @mention starts a new
  reef conversation, replies in thread continue it
- Bot always replies in-thread to keep channels clean

Both services: reef_*_configure demoted to BYO-token fallback,
reef_*_setup is the default path for users.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
"SLACK_NOTIFICATION_CHANNEL",
"SLACK_APP_TOKEN",
"DISCORD_APP_ID",
]);
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new ENV vars with varying notif levels, I'm sure we can pare these down but

@joshupadhyay joshupadhyay force-pushed the slack-and-discord-integration branch from 049913e to d0fa25b Compare March 30, 2026 15:23
@joshupadhyay joshupadhyay marked this pull request as ready for review March 30, 2026 20:20
@joshupadhyay joshupadhyay marked this pull request as draft March 30, 2026 20:32
…euristic

The invite routes and setup tools were comparing app IDs against hardcoded
defaults to determine if the bot was "configured", which always returned
false since the default IS the real Vers bot. Now checks actual token
validity and gateway/socket connection status, returning "already connected"
when the bot is live.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@joshupadhyay
Copy link
Copy Markdown
Author

Screenshot 2026-03-30 at 5 33 46 PM chat with bot, tells you about connected discord / slack

@joshupadhyay joshupadhyay marked this pull request as ready for review March 30, 2026 21:34
@joshupadhyay
Copy link
Copy Markdown
Author

joshupadhyay commented Mar 30, 2026

Screenshot 2026-03-30 at 5 35 18 PM uses threads exclusively, to ensure context is preserved. Will react to messages when tagged!

(it's not called test-bot anymore :) )

@joshupadhyay
Copy link
Copy Markdown
Author

Screenshot 2026-03-31 at 10 57 52 AM Screenshot 2026-03-31 at 10 59 06 AM

discord, slack bots look good as well.

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.

1 participant