A Telegram bot that bridges to Claude Code CLI. Chat with Claude, run slash commands, and execute skills, all from Telegram.
Works in 1:1 chats and group conversations.
The Claude mobile app is great for conversations. This bot does something different. It connects to Claude Code CLI running on your machine, which means:
| Claude Mobile App | This Bot | |
|---|---|---|
| Runs code on your machine | No | Yes (executes Bash, reads/writes files) |
| Git operations | No | Yes (/commit, /commit_push_pr, /code_review) |
| Access to your codebase | No | Yes (Claude sees your actual project files) |
| Custom skills | No | Yes (auto-discovers ~/.claude/skills/) |
| Working directory control | No | Yes (/workdir targets any local project) |
| Group collaboration | No | Yes (add to a Telegram group, share one Claude session) |
| Tool use (Read, Edit, Grep, etc.) | No | Yes (full Claude Code tool suite) |
| Works offline from Anthropic's servers | No | No (both need API access) |
This bot can also do everything Claude Code already does: regular conversations, code generation, debugging, explanations. Every message is passed directly through the CLI. You get the full Claude Code experience, just over Telegram.
The group chat angle is especially useful: create purpose-specific Telegram groups (e.g. "Backend Refactor", "Release Prep"), add the bot, and your whole team shares one Claude session with full context. That's something neither the Claude app nor Claude Code CLI offer today.
- Chat with Claude: send any message, get Claude's response
- All Claude Code skills available as Telegram commands (
/commit,/simplify,/code_review, etc.) - Session continuity: conversations persist across messages (Claude remembers context)
- Per-chat settings: set model, effort level, and working directory per chat
- Group support: add the bot to a group, interact via commands or @mentions
- Live progress updates: see what Claude is doing in real time ("Using Bash...", "Using Read...")
- Cancel support:
/cancelaborts a running operation - Voice messages: send voice notes, transcribed via OpenAI Whisper and forwarded to Claude
- Message queuing: send multiple messages while Claude is working; they queue up (max 5) and process in order
- File delivery: when Claude creates or modifies files, they're sent back to the chat as documents
- Smart cost optimization: auto-detects casual chat vs code work and uses lightweight mode for simple questions (~10x cheaper)
- Image and file support: send photos, screenshots, or documents and Claude will analyze them
- Retry on error: if Claude errors out, hit the Retry button instead of retyping
- Auto-discover custom skills: picks up skills from
~/.claude/skills/automatically - Long response handling: auto-chunks responses that exceed Telegram's 4096 char limit
- Markdown formatting: Claude's markdown output converted to Telegram-compatible HTML
- Node.js 22+
- Claude Code CLI installed and authenticated
- A Telegram bot token from @BotFather
- Clone the repo
git clone https://github.com/hkrathore/claude-telegram-bot.git
cd claude-telegram-bot
npm install- Create a Telegram bot
Open @BotFather on Telegram, send /newbot, follow the prompts, and copy the token.
- Get your Telegram user ID
Send a message to @userinfobot on Telegram. It will reply with your numeric user ID.
- Configure
cp .env.example .envEdit .env:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
ALLOWED_USER_IDS=12345678
- Start
npm startThe bot will start polling for messages. Send /start to your bot on Telegram.
| Variable | Required | Default | Description |
|---|---|---|---|
TELEGRAM_BOT_TOKEN |
Yes | Bot token from BotFather | |
ALLOWED_USER_IDS |
Yes | Comma-separated Telegram user IDs | |
CLAUDE_MODEL |
No | sonnet |
Default model (sonnet, opus, haiku) |
DEFAULT_WORKING_DIR |
No | Current dir | Working directory for Claude operations |
ALLOWED_WORKDIR_BASE |
No | Restrict /workdir to this base path (security) |
|
CLAUDE_BINARY |
No | claude |
Path to Claude CLI binary |
MAX_BUDGET_USD |
No | Cost cap per invocation | |
ALLOWED_TOOLS |
No | All | Comma-separated list of tools Claude can use |
OPENAI_API_KEY |
No | OpenAI API key for voice message transcription | |
SHOW_COST |
No | false |
Set to true to show API cost after each response |
CLAUDE_BARE |
No | false |
Force lightweight mode globally (skips CLAUDE.md, hooks, plugins) |
SESSION_TTL_HOURS |
No | 24 |
Session expiry time |
WEBHOOK_URL |
No | Set to enable webhook mode (polling by default) | |
WEBHOOK_PORT |
No | 8443 |
Port for webhook server |
WEBHOOK_SECRET |
No | Auto-generated | Secret for webhook verification |
| Command | Description |
|---|---|
/start |
Welcome message |
/help |
List all commands |
/model <name> |
Switch model (sonnet/opus/haiku) |
/effort <level> |
Set effort level (low/medium/high/max/auto) |
/workdir <path> |
Set working directory |
/session new |
Start fresh conversation |
/session |
Show current session info |
/cancel |
Cancel running operation |
/compact |
Compress conversation context (frees up context window) |
| Command | Description |
|---|---|
/commit |
Create a git commit |
/commit_push_pr |
Commit, push, and create PR |
/simplify |
Review and simplify code |
/code_review |
Review code changes |
/feature_dev |
Develop a new feature |
/ralph_loop |
Iterative development loop |
/cancel_ralph |
Cancel active Ralph loop |
/clean_gone |
Clean up deleted branches |
Telegram commands don't support hyphens, so
commit-push-prbecomescommit_push_pr. The bot maps them back automatically.
Any skills you've created in ~/.claude/skills/ are automatically discovered at startup and registered as Telegram commands. They appear in /help under "Custom Skills" and get Telegram autocomplete.
Telegram > grammY bot > spawn claude -p "<prompt>" --output-format stream-json > parse events > format > send back
src/
├── index.ts # Entry point (polling or webhook)
├── bot.ts # Bot instance + middleware chain
├── config.ts # Environment config loader
├── types.ts # Shared types (BotContext, BotCommand)
├── state.ts # Per-chat active invocation tracking
├── claude/
│ ├── cli.ts # Spawns Claude CLI, parses stream-json
│ ├── invoke.ts # Shared invoke-and-respond flow
│ ├── session-store.ts # Chat ID > Claude session mapping
│ └── types.ts # CLI output types
├── commands/
│ ├── index.ts # Command registry + skill auto-discovery
│ ├── chat.ts # Freeform message handler
│ ├── skills.ts # Skill command passthrough
│ ├── cli-commands.ts # CLI slash command passthrough (/compact)
│ ├── effort.ts # /effort
│ ├── media.ts # Photo and document handler
│ ├── voice.ts # Voice message transcription + handler
│ ├── start.ts # /start
│ ├── help.ts # /help
│ ├── model.ts # /model
│ ├── workdir.ts # /workdir
│ └── session.ts # /session
├── middleware/
│ ├── auth.ts # User allowlist
│ ├── typing.ts # Typing indicator refresh
│ ├── error.ts # Error boundary + retry button
│ └── retry.ts # Failed prompt storage for retry
└── util/
├── format.ts # Markdown > Telegram HTML
├── chunker.ts # Message splitting (4096 char limit)
├── reply.ts # Send with HTML fallback
└── files.ts # Detect and send output files back to chat
- Message arrives from Telegram
- Auth middleware checks user ID against allowlist
- Command router dispatches to the right handler
- Handler spawns
claude -p "<prompt>" --output-format stream-json - CLI output is parsed line-by-line as JSON events
- Response is converted from Markdown to Telegram HTML
- Long responses are chunked at paragraph/sentence boundaries
- Typing indicator refreshes every 4s while Claude works
Each chat gets its own Claude session. The bot stores session IDs in ~/.claude-telegram-bot/sessions.json and passes --resume <sessionId> on subsequent messages so Claude retains conversation context.
Default mode. No public URL needed.
npm startSet WEBHOOK_URL in .env to your public HTTPS endpoint:
WEBHOOK_URL=https://your-server.com/webhook
WEBHOOK_PORT=8443
FROM node:22-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["npm", "start"]macOS (launchd)
cp scripts/launchd.plist ~/Library/LaunchAgents/com.claude-telegram-bot.plist
# Edit the plist to fix paths (node, tsx, project dir)
launchctl load ~/Library/LaunchAgents/com.claude-telegram-bot.plistLinux (systemd)
sudo cp scripts/systemd.service /etc/systemd/system/claude-telegram-bot.service
# Edit the service file to fix paths and User
sudo systemctl enable claude-telegram-bot
sudo systemctl start claude-telegram-botWindows (Task Scheduler)
# Run at logon via Task Scheduler
schtasks /create /tn "ClaudeTelegramBot" /tr "npm start --prefix C:\path\to\claude-telegram-bot" /sc onlogon /rl highestCross-platform (PM2)
npm i -g pm2
pm2 start npm --name claude-telegram -- start
pm2 save
pm2 startup # generates OS-specific auto-start command- Allowlist-only: Only Telegram user IDs in
ALLOWED_USER_IDScan interact - Workdir sandboxing: Set
ALLOWED_WORKDIR_BASEto restrict/workdirto a specific directory tree (e.g./home/user/projects). Prevents users from pointing Claude at/etcor other sensitive paths - Budget cap: Set
MAX_BUDGET_USDto limit per-invocation cost - Tool permissions: Configure
ALLOWED_TOOLSto restrict what Claude can do - Graceful shutdown: Bot cleanly stops polling on SIGINT/SIGTERM
- No secrets in code: All config via environment variables
MIT