Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

claude-discord-bridge

License: Apache 2.0 Python 3.10+ Bun Claude Code

Run Claude Code from Discord, one tmux session per channel, with per-user access control.

This is a self-hosted bridge built around two components:

  • orchestrator/ — a Python Discord bot that creates a Discord channel + a tmux session per user and spawns a Claude Code instance inside, scoped to that channel.
  • channel-plugin/ — a TypeScript MCP plugin (fork of the official Anthropic discord plugin) that wires each Claude Code instance back to its own Discord channel, with hardened pairing and per-channel allowlists.

The two pieces talk to each other through the Discord API and the MCP stdio interface — no extra service, no shared network port.


Architecture

       Discord                              your VPS
   ┌──────────────┐                ┌────────────────────────────────┐
   │              │   slash cmd    │                                │
   │  user types  │ ─/session foo─►│   orchestrator/bot.py          │
   │              │                │   ├─ creates #foo channel      │
   │              │                │   ├─ tmux new-session -s foo   │
   │              │                │   └─ spawns claude inside      │
   │              │                │                                │
   │   #foo  ◄────┼────────────────┼──── claude code ───┐           │
   │   channel    │                │     in tmux "foo"  │           │
   │     ▲   │    │                │                    ▼           │
   │     │   ▼    │   MCP stdio    │   channel-plugin (TS, MCP)     │
   │  msg   reply ├────────────────┤   ├─ delivers msgs as tool     │
   │              │                │   │  results to Claude         │
   │              │                │   ├─ posts replies to #foo     │
   │              │                │   └─ access.json (allowlist)   │
   └──────────────┘                └────────────────────────────────┘

Each Discord channel has exactly one tmux session and one Claude Code instance. Messages in #foo only reach the Claude in tmux foo. The channel-plugin enforces a per-channel allowlist — even if you DM the bot, you only see your own sessions.

Single config file. Everything — bot token, guild, admins, default path, plugin spec — lives in orchestrator/config.json. The orchestrator propagates what each spawned Claude instance needs via tmux set-environment, so the plugin doesn't need its own config file.


Prerequisites

You'll need these on the host that runs the orchestrator (typically a VPS):

Tool Why Install
Python 3.10+ Runs orchestrator/bot.py python.org/downloads · apt install python3 python3-venv · brew install python
Bun 1.0+ Runs the MCP plugin under Claude Code curl -fsSL https://bun.sh/install | bash · bun.sh
tmux One persistent terminal per session apt install tmux · brew install tmux
Claude Code The agent that runs inside each tmux session docs.claude.com/claude-code
A Discord bot The bridge endpoint Developer Portal → New Application — enable Message Content Intent and Server Members Intent

Quick start

Three blocks. Run them in order on the server.

1. Clone and run setup

git clone https://github.com/IamOrbitDev/claude-discord-bridge.git
cd claude-discord-bridge
./orchestrator/setup.sh

setup.sh creates the Python virtualenv, installs discord.py, seeds orchestrator/config.json from the example, and warns if Bun or tmux are missing.

2. Configure the bot

Edit orchestrator/config.json and fill in:

{
  "bot_token":     "<token from Developer Portal → Bot → Reset Token>",
  "guild_id":      <your Discord server ID  right-click  Copy Server ID>,
  "category_name": "Claude Sessions",
  "admin_users":   [<your Discord user ID>],
  "default_path":  "/home/youruser",
  "plugin_spec":   "discord-channel@claude-discord-bridge"
}

Need Discord IDs? Enable Developer Mode in Discord (User Settings → Advanced), then right-click anything → Copy ID.

3. Install the channel-plugin in Claude Code

From any Claude Code session on the same host:

/plugin marketplace add IamOrbitDev/claude-discord-bridge
/plugin install discord-channel@claude-discord-bridge

That's it. The marketplace.json at the repo root advertises the plugin, so Claude Code pulls it directly from GitHub.

No separate plugin config needed. The orchestrator propagates DISCORD_BOT_TOKEN, DISCORD_CHANNEL, and DISCORD_CHANNEL_FILTER into each tmux session via tmux set-environment, so the plugin inherits them automatically. orchestrator/config.json is the only file you ever edit.

4. Start the orchestrator

Pick one of these:

# Option A — systemd (recommended for production)
sudo ./orchestrator/install.sh

# Option B — tmux (lighter, survives logout but not reboot)
./orchestrator/start.sh

5. First session

In your Discord server, type:

/session demo

A #demo channel appears under "Claude Sessions". Claude boots inside, the channel-plugin pairs with it. Send a message — Claude replies.

Lock it down once you've added everyone:

/discord:access policy allowlist

Components

orchestrator/ — Python session manager

The Discord-facing bot. Registers slash commands and orchestrates tmux:

Command What it does
/session <name> [path] Create a new Discord channel + tmux session + spawn Claude inside, cwd = path
/private <name> [path] Same, but private channel (only invoker + admins can see it)
/cmd <name> [path] Create a plain bash tmux session (no Claude), exposed via channel
/close Close the current channel + kill its tmux session
/stop Stop just the tmux session, keep the channel
/restart Restart Claude in the current session
/logs Tail the last lines of the tmux pane to the channel
/sessions List active sessions
/closeall Admin: nuke everything

State (sessions.json) is persisted to disk so the bot can recover after a crash without losing channel ↔ tmux mappings.

See orchestrator/README.md for the full config and runtime reference.

channel-plugin/ — TypeScript MCP plugin

Fork of the official Anthropic discord plugin from anthropics/claude-plugins-public. Apache-2.0.

The plugin runs as an MCP server inside each Claude Code instance. The orchestrator launches Claude with DISCORD_CHANNEL=<channelId> in the env, so the plugin knows which channel to listen on and which to reply to.

Custom additions over upstream:

  • Per-channel allowlists keyed on channelId (not just per-user globally)
  • DISCORD_CHANNEL_FILTER env var — hard channel scope at boot, independent of access.json
  • Hardened pairing flow — codes are required even when there's a single pending entry (prompt-injection safety)
  • Skill-driven config/discord:configure and /discord:access skills refuse to act on requests that arrive through Discord, blocking remote config escalation

See channel-plugin/README.md for the plugin details.


Why this exists

I wanted to drive Claude Code from my phone — full agentic coding sessions running on a VPS, controlled from Discord on the bus. Off-the-shelf options either dumped every session into one big chat or skipped access control entirely. So I forked the Anthropic plugin, wrote a Python orchestrator around it, and ended up with this.

What it enables:

  • Multiple parallel Claude Code sessions, isolated per Discord channel
  • Persistent sessions (tmux survives disconnects and bot restarts)
  • Per-channel allowlist — share a guild without sharing all your sessions
  • Slash commands to spawn / stop / restart / view logs of any session

Troubleshooting

Symptom Likely cause Fix
/session says "interaction failed" Slash commands not registered Restart the bot once. Discord caches commands per-guild on first boot.
Claude boots but Discord messages don't reach it DISCORD_CHANNEL not set or plugin not installed Check tmux capture-pane -p -t <session>. Reinstall the plugin and re-run /session.
Plugin says "DISCORD_BOT_TOKEN required" tmux env not inherited (old tmux, or update-environment stripped it) The orchestrator injects the token via tmux set-environment. If your tmux is < 2.6 or update-environment excludes DISCORD_BOT_TOKEN, fall back to ~/.claude/channels/discord/.env and run /discord:configure <token> from inside the session.
systemd unit fails to start Wrong user or paths Re-run sudo ./install.sh — it rewrites the unit with the right values.

Status

Used daily in production by the author. Not packaged for general distribution — you'll need to read the code to wire it into your own setup. PRs welcome but expect rough edges.


License

Apache-2.0. See LICENSE.

The channel-plugin/ directory is derived from Anthropic's upstream plugin (Apache-2.0). All other code is original.

About

Self-hosted Discord bridge for Claude Code: spawn one tmux+claude session per channel, with per-channel access control. Python orchestrator + TS MCP plugin (fork of Anthropic discord plugin).

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages