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
channelsEnabledswitch 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#
- Open @BotFather.
- Send
/newbot. - Give it a display name, then a unique username ending in
bot. - 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. Unlikeplugins/, which can be shared between config directories, thechannels/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-permissionsYou 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#
- On your phone, open Telegram and send your bot any message.
- The bot replies with a pairing code, something like
a72c2a. - Back in the Claude Code session on your computer:
/telegram:access pair <pairing code> - 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#
- The
--channelsterminal window has to stay open, and the computer must not sleep. Otherwise there is nothing listening for your phone's messages. - One bot token can only run one
--channelssession at a time. Two sessions polling the same token fight each other and both get409 Conflict— neither receives anything. - 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
--channelssession from your project directory, and then message the bot as usual.
Option A — File Explorer, right-click, open terminal#
- Open File Explorer and navigate to the project folder you want to work in.
- Right-click the empty space in the folder and choose Open in Terminal. Windows Terminal opens already positioned in that directory.
- Paste and run:
claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions - Once the
Channels (experimental) …line appears, the channel is up. - 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-permissionsOption 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:
- 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.
- You didn't start with
--channels./reload-pluginsis not enough — the bot only returns a pairing code when the session is running with the flag.- You messaged the wrong bot. Check the username is exactly your bot's, not BotFather or an older bot with a similar name.
- Two channel sessions are running. Two terminals, or two accounts, polling the same token means a 409 conflict. Keep one.
- 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 emptyTo 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
getUpdatescalls 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#
- Official documentation: Channels
- Telegram plugin source: anthropics/claude-plugins-official