Control any Claude Code terminal session remotely via Telegram. Mirror terminal output, send commands, approve/reject actions, and use voice input — all from your phone.
Approve code changes, view diffs, and control Claude Code — all from Telegram
- Two-way sync — Terminal output → Telegram, Telegram input → Terminal
- Smart formatting — Code diffs with syntax highlighting, bash commands in code blocks, tables as mobile cards
- Approval workflow — Approve/reject Claude Code actions with one tap
- Voice input — Send voice messages, review transcription, then send to terminal
- Attachments — Send photos, screenshots, and documents — auto-forwarded to Claude Code for visual/file analysis
- Persistent keyboard — Quick-access buttons: Yes / No / Escape / Status / Continue
- Cross-platform — macOS (Terminal.app), Linux (tmux), Windows (PowerShell + Git Bash)
- ⏳ / ⌛ Working — Alternating hourglass with elapsed time
- ⚡ Running tool — Shows which tool is active
- 🟡 Awaiting approval — Waiting for your response
- ✅ Done — Task completed with duration
- ❌ Error — Error detected with auto-pinning
- 💤 Idle — No activity for 5+ minutes
- 🔁 Auto-reconnect watchdog — Restarts crashed daemons automatically (max 5 retries)
- 🔒 Atomic locking — No duplicate daemon instances
- ⏱️ Session timer — Tracks elapsed time, shown on disconnect
- 💓 Connection heartbeat — Detects connection loss
- 📎 Long output as file — Outputs > 4096 chars sent as .txt attachment
- 🔐 Secret redaction — API keys, tokens, JWTs auto-masked before sending
- 🔑 macOS Keychain support — Store credentials securely (optional)
- 👤 Sender authentication — Only your Telegram ID can control the bot
- 🛡️ Command blocklist — Dangerous commands (rm -rf, etc.) are blocked
- 🔤 Unicode support — Cyrillic, CJK, emoji — uses clipboard paste for non-ASCII
- 📝 Diff highlighting — Green/red syntax with line numbers
- 🧹 Clean status lines — Terminal UI hints stripped (no "shift+tab to cycle" noise)
- 📌 Error pinning — Errors auto-pinned in chat, auto-unpinned after 5 min
# 1. Clone the repo
git clone https://github.com/boot2load/claude-code-telegram-agent.git
cd claude-code-telegram-agent
# 2. Create a Telegram bot via @BotFather and get your bot token
# 3. Run the setup wizard
./setup.sh
# 4. In your project's terminal, launch Claude Code and type:
/terminal-control-start
# Linux: run Claude Code inside tmux first:
# tmux new -s claude
# claude
# Then /terminal-control-start| Button | Action | When to use |
|---|---|---|
| ✅ 1. Yes | Approve | Approve a tool/edit/command |
| ✅ 2. Always | Always approve | Don't ask again for this tool type |
| ❌ 3. No | Reject | Reject a tool/edit/command |
| 🛑 Esc (cancel) | Escape key | Interrupt Claude mid-action |
| 📋 Status | Status request | Get a progress update |
| 🔄 Continue | Continue | Tell Claude to keep going |
| ↩️ Undo last change | Undo | Revert last edit |
| ⏹ /terminal-control-end | Stop session | Disconnect bot (runs stop.sh directly) |
Send a voice message in Telegram:
- 🎙 Transcribing... — processing notification
- Bot shows the transcribed text
- Press ✅ Yes to send to terminal, or ❌ No to cancel
| Backend | Speed | Cost | Setup |
|---|---|---|---|
| mlx-whisper | ~2-3s | Free | Automatic (setup.sh installs it) |
| OpenAI Whisper API | ~1s | $0.006/min | Requires API key |
All settings in config.json (created by setup.sh):
{
"telegram": {
"bot_token": "your-bot-token",
"chat_id": "your-chat-id",
"allowed_user_id": "your-telegram-user-id"
},
"project": {
"name": "Terminal",
"working_directory": "",
"window_match_string": "",
"tmux_session": ""
},
"voice": {
"backend": "mlx-whisper",
"mlx_model": "mlx-community/whisper-tiny.en-mlx",
"openai_api_key": ""
},
"idle_timeout_seconds": 300
}No reconfiguration needed — if window_match_string is empty, the bot automatically follows whichever Claude Code terminal is active.
To target a specific project, set window_match_string to a unique string in the terminal window title (e.g., "myproject").
Claude Code Telegram Agent
YOUR TERMINAL YOUR PHONE
============ ==========
Terminal.app ◄──── AppleScript ────► terminal-watcher.py
(Claude Code) reads screen │
▲ injects keys │ sends formatted
│ │ output via API
│ ▼
type-to-terminal.sh Telegram Bot API
▲ │
│ │ delivers to
│ ▼
poll.sh ◄──── HTTP polling ────► Telegram Chat 📱
│ every 1-3s (buttons, voice,
│ text, photos,
│ files)
│
watchdog.sh
(monitors poll.sh + watcher,
auto-restarts on crash)
Data Flow:
- Terminal → Phone:
terminal-watcher.pyreads screen via AppleScript/tmux → formats output → sends to Telegram - Phone → Terminal:
poll.shchecks Telegram for messages, downloads attachments →type-to-terminal.shinjects keystrokes - Reliability:
watchdog.shmonitors both daemons, auto-restarts if either crashes
| File | Purpose |
|---|---|
setup.sh |
Interactive setup wizard |
config.json |
All settings (gitignored) |
scripts/start.sh |
Activate session + launch watchdog |
scripts/stop.sh |
Deactivate session + cleanup |
scripts/poll.sh |
Telegram → Terminal daemon |
scripts/terminal-watcher.py |
Terminal → Telegram daemon |
scripts/watchdog.sh |
Auto-restart crashed daemons |
scripts/type-to-terminal.sh |
Keystroke injection (AppleScript/tmux/PowerShell) |
scripts/transcribe-voice.sh |
Voice transcription |
scripts/download-file.sh |
Download attachments from Telegram |
scripts/send.sh |
Send a Telegram message |
scripts/check-inbox.sh |
Check for incoming messages |
commands/ |
Claude Code slash command templates |
macOS: Store credentials in macOS Keychain (optional):
security add-generic-password -U -s "remote-terminal-telegram" -a "bot_token" -w "YOUR_TOKEN"Linux: Credentials stored in config.json with chmod 600 (owner-only).
MIT