Claude Code from Telegram. Your agent runs on your machine — you drive it from your phone.
Telegram ──▶ Grammy Bot ──▶ Claude Agent SDK ──▶ Your Machine
voice/text command router agentic runtime bash, files, code
TeleCoder began in February 2026 as a fork of Claudegram by @NachoSEO and now runs as an independent project maintained by @gitaarik — 185+ commits and ~25k lines beyond the original, including a provider router, PTY transport, multi-instance launcher, background task lifecycle, and an agent watchdog. See Credits for full attribution.
TeleCoder bridges Telegram to a full Claude Code agent running locally on your machine. Send a message in Telegram — Claude reads your files, runs commands, writes code, transcribes voice notes, and speaks responses back. All from your phone.
This is not a simple API wrapper. It's the real Claude Code agent with tool access — Bash, file I/O, code editing, web browsing — packaged behind a Telegram interface with streaming responses, session memory, and rich output formatting.
|
|
Claude Code is the backend. What varies is the model behind it: a provider router sits in front of every message, so when Max throttles or you want a different model, the bot keeps working instead of stopping.
| Provider | What it is | Enable |
|---|---|---|
claude |
Claude Code itself, over one of two transports (/method): SDK (default, Claude Agent SDK) or PTY (drives the real claude CLI in a pseudo-terminal) |
on by default |
ccr |
The same claude binary, routed through a local Claude Code Router proxy so non-Anthropic models can back it |
CCR_ENABLED=true |
/provider opens a picker listing the enabled backends. /ccr is a one-tap toggle
between Claude and CCR for the common "I'm throttled, keep going" case. Both are
sticky — the choice holds until you switch back.
When a Max usage-limit throttle is detected mid-turn, the bot doesn't just surface
the error — it offers a 🔌 Switch to CCR & retry button, with the reset time when
one can be parsed from the response. One tap moves the session to CCR and replays the
message you just sent. Set CCR_AUTO_PROMPT_ON_THROTTLE=false for a plain error instead.
If the CCR proxy isn't reachable, CCR_AUTOSTART=true runs ccr start in the background
rather than letting the request hang on a refused connection.
Sessions can't cross backends — one model can't replay another's thinking blocks, and
attempting it fails with a signature error. So a switch that would abandon a live session
asks for confirmation first, then forks: a fresh session starts on the new backend,
carrying a plain-text summary of the conversation so far. The model preference is cleared
at the same time, since opus/sonnet/haiku don't map 1:1 once CCR's router decides
the real backend per request.
CCR runs the same agent, so nearly everything carries over. The exception:
- PTY transport —
ccralways takes the SDK path, along with the PTY-only features layered on it
# .env
CCR_ENABLED=true
CCR_BASE_URL=http://localhost:3456
CCR_AUTH_TOKEN=your_ccr_token
CCR_AUTO_PROMPT_ON_THROTTLE=true
CCR_AUTOSTART=false| Requirement | Notes |
|---|---|
| Node.js 18+ | with npm |
| Claude Code CLI | installed and authenticated — claude in your PATH |
| Telegram bot token | from @BotFather |
| Your Telegram user ID | from @userinfobot |
git clone https://github.com/gitaarik/telecoder.git
cd telecoder
cp .env.example .envEdit .env:
TELEGRAM_BOT_TOKEN=your_bot_token
ALLOWED_USER_IDS=your_user_idnpm install
npm run dev # dev mode with hot reloadOpen your bot in Telegram → /start
| Command | Description |
|---|---|
/start |
Welcome message |
/project |
Set working directory (interactive picker) |
/newproject <name> |
Create and switch to a new project |
/projectcommands |
List the project's .claude/commands/*.md slash commands |
/clear |
Clear conversation history (project stays selected) |
/status |
Current session info |
/sessions |
List saved sessions |
/resume |
Pick from recent sessions |
/continue |
Resume most recent session |
/recap [N] |
Re-read the last N exchanges of the current session (default 3) |
/sync |
Resend the latest assistant reply from the session log if Telegram missed any of it |
/handoff |
Dump the conversation to markdown — Telegraph link plus downloadable file |
/fork |
Fork the conversation — new branch on this bot, or hand off to a sibling bot |
/accept |
Accept a pending fork from another bot |
/decline |
Discard a pending fork without loading it |
/schedule <when> <prompt> |
Schedule a recurring prompt (every 5m, daily 9am, or raw cron) |
/schedules |
List active scheduled tasks for this chat |
/unschedule <id> |
Remove a scheduled task by id |
/teleport |
Move session to terminal (forked) |
| Command | Description |
|---|---|
/plan |
Plan mode for complex tasks |
/explore |
Explore codebase to answer questions |
/loop |
Run iteratively until task complete |
/model |
Switch Sonnet / Opus / Haiku |
/effort |
Set reasoning effort (low / medium / high / xhigh / max / auto) |
/btw |
Ask a side question without interrupting the running task |
/mode |
Toggle streaming / wait |
/method |
Switch Claude transport (SDK / PTY) |
/provider |
Switch backend — Claude / CCR (shown when CCR_ENABLED) |
/ccr |
Sticky toggle between Claude and CCR routing (shown when CCR_ENABLED) |
/verbosity |
Pick verbosity tier (quiet / normal / verbose / debug) |
/terminalui |
Toggle terminal-style display |
| Command | Description |
|---|---|
/reddit |
Fetch Reddit posts, subreddits, profiles |
/vreddit |
Download Reddit-hosted videos |
/medium |
Fetch Medium articles via Freedium |
/file |
Download a project file |
/telegraph |
Toggle Instant View for long responses |
/suggestions |
Toggle predicted next-prompt buttons under each response |
/extract <url> |
Download media from YouTube, TikTok, Instagram |
| Command | Description |
|---|---|
/tts |
Toggle voice replies, pick voice |
/transcribe |
Transcribe audio to text |
| Send voice note | Auto-transcribed → processed by Claude |
| Command | Description |
|---|---|
/ping |
Health check |
/context |
Show Claude context / token usage |
/compact |
Compact the context window (PTY mode) |
/statusline |
Toggle per-turn status line (effort, model, context %, cost) |
/botname |
Toggle dynamic bot name (shows the active project) |
/topic |
Set or clear the conversation topic |
/tasks |
List active background tasks |
/shells |
List and kill OS-level background shells from the PTY session |
/permissions |
Show the permission-gate state and the patterns it enforces |
/botstatus |
Bot process status |
/restartbot |
Restart the bot |
/rebuildbot |
Rebuild code and restart |
/update |
Update the Claude Code CLI |
/cancel |
Cancel current request (alias: /stop) |
/commands |
Show all commands |
Reddit — /reddit & /vreddit
/reddit is a pure TypeScript module using Reddit's OAuth2 API directly — no external Python dependency.
# .env
REDDIT_CLIENT_ID=your_client_id
REDDIT_CLIENT_SECRET=your_client_secret
REDDIT_USERNAME=bot_account
REDDIT_PASSWORD=bot_passwordCreate a "script" app at https://www.reddit.com/prefs/apps/. Use a dedicated bot account — NOT your personal credentials.
/reddit turns itself on once all four credentials are present, and stays hidden otherwise, so it never shows up in the command menu as something that can only fail. Set REDDIT_ENABLED explicitly to override that either way.
/vreddit is separate — it reads Reddit's public JSON and needs no credentials, only ffmpeg and ffprobe on your PATH.
Medium — /medium
Pure TypeScript via Freedium mirror — no extra dependencies.
# .env (optional tuning)
FREEDIUM_HOST=freedium-mirror.cfd
MEDIUM_TIMEOUT_MS=15000Voice Transcription — Groq Whisper
# .env
GROQ_API_KEY=your_groq_key
GROQ_TRANSCRIBE_PATH=/absolute/path/to/groq_transcribe.pyText-to-Speech — OpenAI TTS
# .env
OPENAI_API_KEY=your_openai_key
TTS_MODEL=gpt-4o-mini-tts
TTS_VOICE=coral
TTS_RESPONSE_FORMAT=opus13 voices available: alloy, ash, ballad, cedar, coral, echo, fable, marin, nova, onyx, sage, shimmer, verse
All config lives in .env. See .env.example for the full annotated reference.
| Variable | Description |
|---|---|
TELEGRAM_BOT_TOKEN |
Bot token from @BotFather |
ALLOWED_USER_IDS |
Comma-separated Telegram user IDs |
| Variable | Default | Description |
|---|---|---|
ANTHROPIC_API_KEY |
— | API key (optional with Claude Max subscription) |
WORKSPACE_DIR |
$HOME |
Root directory for project picker |
CLAUDE_EXECUTABLE_PATH |
claude |
Path to Claude Code CLI |
BOT_NAME |
TeleCoder |
Bot name in system prompt |
STREAMING_MODE |
streaming |
streaming or wait |
DANGEROUS_MODE |
false |
Auto-approve all tool permissions |
CANCEL_ON_NEW_MESSAGE |
false |
Auto-cancel running query on new message |
CLAUDE_SDK_LOG_LEVEL |
off |
SDK log level: off, basic, verbose, trace |
| Variable | Default | Description |
|---|---|---|
CCR_ENABLED |
false |
Enable /ccr and CCR in /provider |
CCR_BASE_URL |
http://localhost:3456 |
Where CCR's local proxy listens |
CCR_AUTH_TOKEN |
— | CCR's local auth token |
CCR_AUTO_PROMPT_ON_THROTTLE |
true |
Offer a one-tap CCR retry on Max throttle |
CCR_AUTOSTART |
false |
Run ccr start when the proxy isn't reachable |
CCR_BINARY |
ccr |
Path or name of the ccr binary for autostart |
| Variable | Default | Description |
|---|---|---|
REDDIT_ENABLED |
on when all four credentials are set | Force /reddit on or off |
REDDIT_CLIENT_ID |
— | Reddit OAuth2 client ID |
REDDIT_CLIENT_SECRET |
— | Reddit OAuth2 client secret |
REDDIT_USERNAME |
— | Reddit bot account username |
REDDIT_PASSWORD |
— | Reddit bot account password |
REDDIT_VIDEO_MAX_SIZE_MB |
50 |
Max video size before compression |
REDDITFETCH_TIMEOUT_MS |
30000 |
Execution timeout |
REDDITFETCH_JSON_THRESHOLD_CHARS |
8000 |
Auto-switch to JSON output |
| Variable | Default | Description |
|---|---|---|
FREEDIUM_HOST |
freedium-mirror.cfd |
Freedium mirror host |
MEDIUM_TIMEOUT_MS |
15000 |
Fetch timeout |
MEDIUM_FILE_THRESHOLD_CHARS |
8000 |
File save threshold |
| Variable | Default | Description |
|---|---|---|
EXTRACT_ENABLED |
true |
Enable /extract command |
YTDLP_COOKIES_PATH |
— | Netscape cookies.txt for yt-dlp |
| Variable | Default | Description |
|---|---|---|
GROQ_API_KEY |
— | Groq API key for Whisper |
GROQ_TRANSCRIBE_PATH |
— | Path to groq_transcribe.py |
OPENAI_API_KEY |
— | OpenAI API key for TTS |
TTS_VOICE |
coral |
Default TTS voice |
TTS_MODEL |
gpt-4o-mini-tts |
TTS model |
VOICE_SHOW_TRANSCRIPT |
true |
Show transcript text before agent response |
src/
├── bot/
│ ├── bot.ts # Bot setup, handler registration
│ ├── handlers/
│ │ ├── command.handler.ts # All slash commands + inline keyboards
│ │ ├── message.handler.ts # Text routing, ForceReply dispatch
│ │ ├── voice.handler.ts # Voice download, transcription, agent relay
│ │ └── photo.handler.ts # Image save + agent notification
│ └── middleware/
│ ├── auth.middleware.ts # User whitelist + group chat auth
│ └── stale-filter.ts # Ignore stale messages on restart
├── claude/
│ ├── agent.ts # Claude Agent SDK, session resume, system prompt
│ ├── mcp-tools.ts # MCP server: Reddit, Medium, Extract, Telegraph tools
│ ├── session-manager.ts # Per-chat session state
│ ├── session-history.ts # Session persistence and history
│ ├── request-queue.ts # Sequential request queue
│ ├── command-parser.ts # Help text + command descriptions
│ └── agent-watchdog.ts # Watchdog for long-running agent tasks
├── reddit/
│ ├── redditfetch.ts # Native TypeScript Reddit client (OAuth2)
│ └── vreddit.ts # Reddit video download + compression pipeline
├── medium/
│ └── freedium.ts # Freedium article fetcher
├── media/
│ └── extract.ts # YouTube/TikTok/Instagram extraction (yt-dlp)
├── telegram/
│ ├── message-sender.ts # Streaming, chunking, Telegraph routing
│ ├── markdown.ts # MarkdownV2 escaping
│ ├── telegraph.ts # Telegraph Instant View client
│ ├── telegraph-settings.ts # Per-chat Telegraph toggle
│ ├── terminal-renderer.ts # Terminal-style UI renderer
│ ├── terminal-settings.ts # Per-chat terminal UI toggle
│ └── deduplication.ts # Message dedup
├── tts/
│ ├── tts.ts # TTS provider routing (Groq Orpheus / OpenAI)
│ ├── tts-settings.ts # Per-chat voice settings
│ └── voice-reply.ts # TTS hook for agent responses
├── audio/
│ └── transcribe.ts # Shared transcription utilities
├── utils/
│ ├── download.ts # URL download with SSRF protection
│ ├── sanitize.ts # Path and error sanitization
│ ├── workspace-guard.ts # Workspace boundary enforcement
│ ├── url-guard.ts # URL validation (protocol, SSRF)
│ ├── file-type.ts # File content validation
│ ├── caffeinate.ts # macOS sleep prevention
│ ├── session-key.ts # Session key generation (DM + forum topics)
│ ├── agent-timer.ts # Agent execution timing
│ └── debug-agent.ts # Debug utilities
├── config.ts # Zod-validated environment config
└── index.ts # Entry point
npm run dev # Dev mode with hot reload (tsx watch)
npm run typecheck # Type check only
npm run build # Compile to dist/
npm start # Run compiled build./scripts/telecoder-botctl.sh dev start # Start dev mode
./scripts/telecoder-botctl.sh dev restart # Restart dev
./scripts/telecoder-botctl.sh prod start # Start production
./scripts/telecoder-botctl.sh dev log # Tail logs
./scripts/telecoder-botctl.sh dev status # Check if runningIf TeleCoder is editing its own codebase, use prod mode to avoid hot-reload restarts:
./scripts/telecoder-botctl.sh prod start # No hot reload
# ... let Claude edit files ...
./scripts/telecoder-botctl.sh prod restart # Apply changesThen /continue or /resume in Telegram to restore your session.
- User whitelist — only approved Telegram IDs can interact
- Project sandbox — Claude operates within the configured working directory
- Permission mode — uses
acceptEditsby default - Dangerous mode — opt-in auto-approve for all tool permissions
- Secrets — loaded from
.env(gitignored), never committed
TeleCoder is a derivative of Claudegram, created by @NachoSEO and MIT-licensed. That project is the foundation this one is built on, and its copyright notice is retained in LICENSE.
TeleCoder is maintained independently by @gitaarik and adds:
- Auto-topic & dynamic bot name — bot display name reflects current work topic, derived via parallel Haiku side-call; per-chat /topic and /botname controls
- Multi-instance launcher — run multiple bots from one process with per-bot session scoping
- Background task lifecycle — surface SDK task lifecycle (started, progress, notifications) in the streaming UI; /tasks command to inspect
- Monitor events — separate Telegram messages for streaming Monitor tool output
- Reasoning effort control — /effort command (low/medium/high/xhigh/ max) with icon prefix in bot name; /btw side-question command
- Plan mode surfacing — extract plan content from spontaneous plan mode and inject into chat
- Skills + TodoWrite — full SDK skill discovery; live-updating per-turn checklist for TodoWrite calls
- send_file MCP tool — Claude can deliver files directly via Telegram
- Session resilience — auto-restore on restart (/rebuildbot), persistent topic + preview across restarts, last-response display on resume
- Agent watchdog — silence/stuck-tool detection, force-abort on stuck queries, /cancel works during hangs
- Message batching middleware — combines rapid split pastes into one prompt
- SDK isolation — bot runs in a clean SDK env to avoid user-level plugin tool-deferral interfering with proactive MCP calls
MIT