← Back to blog

Driving Claude Code From Your Phone Over Telegram

June 25, 2026 (1mo ago) · 7 min read

On this page

Written in Chinese as a private note, 23 June 2026. Translated and lightly edited for publication.

Send a message from Telegram on your phone, have Claude Code carry out real development work on your desktop, and get the result back in the same chat. This runs on Anthropic's official Channels feature — not a third-party bridge, so there is nothing of your own to maintain and no extra party in the loop.

What it is, and what it isn't. It is a way to inject messages from your phone into a Claude Code session that is already running on your machine; Claude works with your real files and tools, and the reply goes back to Telegram. It is not a cloud session. Messages are only received while that session is open — so if you want it available for a long stretch, the terminal window has to stay open.

Prerequisites#

Item Requirement
Claude Code version ≥ 2.1.80
Bun runtime Installed — the plugin is a Bun script
Account Signed in to Anthropic (claude.ai / Max)

The one that will actually bite you — use a personal account, not an organization account. On an organization account, Channels is gated behind an org-level channelsEnabled switch that is off by default, and unless you administer that organization you cannot turn it on yourself.

What makes this expensive is that it fails silently and convincingly: the session starts normally, the Channels banner appears, the token is valid — and messages from your phone simply never get a reply. The bot does not even return a pairing code. If you have both kinds of account on one machine, run this line on the personal one.

First-time setup (once)#

Step 1 happens in Telegram. Steps 2 through 6 happen in a Claude Code session on your computer.

1. Create a bot in Telegram#

  1. Open @BotFather.
  2. Send /newbot.
  3. Give it a display name, then a unique username ending in bot.
  4. Copy the token BotFather returns — it looks like 8894810416:AAxxxxxxxx..., about 46 characters.

The token is the bot's password. Don't leak it, and don't commit it to git.

2. Install the Telegram plugin#

In a Claude Code session:

/plugin install telegram@claude-plugins-official
/reload-plugins

If it reports the plugin cannot be found, run /plugin marketplace add anthropics/claude-plugins-official (or /plugin marketplace update claude-plugins-official) and retry.

3. Configure the token#

/telegram:configure <paste the token here>

This saves to ~/.claude/channels/telegram/.env.

channels/ is per-account. Unlike plugins/, which can be shared between config directories, the channels/ directory belongs to whichever config directory you are running under. If you later want to use a second account, you have to configure the token again under that account.

4. Restart Claude Code with the channel flag#

Exit the current session, then relaunch from your project directory:

claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions

You should see a line like:

▎ Channels (experimental) messages from plugin:telegram@claude-plugins-official inject directly in this session

About --dangerously-skip-permissions. This stops Claude asking permission for each action, so whatever you send from your phone gets executed directly. That is the point when nobody is sitting at the computer — and it is also the risk. Use it only on a machine you trust, and turn on two-step verification for your Telegram account. If you would rather confirm every action from your phone, drop the flag. See Claude Code Skip Permission Confirmation for the finer-grained alternatives.

5. Pair your phone with the bot#

  1. On your phone, open Telegram and send your bot any message.
  2. The bot replies with a pairing code, something like a72c2a.
  3. Back in the Claude Code session on your computer:
    /telegram:access pair <pairing code>
    
  4. Lock down access so only paired accounts can send messages:
    /telegram:access policy allowlist
    

Pairing is persistent — it is stored in ~/.claude/channels/telegram/access.json and survives restarts and reconnects, so you only do this once.

6. End-to-end test#

From your phone, send the bot:

list the files in the current directory

Within a few seconds you should get back the result of Claude running that in your project directory. If you see it, the whole chain works.

What the chain looks like#

iPhone Telegram  →  @your_bot_name  →  local Claude Code session (--channels)
        ↑                                          ↓
        └──────── result back to Telegram ←──── actually executed in your project dir

Three rules#

  1. The --channels terminal window has to stay open, and the computer must not sleep. Otherwise there is nothing listening for your phone's messages.
  2. One bot token can only run one --channels session at a time. Two sessions polling the same token fight each other and both get 409 Conflict — neither receives anything.
  3. Guard your Telegram account. Turn on two-step verification. Under --dangerously-skip-permissions, anyone who can message the bot is someone who can run commands on your computer.

Reconnecting after a restart#

Good news: day-to-day reconnection needs none of the setup above. No new bot, no reconfigured token, no re-pairing. The token and the pairing are already saved on your machine. All you do is relaunch the --channels session from your project directory, and then message the bot as usual.

Option A — File Explorer, right-click, open terminal#

  1. Open File Explorer and navigate to the project folder you want to work in.
  2. Right-click the empty space in the folder and choose Open in Terminal. Windows Terminal opens already positioned in that directory.
  3. Paste and run:
    claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions
  4. Once the Channels (experimental) … line appears, the channel is up.
  5. Message the bot from your phone. No pairing needed.

Switching projects? Do steps 2 and 3 in that project folder instead — Claude's working directory is whatever directory you started the terminal in. Running two projects at once needs two bots and two tokens, since one token cannot run two channels.

Option B — open a terminal and cd#

cd <your project dir>
claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions

Option C — a one-click script#

Save this as a .cmd file on your desktop and double-click it from then on:

@echo off
REM Double-click to enter the project directory and start Claude with the Telegram channel.
REM Change the path below to switch projects.
cd /d <your project dir>
pwsh -NoExit -Command "claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions"

-NoExit keeps the window open after the command runs. If you define claude as a PowerShell function in your profile rather than as an executable on PATH, launching it through pwsh -Command like this is what makes the function resolvable. Copy the file and edit the cd /d line to make one shortcut per project.

Troubleshooting#

Symptom: you message the bot and get nothing back — not even a pairing code.

In order of likelihood:

  1. Wrong account. Are you on an organization account? Channels is disabled there by default. Switch to the personal one. This is by far the most common cause, and the most convincing imposter, because everything else looks healthy.
  2. You didn't start with --channels. /reload-plugins is not enough — the bot only returns a pairing code when the session is running with the flag.
  3. You messaged the wrong bot. Check the username is exactly your bot's, not BotFather or an older bot with a similar name.
  4. Two channel sessions are running. Two terminals, or two accounts, polling the same token means a 409 conflict. Keep one.
  5. The token is configured under a different account. Each config directory has its own channels/ folder, and they are independent.

Self-diagnosis from a plain PowerShell window#

This confirms the token is valid, shows the bot's identity, and checks whether a webhook is set — a webhook would displace polling. The token itself is never printed:

$token = ((Get-Content "$HOME\.claude\channels\telegram\.env" | Where-Object { $_ -match 'TELEGRAM_BOT_TOKEN' }) -split '=',2)[1].Trim()
Invoke-RestMethod "https://api.telegram.org/bot$token/getMe"            # the bot's username
Invoke-RestMethod "https://api.telegram.org/bot$token/getWebhookInfo"   # url should be empty

To work out whether a session is actually polling, call getUpdates a few times in a row. Hitting a 409 means yes, something is pulling messages. Consistently getting ok=True with zero updates and never a 409 means nothing is polling — usually because the session was started without --channels, or under an account where Channels is disabled.

1..3 | ForEach-Object {
  try { (Invoke-RestMethod "https://api.telegram.org/bot$token/getUpdates?timeout=2&limit=5").result.Count }
  catch { "409/error: $($_.Exception.Message)" }
}

Don't leave that running. These manual getUpdates calls compete with the live channel session for the connection, which is exactly the 409 you are testing for. Stop once you have your answer, or you will be the thing breaking your own setup.

Reference#

One argument a week about where AI is actually heading — written by an autonomous editor I built, with the week's events as the evidence. Monday mornings, five minutes, no hype.