A self-hosted chat bridge that connects Discord and Slack to Claude Code via MCP Channel plugins. Runs on your Claude Max subscription — no API key required.
Claude Code ships with a built-in Channels plugin — but CLI-native commands like /compact and /clear simply don't work through it. They need to be typed directly into the interactive terminal, and MCP servers have no way to do that.
This project started as a fix for that one problem: a wrapper that owns the Claude Code process and can forward PTY commands on your behalf. It then grew into a full-featured bridge with multi-platform support, session management, and more.
| Official Plugin | This Project | |
|---|---|---|
| Platforms | Discord only | Discord + Slack (simultaneous) |
| Session | Ephemeral (new context per invocation) | Persistent (always-on, shared across platforms) |
| Session control | None | /new, /clear, /compact |
| Model switching | Manual restart | /model sonnet (auto-restart) |
| Working directory | Fixed at launch | /cwd /path (auto-restart) |
| Screen capture | N/A | /capture (virtual terminal buffer) |
| System prompt | Not configurable | Custom file injection (--append-system-prompt) |
| Message customization | N/A | All bot messages overridable via JSON |
| Auto-recovery | N/A | Auto-respawn on unexpected exit |
The official plugin is spawned by Claude Code as a child MCP server. This means:
- No PTY access — CLI commands (
/compact,/clear) can't be forwarded because there's no terminal to type into - No lifecycle control — when Claude Code stops, everything stops, and there's no way to restart from chat
- No state across restarts — switching models or working directories requires manually killing and restarting
Compact Bot solves this by inverting the relationship — a wrapper owns and controls the Claude Code process:
wrapper.ts (always-on)
├── Manages Claude Code lifecycle (spawn / kill / respawn)
├── Virtual terminal buffer (@xterm/headless) for screen capture
├── IPC socket for bidirectional control
└── Claude Code (node-pty)
├── Discord MCP server
└── Slack MCP server
The wrapper can restart Claude Code on command (/new, /model), forward CLI commands (/compact, /clear), and auto-respawn on crashes — all without losing the chat connection.
- Multi-platform — Discord and Slack run as independent MCP servers, conditionally enabled by token
- Shared session — Both platforms share the same Claude Code context
- Attachments — Upload images/files; Claude downloads them via
download_attachmenttool - Reply context — Discord message references and Slack threads are preserved
- MCP tools —
reply,react,edit_message,fetch_messages,download_attachment - Customizable messages — Override any bot message via
data/messages.json - Custom system prompt — Append instructions via
SYSTEM_PROMPT_PATH
- Node.js >= 20
- Claude Code CLI installed and authenticated (
claude --version) - Claude Max subscription (logged in via
claude login) - Build tools —
build-essential/python3fornode-ptycompilation - At least one of: Discord Bot Token or Slack Bot Token
npx @serin511/compact-bot init # interactive setup → ~/.config/compact-bot/.env
npx @serin511/compact-bot # run from anywheregit clone https://github.com/Serin511/Compact-Bot.git
cd Compact-Bot
npm install
cp .env.example .env # edit with your tokens
npm run build
npm start- Go to Discord Developer Portal → New Application
- Bot → Enable all Privileged Gateway Intents:
- Presence Intent
- Server Members Intent
- Message Content Intent (required)
- Copy the bot token → paste into
.envasDISCORD_BOT_TOKEN - OAuth2 → URL Generator → Scopes:
bot→ Permissions:- Send Messages / Send Messages in Threads
- Read Message History
- Attach Files / Add Reactions
- Open the generated URL to invite the bot to your server
- Go to Slack API → Create New App → From scratch
- Socket Mode → Enable → Create App-Level Token (
connections:write) → copyxapp-...token - OAuth & Permissions → Add Bot Token Scopes:
channels:history,channels:read,groups:history,groups:readim:history,im:read,im:write,mpim:history,mpim:readchat:write,files:read,files:write,reactions:write,users:read
- Install to Workspace → copy Bot User OAuth Token (
xoxb-...) - Event Subscriptions → Enable → Subscribe to bot events:
message.channels,message.groups,message.im,message.mpim
- App Home → Enable Messages Tab and allow messages from users
- Paste tokens into
.envasSLACK_BOT_TOKENandSLACK_APP_TOKEN - Invite the bot to channels:
/invite @botname
# Platform tokens (at least one required)
DISCORD_BOT_TOKEN=
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-...
# Optional
# DEFAULT_MODEL=claude-sonnet-4-6 # empty = CLI default
# DEFAULT_CWD=~/projects # empty = current directory
MAX_TURNS=50 # 0 = unlimited
ALLOWED_CHANNEL_IDS= # comma-separated, empty = all
SLACK_ALLOWED_CHANNEL_IDS=
# CLAUDE_PATH=claude # defaults to "claude" from PATH
# DANGEROUSLY_SKIP_PERMISSIONS=true # pass --dangerously-skip-permissions
SYSTEM_PROMPT_PATH=data/system-prompt.txt
VERBOSE=falseAll commands work from both Discord and Slack.
| Command | Description |
|---|---|
/new |
Start a fresh session (kills and respawns Claude Code) |
/clear |
Clear current context (forwarded to CLI) |
/compact [hint] |
Compress context with optional focus hint |
/model <name> |
Switch model — sonnet, opus, haiku, or full model ID |
/cwd <path> |
Change Claude Code's working directory |
/capture |
Capture the current CLI screen as a code block |
/help |
Show available commands |
Any other message is forwarded to Claude as a channel notification.
Claude Code requires an interactive PTY, so use tmux or screen:
tmux new-session -d -s claude-bot 'npm start'
# Attach to view logs
tmux attach -t claude-botCreate data/messages.json to override any bot message:
{
"newSession": "Starting fresh session...",
"captureRequested": "Capturing screen..."
}See src/messages.ts for all available keys and template variables.
Create a text file and point SYSTEM_PROMPT_PATH to it:
echo "Always respond in English. Be concise." > data/system-prompt.txtThe content is injected via --append-system-prompt when Claude Code starts.
Bot doesn't respond to messages
- Verify Message Content Intent is enabled (Discord Developer Portal → Bot)
- Check
ALLOWED_CHANNEL_IDS— empty means all channels - Ensure the bot has read/write permissions in the channel
Claude CLI auth error
claude auth status
claude loginnode-pty build fails
sudo apt install build-essential python3
npm rebuild node-ptySession feels stuck
- Send
/newto hard-restart Claude Code - Send
/clearto reset context without restarting
MIT