Control Claude Code from your phone via Telegram.
ccremote bridges Claude Code CLI to Telegram DMs. Send prompts from your phone, get streaming responses via live draft previews, send photos/documents/voice messages — all without sitting at your computer.
Phone (Telegram) Local Machine
────────────────── ──────────────────
DM with bot ccremote
"fix the bug" ────► ├─ Telegram bot (aiogram)
◄ streaming draft... ├─ claude --print --resume <id>
◄ final response └─ Whisper transcription
- Run
uvx ccremote .in any project directory - Chat with Claude in your bot's DM
- Responses stream as live draft previews, then appear as final messages
- Send photos, documents, or voice messages
- Permission denials show inline buttons to approve and retry
- Create a Telegram bot — open @BotFather, send
/newbot, follow the prompts, copy the token - Get your Telegram user ID — open @userinfobot, send
/start, copy the number - Create a
.ccremotefile in your project directory:CCREMOTE_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11 CCREMOTE_ALLOWED_USER=123456789
- Run:
uvx ccremote . - Open your bot's DM in Telegram and start chatting with Claude
Tip: Add
.ccremoteto your global.gitignore— it contains secrets.
- Claude Code CLI installed and authenticated
- Python 3.11+ and uv (recommended) or pip
- A Telegram bot token (see step 1 above)
- OpenAI API key (optional, only needed for voice message transcription)
git clone https://github.com/nurikk/ccremote.git
cd ccremote
uv venv .venv
source .venv/bin/activate
uv pip install -e .You can configure ccremote in two ways — they can be combined:
Option A: Global environment variables (apply to all projects)
# Add to ~/.zshrc or ~/.bashrc
export CCREMOTE_BOT_TOKEN=123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
export CCREMOTE_ALLOWED_USER=123456789
export CCREMOTE_OPENAI_API_KEY=sk-... # optional, for voice messagesOption B: Per-project .ccremote file (overrides env vars for that project)
CCREMOTE_BOT_TOKEN=999888:XYZ-different-bot-token
CCREMOTE_ALLOWED_USER=123456789
CCREMOTE_OPENAI_API_KEY=sk-...Priority: .ccremote file > environment variables > defaults.
| Variable | Required | Default | Description |
|---|---|---|---|
CCREMOTE_BOT_TOKEN |
yes | — | Telegram bot token from @BotFather |
CCREMOTE_ALLOWED_USER |
yes | — | Your Telegram user ID |
CCREMOTE_OPENAI_API_KEY |
no | "" |
OpenAI key for voice transcription |
CCREMOTE_LOG_LEVEL |
no | info |
debug, info, warning, error |
CCREMOTE_INCLUDE_PARTIAL_MESSAGES |
no | true |
Include partial messages in stream |
CCREMOTE_DRAFT_THROTTLE_MS |
no | 300 |
Min ms between draft updates |
CCREMOTE_MAX_MESSAGE_LENGTH |
no | 4000 |
Max chars per Telegram message |
CCREMOTE_CLAUDE_ALLOWED_TOOLS |
no | — | JSON array of allowed tools (all if unset) |
# With uvx (no install needed)
uvx ccremote .
# Or if installed locally
ccremote .
ccremote ~/code/myprojectThat's it. The bot connects to Telegram and you can start chatting.
- Text — sent directly as prompts to Claude
- Photos — downloaded to
.ccremote-attachments/in the project, path passed to Claude - Documents — same as photos, keeps original filename
- Voice messages — transcribed via OpenAI Whisper, sent as text (requires
CCREMOTE_OPENAI_API_KEY)
When Claude tries to use a tool that's blocked by permissions, you'll see an inline keyboard:
⚠️ Permission denied:
• Bash: ls ~/Downloads
[✅ Allow] [❌ Skip]
Tapping Allow re-runs the prompt with the denied tools added to --allowedTools.
ccremote uses claude --print --resume <session_id> to maintain conversation context. Each message continues the same Claude session, so context builds up naturally across your conversation.
src/ccremote/
├── cli.py Entry point — starts bot, creates session
├── bot.py aiogram dispatcher, message sending helpers
├── relay.py Claude ↔ Telegram relay, streaming, permissions
├── markdown.py Markdown → Telegram HTML converter
├── config.py pydantic-settings configuration
└── models.py Pydantic data models (Session)
Key design decisions:
- Single session mode — one
ccremoteprocess per project, DM-only. This is intentional:sendMessageDraftonly works in private chats, supergroup forums don't allow bots to create new threads via the Bot API, making group-based workflows impractical - Each prompt spawns
claude --print --resume <id>(stateless process, persistent session) sendMessageDraft(Bot API 9.3+) for flicker-free live streaming- Markdown converted to Telegram HTML for formatted output
- Per-project
.ccremoteoverrides global env vars
# Install dev dependencies
uv pip install -e ".[dev]"
# Run tests
python -m pytest tests/ -v
# Lint
ruff check src/ tests/
# Format
ruff format src/ tests/
# Type check
ty check src/MIT

