https://github.com/alexei-led/ccgram
Telegram ↔ tmux bridge for Claude Code, Codex CLI, and Gemini CLI. Monitor output, respond to prompts, manage parallel sessions. Control AI coding agents from your phone.
https://github.com/alexei-led/ccgram
ai-coding claude-code cli codex codex-cli developer-tools gemini gemini-cli python telegram telegram-bot tmux
Last synced: 29 days ago
JSON representation
Telegram ↔ tmux bridge for Claude Code, Codex CLI, and Gemini CLI. Monitor output, respond to prompts, manage parallel sessions. Control AI coding agents from your phone.
- Host: GitHub
- URL: https://github.com/alexei-led/ccgram
- Owner: alexei-led
- License: mit
- Created: 2026-02-10T09:35:58.000Z (4 months ago)
- Default Branch: main
- Last Pushed: 2026-04-02T15:33:46.000Z (2 months ago)
- Last Synced: 2026-04-03T00:41:48.700Z (about 2 months ago)
- Topics: ai-coding, claude-code, cli, codex, codex-cli, developer-tools, gemini, gemini-cli, python, telegram, telegram-bot, tmux
- Language: Python
- Homepage:
- Size: 16.2 MB
- Stars: 38
- Watchers: 0
- Forks: 17
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# CCGram — Control AI Coding Agents from Telegram
[](https://github.com/alexei-led/ccgram/actions/workflows/ci.yml)
[](https://pypi.org/project/ccgram/)
[](https://pypi.org/project/ccgram/)
[](https://pypi.org/project/ccgram/)
[](https://pypi.org/project/ccgram/)
[](LICENSE)
[](https://github.com/astral-sh/ruff)
**Control AI coding agents from your phone.** CCGram bridges Telegram to tmux — monitor output, respond to prompts, and manage multiple sessions without touching your computer. Supports [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Codex CLI](https://github.com/openai/codex), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [Pi](https://pi.dev), and plain shell sessions.
---
## Why CCGram?
AI coding agents run in your terminal. When you step away — commuting, on the couch, or just away from your desk — the session keeps working, but you lose visibility and control.
CCGram fixes this. It operates on **tmux**, not any agent SDK. Your agent process stays exactly where it is, in a tmux window on your machine. CCGram reads its output and sends keystrokes to it. This means:
- **Desktop to phone, mid-conversation** — walk away and keep monitoring from Telegram
- **Phone back to desktop, anytime** — `tmux attach` and you're back with full scrollback
- **Multiple sessions in parallel** — each Telegram topic maps to a separate tmux window, each running a different agent
Other Telegram bots wrap agent SDKs into isolated API sessions that can't be resumed in your terminal. CCGram is a thin control layer over tmux — the terminal stays the source of truth.
---
## How It Works
```mermaid
graph LR
subgraph phone["📱 Telegram Group (Forum Topics)"]
direction TB
T1["💬 api — Claude"]
T2["💬 ui — Codex"]
T3["💬 data — Gemini"]
T4["💬 ops — Shell"]
T5["💬 lab — Pi"]
end
subgraph bridge["⚡ CCGram"]
direction TB
B1["read output\n(transcripts + terminal)"]
B2["send keystrokes\n(tmux send-keys)"]
B3["instant notifications\n(Claude hooks)"]
end
subgraph machine["🖥️ Your Machine — tmux session"]
direction TB
W1["window @0 · claude"]
W2["window @1 · codex"]
W3["window @2 · gemini"]
W4["window @3 · bash"]
W5["window @4 · pi"]
end
phone -- "messages / voice" --> bridge
bridge -- "responses / live view" --> phone
bridge <--> machine
style phone fill:#e8f4fd,stroke:#0088cc,stroke-width:2px,color:#333
style bridge fill:#fff8e1,stroke:#f9a825,stroke-width:2px,color:#333
style machine fill:#f0faf0,stroke:#2ea44f,stroke-width:2px,color:#333
```
Each Telegram Forum topic binds to one tmux window. Messages you type are sent as keystrokes to the pane; responses are parsed from session transcripts and delivered back as Telegram messages.
---
## Features
### Session Control
- **Topic-per-agent** — each Telegram Forum topic is one tmux window running one agent CLI
- **Interactive prompts** — AskUserQuestion, ExitPlanMode, and Permission dialogs rendered as inline keyboards
- **Slash commands** — provider-aware menu (Claude `/cost`, Codex `/status`, Gemini `/chat`, Pi `/compact`, etc.); mismatched commands report errors
- **Voice messages** — transcribed via Whisper API (OpenAI/Groq), shown with **Send / Discard** buttons before forwarding
- **Multi-pane support** — auto-detects blocked panes in agent teams, surfaces prompts as alerts; `/panes` for overview
- **Terminal screenshots** — capture the current pane (or any specific pane) as a PNG image
- **Terminal live view** — auto-refreshing screenshots every 5 seconds via **Live** button or `/live` command; content-hash gating skips edits when nothing changed; auto-stops after timeout (configurable)
- **File delivery** (`/send`) — send workspace files to Telegram: exact path (`/send docs/arch.png`), glob (`/send *.png`), substring search (`/send arch`), or interactive browser (`/send`). Project-scoped with security filtering (hidden files, credentials, gitignored, >50 MB denied)
- **Action toolbar** (`/toolbar`) — provider-specific inline buttons. Universal row: Screenshot, Ctrl-C, Live, Send. Provider row varies: Claude (Mode, Think, Esc), Codex (Esc, Enter, Tab), Gemini (Mode, YOLO, Esc), Pi (Esc, Enter, Tab), Shell (Enter, EOF, Suspend)
- **Remote Control** — 📡 topic badge when RC is active; one-tap activation from status keyboard
### Real-Time Monitoring
- **Full status context** — status line shows what the agent is actually doing ("📝 Writing tests for auth module"), not a generic label
- **Configurable topic emoji color scheme** — `CCGRAM_STATUS_MODE=system` (default, green = agent working) or `user` (green = idle, ready for input) — pick the convention that matches how you scan the topic list
- **Completion summaries** — when an agent finishes, a single-line LLM summary of what was accomplished edits the Ready message in-place (~1-2s delay; static enriched Ready appears immediately)
- **Enriched Ready message** — task checklist, turn count, and last status shown on completion
- **Tool results** — tool use/result pairs, thinking content, Bash exit codes, and error/success indicators in batched output
- **Tool-call visibility toggle** — `CCGRAM_HIDE_TOOL_CALLS=true` globally hides `tool_use`/`tool_result` messages; `/toolcalls` cycles per-window (`default → shown → hidden`). Hook events (Stop, errors, subagent updates) bypass the gate
- **Entity-based formatting** — markdown converted to plain text + MessageEntity offsets; automatic plain text fallback, no parse errors
### Session Management
- **Directory browser** — create sessions from Telegram by navigating your file system
- **Auto-sync** — create a tmux window manually and the bot auto-creates a matching topic
- **Recovery** — Fresh / Continue / Resume keyboard when a session dies (buttons adapt per provider)
- **Message history** — paginated browsing via `/history`
- **Sessions dashboard** — `/sessions` shows all active sessions with status and kill buttons
- **Persistent state** — bindings and read offsets survive bot restarts
### Multi-Provider Support
```mermaid
graph TB
subgraph providers["Agent Providers"]
direction LR
C["🟠 Claude Code\nhook events · resume · JSONL"]
X["🧩 Codex CLI\nresume · continue · JSONL"]
G["♊ Gemini CLI\nresume · continue · JSONL"]
P["🥧 Pi\nresume · continue · JSONL"]
S["🐚 Shell\nnl→command · raw mode"]
end
subgraph detection["Auto-Detection"]
D1["process name\n(fast path)"]
D2["ps -t tty\n(JS runtime fallback)"]
D3["pane title symbols\n(Gemini fallback)"]
end
providers --> detection
style providers fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px,color:#333
style detection fill:#e8f4fd,stroke:#0088cc,stroke-width:2px,color:#333
```
- **Per-topic provider** — different topics can use different agents simultaneously
- **Auto-detect** — externally created tmux windows are detected via process name, with `ps -t` TTY fallback for JS runtime wrappers (node/bun)
- **[Emdash](https://emdash.ai) integration** — auto-discovers emdash tmux sessions; bind Telegram topics to emdash-managed agents with zero configuration
### Shell Provider
- **Chat-first** — type natural language → LLM generates a shell command → approve with one tap → output streams back
- **Raw mode** — prefix with `!` to bypass the LLM and send commands directly
- **Voice-to-command** — voice messages transcribed via Whisper, then routed through the LLM
- **Dangerous command detection** — extra confirmation step before running destructive commands
- **BYOK LLM** — OpenAI, Anthropic, xAI, DeepSeek, Groq, Ollama (zero new dependencies)
### Inter-Agent Messaging (Swarm)
```mermaid
graph LR
subgraph agents["Agent Windows"]
A1["claude · api"]
A2["codex · ui"]
A3["shell · ops"]
end
subgraph mailbox["~/.ccgram/mailbox/"]
M["file-based\nper-window inboxes\nJSON messages · TTL"]
end
subgraph telegram["Telegram"]
N["silent notifications\nin sender + recipient topics"]
S["spawn approval\ninline keyboard"]
end
A1 -- "ccgram msg send" --> mailbox
mailbox -- "broker injects\nvia send-keys" --> A2
A3 -- "ccgram msg spawn" --> S
mailbox --> N
style agents fill:#f0faf0,stroke:#2ea44f,stroke-width:2px,color:#333
style mailbox fill:#fce4ec,stroke:#c62828,stroke-width:2px,color:#333
style telegram fill:#e8f4fd,stroke:#0088cc,stroke-width:2px,color:#333
```
- Agents discover each other, exchange messages, broadcast notifications, and spawn new agents
- File-based mailbox (`~/.ccgram/mailbox/`) — no database, no daemon
- Broker delivers pending messages to idle windows automatically
- Spawn approval requires Telegram keyboard confirmation
- See **[docs/guides.md](docs/guides.md#inter-agent-messaging)** for setup and usage
---
## Quick Start
### Prerequisites
- **Python 3.14+**
- **tmux** — installed and in PATH
- **At least one agent CLI** — `claude` (default), `codex`, `gemini`, or `pi` installed and authenticated (or use `shell` with no extra install)
### Install
```bash
uv tool install ccgram # recommended
pipx install ccgram # pipx
brew install alexei-led/tap/ccgram # Homebrew (macOS)
```
### Configure
1. Create a Telegram bot via [@BotFather](https://t.me/BotFather)
2. In BotFather settings:
- **Allow Groups**: On
- **Group Privacy**: Off _(required to see all topic messages)_
- **Topics**: On
3. Add the bot to a Telegram group with Topics enabled
4. **Promote the bot to Administrator** with **Create Topics** and **Pin Messages** permissions
5. Create `~/.ccgram/.env`:
```ini
TELEGRAM_BOT_TOKEN=your_bot_token_here
ALLOWED_USERS=your_telegram_user_id
CCGRAM_GROUP_ID=your_telegram_group_id
```
> Get your user ID from [@userinfobot](https://t.me/userinfobot). Get the group ID via [@RawDataBot](https://t.me/RawDataBot) (prefix the Peer ID with `-100`).
### Install Claude Hooks (Claude Code only)
```bash
ccgram hook --install
```
Registers Claude Code hooks for automatic session tracking, instant interactive UI detection, API error alerting, and subagent/team notifications. Not needed for Codex, Gemini, or Pi.
> If hooks are missing, ccgram warns at startup with the fix command. Hooks are optional — terminal scraping works as fallback.
### Run
```bash
ccgram
```
Open your Telegram group, create a new topic, send a message — a directory browser appears. Pick a project directory, choose your agent (Claude, Codex, Gemini, Pi, or Shell), choose session mode (`✅ Standard` or `🚀 YOLO`), and you're connected.
---
## Configuration Reference
| Variable / Flag | Default | Description |
| ------------------------------ | ----------------- | -------------------------------------------------------------------------- |
| `TELEGRAM_BOT_TOKEN` | _(required)_ | Bot token from @BotFather (env only) |
| `ALLOWED_USERS` | _(required)_ | Comma-separated Telegram user IDs |
| `CCGRAM_DIR` | `~/.ccgram` | Config and state directory |
| `CCGRAM_PROVIDER` | `claude` | Default provider (`claude`, `codex`, `gemini`, `pi`, `shell`) |
| `CCGRAM__COMMAND` | _(from provider)_ | Override launch command per provider |
| `CCGRAM_GROUP_ID` | _(all groups)_ | Restrict to one Telegram group |
| `CCGRAM_STATUS_MODE` | `system` | Topic emoji color scheme: `system` (green=working) or `user` (green=ready) |
| `CCGRAM_HIDE_TOOL_CALLS` | `false` | Global default for hiding `tool_use`/`tool_result` messages |
| `CCGRAM_LLM_PROVIDER` | _(disabled)_ | LLM for shell command generation + completion summaries |
| `CCGRAM_LLM_API_KEY` | _(empty)_ | LLM API key (env only) |
| `CCGRAM_WHISPER_PROVIDER` | _(disabled)_ | Whisper provider for voice transcription (`openai`, `groq`) |
| `CCGRAM_LIVE_VIEW_INTERVAL` | `5` | Live view refresh interval in seconds |
| `CCGRAM_LIVE_VIEW_TIMEOUT` | `300` | Live view auto-stop timeout in seconds |
| `CCGRAM_SEND_SEARCH_DEPTH` | `5` | Max directory depth for `/send` file search |
| `CCGRAM_SEND_MAX_RESULTS` | `50` | Max file results returned by `/send` search |
| `AUTOCLOSE_DONE_MINUTES` | `30` | Auto-close completed topics after N minutes |
| `AUTOCLOSE_DEAD_MINUTES` | `10` | Auto-close dead sessions after N minutes |
| `CCGRAM_PANE_LIFECYCLE_NOTIFY` | `false` | Default for per-window pane create/close notifications |
| `CCGRAM_MINIAPP_BASE_URL` | _(disabled)_ | Externally reachable HTTPS URL for the Mini App dashboard |
| `CCGRAM_MINIAPP_HOST` | `127.0.0.1` | Local aiohttp bind host for the Mini App server |
| `CCGRAM_MINIAPP_PORT` | `8765` | Local aiohttp bind port for the Mini App server |
Full reference: **[docs/guides.md](docs/guides.md#configuration)**
---
## Mini App Dashboard (Optional)
CCGram ships an optional web dashboard that opens from a Telegram inline button and runs inside Telegram's WebApp container. Three surfaces are available in v3.0:
- **Live terminal** — xterm.js stream of the bound tmux pane (read-only)
- **Transcript** — paginated session history with full-text search
- **Multi-pane grid** — every pane in the window in one view; click to focus
The Mini App is **disabled by default**. When `CCGRAM_MINIAPP_BASE_URL` is unset, neither the HTTP server nor the dashboard button are exposed.
### Enable
1. Set the three Mini App env vars:
```ini
CCGRAM_MINIAPP_BASE_URL=https://ccgram.example.com
CCGRAM_MINIAPP_HOST=127.0.0.1
CCGRAM_MINIAPP_PORT=8765
```
2. Terminate TLS in front of the local aiohttp server (cloudflared, caddy, or nginx). The server listens on plain HTTP at `MINIAPP_HOST:MINIAPP_PORT`; the public domain in `MINIAPP_BASE_URL` must serve it over HTTPS — Telegram WebApps refuse plain HTTP.
3. In [@BotFather](https://t.me/BotFather):
- `/setdomain` — register your domain
- `/newapp` — create a Mini App entry pointing to the same URL
4. Restart `ccgram`. A new "🪟 Dashboard" button appears on the status bubble.
Tokens are HMAC-signed with the bot token, scoped to a single window + user, and expire on a short clock. There is no cross-window access — every API route validates the token on every call.
### Reverse-proxy snippet (caddy)
```
ccgram.example.com {
reverse_proxy 127.0.0.1:8765
}
```
For nginx, ensure `proxy_http_version 1.1` and the standard `Upgrade`/`Connection` headers are forwarded so the live terminal websocket works.
---
---
## Development
```bash
git clone https://github.com/alexei-led/ccgram.git
cd ccgram
uv sync --extra dev
make check # fmt + lint + typecheck + unit + integration tests
make test-e2e # E2E tests (requires agent CLIs, see docs/guides.md)
```
---
## Documentation
- **[docs/guides.md](docs/guides.md)** — CLI reference, configuration, voice messages, multi-instance setup, session recovery, testing
- **[docs/providers.md](docs/providers.md)** — Provider details (Claude, Codex, Gemini, Pi, Shell), session modes, LLM configuration, custom launch commands
---
## Migrating from ccbot
CCGram was previously named `ccbot`. If upgrading from v1.x:
```bash
pip install ccgram # or: brew install alexei-led/tap/ccgram
mv ~/.ccbot ~/.ccgram # migrate config directory
# Update CCBOT_* env vars → CCGRAM_* (old vars still work with deprecation warnings)
ccgram hook --install # re-install hooks
```
---
## Acknowledgments
Inspired by [ccbot](https://github.com/six-ddc/ccbot) by [six-ddc](https://github.com/six-ddc), the original Telegram-to-Claude-Code bridge. Thanks for the spark.
## License
[MIT](LICENSE)