- Message @BotFather on Telegram
- Send
/newbotand follow prompts - Copy the bot token (looks like
123456789:ABCdef...)
- Message @userinfobot on Telegram
- It will reply with your user ID (a number like
123456789)
Create a docker-compose.yml:
services:
telegram-code:
image: node:20
volumes:
# Your project directory
- ./my-project:/workspace:rw
# Persist npm global installs (claude, opencode)
- telegram-code-npm:/home/agent/.npm-global
# Host configs for git
- ~/.gitconfig:/home/agent/.gitconfig:ro
- ~/.ssh:/home/agent/.ssh:ro
environment:
- HOME=/home/agent
- TELEGRAM_BOT_TOKEN=your-bot-token-here
- ALLOWED_USERS=your-telegram-id
- WORK_DIR=/workspace
# Optional: voice transcription
- GROQ_API_KEY=your-groq-key
# Optional: for Claude (or set in container)
- ANTHROPIC_API_KEY=your-anthropic-key
working_dir: /workspace
command: npx -y telegram-code-bot
restart: unless-stopped
volumes:
telegram-code-npm:docker compose up -dDocker is recommended for environment isolation, but you can run directly:
# Prerequisites: Node.js 20+, tmux (for Claude CLI)
# Clone and install
git clone https://github.com/anthropics/telegram-code-bot
cd telegram-code-bot
yarn install
# Set environment variables
export TELEGRAM_BOT_TOKEN=your-bot-token
export ALLOWED_USERS=your-telegram-id
export WORK_DIR=/path/to/your/project
export ANTHROPIC_API_KEY=your-key # for Claude
# Run
yarn startNote: When running without Docker, ensure claude and/or opencode CLI tools are installed and available in PATH.
- Open your bot in Telegram
- Send
/claudeor/opencodeto start a session - Send your coding request
- Use
/stopwhen done
| Agent | Command | Description |
|---|---|---|
| Claude Code | /claude |
Anthropic's Claude Code CLI (tmux-based) |
| OpenCode | /opencode or /oc |
OpenCode AI agent (HTTP API) |
Switch agents anytime with /agent command.
| Command | Description |
|---|---|
/claude |
Start Claude Code session |
/opencode |
Start OpenCode session |
/agent |
Choose agent (shows buttons) |
/model |
Switch model (shows numbered list) |
/sessions |
Show previous sessions to resume |
/stop |
Stop current session |
/status |
Show current status |
/output |
Show last 500 lines of output |
/c |
Send Ctrl+C (interrupt) |
/y |
Send "y" (yes) |
/n |
Send "n" (no) |
/enter |
Press Enter |
/up / /down |
Arrow keys |
/tab |
Tab (autocomplete) |
/clear |
Delete chat messages |
Start agents by typing phrases like:
- "claude", "claude fix the bug"
- "opencode", "opencode add tests"
| Variable | Required | Description |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Yes | From @BotFather |
ALLOWED_USERS |
Yes | Comma-separated Telegram user IDs |
WORK_DIR |
No | Working directory (default: /workspace) |
DEFAULT_AGENT |
No | Default agent: claude or opencode |
GROQ_API_KEY |
No | Voice transcription (free, preferred) |
OPENAI_API_KEY |
No | Voice transcription (fallback) |
ANTHROPIC_API_KEY |
No | For Claude Code |
OPENCODE_URL |
No | OpenCode server URL (default: http://localhost:4096) |
OPENCODE_BIN |
No | Custom opencode binary path |
Telegram <-> Bot (Node.js) <-> Adapter <-> AI Agent
|
+-> Claude CLI (via tmux)
+-> OpenCode (via HTTP API)
Each AI backend implements the AgentAdapter interface:
startSession()/stopSession()- lifecyclesendInput()/sendSignal()- communicationsetModel()/getAvailableModels()- model selection- Events:
output,closed,error
src/bot.ts- Telegram bot, commands, message handlingsrc/adapters/- Agent adapters (Claude CLI, OpenCode)src/types.ts- AgentAdapter interfacesrc/rateLimiter.ts- Telegram API rate limit handlingsrc/installManager.ts- Auto-install tools
yarn install
yarn dev # Uses tsx watch for hot reload# Restart to apply changes
docker compose restart telegram-code
# Full recreate
docker compose down telegram-code && docker compose up -d telegram-codeyarn dev- Development with hot reloadyarn build- Compile TypeScriptyarn start- Run compiled versionyarn typecheck- Type check
The bot edits messages in place instead of spamming:
- User sends input -> new message created for response
- AI produces output -> same message is updated
- Rapid updates are debounced (1s batching)
Telegram API rate limits (429) are handled automatically:
- Waits for
retry_after+ jitter - Retries once, then marks user as rate-limited
- Skips sends during cooldown period
Claude CLI TUI elements are stripped from output:
- Status lines, borders, spinners
- Tool calls are preserved with status icons (
⏳running,✓done)
Bot not responding:
- Check
TELEGRAM_BOT_TOKENis correct - Verify your user ID is in
ALLOWED_USERS - Check container logs:
docker compose logs telegram-code
Voice messages not working:
- Set
GROQ_API_KEY(free) orOPENAI_API_KEY
Claude not starting:
- Check
ANTHROPIC_API_KEYis set - Verify tmux is installed in container
OpenCode not starting:
- Check if server is running:
/status - OpenCode auto-starts on first use
MIT
