Discord bot that maps Discord channels to local OpenCode projects. Users start or connect to OpenCode sessions with slash commands, then continue the conversation in Discord threads.
This repository is a Node.js and TypeScript project using discord.js v14 and @opencode-ai/sdk/v2.
Each configured Discord channel points at one local project path. The bot starts one opencode serve process per unique project path, creates Discord threads for sessions, streams OpenCode output back to Discord, and persists runtime state so sessions can recover after restarts.
Typical flow:
- Configure a Discord server and one or more channel mappings in
config.yaml. - Run the bot locally on the machine that has access to the configured project paths.
- Use
/newin a mapped Discord channel to create an OpenCode session thread. - Send normal messages in the thread to talk to the OpenCode agent.
- Use slash commands in the thread for session controls such as model selection, queue management, diffs, reverts, summaries, and file context.
| Requirement | Notes |
|---|---|
| Node.js | Built for modern Node.js. |
| pnpm | The repo declares pnpm@10.33.1. |
| OpenCode CLI | opencode must be available in PATH. Startup checks opencode --version. |
| Discord bot token | Create an application and bot in the Discord Developer Portal. |
| Discord message content intent | Required for thread passthrough messages. |
| Local project paths | The bot must run on the same machine where configured projects exist. |
Install dependencies:
pnpm installCopy the example config:
cp config.example.yaml config.yamlEdit config.yaml with your Discord token, guild IDs, channel IDs, and local project paths.
Run in development:
pnpm devRun checks:
pnpm typecheck
pnpm testRuntime configuration lives in config.yaml at the repo root. This file is ignored by git because it contains secrets.
Use config.example.yaml as the reference. Minimal shape:
discordToken: "YOUR_BOT_TOKEN_HERE"
servers:
- serverId: "111111111111111111"
channels:
- channelId: "123456789012345678"
projectPath: "../project"Channel options:
| Field | Default | Purpose |
|---|---|---|
channelId |
Required | Discord text channel ID. |
projectPath |
Required | Local project path served by OpenCode. Absolute paths, config-relative paths such as ../project, and home-relative paths such as ~/Developer/project are supported. |
defaultAgent |
build in callers when omitted |
Agent used when a command does not specify one. |
allowAgentSwitch |
true |
Allows /agent set and /new agent:<name>. |
allowedAgents |
[] |
Agent allowlist. Empty means all agents. |
allowedUsers |
[] |
Discord user allowlist. Empty means all channel members. |
permissions |
auto |
auto grants agent permissions automatically. interactive asks with buttons. |
questionTimeout |
300 |
Seconds to wait for user answers to agent questions. |
connectHistoryLimit |
10 |
Number of prior messages replayed by /connect. Use 0 to disable replay. |
autoConnect |
false |
Auto-create Discord threads for externally created OpenCode sessions. |
Notes:
| Topic | Behavior |
|---|---|
| Multiple channels per project | Allowed. They share one opencode serve process for the same projectPath. |
Multiple autoConnect channels |
Avoid this for the same projectPath. The implementation uses the first matching channel. |
| Model config | Not configured in config.yaml. Configure models in each project OpenCode config. |
| Hot reload | Config changes are watched and valid reloads update in-memory config. Invalid reloads are rejected and the previous config remains active. |
Use channel-level commands in configured parent channels. Use thread-level commands inside session threads.
Channel-level flow:
- Run
/new prompt:<text>to create a new OpenCode session and Discord thread. - Optionally pass
agent:<name>andtitle:<thread title>. - Use
/connect session:<id>to attach a new thread to an existing OpenCode session. - Use
/status,/agent list,/model list,/ls,/cat,/download,/git,/mcp, and/helpfrom a mapped channel.
Thread-level flow:
- Send normal messages in the thread to prompt the agent.
- Send more messages while the agent is busy to queue them.
- Use
/interruptto abort the current session work and clear the queue. - Use
/context addbefore the next message to include files from the project. - Use
/diff,/revert,/unrevert,/summary,/fork,/todo, and/retryfor session workflow controls. - Use
/endto end the Discord thread mapping and archive the thread.
| Command | Context | Purpose |
|---|---|---|
/new |
Channel | Create a new OpenCode session thread. |
/connect |
Channel | Attach a Discord thread to an existing OpenCode session. |
/agent set |
Thread | Change the active session agent. |
/agent list |
Channel or thread | List available agents. |
/model set |
Thread | Change the active session model. |
/model list |
Channel or thread | List available models. |
/interrupt |
Thread | Abort the active OpenCode session task and clear queued messages. |
/queue list |
Thread | Show queued messages. |
/queue clear |
Thread | Clear queued messages. |
/info |
Thread | Show session metadata, queue length, MCP status, usage, and cost. |
/end |
Thread | End the Discord mapping and archive the thread. |
/status |
Channel | Show project server and active session status. |
/help |
Channel or thread | Show context-aware command help. |
/git status |
Channel or thread | Show local git status for the project. |
/git log |
Channel or thread | Show recent commits. |
/git diff |
Channel or thread | Show local git diff. |
/git branch |
Channel or thread | Show current branch. |
/git branches |
Channel or thread | List local branches. |
/git checkout |
Channel or thread | Checkout or create a local branch. |
/git stash save |
Channel or thread | Save a git stash. |
/git stash pop |
Channel or thread | Pop the latest git stash. |
/git stash list |
Channel or thread | List git stashes. |
/git reset |
Channel or thread | Unstage files or run confirmed hard reset. |
/ls |
Channel or thread | List project files or directories. |
/cat |
Channel or thread | Show project file contents. |
/download |
Channel or thread | Download a project file. |
/restart |
Channel or thread | Restart the OpenCode server for the project after confirmation. |
/mcp list |
Channel or thread | Show MCP server connection status. |
/mcp reconnect |
Channel or thread | Reconnect one or all MCP servers. |
/mcp disconnect |
Channel or thread | Disconnect an MCP server. |
/diff |
Thread | Show OpenCode session diff. |
/revert |
Thread | Revert the selected or latest assistant message. |
/unrevert |
Thread | Undo the last revert. |
/summary |
Thread | Summarize and compact the session. |
/fork |
Thread | Fork the current session into a new thread. |
/todo |
Thread | Show the agent todo list. |
/retry |
Thread | Revert and resend the last user prompt. |
/context add |
Thread | Add up to five project files to the next prompt. |
/context list |
Thread | List pending context files. |
/context clear |
Thread | Clear pending context files. |
| Path | Purpose |
|---|---|
config.yaml |
Local bot configuration and Discord token. Ignored by git. |
state.json |
Persisted server, session, and queue state. Ignored by git. |
.cache/ |
Cached agents, models, sessions, and MCP status. Ignored by git. |
logs/ |
LaunchAgent stdout and stderr logs. Ignored by git. |
<project>/.opencode/attachments/ |
Downloaded Discord attachments for prompt file parts. |
Useful scripts:
| Command | Purpose |
|---|---|
pnpm dev |
Run src/index.ts through tsx. |
pnpm test |
Run Vitest once. |
pnpm test:watch |
Run Vitest in watch mode. |
pnpm typecheck |
Run TypeScript without emitting files. |
pnpm service:setup |
Install/update the macOS LaunchAgent and start the bot at user login. |
pnpm service:status |
Print LaunchAgent status for com.opencode.discord. |
pnpm service:stop |
Stop the running LaunchAgent-managed process without removing auto-start. |
pnpm service:restart |
Restart the LaunchAgent-managed process. |
pnpm service:unsetup |
Stop, unload, and remove the macOS LaunchAgent. |
Project conventions are documented in AGENTS.md. The short version is strict TypeScript, named exports, Zod config validation, BotError for structured errors, atomic state writes, and TDD for code changes.
The bot manages opencode serve processes itself. It starts servers on demand, shares one server per project path, watches health, and persists process metadata in state.json.
macOS background service management is available through pnpm service:* scripts. The service starts when the current macOS user logs in, selects the Node.js version from .nvmrc through nvm, runs ./node_modules/.bin/tsx src/index.ts from this repository, and writes logs to logs/opencode-discord.out.log and logs/opencode-discord.err.log.
Before enabling the service, install the .nvmrc Node.js version and project dependencies manually:
nvm install
nvm use
pnpm installThe service does not run npm, pnpm, corepack, or nvm install at startup. If Node.js or node_modules is missing, check logs/opencode-discord.err.log, install the missing dependency manually, and run pnpm service:restart.
For production-like use:
- Keep
config.yaml,state.json,.cache/, and logs out of git. - Run the bot on a machine with stable access to every configured project path.
- Enable the Discord bot intents needed for guild messages and message content.
- Treat
permissions: autoas full trust for the configured project.