Bridge AI agent CLIs to Discord for remote monitoring and control.
Derived from DoBuDevel/discord-agent-bridge. This project preserves original authorship and builds on top of the upstream work.
Discoding - run AI coding CLIs locally and relay them to Discord.
I built this after experimenting with OpenClaw. Even with full system permissions, I realized I preferred conversational control over full autonomy.
Instead of building another dashboard, I wired my AI CLI to Discord.
Discode runs your AI agent in tmux and simply relays output to Discord - no wrappers, no hidden execution layers, no cloud dependency.
- Local-first
- Relay-only architecture
- Persistent tmux sessions
- Single daemon managing multiple projects
- Multi-Agent Support: Works with Claude Code, Gemini CLI, and OpenCode
- Auto-Discovery: Automatically detects installed AI agents on your system
- Real-Time Streaming: Sends agent outputs to Discord/Slack through event hooks
- Project Isolation: Each project gets a dedicated Discord channel
- Single Daemon: One Discord bot connection manages all projects
- Session Management: Persistent tmux sessions survive disconnections
- Rich CLI: Intuitive commands for setup, control, and monitoring
- Type-Safe: Written in TypeScript with dependency injection pattern
- Well-Tested: 129 unit tests with Vitest
| Platform | Supported | Notes |
|---|---|---|
| macOS | Yes | Developed and tested |
| Linux | Expected | Should work (tmux-based), not yet tested |
| Windows (WSL) | Expected | Should work with tmux installed in WSL, not yet tested |
| Windows (native) | No | tmux is not available natively |
- Bun: Version 1.3 or higher
- tmux: Version 3.0 or higher
- Basic tmux proficiency (session/window/pane navigation, attach/detach) is recommended
- Discord Bot: Create a bot following the Discord Bot Setup Guide
- Required permissions: Send Messages, Manage Channels, Read Message History, Embed Links, Add Reactions
- Required intents: Guilds, GuildMessages, MessageContent, GuildMessageReactions
- Slack (optional): Use Slack instead of Discord by following the Slack Setup Guide
- AI Agent: At least one of:
npm install -g @siisee11/discode
bun add -g @siisee11/discodecurl -fsSL https://discode.chat/install | bashFallback:
curl -fsSL https://raw.githubusercontent.com/siisee11/discode/main/install | bashgit clone https://github.com/siisee11/discode.git
cd discode
bun install
bun run buildFor local runtime switching and development workflows, see DEVELOPMENT.md.
discode uninstallFull cleanup (remove config/state/logs and installed bridge plugins too):
discode uninstall --purge --yes# One-time onboarding
discode onboardThe onboard command prompts for your bot token, auto-detects the Discord server ID, lets you choose a default AI CLI, asks whether to enable OpenCode allow permission mode, and asks for telemetry opt-in. You can verify or change settings later:
discode config --show # View current configuration
discode config --server SERVER_ID # Change server ID manuallyNote:
onboardis required for initial configuration — it auto-detects the server ID by connecting to Discord. Theconfigcommand only updates individual values without auto-detection.
cd ~/projects/my-app
# Just run new — that's it!
discode newnew handles everything automatically: detects installed agents, starts the daemon, creates a Discord channel, launches the agent in tmux, and attaches you to the session.
discode new claude # Specify an agent explicitlyYour AI agent is now running in tmux, with output delivered to Discord/Slack in real time through hooks.
One-time onboarding: prompts for bot token, connects to Discord to auto-detect your server, lets you choose your default AI CLI, configures OpenCode permission mode, and asks telemetry opt-in.
discode onboard
# Optional for non-interactive shells
discode onboard --token YOUR_BOT_TOKENThe onboarding flow will:
- Save your bot token to
~/.discode/config.json - Connect to Discord and detect which server(s) your bot is in
- If the bot is in multiple servers, prompt you to select one
- Let you choose a default AI CLI for
discode new - Ask whether to set OpenCode permission mode to
allow - Warn that non-
allowmode may cause inconvenient approval prompts in Discord - Ask whether to enable anonymous CLI telemetry (opt-in)
Control the global daemon process.
discode daemon start # Start daemon
discode daemon stop # Stop daemon
discode daemon status # Check daemon statusList all registered projects.
discode listList available AI agents detected on your system.
discode agentsOpen interactive terminal UI. Use /new inside the TUI to create a new agent session.
discode tuiView or update global configuration.
discode config --show # Show current configuration
discode config --token NEW_TOKEN # Update bot token
discode config --server SERVER_ID # Set Discord server ID manually
discode config --port 18470 # Set hook server port
discode config --telemetry on # Enable anonymous CLI telemetry (opt-in)
discode config --telemetry-endpoint https://telemetry.discode.chat/v1/eventsRun these commands from your project directory.
Start the bridge server for registered projects.
discode start # Start all projects
discode start -p my-app # Start a specific project
discode start -p my-app --attach # Start and attach to tmuxStop a project: kills tmux session, deletes Discord channel, and removes project state. Defaults to current directory name if project is not specified.
discode stop # Stop current directory's project
discode stop my-app # Stop a specific project
discode stop --keep-channel # Keep Discord channel (only kill tmux)Show project status.
discode statusAttach to a project's tmux session. Defaults to current directory name if project is not specified.
discode attach # Attach to current directory's project
discode attach my-app # Attach to a specific projectPress Ctrl-b d to detach from tmux without stopping the agent.
Quick start: start daemon, set up project if needed, and attach to tmux. Auto-detects installed agents and creates the Discord channel automatically.
discode new # Auto-detect agent, setup & attach
discode new claude # Use a specific agent
discode new --no-attach # Start without attaching to tmux| Agent | Binary | Auto-Detect | Notes |
|---|---|---|---|
| Claude Code | claude |
Yes | Official Anthropic CLI |
| Gemini CLI | gemini |
Yes | Google Gemini CLI |
| OpenCode | opencode |
Yes | Open-source alternative |
Note: Codex support is temporarily removed and will be restored once Codex provides hook support. Tracking discussion: openai/codex#2150
The CLI automatically detects installed agents using command -v <binary>. Run discode agents to see available agents on your system.
Stored in ~/.discode/config.json:
{
"token": "YOUR_BOT_TOKEN",
"serverId": "YOUR_SERVER_ID",
"hookServerPort": 18470,
"telemetryEnabled": false
}| Key | Required | Description | Default |
|---|---|---|---|
token |
Yes | Discord bot token. Set via discode onboard or config --token |
- |
serverId |
Yes | Discord server (guild) ID. Auto-detected by onboard, or set via config --server |
- |
hookServerPort |
No | Port for the hook server | 18470 |
defaultAgentCli |
No | Default AI CLI used by discode new when agent is omitted |
First installed CLI |
telemetryEnabled |
No | Opt-in flag for anonymous CLI telemetry | false |
telemetryEndpoint |
No | HTTP endpoint for telemetry proxy (recommended: Cloudflare Worker) | https://telemetry.discode.chat/v1/events |
telemetryInstallId |
No | Anonymous per-install random ID used as GA client ID | Auto-generated on opt-in |
discode config --show # View current config
discode config --token NEW_TOKEN # Update bot token
discode config --server SERVER_ID # Set server ID manually
discode config --port 18470 # Set hook server port
discode config --telemetry on # Enable anonymous telemetry
discode config --telemetry-endpoint https://telemetry.discode.chat/v1/eventsProject state is stored in ~/.discode/state.json and managed automatically.
Config values can be overridden with environment variables:
| Variable | Required | Description | Default |
|---|---|---|---|
DISCORD_BOT_TOKEN |
Yes (if not in config.json) | Discord bot token | - |
DISCORD_GUILD_ID |
Yes (if not in config.json) | Discord server ID | - |
DISCORD_CHANNEL_ID |
No | Override default channel | Auto-created per project |
TMUX_SESSION_PREFIX |
No | Prefix for tmux session names | `` |
TMUX_SHARED_SESSION_NAME |
No | Shared tmux session name (without prefix) | bridge |
DISCODE_DEFAULT_AGENT_CLI |
No | Default AI CLI used by discode new when agent is omitted |
First installed CLI |
HOOK_SERVER_PORT |
No | Port for the hook server | 18470 |
DISCODE_TELEMETRY_ENABLED |
No | Enable telemetry without writing config (true/false) |
false |
DISCODE_TELEMETRY_ENDPOINT |
No | Telemetry proxy endpoint URL | - |
DISCODE_TELEMETRY_INSTALL_ID |
No | Override anonymous install ID | - |
DISCORD_BOT_TOKEN=token discode daemon start
DISCORD_GUILD_ID=server_id discode newDeploy Cloudflare Worker proxy:
npm run telemetry:deploy
npm run telemetry:secretCLI telemetry defaults to https://telemetry.discode.chat/v1/events.
To override it with your own deployed Worker URL:
discode config --telemetry-endpoint https://discode-telemetry-proxy.<your-subdomain>.workers.dev
discode config --telemetry onWorker source: workers/telemetry-proxy
Architecture overview: ARCHITECTURE.md Module boundaries: docs/MODULE_BOUNDARIES.md Documentation maps: docs/DESIGN.md, docs/PRODUCT_SENSE.md, docs/PLANS.md
bun install
bun run build # Compile TypeScript
bun run dev # Dev modenpm run build:release # Build CLI/daemon/sidecar/runtime-client binaries + npm meta package
npm run build:release:binaries:single # Build only current OS/arch binary
npm run pack:release # Create npm tarballs in dist/releasebun test # Run all tests
bun run test:watch # Watch mode
bun run test:coverage # Coverage reportTest suite includes 129 tests covering:
- Agent adapters
- State management
- Discord client
- Hook-based event delivery
- CLI commands
- Storage and execution mocks
discode/
├── bin/ # CLI entry point (discode)
├── src/
│ ├── agents/ # Agent adapters (Claude, Gemini, OpenCode)
│ ├── capture/ # shared message parsing utilities
│ ├── config/ # Configuration management
│ ├── discord/ # Discord client and message handlers
│ ├── infra/ # Infrastructure (storage, shell, environment)
│ ├── state/ # Project state management
│ ├── tmux/ # tmux session management
│ └── types/ # TypeScript interfaces
├── tests/ # Vitest test suite
├── package.json
└── tsconfig.json
The codebase uses constructor injection with interfaces for testability:
// Interfaces
interface IStorage { readFile, writeFile, exists, unlink, mkdirp, chmod }
interface ICommandExecutor { exec, execVoid }
interface IEnvironment { get, homedir, platform }
// Usage
class DaemonManager {
constructor(
private storage: IStorage = new FileStorage(),
private executor: ICommandExecutor = new ShellCommandExecutor()
) {}
}
// Testing
const mockStorage = new MockStorage();
const daemon = new DaemonManager(mockStorage);- TypeScript strict mode enabled
- ESM modules with
.jsextensions in imports - Vitest with 129 passing tests
- No unused locals/parameters (enforced by
tsconfig.json)
- Verify token:
discode config --show - Check bot permissions in Discord Developer Portal
- Ensure MessageContent intent is enabled
- Restart daemon:
discode daemon stop && discode daemon start
- Run
discode agentsto see available agents - Verify agent binary is in PATH:
which claude - Install missing agent and retry
- Check session exists:
tmux ls - Kill stale session:
tmux kill-session -t <session-name> - Restart project:
discode stop && discode start
- Check daemon status:
discode daemon status - Check daemon logs
- Check Discord channel permissions (bot needs Send Messages)
If you want Discode to keep working when the laptop lid is closed on battery power, run:
sudo pmset -b disablesleep 1To revert to normal sleep behavior:
sudo pmset -b disablesleep 0Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Add tests for new features
- Maintain TypeScript strict mode compliance
- Follow existing code style
- Update documentation as needed
MIT License - see LICENSE file for details.
- Built with Discord.js
- Powered by Claude Code, Gemini CLI, and OpenCode
- Inspired by OpenClaw's messenger-based command system. The motivation was to remotely control and monitor long-running AI agent tasks from anywhere via Discord.
- Issues: GitHub Issues
- Discord Bot Setup: Setup Guide
- Slack Setup: Setup Guide

