TeleCoder

Claude Code
from Telegram

The real Claude Code on your own machine, driven from Telegram. Sessions, plan mode, todos and tool output arrive as native chat — plus background jobs that ping you when done, file delivery, images and voice.

Open source · MIT · self-hosted
TeleCoder
online

Built to keep going

A bot per project

Run several bots side by side, each with its own project, model and reasoning effort. A watchdog spots a hung query instead of leaving you staring at a silent chat.

It tells you when it's done

Long jobs run in the background and ping you the moment they finish. Short ones edit their own message in place, so progress shows as it happens rather than all at the end.

Two ways to run it

Point it at the Claude Agent SDK, or drive the real claude CLI in a terminal with /method. Sessions, forks and /compact work the same either way, and each mode reports the commands its own CLI build actually has.

It keeps going past your limit

When Claude Max throttles mid-turn, one tap switches to a fallback provider and replays the message you just sent. Swap back whenever you like with /provider.

Full Agent Power in Your Pocket

Drive it from your phone

Send coding requests from anywhere over Telegram — quick fixes, code reviews, or steering a long job while you are away from the desk.

The whole toolset

Read files, write code, run bash, search a codebase. Every Claude Code capability is available through chat, not a cut-down subset.

SDK or the real CLI

/method switches between the Agent SDK and driving the actual claude binary — the path built for Pro/Max subscriptions. Sessions and forks work either way.

Watch it work

Tool status, edit diffs and Claude Code's own contextual tips stream into the chat as it goes. /terminalui switches to a terminal-style view.

Pick the model

Switch between Fable, Opus, Sonnet and Haiku with /model — including opusplan, best and the 1M-context variants — and set reasoning effort per bot. Opus by default.

One bot, or all of them

/model and /effort change the bot you typed them in. Add all, or tap the button on the confirmation, and the change is relayed to every instance — which then tells you which ones took it, which are on another backend, and which were mid-turn.

Plans and decisions

Claude posts a live checklist for multi-step work, and when it needs a decision it asks with an inline keyboard — reasoning in the same message, and every option written out in full above the buttons, keyed A/B/C, so a long one is never lost to a clipped button.

Skills

Claude invokes project-level skills from .claude/skills/ via the Skill tool, with user-level skills loadable too.

Claude Code's own slash commands

/code-review, /security-review, /simplify, /init — Claude Code's built-in commands work by typing them in chat, as do your .claude/commands/ ones. /projectcommands lists what this project has, and flags the few names TeleCoder claims for itself.

Your own MCP servers

Point EXTRA_MCP_CONFIG at a JSON file and its servers spawn beside the bot's own, without dragging in every server the machine has ever registered.

Your Claude Code plugins

Name them in CLAUDE_PLUGINS and their skills and commands are there in Telegram too — enabling a plugin in the terminal writes to a settings file the bot deliberately skips, so it would otherwise go missing with nothing to say why.

How much you see

One setting per chat, quiet through debug, controls how much each turn shows. An optional status line carries topic, model, context and cost.

Choose how much Claude asks

Per chat, pick the permission mode the desktop cycles with shift+tab — manual, accept edits, plan or auto. PTY sessions default to auto, so Claude checks in before the riskier steps instead of never asking; /mode bypass is one tap back. The bot puts the session in the mode before your message goes in, and refuses the turn rather than run it in a looser mode than you chose.

Claude Code's dialogs reach you

When Claude Code opens a dialog the bot can't answer — trusting a new folder, picking from a list, asking permission to run a command — it arrives in the chat as buttons with the dialog's own wording. That holds mid-turn too, so the modes that ask before acting work here instead of stalling the turn. Your tap is pressed in the terminal and the turn carries on. Nothing is guessed: unanswered dialogs are left exactly as they are, and the turn ends saying so rather than hanging.

It survives your usage limit

When Claude Max throttles mid-turn, one tap switches to CCR and replays the message you just sent. /provider moves between them any time, carrying a summary across.

Know where your limits stand

/cost shows how much of your session and weekly windows is spent and when each resets, and — by reading the panel your own live session draws — what this conversation has actually cost: dollars, durations, per-model tokens, cache hit rate. The same report you get in the terminal.

Restarts cost you nothing

Sessions survive any restart, planned or not — recent ones reattach silently. /rebuildbot rebuilds and comes back with everything still in place, whether a shell script or systemd is the one holding the bot up.

A crashed bot comes back

An unplanned exit respawns on a backoff, so one crash doesn't leave a chat silent. A bot that can't start at all backs off instead of spinning.

It waits out a busy machine

When the host stalls under load, TeleCoder rides it out rather than reading a starved bot as a dead one — and holds your prompt back until the TUI can take it.

Send while it's still working

A message that lands mid-turn waits for that turn to finish and then goes in, rather than timing out on a Claude that was never going to answer it yet. Long turns run to the end instead of being answered halfway.

A rebuild that can't apply itself says so

/rebuildbot respawns every instance off the new build, but the launcher they run inside keeps the code it started with. When a build changes that too, the restart replies and /botstatus name the restart still owed.

Nothing gets dropped

After every turn TeleCoder checks what it sent against Claude Code's own session log and posts anything missing. /sync re-checks by hand.

Dangerous commands wait for an admin

A guarded pattern — rm -rf, sudo, a force-push, a DROP TABLE — pauses the tool call and posts an approval prompt only an admin can answer. It mentions them by name, so it lands even in a muted group.

A real boundary, one command away

setup-shared-bot-user.sh gives the shared bot its own Unix account — no sudo, no docker, nothing but the shared projects — behind a hardened systemd service. --verify becomes that account and tries to read your secrets, rather than reasoning about file modes.

Work stays inside the shared projects

A tool call naming a path outside them — another project, ~/.ssh, the bot's own .env — pauses for an admin. System paths and language toolchains stay readable, so ordinary work never triggers it.

A charter, read before anything runs

Write the house rules in plain language. A Haiku side-call reads every guest message against them first and holds anything out of bounds — catching "open a tunnel to this box", which names no path and breaks nothing.

Share a bot without handing over the machine

ADMIN_USER_IDS splits your users into admins and guests. Guests use the agent normally; approvals, /restartbot and the transport switch stay yours, and RESTRICT_TO_GROUPS keeps them out of private chats.

Let someone in with one tap

A stranger posts in the shared group and the refusal comes with an approve card naming them — no editing .env, no restart. Telegram gives bots no way to look up a @username, so the bot remembers everyone it has seen: /allow as a reply is exact, and /users shows who is in.

Self-hosted and hardened

Runs on your own machine. SSRF protection, workspace boundaries and restrictive file permissions by default; proxies and optional features are environment-configurable.

Fork a conversation

Every reply carries a 🍴 Fork button that branches from that point — into a fresh conversation, or handed to a sibling bot. The original is kept either way.

Ask without interrupting

/btw answers a question about the running task without pausing it, forking a read-only copy of the transcript.

Pick up where you left off

A one-tap button resumes the session you just cleared, /recap re-reads the last few exchanges, and /prompts lists only what you typed — usually the fastest way to remember what a conversation was about.

A session per forum topic

Each topic in a Telegram group runs as its own independent session, so several projects can run in parallel in one place.

Share a bot with a group

Allow-list a group in ALLOWED_GROUP_IDS and the bot works there. Telegram membership is the outer gate, so removing someone revokes their access on the next message — keep the group invite-only.

Contributors and spectators

Prompting the agent is shell access, but reading along isn't. By default joining the group buys a seat, not a shell: people talk to each other and watch the work, and only those an admin has /allowed can send prompts. Set GROUP_MEMBERS_DEFAULT=contributor for a group of peers who all own the box. Commands that reconfigure the bot — /restartbot, /project, /permissions — stay with admins either way.

Speaks only when spoken to

In a group the bot answers an @mention or a slash command and ignores everything else — including plain replies, so you can quote what it said and talk it over with the others. Answers to its own /project-style prompts still land, since Telegram leaves nowhere to put a mention in those.

Projects and handoff

/project opens on your favorites for one-tap switching, or takes any path on disk. /teleport hands the conversation to a terminal and continues in both.

It pings you when it's done

The activity card lists everything running with its elapsed time and ticks tasks off as they land. Slow or failed ones re-post the card so your phone still buzzes.

Live event relay

Log tails, file watches and subagents report into the chat between turns — all onto one activity card that updates in place, so a monitor firing ten times costs you one message, not ten.

Scheduled tasks

/schedule runs a prompt on a cadence — every 5m, weekdays 14:00. Claude can set its own up too, with hard caps on spend.

Kill a runaway watcher

/shells lists the OS processes the session has spawned, with age. One tap kills the chosen one and its children.

Talk to it, hear it back

Send a voice message and it is transcribed with Whisper. Replies can come back as speech, with a choice of voices and playback speed.

Send it a picture

Photos go in as real multimodal vision input, so Claude sees the image itself rather than a description of it.

Long output stays readable

Long replies render as Telegraph articles with Instant View, and markdown tables become clean key-value blocks instead of garbled pipes.

It sends you files

Generated files — SVGs, images, reports — arrive directly in the chat, with nothing to download by hand.

It reads links for you

Paste a YouTube, Reddit, Medium or TikTok link and it fetches the content — transcripts, threads, full articles — without an explicit command.

Getting Started

Prerequisites

Required

Node.js 20+ and npm Claude Code CLI, authenticated Telegram bot token Your Telegram user ID

One of these — how the CLI authenticates

Claude Pro or Max subscription Anthropic API key
Note: On macOS, TeleCoder uses caffeinate to prevent sleep during long operations.

Quick Start

Terminal
git clone https://github.com/gitaarik/telecoder.git
cd telecoder
npm install
cp .env.example .env
# Edit .env with your credentials
npm run dev

Step-by-Step Setup

1

Clone the repository

Download the project using git clone

2

Install dependencies

Run npm install in the project directory

3

Create your bot

Message @BotFather, send /newbot, then pick a display name and a username ending in bot. It replies with an API token — that token is the bot.

4

Get your Telegram user ID

Message @userinfobot for your numeric ID. TeleCoder only answers accounts on this list, so the bot is inert to anyone else who finds it.

5

Connect the bot to TeleCoder

Copy .env.example to .env, then set TELEGRAM_BOT_TOKEN to the token BotFather gave you and ALLOWED_USER_IDS to your numeric ID.

6

Run the bot

Start with npm run dev for development or npm start for production

7

Say hello

Open the bot in Telegram, send /start, and it should answer. From there /project points it at a folder to work in.

Optional: run several bots at once

A bot is just a token, so repeat the /newbot step for each one you want. Listing the tokens in instances.json makes a single process run them side by side, each with its own project, model and sessions.

instances.json
{
  "defaults": { "ALLOWED_USER_IDS": "123456789" },
  "instances": [
    { "name": "TeleCoder {n}", "tokens": ["token-one", "token-two"] },
    { "name": "Admin Bot", "token": "token-three",
      "overrides": { "WORKSPACE_DIR": "/home/you/projects" } }
  ]
}

defaults applies to every bot and accepts any .env variable; overrides changes it for one. A list of tokens auto-names the bots, with {n} for the number. Start them with npm run dev:multi in place of npm run dev.

Optional: Claude Code Router

CCR is a separate open-source project, not part of TeleCoder — a local proxy that sits in front of the claude binary and can route it to non-Anthropic models. Install it if you want the bot to keep working after your Claude usage runs out. Everything else on this page works without it.

Terminal
npm install -g @musistudio/claude-code-router
# opens a browser UI to add providers and models
ccr ui

CCR keeps its config and logs in ~/.claude-code-router/ and serves its proxy on port 3456. Once a model is configured there, point TeleCoder at it:

.env
CCR_ENABLED=true
CCR_BASE_URL=http://localhost:3456
CCR_AUTH_TOKEN=your_ccr_token
# run `ccr start` automatically if the proxy is down
CCR_AUTOSTART=true

After that, a mid-turn throttle offers a one-tap switch and replays the message you just sent. /provider picks a backend at any time and /ccr toggles between the two. Full documentation lives in the CCR repository.

CCR always takes the SDK path, so PTY-only behaviour does not carry across — and the two backends never share a session, since one model cannot replay another's thinking blocks. Switching starts a fresh session with a plain-text summary carried over.

Configuration

Variable Description Required
Core
TELEGRAM_BOT_TOKEN Bot token from BotFather Yes
ALLOWED_USER_IDS Comma-separated Telegram user IDs Yes
Sharing
ADMIN_USER_IDS Who may approve permission prompts and run lifecycle/transport commands (default: every allowed user) Optional
ALLOWED_GROUP_IDS Group chat IDs the bot is shared in Optional
RESTRICT_TO_GROUPS Confine non-admins to those groups; admins can still DM the bot (default: false) Optional
TELECODER_PERMISSION_PROMPTS Force the permission gate on (1) or off (0); on by itself once the bot has non-admin users Optional
PERMISSION_PROMPT_TIMEOUT_MINUTES How long a prompt waits for an admin before auto-denying (default: 10) Optional
SCOPE_GUARD Prompt on tool calls naming paths outside the shared projects: auto (follows the gate), on, off Optional
SCOPE_ALLOWED_PATHS Extra in-bounds directories, comma-separated, on top of WORKSPACE_DIR and the temp dir Optional
CHARTER_JUDGE Read each guest message against the charter before it reaches Claude: auto, on, off Optional
CHARTER_FILE The charter the judge reads (default: CHARTER.md in the workspace root, else a generated one) Optional
CLAUDE_METHOD_DEFAULT Transport for chats that haven't run /method; the permission gate only runs on pty (default: sdk) Optional
Claude
ANTHROPIC_API_KEY Your Anthropic API key Optional*
WORKSPACE_DIR Default workspace path for projects No
CLAUDE_PLUGINS Marketplace plugins to enable in the agent, as plugin@marketplace ids, comma-separated Optional
STREAMING_MODE streaming or wait for responses No
BOT_MODE dev or prod No
DANGEROUS_MODE Auto-approve all tool permissions (default: false) No
API Keys
OPENAI_API_KEY For OpenAI TTS voices For TTS
GROQ_API_KEY For voice transcription & Orpheus TTS For voice
REDDIT_CLIENT_ID & 3 more OAuth2 app credentials for /reddit. Once all four are set the command turns itself on — see the README. For Reddit
Feature Flags
TTS_ENABLED Enable text-to-speech (default: true) No
REDDIT_ENABLED Force /reddit on or off (default: on once credentials are set) No
VREDDIT_ENABLED Enable /vreddit command (default: true) No
MEDIUM_ENABLED Enable /medium command (default: true) No
TRANSCRIBE_ENABLED Enable voice transcription (default: true) No
EXTRACT_ENABLED Enable /extract command (default: true) No
TTS Configuration
TTS_PROVIDER openai or groq (default: groq) No
TTS_VOICE Default voice name (default: coral) No
TTS_SPEED Playback speed multiplier (default: 1.0) No
Display & Behavior
TERMINAL_UI_DEFAULT Terminal-style display on by default (default: true) No
MAX_LOOP_ITERATIONS Max iterations for /loop mode (default: 5) No
CANCEL_ON_NEW_MESSAGE Auto-cancel running query on new message (default: false) No
*ANTHROPIC_API_KEY is optional if using a Claude Max subscription with claude CLI configured. All feature flags default to true — disabled features auto-hide from the Telegram menu.

How It Works

Telegram
TeleCoder
Provider router
Claude Code · CCR
Your Machine

Commands

📁 Project Management

/start Welcome message and getting started guide
/project <name> Open a project from your workspace directory
/newproject <name> Create and open a new project
/clear [-y] Clear conversation history (project stays selected); pass -y to skip the confirmation prompt
/status Show current session and project info
/projectcommands List every slash command this project offers — .claude/commands/*.md, Claude Code's built-in skills like /code-review, and any plugin commands. They pass straight through, so typing one in chat just works. Also names the commands TeleCoder shadows, where the bot's version runs instead of Claude Code's.

💾 Session Management

/resume Resume the last session for current project
/continue Continue last session after bot restart
/sessions Browse and restore previous sessions
/recap [N] Re-read the last N exchanges of the current session (default 3)
/prompts [N] List just the last N prompts you sent, one line each, without the replies (default 5, max 20)
/sync Resend the latest assistant reply from the session log if Telegram missed any of it
/fork Fork the current conversation — into a new branch on this same bot, or hand it off to a sibling bot (alternative to tapping the 🍴 Fork button on a past assistant message)
/accept Accept a pending fork from another bot — loads the forked transcript into this bot (your current conversation stays in /resume history)
/decline Discard a pending fork from another bot without loading it
/schedule <when> <prompt> Schedule a recurring prompt — supports every 5m, every 1h, daily 9am, weekdays 14:00, mon,wed,fri 10:30, or a raw 5-field cron. Options: --max-runs N, --label "...". Each fire posts a "🔔 Scheduled" header and runs through the current session.
/schedules List active scheduled tasks for this chat with id, next-fire time, run count, and the prompt preview
/unschedule <id> Remove a scheduled task by id (get the id from /schedules)
/handoff Dump the current conversation to a markdown file and deliver it as a Telegraph link plus a downloadable file — useful before switching projects, clearing context, or handing work to a teammate. Captures up to 200 exchanges plus session metadata.
/teleport Move session to terminal (forked)

🧠 Agent Modes

/provider Switch AI provider (Claude / CCR). Admin-only when the bot has non-admin users.
/method Switch Claude transport: SDK (default) or PTY (drives an interactive Claude Code session over a pseudo-terminal — experimental, intended to stay on the Pro/Max subscription after the 2026-06-15 programmatic-usage split). Admin-only when the bot has non-admin users.
/ccr Toggle routing through Claude Code Router (sticky fallback when Max runs out). Admin-only when the bot has non-admin users.
/model [all] Switch AI model (provider-aware). Offers every alias Claude Code's --model accepts — fable, opus, sonnet, haiku, opusplan, best and the fable/opus/sonnet 1M-context variants — filtered to what your installed CLI actually supports, so an alias your binary predates never reaches a turn. Pass a full model ID instead (/model claude-opus-4-8) to pin an exact release; unrecognised names are forwarded to the CLI as-is with a warning. Applies to the bot you typed it in; add all (/model sonnet all) or tap the button on the confirmation to set every instance at once. Works in both SDK and PTY mode; in PTY mode Claude Code restarts on your next message to pick it up, keeping the conversation. Reports the model that actually served the last turn rather than a default.
/effort <level> [all] Set reasoning effort (low/medium/high/xhigh/max/auto). Per bot, with the same all argument and one-tap fan-out as /model. Works in both SDK and PTY mode; in PTY mode Claude Code restarts on your next message to pick it up, keeping the conversation. Enable /statusline to see the current level's icon (🐇/⚖️/🧠/🔬/🚀) after each turn.
/verbosity <tier> Pick how much detail TeleCoder surfaces per turn (quiet / normal / verbose / debug). Verbose adds the per-turn usage footer, untruncated tool inputs, and a consolidated action log that streams live then collapses to a Telegraph link at the end of the turn. Debug extends the action log with longer previews (40 lines vs 20); quiet suppresses the completion ping. Per-chat — overrides VERBOSITY_DEFAULT.
/btw <question> Ask a side question without interrupting the current task. Works in both modes: SDK mode uses the live query's side-question channel, PTY mode answers from a read-only, non-persisted fork of the running session — so the transcript is never touched and the turn keeps going.
/tasks List active background work — subagents, monitors, backgrounded shells and workflows — grouped by kind, with elapsed time; tap a number to view details. Entries that have gone silent for 15 minutes are flagged ⚠️ — a finished task normally drops off the list, so a long-quiet one usually means its completion event never arrived; monitors are exempt, since idling until an event fires is exactly what they do. Works in both SDK and PTY mode. In PTY mode, 🔎 Ask claude types /tasks into the live TUI and relays Claude Code's own background view, which also covers shells it started on its own and anything armed before the last bot restart.
/shells List OS-level background shells spawned by the PTY claude session (e.g. Bash(run_in_background=true) pollers, Monitor loops). Each row shows age, PID, and the cmdline so you can decide before tapping — buttons SIGTERM that process and its descendants. Rescues sessions hung on a watcher whose condition will never fire.
/mode <manual|acceptEdits|plan|auto|bypass> How much Claude asks before acting, per chat. Same modes the desktop cycles with shift+tab; buttons if you pass no argument. Default follows the transport, and the menu spells out what that resolves to — auto on PTY, accept edits on the SDK unless DANGEROUS_MODE promotes it. Admin-only.
/streaming Toggle streaming vs wait response mode
/terminalui Toggle terminal-style display with spinners
/statusline Toggle per-turn status line (effort, model, context %, cost) with sub-toggles for topic, your last prompt, and a copy-pasteable claude --resume command
/botname Toggle dynamic bot name (shows the active project)
/suggestions Toggle predicted next-prompt buttons. When on, TeleCoder scrapes Claude Code's ghost-text suggestion from the TUI at end-of-turn and surfaces it as a tappable inline button under each response. Takes effect on next session spawn.
/topic <text> Set or clear the conversation topic (shown in the status line when enabled)
/plan Enter plan mode for architecture discussions
/explore Enter explore mode for codebase analysis
/loop Toggle loop mode for continuous tasks

🎬 Media & Content

/extract <url> Download media from YouTube, TikTok, Instagram
/reddit <sub> Browse subreddit posts
/vreddit <url> Download Reddit videos with audio
/medium <url> Fetch a Medium article as readable text, via Freedium
/file <path> Get a project file as Telegram download
/telegraph Toggle Instant View for long responses, or view a file

🎤 Voice & Audio

/tts Toggle text-to-speech for responses
/transcribe Transcribe audio without sending to agent

⚙️ Utility

/context Show current context window usage. When it has to ask the CLI directly it does so on a throwaway fork, so the live conversation's transcript is never written to.
/cost Show what Claude Code's own /cost reports, from two sources at once. A spawned probe gives the account-wide limits view — how much of the session and weekly windows is spent and when each resets, the same text /usage prints — which it can answer in any mode, with no session, before a project is even open. In PTY mode your chat's live session is asked too, and the Session block is read off the panel it draws: total cost, API and wall durations, code changes, per-model token counts and the prompt-cache line. Those are the numbers a probe can never have — the cost counter belongs to the process that spent it and no session log preserves it — so when they arrive the probe's own totals are dropped rather than printed beside them. In SDK mode, where there is no panel to read, TeleCoder's per-turn tally stands in. Bypasses the queue to answer mid-turn; the Session block is the one part that waits, since reading it needs the TUI keyboard. Asks your own CLI install rather than the copy bundled with the SDK, which trails it by many releases and replies with a single sentence.
/compact Compact the context window — runs native Claude Code compaction and replies with the token reduction. Works in both SDK and PTY mode; when the context is already small enough to skip, it says so instead.
/cancel Cancel current request (alias: /stop)
/commands Show all available commands
/ping Health check (bypasses processing queue)
/botstatus Show bot process status
/restartbot Restart the bot — inline menu picks this instance, all instances, or cancel. Admin-only when the bot has non-admin users.
/rebuildbot Rebuild code and restart — inline menu picks this instance, all instances, or cancel. Admin-only when the bot has non-admin users.
/permissions Show the permission-gate state, the scope guard's in-bounds roots, which charter is in force, your role (admin or guest), the patterns it enforces, and a warning when the current chat is on a transport the gate cannot run on.
/users Show who can use this bot — admins, guests from .env, guests admitted from chat, and people seen in the group but not let in. Admin-only.
/allow [@user|id] Let someone in, effective immediately with no restart. In a group it makes them a contributor there; in a DM it admits them to the bot everywhere. Reply to their message for an exact match — Telegram gives bots no way to resolve a @username, so a typed handle only matches people the bot has already seen. Admin-only.
/deny [@user|id] The mirror of /allow: in a group it makes someone a spectator there, in a DM it removes them from the bot. Ids that come from ALLOWED_USER_IDS are reported rather than silently ignored — those live in the .env. Admin-only.
/update Update the Claude Code CLI — confirms with current version, then runs claude update. Admin-only when the bot has non-admin users.

👥 Group Access

/members Who may prompt the agent in this group — admins, contributors, explicit spectators, and the default everyone else falls into. The per-group half of /users.

Contributors

TeleCoder began in February 2026 as a fork of Claudegram by Nacho Mascort, and is maintained independently today by Rik Wanders.