Claude Code in your pocket

A single Python file turns a Telegram bot into a full Claude Code session on your own server. What it does, how it stays safe, and the bugs you do not have to rediscover.

Claude Code lives in a terminal. That is where it is strongest: real tools, real files, a real shell. It is also where it is least reachable, because a terminal stays on a desk.

The Claude Code Telegram Bridge fixes that. It is a single-file Python daemon that turns a Telegram bot into a full Claude Code session, with tools, memory and skills, running on your own machine, locked to its owner and always on. You send a message from your phone, a real headless Claude Code turn runs on your server, and the replies come back to the chat.

It is open source under the MIT licence. This post is the tour.

What a message does

Every message you send runs claude -p headless, with full tool access and --resume continuity. That last part matters: a conversation on Telegram behaves exactly like one in the terminal, because it is one. Claude remembers the previous turn, can read the files it just wrote, and picks up where it left off.

A few things make it feel native on a phone.

  • Photos. Send a picture and Claude looks at it. Documents, albums and video land in an upload folder, and their paths are added to the turn, so Claude can open them like any other file.
  • Voice. Voice notes are transcribed (ElevenLabs, falling back to Gemini) and the transcript becomes the prompt, with the audio path included. You can speak your commands.
  • Files out. /file /path sends any file from the server to the chat. Claude itself gets the bot token and chat id in its environment, so it can push a finished artifact to you in the middle of a task.

Your sessions, from anywhere

The feature I use most is session remote control. /sessions lists every Claude Code conversation on the box, including the ones started in the terminal, with a snippet of their first message. /attach <id> continues any of them from the phone, and eight characters of the id are enough. /last jumps to the newest.

In practice: start something at the desk, walk out, finish it from the street.

The commands

Command What it does
/new Fresh conversation
/sessions List recent Claude Code sessions
/attach <id> Continue any session here
/last Attach the most recent session
/file <path> Send a file from the server to the chat
/stop Kill the running turn and drain the queue
/status, /log Bridge state and log tail
/reboot Restart the bridge
anything else A Claude Code turn, slash skills included

A small dashboard

The bridge can also serve a status page: live status, the queue, conversations with their attach ids, recent runs, uploads, and system vitals like CPU, memory and disk. It is a single static HTML file served by the bridge itself, read-only, and it asks for a key. There is an optional panel for a Solana treasury, for people who run agents with a wallet.

Setting it up

You need Linux with systemd, Python 3.10 or newer, and a working Claude Code login for the user that runs the bridge. There is nothing to pip install: the whole bridge uses the standard library.

# 1. Get a bot token from @BotFather and your numeric user id from @userinfobot

# 2. Install
sudo git clone https://github.com/naoufac/claude-code-telegram-bridge /opt/claude-tg-bridge
sudo chown -R "$(whoami)" /opt/claude-tg-bridge
cd /opt/claude-tg-bridge
cp .env.example .env && $EDITOR .env   # set TG_TOKEN and OWNER_ID at minimum
chmod 600 .env

# 3. Run it as a service
sudo cp claude-tg-bridge.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now claude-tg-bridge

Then open your bot in Telegram, press Start, and say hi.

The security model, plainly

This is a remote control for a machine, so it is worth being clear about what it trusts.

  • It is owner-locked. Only the Telegram account set as OWNER_ID gets turns. Strangers get silence in groups and a single, throttled refusal in direct messages.
  • Claude runs with --dangerously-skip-permissions, as your user, on your machine. That is the point of the tool, and it also means that whoever controls the owner’s Telegram account controls the server. Protect that account with two-factor authentication, and protect the bot token.
  • The token never leaks into chat. It is redacted from every outbound message.
  • The dashboard needs a key, compared in constant time, and it only serves read-only state.
  • Only one poller per token. A file lock guarantees it: starting a second copy exits instead of letting two processes fight over the same updates.

The bugs you do not have to rediscover

The most useful part of the README might be its design notes. They came out of adversarial review and live testing, and each one is a bug that is easy to write and annoying to find.

Drain stderr in a thread. A chatty claude child process fills its error pipe, the pipe blocks, and the run freezes halfway. Reading stderr on its own thread keeps the pipe empty.

Save the update offset after handling, not before. Telegram hands out messages by offset. If the bridge saves the offset first and then crashes, the message is gone. Saving it after means a crash replays the message instead of dropping it. Exceptions still advance the offset, so one poisonous message cannot loop the bridge forever.

Let /reboot exit only once the offset is saved. Otherwise Telegram redelivers /reboot after every restart, and the bridge reboots itself for the rest of time.

Do not trust a dead --resume id to fail loudly. When the session to resume no longer exists, claude returns an error result and echoes the requested session id back, which looks like success at a glance. The bridge checks the session file on disk first, and heals by retrying once on a fresh session.

Register album items before downloading them. Telegram sends an album as separate messages. If each item joins the batch only after its download finishes, a slow video arrives late and gets split into its own prompt. Registering first, downloading second keeps albums whole.

Keep media off the polling thread. Transcribing a long voice note can take two minutes. Doing it on the thread that listens for new messages would make /stop unresponsive exactly when you need it.

Deploy while idle. Restarting the service kills its whole control group, including a turn that is still running.

None of these are exotic. They are the kind of thing that works on the first demo and fails on the tenth day, which is why they are written down.

Built by its own subject

The bridge was built on a Hetzner server by Claude Code driving itself: specified, written, reviewed adversarially and tested live over Telegram before it was published. The whole thing is one file of about 800 lines, a dashboard, a systemd unit and a documented .env.example.

If you use Claude Code and a phone, take it. It is free, and it is small enough to read in an afternoon.

Keep reading

Web

Reading time, counted not guessed

How a small plugin for Astro’s new Markdown engine counts the words in every post, in any language, and files it as a quick read, an essay or a long read.

4 min read Essay

Stars

Why your birth time matters

The Sun barely moves in a day. The Ascendant goes all the way round the zodiac. A plain guide to what a birth time changes in a chart, and what to do if you do not know yours.

3 min read Essay

Notes

A slower home on the internet

Why this site is one calm page, a short bio and a notebook, and why almost everything on it is drawn by hand in SVG.

2 min read Quick read