Skip to content

feat: Add Discord channel sidecar #3#9

Merged
willamhou merged 5 commits intoPrismer-AI:mainfrom
cugblbs:main
Apr 15, 2026
Merged

feat: Add Discord channel sidecar #3#9
willamhou merged 5 commits intoPrismer-AI:mainfrom
cugblbs:main

Conversation

@cugblbs
Copy link
Copy Markdown
Contributor

@cugblbs cugblbs commented Apr 7, 2026

What

Add a built-in Discord channel sidecar under cmd/channel-discord/ and align channel/IPC Bus socket paths to use /var/run/claw/bus.sock.

Why

Discord is a requested built-in integration, and issue #3 asks for a Discord sidecar that forwards messages between a Discord bot and the Claw runtime through the IPC Bus.

This PR also fixes a related socket-path mismatch that would prevent the new sidecar from connecting reliably in-cluster.

Fixes #3

How

  • Add cmd/channel-discord/ using github.com/bwmarrin/discordgo
  • Read bot credentials from DISCORD_TOKEN
  • Connect to the IPC Bus over UDS, using IPC_SOCKET_PATH when provided and defaulting to /var/run/claw/bus.sock
  • Forward inbound Discord messages to the runtime as normalized payloads (text, user, thread)
  • Forward runtime responses back to Discord, preferring:
    • explicit thread
    • explicit channel
    • configured default channel
    • last observed inbound channel
  • Add health checks and startup-path tests for the Discord sidecar
  • Add a Discord image build target and Dockerfile
  • Update built-in sidecar image mapping to include "discord"
  • Standardize the SDK default socket path and injected sidecar env vars to /var/run/claw/bus.sock

Checklist

  • Tests added/updated
  • make lint passes
  • make test passes

Type of Change

  • New feature

Copy link
Copy Markdown
Member

@willamhou willamhou left a comment

Choose a reason for hiding this comment

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

Thanks for the Discord sidecar implementation @cugblbs! The overall structure follows the existing Slack/Webhook sidecar patterns well, and the test coverage is solid. However, there are a few issues that need to be addressed:

Must Fix

  1. Unrelated socket path change should be a separate PR — This PR changes the SDK's defaultSocketPath in sdk/channel/options.go from /var/run/claw/ipc.sock to /var/run/claw/bus.sock. While the change itself is arguably correct (aligning with the IPC Bus's actual socket path), it's unrelated to the Discord feature and could break existing channel sidecar deployments that rely on the current SDK default.

    Please split this into a separate fix PR. The Discord sidecar can set IPC_SOCKET_PATH explicitly via environment variable injection (which the controller already does in claw_ipcbus.go:31), so it doesn't need to change the SDK default.

  2. CRD enum validation — Does this PR add "discord" to the ChannelType enum in api/v1alpha1/channel_types.go? If not, the CRD admission webhook will reject any ClawChannel with type: discord. Please verify and add:

    ChannelTypeDiscord ChannelType = "discord"

    Then run make manifests to regenerate the CRD YAML.

  3. builtinChannelImage() change — The current implementation uses a generic fmt.Sprintf pattern that automatically handles any channel type string:

    func builtinChannelImage(channelType clawv1alpha1.ChannelType) string {
        return fmt.Sprintf("ghcr.io/prismer-ai/claw-channel-%s:latest", string(channelType))
    }

    This already produces ghcr.io/prismer-ai/claw-channel-discord:latest for Discord. If you changed this to explicit switch/case, please ensure there's still a default fallback for custom channel types, or revert this change since it's unnecessary.

Should Fix

  1. New dependency audit — The PR adds github.com/bwmarrin/discordgo v0.28.1 which pulls in gorilla/websocket and golang.org/x/crypto. Please confirm:

    • Run go mod tidy to clean up
    • Check for known vulnerabilities: govulncheck ./...
  2. Bot token security — The DISCORD_TOKEN environment variable contains a sensitive bot token. Make sure the sidecar container's env var is injected via the channel's config field (secretRef) rather than plaintext in the ClawChannel spec. The existing Slack sidecar pattern should be followed here.

Nit

  1. Dockerfile base image — Using gcr.io/distroless/static-debian12:nonroot is good. Just make sure it matches the base images used by the other channel sidecars (Dockerfile.channel-slack, Dockerfile.channel-webhook) for consistency.

Please address items 1-3 and this will be ready for another round of review. Nice work on the test coverage!

@cugblbs
Copy link
Copy Markdown
Contributor Author

cugblbs commented Apr 10, 2026

@willamhou Thanks for the careful follow-up. I pushed an update and fully scoped the IPC/socket-path changes back out of the Discord PR.

Addressed items:

  • Reverted the unrelated shared socket-path changes:
    • restored sdk/channel's defaultSocketPath to /var/run/claw/ipc.sock
    • removed the extra IPC_SOCKET_PATH injection from buildChannelContainer()
    • restored injectIPCBusSidecar() to /var/run/claw
  • Reverted builtinChannelImage() back to the generic fmt.Sprintf(...) form so the default fallback behavior is preserved.
  • Rechecked the enum/CRD side: ChannelTypeDiscord and the generated CRD enum already include discord, so there was no missing CRD change to add for this PR.
  • Ran go mod tidy; no module diff.
  • DISCORD_TOKEN still follows the existing credentials.secretRef -> envFrom pattern, not plaintext config.
  • Dockerfile.channel-discord remains aligned with the existing Slack/Webhook sidecar base image pattern.

The Discord adapter no longer depends on changing any shared SDK/controller default. The only Discord-specific socket-path handling left is local to cmd/channel-discord, where it falls
back to /var/run/claw/bus.sock if IPC_SOCKET_PATH is unset.

I also added a small regression test around the SDK default socket path so this scope issue does not regress. Please take another look.

Copy link
Copy Markdown
Member

@willamhou willamhou left a comment

Choose a reason for hiding this comment

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

Great work — this is a high-quality PR. Architecture closely mirrors the Slack sidecar, tests are thorough (615 lines!), and the channel state tracker is a nice touch.

One issue to resolve before merge:

In sdk/channel/options_test.go, the default socket path is asserted as /var/run/claw/ipc.sock, but the rest of the codebase uses /var/run/claw/bus.sock (see cmd/ipcbus/main.go, cmd/channel-slack/main.go). Could you check if this introduces a path mismatch? If the channel SDK already defaults to ipc.sock, this test is correct but we may need a follow-up to align paths.

Minor suggestions (non-blocking):

  • The custom responseRecorder (lines 996-1027) can be replaced with httptest.NewRecorder() from stdlib
  • gorilla/websocket comes in as an indirect dep from discordgo — not an issue, just noting we now have two WS libs in go.sum

Otherwise LGTM. Will approve once the socket path question is clarified.

@cugblbs
Copy link
Copy Markdown
Contributor Author

cugblbs commented Apr 13, 2026

Good catch. This was a real mismatch rather than just a test issue. I updated sdk/channel to default to /var/run/claw/bus.sock and adjusted the corresponding test, so it now matches cmd/ipcbus and
the channel sidecars.

@cugblbs cugblbs requested a review from willamhou April 13, 2026 02:34
Copy link
Copy Markdown
Member

@willamhou willamhou left a comment

Choose a reason for hiding this comment

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

Socket path issue resolved — both the Discord sidecar and the SDK now default to /var/run/claw/bus.sock, consistent with the IPC bus. Thanks for the quick follow-up!

LGTM, merging.

@willamhou willamhou merged commit cb7d348 into Prismer-AI:main Apr 15, 2026
1 check passed
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.

[Good First Issue]: Add Discord channel sidecar

2 participants