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.
Why TeleCoder
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.
Capabilities
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.
Installation
Getting Started
Prerequisites
Required
One of these — how the CLI authenticates
caffeinate to prevent sleep during long operations.
Quick Start
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
Clone the repository
Download the project using git clone
Install dependencies
Run npm install in the project directory
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.
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.
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.
Run the bot
Start with npm run dev for development or npm start for production
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.
{
"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.
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:
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.
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.
Architecture
How It Works
Reference
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.
Community
Contributors
TeleCoder began in February 2026 as a fork of Claudegram by Nacho Mascort, and is maintained independently today by Rik Wanders.