Drive Claude Code from Telegram: live session cards, policy-gated auto-approval, remote approve/deny, mid-run questions, resume, and a Mini App dashboard.
Project description
Claude Code Telegram Bridge
Drive Claude Code from your phone.
The bridge runs real Claude Code agent sessions on your machine (through the
official claude-agent-sdk, reusing your local claude CLI login) and puts
you in control from Telegram:
- Live session cards. Each session renders as a single self-editing message: state, elapsed time, turn/tool counters, files touched, cost, and the agent's latest line — throttled to respect Telegram's edit rate limits.
- Mission Control. Run several sessions at once; a pinned panel lists them all with per-session stop / pause / focus / log buttons.
- A real permission policy, not a YOLO flag. Every tool call the agent
makes is classified by a pure, unit-tested policy module: auto-approve,
escalate to you as approve/deny buttons, or hard-deny. Three postures
(
guarded,trusted,yolo) trade convenience against control — and evenyolokeeps a catastrophic denylist (rm -rf,git push, disk writes, shutdown). - The agent can ask you questions. A built-in
ask_ownerMCP tool lets the agent pause mid-run and ask a clarifying question in Telegram — tap an option or reply in your own words, and the answer lands in the run as the tool result. One good question beats a confident wrong guess. - Conversation resume.
/resume fix the failing test toocontinues the last session's conversation — across bridge restarts, because conversation ids persist in a local SQLite event store. - Full transcripts. Every assistant line, tool call (with inputs), tool
result, and approval decision is recorded and browsable via
/logor the dashboard. - Optional Mini App dashboard. A Telegram Mini App streams the transcript
live over SSE with inline approve/deny and new-task controls, authenticated
with Telegram's signed
initData— no separate login. - Optional Cloudflare integration. Attach Cloudflare's official MCP
servers and headless
wranglercredentials so sessions can deploy Workers and Pages — with every deploy going through the approval flow. - Bills your Claude subscription, not API credit. By default the spawned
CLI's
ANTHROPIC_API_KEYis blanked so it falls back to your stored subscription login (CLAUDE_CODE_FORCE_LOGIN).
Single-user by design: the bridge answers to exactly one Telegram account
(OWNER_ID) and silently ignores everyone else.
Quickstart
Prerequisites: Python 3.10+, the Claude Code CLI
installed and logged in (claude runs in your terminal), and a Telegram bot
token from @BotFather.
pip install claude-code-telegram-bridge
# in the directory you want Claude Code to work on:
cp .env.example .env # or export the variables directly
# set BOT_TOKEN and OWNER_ID (your numeric user id — ask @userinfobot)
ccbridge
Then message your bot:
add dark mode to the settings page and run the tests
A live card appears, updates as the agent works, escalations arrive as approve/deny buttons, and the final summary (with files touched and cost) is posted when the run completes.
Commands
| Command | Effect |
|---|---|
| any plain message | start a new session on it |
/new <task> |
same, explicit |
/resume <task> |
continue the last conversation with a new task |
/resume <sid> <task> |
continue a specific session's conversation |
/status |
list sessions |
/stop <sid> / /stop all |
stop sessions |
/pause <sid> |
hold at the next non-read action; repeat to resume |
/log <sid> |
recent transcript for a session |
Security model
You are handing a coding agent a remote control — the policy layer is the
product. It lives in ccbridge/policy.py as pure logic
with no I/O, and it is the single gate every tool call passes through (the SDK
is always run with a can_use_tool callback; the bridge never uses the SDK's
bypassPermissions mode, in any posture).
guarded |
trusted (default) |
yolo |
|
|---|---|---|---|
| Read-only tools (Read, Grep, ...) | allow | allow | allow |
| Writes inside the workspace | ask | allow | allow |
| Writes outside the workspace | ask | ask | allow |
| Shell inside the workspace | ask | allow | allow |
Destructive/network shell (rm -r, git push, curl, pip install, ...) |
ask | ask | allow |
Catastrophic (rm -rf, git reset --hard, shutdown, disk writes) |
ask | ask | ask |
Writes to the bridge's own code, state, or .env |
ask | ask | ask |
CLAUDE_CODE_FORBIDDEN_PATTERNS matches |
deny | deny | deny |
"Ask" means an approve/deny button pair in Telegram; no answer within
CLAUDE_CODE_APPROVAL_TIMEOUT_SEC is a deny. The bridge also protects itself:
writes to its installed package, its data directory, or a .env file escalate
in every posture, because a session that can rewrite its own policy can disarm
its own leash.
Honest limitations, stated plainly:
- Shell-command classification is regex-based, not a shell parser. An
interpreter invocation (
python -c ...) can write anywhere without tripping the write heuristics. If that matters for your threat model, runguarded, where every shell command asks. CLAUDE_CODE_LOAD_PROJECT_SETTINGS=true(the default) loads the workspace's.claudesettings, whose allow-rules are honored by the CLI before the bridge's callback runs. Set it tofalseto make the bridge's policy the only authority.- This is a power tool for your own machine and your own repos. Do not point it at untrusted code or expose the bot to accounts you do not control.
Mini App dashboard (optional)
pip install 'claude-code-telegram-bridge[miniapp]'
Set CLAUDE_CODE_MINIAPP_ENABLED=true. The bridge then serves the dashboard
in-process (default 127.0.0.1:8722). Telegram only loads Mini Apps over
public https, so put a TLS proxy or tunnel in front (Cloudflare Tunnel, ngrok,
Tailscale Funnel) and set CLAUDE_CODE_MINIAPP_BASE_URL=https://your-host.
Session cards then grow an "Open dashboard" button.
The API authenticates every request by validating Telegram's HMAC-signed
initData against your bot token and checking the user is OWNER_ID — the
dashboard is useless to anyone else even if they find the URL.
Configuration
Everything is an environment variable (a .env in the launch directory is
read automatically). See .env.example for the full annotated
list. The interesting ones:
| Variable | Default | Meaning |
|---|---|---|
BOT_TOKEN |
— | bot token from @BotFather (required) |
OWNER_ID |
— | your numeric Telegram user id (required) |
CLAUDE_CODE_WORKSPACE |
launch dir | directory sessions work in |
CLAUDE_CODE_PERMISSION_POSTURE |
trusted |
guarded / trusted / yolo |
CLAUDE_CODE_APPROVAL_TIMEOUT_SEC |
300 |
approval wait before auto-deny |
CLAUDE_CODE_MAX_CONCURRENT |
3 |
concurrent session cap |
CLAUDE_CODE_MODEL |
CLI default | model override |
CLAUDE_CODE_FORCE_LOGIN |
true |
bill subscription login, not API key |
CLAUDE_CODE_FORUM_MODE |
false |
one forum topic per session |
CLAUDE_CODE_MINIAPP_ENABLED |
false |
serve the dashboard |
CCBRIDGE_DATA_DIR |
~/.ccbridge |
event store + state location |
How it works
you (Telegram) ──── python-telegram-bot ────┐
▲ ▼
│ ClaudeCodeManager
live cards, one asyncio task per session
buttons, questions │
▲ ▼
│ claude-agent-sdk ──> claude CLI
│ │ can_use_tool callback
└── policy.decide() ── allow / escalate / deny
│
SQLite event store (transcripts, resume, controls)
▲
Mini App (FastAPI + SSE) ┘
- One process runs everything by default. The SQLite event store makes the
Mini App separable (run it elsewhere, point both at the same
CCBRIDGE_DATA_DIR) and doubles as transcript persistence and resume-after-restart. - Sessions are steered to finish everything in a single turn (the driver is fire-and-forget), and scheduler-shaped tools are removed from the agent's context so it cannot promise background work that would never run.
- The
ask_ownertool is an in-process MCP server injected per session; the policy auto-approves it in every posture because asking is always safer than guessing.
Development
git clone https://github.com/rsprowler/claude-code-telegram-bridge
cd claude-code-telegram-bridge
pip install -e '.[dev,miniapp]'
pytest
The policy module is deliberately dependency-free — if you extend it, add a
test next to the existing ones in tests/test_policy.py.
Origins
Extracted from a larger private personal-AI stack, where this bridge has been daily-driven for real work: multi-hour refactors approved from a phone, parallel sessions, deploys to Cloudflare, and an agent that asks before it guesses.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_code_telegram_bridge-0.1.0.tar.gz.
File metadata
- Download URL: claude_code_telegram_bridge-0.1.0.tar.gz
- Upload date:
- Size: 10.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c85f11d5b7a76ff24300c34f71bbe30022bc7104a01f18b4490139e83e3bff5
|
|
| MD5 |
b4bec502d3bb05fffaf353dd01626b1c
|
|
| BLAKE2b-256 |
afcb40a7a6fd66902aeb908eada279d802fa6bab89188be6e34229c18307a13c
|
Provenance
The following attestation bundles were made for claude_code_telegram_bridge-0.1.0.tar.gz:
Publisher:
publish.yml on rsprowler/claude-code-telegram-bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_code_telegram_bridge-0.1.0.tar.gz -
Subject digest:
9c85f11d5b7a76ff24300c34f71bbe30022bc7104a01f18b4490139e83e3bff5 - Sigstore transparency entry: 2168549876
- Sigstore integration time:
-
Permalink:
rsprowler/claude-code-telegram-bridge@694b14c3bb437edcf927dfd37550b3a9ddf958ef -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/rsprowler
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@694b14c3bb437edcf927dfd37550b3a9ddf958ef -
Trigger Event:
release
-
Statement type:
File details
Details for the file claude_code_telegram_bridge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: claude_code_telegram_bridge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 48.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2e88afb7452bf9b3103181d6baa30d3ee7ae10abde511f7e51aa8d76980b5335
|
|
| MD5 |
e13cf66077b29575bbab0766d998402e
|
|
| BLAKE2b-256 |
8ea2d503304e07e329dd4039c9f3459c4d5b61cbd6d7103de0ac381b4b203eab
|
Provenance
The following attestation bundles were made for claude_code_telegram_bridge-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on rsprowler/claude-code-telegram-bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
claude_code_telegram_bridge-0.1.0-py3-none-any.whl -
Subject digest:
2e88afb7452bf9b3103181d6baa30d3ee7ae10abde511f7e51aa8d76980b5335 - Sigstore transparency entry: 2168550144
- Sigstore integration time:
-
Permalink:
rsprowler/claude-code-telegram-bridge@694b14c3bb437edcf927dfd37550b3a9ddf958ef -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/rsprowler
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@694b14c3bb437edcf927dfd37550b3a9ddf958ef -
Trigger Event:
release
-
Statement type: