Skip to content

Discord user-proxy frontend for private-channel real-time chat/notifications #295

@rockfordlhotka

Description

@rockfordlhotka

Summary

Add a Discord IUserFrontend implementation so RockBot can push real-time notifications to the user (and accept replies) via a Discord bot, initially scoped to a private channel with a single trusted user — i.e. just you and rockbot.

This gives us push-to-mobile notifications (which email-to-self doesn't, for most people's phones) without building a full multi-tenant auth layer.

Motivation

Currently the agent has no way to proactively alert the user in real time. Email-from-self works but isn't a great push/alert channel. Discord bots support mobile push natively, and the existing UserProxy / IUserFrontend abstraction is the right seam to plug into — we already have CLI (Spectre) and Blazor frontends, Discord is a third.

Design

New projects:

  • src/RockBot.UserProxy.Discord/ — implements IUserFrontend
    • Owns the Discord gateway connection and bot token (single point of Discord credential/library exposure)
    • Outbound: receives AgentReply from UserProxyService, posts to the configured channel
    • Inbound: receives user messages from the configured channel, forwards to UserProxyService as user input
  • src/RockBot.UserProxy.Discord.Host/ (or merge into Discord project) — hostable entry point, mirrors the CLI/Blazor hosts

Configuration (UserProxyOptions or a Discord-specific options type)

  • BotToken — via user-secrets locally, Kubernetes Secret in deployment
  • GuildId + ChannelId — restrict the bot to a single server + channel
  • AuthorizedUserId — Discord user ID allowed to interact; all other authors are ignored

Least-privilege / "nothing trusts the LLM"

  • Only this process has the Discord token and a Discord library dependency
  • Messages from any Discord user other than AuthorizedUserId are dropped before they hit the bus
  • Even in private-channel mode, outbound events carry source: discord + principal: <discord-user-id> so we don't have to rework the bus contract when/if we add shared-channel support later
  • If the Discord frontend crashes or is compromised, blast radius is one process and one credential

Deployment

  • New Helm subchart or deployment in deploy/helm/rockbot/ — runs as its own pod alongside the agent, similar to how Blazor frontend is deployed
  • New Dockerfile: deploy/Dockerfile.userproxy-discord

Out of scope (future issues)

  • Shared/public channels — requires per-principal identity mapping, ACLs, rate limiting, denial-of-wallet protection, context isolation. File separately when we actually want it.
  • Signal frontend — Signal has no official bot API; signal-cli is unofficial and fragile. Separate investigation if ever needed.
  • Rich Discord features — slash commands, threads, reactions, role management. Start with plain message send/receive.

Acceptance criteria

  • New RockBot.UserProxy.Discord project implementing IUserFrontend
  • Bot posts agent replies to the configured channel and receives user messages back
  • Messages from unauthorized Discord user IDs are dropped (never reach the bus)
  • Outbound bus events tagged with source + principal metadata, even in single-user mode
  • Unit tests for the frontend (mocking the Discord client)
  • Dockerfile + Helm wiring for deployment
  • README documenting bot creation / invite flow / required Discord permissions / secret configuration

Open questions

  • Which Discord .NET library — Discord.Net, DSharpPlus, or just the REST+gateway API directly for a minimal surface?
  • Gateway connection (supports inbound events) vs. webhook-only (outbound alerts only, much simpler). The full bidirectional experience wants the gateway; a webhook-only "alerts" mode might be a useful stepping stone.
  • Should this and a future Signal/Slack/etc. frontend share a "chat-transport" abstraction, or is IUserFrontend already that abstraction?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions