Metadata-Version: 2.4
Name: claude-code-telegram-bridge
Version: 0.1.0
Summary: 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-URL: Homepage, https://github.com/rsprowler/claude-code-telegram-bridge
Project-URL: Issues, https://github.com/rsprowler/claude-code-telegram-bridge/issues
Author: rsprowler
License: MIT License
        
        Copyright (c) 2026 rsprowler
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: agent,anthropic,bot,claude,claude-code,telegram
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Build Tools
Requires-Python: >=3.10
Requires-Dist: claude-agent-sdk>=0.1.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: python-telegram-bot>=21.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Provides-Extra: miniapp
Requires-Dist: fastapi>=0.110; extra == 'miniapp'
Requires-Dist: uvicorn>=0.29; extra == 'miniapp'
Description-Content-Type: text/markdown

# Claude Code Telegram Bridge

[![tests](https://github.com/rsprowler/claude-code-telegram-bridge/actions/workflows/ci.yml/badge.svg)](https://github.com/rsprowler/claude-code-telegram-bridge/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/claude-code-telegram-bridge)](https://pypi.org/project/claude-code-telegram-bridge/)

Drive [Claude Code](https://claude.com/claude-code) from your phone.

<p align="center">
  <img src="docs/usage.gif" width="380" alt="A Claude Code session driven from Telegram: live card updates, an approval prompt, and the final result.">
</p>

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 even
  `yolo` keeps a catastrophic denylist (`rm -rf`, `git push`, disk writes,
  shutdown).
- **The agent can ask you questions.** A built-in `ask_owner` MCP 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 too` continues 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 `/log` or 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 `wrangler` credentials 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_KEY` is 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](https://claude.com/claude-code)
installed and logged in (`claude` runs in your terminal), and a Telegram bot
token from [@BotFather](https://t.me/BotFather).

```bash
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`](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, run `guarded`,
  where every shell command asks.
- `CLAUDE_CODE_LOAD_PROJECT_SETTINGS=true` (the default) loads the workspace's
  `.claude` settings, whose allow-rules are honored by the CLI *before* the
  bridge's callback runs. Set it to `false` to 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)

```bash
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](.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_owner` tool 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

```bash
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
