Control OpenCode from Telegram. The agent runs in an isolated Docker container - it can work on your repo but can't touch anything else on your system.
Telegram --> Bridge Container --> Agent Container (OpenCode)
(Node.js) (Ubuntu, read-only rootfs)
└── /workspace = your repo
- Docker
- OpenCode installed on host (
pacman -S opencodeor however you install it) - Authenticated with OpenCode (
opencode auth login) - A Telegram bot token from @BotFather
- Your Telegram user ID from @userinfobot
git clone https://github.com/bil9148/opencode-telegram-bridge.git
cd opencode-telegram-bridge
# Copy the opencode binary into the build context
cp $(which opencode) ./opencode
# Configure
cp .env.example .env
# Edit .env with your valuesTELEGRAM_BOT_TOKEN=<from @BotFather>
ALLOWED_USER_IDS=<your numeric Telegram user ID>
PROJECT_PATH=/home/you/repos/your-project
PROJECT_NAME=your-projectThe agent authenticates using your existing OpenCode OAuth tokens (~/.local/share/opencode/auth.json), mounted read-only. No API key needed. If tokens expire, run opencode auth login on your host.
# Build images (use --network host if behind VPN)
docker build --network host -t opencode-telegram-bridge-opencode-agent .
docker build --network host -t opencode-telegram-bridge-telegram-bridge -f Dockerfile.bridge .
# Start
docker compose up -d
# Watch logs
docker compose logs -f telegram-bridgeOr use the start script:
chmod +x start.sh
./start.sh| Command | Description |
|---|---|
/code <prompt> |
Send a prompt to OpenCode |
/exec <command> |
Run a shell command in the container |
| Command | Description |
|---|---|
/model [provider/model] |
Get or set the model |
/models [provider] |
List available models |
/agent [name] |
Get or set the agent |
/agents |
List available agents |
/variant [high|max|minimal] |
Set reasoning effort |
| Command | Description |
|---|---|
/session [last|id|new] |
Get or set the active session |
/sessions |
List recent sessions |
/export [session-id] |
Export session as JSON |
| Command | Description |
|---|---|
/workspace [subpath] |
List files in workspace |
/pr <number> |
Checkout and review a GitHub PR |
/stats [days] |
Token usage and cost stats |
| Command | Description |
|---|---|
/status |
Container status and current settings |
/auth |
Check auth status |
/mcp |
List MCP servers |
/config |
Show resolved OpenCode config |
/paths |
Show OpenCode paths |
Two containers:
- opencode-agent - Ubuntu with the OpenCode binary. Mounts your repo at
/workspace. Read-only root filesystem, all capabilities dropped, no sudo, resource-limited (8 CPU / 16GB RAM). - telegram-bridge - Node.js bot that receives Telegram messages and executes commands in the agent container via Docker socket. Also hardened (read-only, caps dropped, 1 CPU / 512MB RAM).
What the agent can access:
/workspace(your repo, read-write)- OAuth tokens (read-only, for Anthropic API)
- OpenCode config (read-only)
- Internet (for API calls, routed through host network)
What the agent cannot access:
- Your host filesystem (outside the mounted repo)
- Other Docker containers
- The Docker socket
Deploy one instance per project. Clone the repo into separate directories or use different .env files:
# Project A
PROJECT_PATH=/home/you/repos/project-a
PROJECT_NAME=project-a
# Project B (separate .env, separate bot token)
PROJECT_PATH=/home/you/repos/project-b
PROJECT_NAME=project-bEach gets its own pair of containers (opencode-project-a, bridge-project-a, etc).
Both containers use network_mode: host because Docker bridge networks can't route through Wireguard tunnels. This means the containers share the host's network stack. Filesystem isolation is still fully intact.
If you're not using a VPN, you can switch to bridge networking by removing network_mode: host and adding a networks: section. This adds network namespace isolation at the cost of needing DNS configuration.
- The Docker socket is mounted into the bridge container. If the bridge is compromised, an attacker could interact with Docker on your host. The bridge is hardened (read-only, no capabilities, resource-limited) to minimize this risk.
- OAuth tokens are mounted read-only but readable by the agent. A malicious prompt or repo config could theoretically exfiltrate them. The blast radius is limited to your Anthropic subscription.
hostnetwork mode means the agent can see your LAN. If this concerns you and you're not on a VPN, use bridge networking instead.- The bot refuses to start without
ALLOWED_USER_IDSset. Commands are queued one at a time to prevent races.