Control Claude Code from Telegram with an allowlisted local bot.
You want to check on Claude Code from your phone without exposing a full remote shell or copying your private automation stack into a public repo.
This template gives you a small local Telegram control surface for Claude Code. It keeps the bot local, requires an explicit allowlist by default, and leaves deployment choices to you.
One command. Takes 60 seconds.
curl -fsSL https://raw.githubusercontent.com/nardovibecoding/simply-telegram-bridge/main/install.sh | bashClones the repo, installs dependencies, prompts for bot token + settings, writes .env. Just run python3 bot.py after. The installer requires ALLOWED_USERS unless you explicitly opt into ALLOW_ALL_USERS=true.
Prerequisites:
- Python 3.10+
- Claude Code CLI installed and authenticated
- A Telegram bot token (from @BotFather)
export BOT_TOKEN="000000000:FAKE_TELEGRAM_BOT_TOKEN_FOR_LOCAL_TESTS"
export ALLOWED_USERS="123456789" # your Telegram user ID
export WORKING_DIR="/path/to/project"
export MODEL="sonnet" # haiku | sonnet | opus
python bot.pyThen open your bot in Telegram and start messaging:
You: What's the git status?
Bot: Working...
$ git status
Read README.md
Bot: Clean — on branch main, 3 commits ahead of origin.
Last commit: "fix: handle edge case in parser"
(4.2s, 2 tool calls)
Telegram message
│
▼
Bot (bot.py)
│ auth check → allowed users only
│
▼
Claude Code SDK (sdk_client.py)
│ persistent connection, auto-reconnect
│
├──▶ Bash $ git status, pytest, npm run build …
├──▶ Read open any file in the working directory
├──▶ Write create new files
├──▶ Edit patch existing files
├──▶ Grep search file contents
├──▶ Glob find files by pattern
├──▶ WebSearch research from the web
├──▶ WebFetch fetch a URL
└──▶ Agent spawn sub-agents for complex tasks
│
▼
streaming response
(tool calls shown live as they happen)
│
▼
Telegram reply with timing stats
Cold start: ~6 s once. Subsequent messages: 2–3 s.
| Capability | Detail |
|---|---|
| Full tool access | Bash, Read, Write, Edit, Grep, Glob, WebSearch, WebFetch, Agent |
| Live tool progress | Each tool call shown in real-time as Claude works |
| Streaming text | Response text updates as it arrives, not just at the end |
| Long message splitting | Responses >4096 chars split automatically |
| Task cancellation | /cancel stops a running task mid-execution |
| Auto-reconnect | Persistent SDK connection restarts transparently on crash |
| Multi-model | Switch between Haiku, Sonnet, and Opus via env var |
| Allowlist auth | Restrict access to specific Telegram user IDs |
| Custom working dir | Point Claude at any directory on the host machine |
| Custom system prompt | Override the default assistant persona |
| Markdown rendering | Bot responses rendered as HTML — bold, code, links preserved |
| Rate limiting | Configurable per-user message rate limit (default: 5 req/min) |
| File/image input | Send photos or documents — bot passes them to Claude as input |
| Multi-session | Per-chat working directories via JSON mapping |
| 3-file footprint | bot.py + sdk_client.py + requirements.txt — ~300 lines total |
- Open @BotFather in Telegram
- Send
/newbotand follow the prompts - Copy the token. Public examples in this repo use fake token placeholders.
Message @userinfobot — it replies with your numeric user ID.
export BOT_TOKEN="000000000:FAKE_TELEGRAM_BOT_TOKEN_FOR_LOCAL_TESTS"
export ALLOWED_USERS="111222333" # your user ID (comma-separated for multiple)
export WORKING_DIR="$HOME/myproject" # directory Claude operates in
export MODEL="sonnet" # haiku | sonnet | opus
export SYSTEM_PROMPT="You are a helpful coding assistant." # optionalpython bot.pyTo keep it running in the background:
nohup python bot.py > bridge.log 2>&1 &Or as a systemd service (Linux):
[Unit]
Description=Claude Telegram Bridge
[Service]
ExecStart=/usr/bin/python3 /opt/simply-telegram-bridge/bot.py
EnvironmentFile=/opt/simply-telegram-bridge/.env
Restart=always
[Install]
WantedBy=multi-user.target| Variable | Required | Default | Description |
|---|---|---|---|
BOT_TOKEN |
Yes | — | Telegram bot token from BotFather |
ALLOWED_USERS |
Yes by default | empty | Comma-separated Telegram user IDs |
ALLOW_ALL_USERS |
No | false |
Set true only for a private test bot |
WORKING_DIR |
No | ~ |
Directory Claude operates in |
MODEL |
No | sonnet |
haiku, sonnet, or opus |
SYSTEM_PROMPT |
No | "You are a helpful coding assistant." |
System prompt for the session |
RATE_LIMIT |
No | 5 |
Max messages per user per minute |
CHAT_DIRS |
No | — | JSON mapping of chat ID → working dir, e.g. {"123456": "/projects/foo"} |
| Command | What it does |
|---|---|
| (any text) | Sent to Claude Code — full tool access |
/cancel |
Cancel the currently running task |
ALLOWED_USERS is your first line of defense. Set it to your Telegram user ID. If it is empty, this template denies all users unless ALLOW_ALL_USERS=true.
# Single user
export ALLOWED_USERS="111222333"
# Multiple users
export ALLOWED_USERS="111222333,444555666"What Claude can do: The bot can execute Claude Code tools from the configured working directory. Only grant access to users you trust completely.
Credentials: BOT_TOKEN and ALLOWED_USERS are env vars — never committed to git. Use a .env file locally and EnvironmentFile in systemd.
3 files, ~300 lines:
| File | Lines | Responsibility |
|---|---|---|
bot.py |
~160 | Telegram bot — auth, message handling, progress display, cancellation |
sdk_client.py |
~130 | Claude SDK wrapper — persistent connection, streaming, auto-reconnect |
requirements.txt |
2 | python-telegram-bot + claude-agent-sdk |
The SDK client maintains a single persistent connection per process. On disconnect or crash, it reconnects transparently before the next query. The lock ensures concurrent Telegram messages are serialized to the same session.
This public template is intentionally smaller than a private production bot stack. It omits private deployment wiring, logs, runtime state, and operational workflows.
