CCGram — manage AI coding agents from Telegram via tmux
Project description
CCGram — Control AI Coding Agents from Telegram
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, Codex CLI, Gemini CLI, Pi, 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 attachand 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
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;
/panesfor 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
/livecommand; 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) oruser(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=trueglobally hidestool_use/tool_resultmessages;/toolcallscycles 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 —
/sessionsshows all active sessions with status and kill buttons - Persistent state — bindings and read offsets survive bot restarts
Multi-Provider Support
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 -tTTY fallback for JS runtime wrappers (node/bun) - Emdash 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)
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 for setup and usage
Quick Start
Prerequisites
- Python 3.14+
- tmux — installed and in PATH
- At least one agent CLI —
claude(default),codex,gemini, orpiinstalled and authenticated (or useshellwith no extra install)
Install
uv tool install ccgram # recommended
pipx install ccgram # pipx
brew install alexei-led/tap/ccgram # Homebrew (macOS)
Configure
- Create a Telegram bot via @BotFather
- In BotFather settings:
- Allow Groups: On
- Group Privacy: Off (required to see all topic messages)
- Topics: On
- Add the bot to a Telegram group with Topics enabled
- Promote the bot to Administrator with Create Topics and Pin Messages permissions
- Create
~/.ccgram/.env:
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. Get the group ID via @RawDataBot (prefix the Peer ID with
-100).
Install Claude Hooks (Claude Code only)
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
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_<NAME>_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_TTS_PROVIDER |
(disabled) | TTS backend for voice replies (edge). Requires pip install ccgram[tts] |
CCGRAM_TTS_VOICE |
en-US-EmmaMultilingualNeural |
Voice name for the selected TTS provider |
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
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
- Set the three Mini App env vars:
CCGRAM_MINIAPP_BASE_URL=https://ccgram.example.com CCGRAM_MINIAPP_HOST=127.0.0.1 CCGRAM_MINIAPP_PORT=8765
- 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 inMINIAPP_BASE_URLmust serve it over HTTPS — Telegram WebApps refuse plain HTTP. - In @BotFather:
/setdomain— register your domain/newapp— create a Mini App entry pointing to the same URL
- 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
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 — CLI reference, configuration, voice messages, multi-instance setup, session recovery, testing
- 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:
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 by six-ddc, the original Telegram-to-Claude-Code bridge. Thanks for the spark.
License
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 ccgram-3.0.5.tar.gz.
File metadata
- Download URL: ccgram-3.0.5.tar.gz
- Upload date:
- Size: 16.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9fb0201e645a0c58adecaa75e61430837790437ac57d2501934cd8ebc00477db
|
|
| MD5 |
8abe0ed7a993d4d1e98818b036f3c0ef
|
|
| BLAKE2b-256 |
86f086c094c782813d80fa7a309d25cea0488e62e2c02b6a5e89d1c5eee9697b
|
Provenance
The following attestation bundles were made for ccgram-3.0.5.tar.gz:
Publisher:
release.yml on alexei-led/ccgram
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ccgram-3.0.5.tar.gz -
Subject digest:
9fb0201e645a0c58adecaa75e61430837790437ac57d2501934cd8ebc00477db - Sigstore transparency entry: 1435376506
- Sigstore integration time:
-
Permalink:
alexei-led/ccgram@3ab85c04db238a18b351bd8e7dbb4140103b5388 -
Branch / Tag:
refs/tags/v3.0.5 - Owner: https://github.com/alexei-led
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3ab85c04db238a18b351bd8e7dbb4140103b5388 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ccgram-3.0.5-py3-none-any.whl.
File metadata
- Download URL: ccgram-3.0.5-py3-none-any.whl
- Upload date:
- Size: 15.7 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1733fb656c20cad7d02f162188969856d5c227c8d91f38928988016a62281ca8
|
|
| MD5 |
eac05bb2b9110cd9d689d100278f336a
|
|
| BLAKE2b-256 |
0cf8c7f4e92ba1f9410d29d6c419d5b5e160fddfe4ae14b5acb2286e92575af1
|
Provenance
The following attestation bundles were made for ccgram-3.0.5-py3-none-any.whl:
Publisher:
release.yml on alexei-led/ccgram
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ccgram-3.0.5-py3-none-any.whl -
Subject digest:
1733fb656c20cad7d02f162188969856d5c227c8d91f38928988016a62281ca8 - Sigstore transparency entry: 1435376610
- Sigstore integration time:
-
Permalink:
alexei-led/ccgram@3ab85c04db238a18b351bd8e7dbb4140103b5388 -
Branch / Tag:
refs/tags/v3.0.5 - Owner: https://github.com/alexei-led
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3ab85c04db238a18b351bd8e7dbb4140103b5388 -
Trigger Event:
push
-
Statement type: