Blog

How to Control Claude Code from Your Phone via Telegram in 2026

Markdown

Step by step: create a Telegram bot, install the Claude Code Channels plugin, secure it with an allowlist, and run it 24/7 on a VPS. A ready-to-follow guide with commands.

Read full article

Key points

Claude Code Channels is Anthropic’s official plugin as of March 20, 2026. Create a bot through BotFather, install the plugin with one command, restart Claude with the --channels flag, and send messages to the bot from your phone. Claude reads them directly in your local session, writes code to your files, and replies in Telegram. To make it work 24/7, move the session to your own VPS using systemd.

More materials on configuring tools are available in the Ailoot documentation.

What Claude Code Channels is and why you need it

Key points

Channels is an MCP plugin that forwards messages from Telegram, Discord, or iMessage to an already-running Claude Code session. The session sees the message as a regular user request, works with your local files, and replies in the same chat. Your laptop stays open while you go about your business with your phone.

On March 20, 2026, Anthropic released Claude Code Channels, an official plugin for connecting a Claude session with messaging apps. Telegram, Discord, and iMessage are supported. The feature is in research preview: documentation is at code.claude.com/docs/en/channels, and the plugin source code is in the open repository anthropics/claude-plugins-official.

In short, it’s a “chat bridge” between your phone and your Claude Code session. I message the bot, “Continue rewriting the pricing grid; in business/products/practicum/README.md, update the dates for the next cohort,” and the bot forwards the message to the session on my VPS. Claude retrieves the context, edits the file, commits the changes, and replies in Telegram, “Done, check the commit.” The laptop stays shut at home.

⚠️ The main research preview limitation: Channels is an MCP bridge. The session must be running on your machine or VPS. When the session is closed, no one receives messages. That’s why 24/7 operation has to be configured separately (see the VPS section below).

How Channels differs from other ways to work remotely

In its official documentation, Anthropic provides a direct comparison table. Here is an adaptation:

FeatureWhat it doesWhen to choose it
Claude Code on the webRuns a task in a fresh cloud sandbox, clones a repo from GitHubDelegate an independent background task and check on it later
Slack integrationStarts a web session in a thread when @Claude is mentionedStart tasks directly from team conversations
MCP server (regular)Claude calls it during a task; it doesn’t push anything into the sessionGive Claude on-demand access to external systems
Remote ControlYou control a local session from claude.ai or the mobile appOperate an existing session from your phone screen
Channels ⭐Pushes events from non-Claude sources into an already-running local sessionAsk something from your phone and get a reply in chat; catch a webhook from CI

The main difference between Channels and Remote Control: Remote Control is “your phone as a window into the terminal”—you literally see the cursor and press buttons. Channels is a chatbot whose brain is your local Claude session. With Remote Control, I look at the terminal. With Channels, I message someone who reads my files.

If you need full control from the screen, use Remote Control. If you want to “send a question, get on with your day, and receive a reply,” use Channels. I use both: Remote Control when I need to approve critical changes, and Channels when I’m confident about the task and want my evening back.

What you need before getting started

Key points

Claude Code v2.1.80 or newer, supported claude.ai authentication or an Anthropic Console API key, Bun installed, and access to Telegram. For 24/7 operation, you need a VPS running Ubuntu or Debian. Everything works the same on macOS, Linux, and WSL.

Before getting into the commands, check this list:

  1. Anthropic account. You need Pro, Max, Team, or Enterprise. Channels isn’t available on the free plan. An Anthropic Console API key also works; if the Console organization deploys managed settings, check that channels are enabled there.
  2. Claude Code v2.1.80 or newer. Check with claude --version. If it’s older, update with claude update or npm install -g @anthropic-ai/claude-code@latest.
  3. Bun. Channels plugins are Bun scripts, not Node scripts. Check with bun --version. If it isn’t installed, run curl -fsSL https://bun.sh/install | bash, then source ~/.bashrc.
  4. Telegram account. Any account will do; the main thing is that you’re logged in on your phone.
  5. If you’re on a Team/Enterprise plan, ask your admin to enable channelsEnabled in managed settings or through admin-settings/claude-code. Organizations have it disabled by default.

Don’t worry about Bun if this is your first time seeing it. Bun is an alternative JavaScript runtime, like Node. Anthropic chose it for Channels plugins because it starts faster and is easier to package into a single binary. Install it once and forget about it.

⚠️ Channels doesn’t work with corporate Bedrock / Google Vertex / Azure Foundry yet. It only works with claude.ai authentication or Anthropic Console.

Step 1. Create a Telegram bot through BotFather

Key points

Open @BotFather in Telegram, send the /newbot command, choose a name and username (the username must end in bot), and get a token in the form 12345678:AAH.... Keep the token safe: it’s the password to your bot. Anyone who sees it can write as the bot and potentially intercept your messages to Claude.

BotFather does all the work for you—you just need to press five buttons. Here are the steps:

  1. Open @BotFather in Telegram (you can use your phone; the rest of the setup can be done on your phone too).
  2. Press “Start” if this is your first time.
  3. Send the /newbot command.
  4. BotFather will ask, “Alright, a new bot. How are we going to call it?” Enter the display name, for example, My Assistant - Claude Code.
  5. Next it will ask for a username. It must be unique across Telegram and must end in bot. For example, my_claude_code_bot or my_dev_helper_bot.
  6. BotFather will reply with a message like this:
Done! Congratulations on your new bot. You will find it at
'<OFFICIAL_URL>'.

Use this token to access the HTTP API:
1234567890:AAHzlAU...

Keep your token secure and store it safely, it can be used by anyone to control your bot.

Copy the token. You’ll need it in two minutes.

⚠️ Token security. The bot token gives full control over it. If it leaks, anyone will be able to write as your bot and (potentially) intercept the messages you send to Claude. Don’t publish it in repositories, paste it into code, or send it in chats. I store tokens in ~/.claude/channels/telegram/.env; the plugin will put it there in the next step.

Step 2. Install the Telegram plugin in Claude Code

Key points

Start Claude Code as usual, then enter /plugin install telegram@claude-plugins-official in the session. If the plugin isn’t found, first add the official marketplace with /plugin marketplace add anthropics/claude-plugins-official. After installation, run /reload-plugins to activate the plugin commands in the current session.

Open a terminal in any folder where you usually work with Claude, and run:

claude

Enter the slash command in the session:

/plugin install telegram@claude-plugins-official

If Claude replies “Plugin not found in any marketplace,” your client doesn’t know about the official marketplace. Add it:

/plugin marketplace add anthropics/claude-plugins-official

Or update it if you added it earlier:

/plugin marketplace update claude-plugins-official

After successful installation, reload the plugins to activate their commands:

/reload-plugins

You should now have slash commands such as /telegram:configure and /telegram:access. To check, enter /help; the list should include a telegram section.

Key points

In the Claude session, enter /telegram:configure <token> with the token from step 1. The command saves it to ~/.claude/channels/telegram/.env (accessible only to your user). Alternatively, set the TELEGRAM_BOT_TOKEN environment variable in the shell before launching Claude. In production, I use the second option: it’s easier to manage through systemd and avoids pulling ~/.claude/ into the repo.

In the Claude session:

/telegram:configure 1234567890:AAHzlAU...

The command will put the token in ~/.claude/channels/telegram/.env. The file is accessible only to your user (chmod 600), so there’s no need to worry about it.

Alternatively, set the token through an environment variable. This is useful if you’re deploying Claude with systemd or Docker and don’t want interactive commands:

export TELEGRAM_BOT_TOKEN="1234567890:AAHzlAU..."
claude --channels plugin:telegram@claude-plugins-official

⚠️ In production, I always use environment variables instead of an .env file in my home directory, ~/. That makes it easier to manage secrets through systemd (Environment=TELEGRAM_BOT_TOKEN=...) and avoids accidentally pulling ~/.claude/ into the repo.

Step 4. Restart Claude with the --channels flag

Key points

Exit the session (exit or Ctrl+D), then launch it again with the --channels plugin:telegram@claude-plugins-official flag. This flag enables the plugin and tells Claude to poll the Telegram API for new messages. Without the flag, the bot exists but stays silent—the plugin is dormant and polling hasn’t started.

This is the most important point, and the one that trips everyone up on the first run. Installing the plugin alone isn’t enough. For the bot to actually start receiving messages, you need to launch Claude with an explicit flag:

claude --channels plugin:telegram@claude-plugins-official

Without the flag, the session works as usual, but the Telegram plugin is dormant. With the flag, Claude starts the plugin’s MCP server, begins polling the Telegram API, and responds to messages sent to the bot.

After launching, you should see something like this in the terminal:

✻ Welcome to Claude Code 2.1.80
  Channels: telegram@claude-plugins-official (active)
  Polling for messages...

If there’s no line about channels, the flag wasn’t picked up. Check that Claude Code is version 2.1.80+ and that the plugin is actually installed (/plugin list inside the session).

⚠️ Handy tip. I put an alias in ~/.zshrc:

alias claude-tg="claude --channels plugin:telegram@claude-plugins-official"

Then I just run claude-tg. You can pass multiple plugins separated by spaces: --channels plugin:telegram@... plugin:discord@....

Step 5. Pair the account and block everyone else

Key points

Open your bot in Telegram and send any message. The bot will reply with a six-digit pairing code. Return to the terminal and enter /telegram:access pair <code>. Then make sure to restrict access with an allowlist: /telegram:access policy allowlist. Only approve pairing codes from people you intend to authorize; the sender allowlist controls who can reach the session.

This step is about security. An approved sender can ask Claude to act on the files and tools available to the session. Pair only the intended account and lock down the sender policy before relying on the bot.

Steps:

  1. Open your bot in Telegram. Find it by the username @my_claude_code_bot or by the link in BotFather’s reply. Press “Start.”
  2. Send the bot any message. For example, hi.
  3. The bot will reply with a pairing code. It will look something like this:
Hi! To pair this account, run in your Claude Code session:
/telegram:access pair 847291

This code is valid for 5 minutes.
  1. Return to the terminal. In your Claude session, enter the command from the reply:
/telegram:access pair 847291

Claude will reply, “Account paired.” Now your Telegram account can send commands.

  1. Enable the allowlist policy. This blocks everyone except accounts that have already been paired:
/telegram:access policy allowlist

After this, messages from other accounts will be silently ignored. They won’t appear in the terminal, and the bot won’t reply—as if they never existed.

⚠️ It’s very important to enable the allowlist right after pairing. Don’t leave it for later. Do not approve unfamiliar pairing requests during setup or assume a successful reply proves the sender policy is correct. My bot was running without an allowlist for ten minutes the first time, and two random Telegram users managed to send “hi” during that time. Fortunately, I wasn’t letting commands write to files then.

If you need to add someone else (for example, a project partner):

/telegram:access pair <code from their account>

They should message the bot first, get a code, and pass it to you. You can add them that way only.

More guides are available in the Ailoot documentation.

How to run Claude 24/7 on your own VPS

Key points

A local session runs while your laptop is open; close the lid and the bot goes silent. To have Claude reply at any time, move the session to your own VPS: install Claude Code and Bun, authenticate and install/pair the plugin as the same dedicated Unix user, and wrap it in systemd with automatic restarts. A Coolify server handles it without problems.

If you want the bot to be “alive around the clock,” rather than “open the laptop for an hour and poke at it,” the session needs to stay running. Locally, you can do this with tmux, but a VPS is simpler and more reliable.

One example setup uses a Coolify VPS that also hosts a website (details in the guide to publishing through Coolify). You can use the same server—Claude uses little memory. If you don’t have a VPS, get the cheapest one for 4–5 euros a month, such as a Hetzner CX11 / Yandex Cloud / Selectel.

Step 1: Install the system on the VPS

First create the dedicated Unix account and workspace as the administrator. Reuse an existing account only after checking its home and ownership:

sudo useradd --create-home --shell /bin/bash claude
sudo install -d -o claude -g claude /home/claude/workspace
sudo -iu claude

Continue in that claude login shell, not in root’s home. Install Bun using its official installer and Claude Code using the native installation flow:

curl -fsSL https://bun.sh/install | bash
curl -fsSL https://claude.ai/install.sh | bash

Open a fresh login shell for the same user so the installer PATH changes apply. Check the account and executable paths:

whoami
printf '%s\n' "$HOME"
command -v bun
command -v claude
bun --version
claude --version
cd /home/claude/workspace
claude

whoami must print claude and HOME must be /home/claude. Record the absolute paths returned by command -v; use the real Claude path in ExecStart and include the Bun directory in the service PATH. Stop if either executable is missing.

Step 2: Authenticate, install, and pair as the service user

In this same interactive claude session, complete the sign-in flow, then repeat steps 2–5 above under this Unix user: install the Telegram plugin in user scope, configure the token, restart with --channels, pair your Telegram account, and set policy allowlist. Test a message and reply before configuring the service. Do not copy root’s Claude configuration or credentials into this home.

Both claude.ai subscription authentication and an Anthropic Console API key are supported. Team/Enterprise require organization enablement; managed Console organizations must also satisfy their channel settings. Console access is API-billed rather than covered by a claude.ai subscription. Keep the chosen account and authentication method consistent when moving from the interactive shell to the service.

Step 3: Wrap the session in systemd

Exit the service-user shell and create the unit as the administrator. The unit below assumes the path checks returned /home/claude/.local/bin/claude and /home/claude/.bun/bin/bun; replace these with the actual outputs if they differ. Supply the same chosen authentication environment and bot token, keep the unit readable only by its administrator, and never commit secrets. Create a service file for automatic startup and restart after a crash:

cat > /etc/systemd/system/claude-code.service <<'EOF'
[Unit]
Description=Claude Code with Telegram channel
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=claude
WorkingDirectory=/home/claude/workspace
Environment="HOME=/home/claude"
Environment="TELEGRAM_BOT_TOKEN=1234567890:AAH..."
Environment="PATH=/home/claude/.local/bin:/home/claude/.bun/bin:/usr/local/bin:/usr/bin:/bin"
ExecStart=/home/claude/.local/bin/claude --channels plugin:telegram@claude-plugins-official --dangerously-skip-permissions
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable claude-code
systemctl start claude-code

Here’s what I enabled:

  • Type=simple — simple mode; systemd considers the process started as soon as it launches.
  • User=claude — runs under a separate user, not root. Safer.
  • WorkingDirectory=/home/claude/workspace — the prepared, service-user-owned workspace. Put the intended repository there before startup; do not leave a root-owned clone or run from root’s home.
  • Environment=TELEGRAM_BOT_TOKEN=... — the token is passed directly to the process. No .env file is needed.
  • --dangerously-skip-permissions — critical for unattended operation. Without this flag, Claude waits for your “yes/no” in the terminal before every action, and the session will hang. The allowlist identifies senders; it does not make their requested commands safe. Use this bypass only in an isolated environment with deliberately limited files, credentials, and network access.
  • Restart=on-failure — if the process crashes (Claude crashes or the network goes down), systemd will bring it back in 10 seconds.

View logs with:

journalctl -u claude-code -f

If something goes wrong, journalctl -u claude-code -n 100 will show the last 100 lines.

Step 4: Check that the bot is alive

Start the service only after the interactive setup has produced a real Telegram reply. Then send the same bot a harmless message from the paired account and confirm both the reply and the service logs. If it works interactively but not under systemd, compare the Unix user, HOME, workspace, executable path, PATH, and authentication environment first.

For later pairing changes, stop the service, run sudo -iu claude, enter /home/claude/workspace, and launch the same channel interactively. Pair and enable the allowlist there, exit, and start the service again. Do not run a second poller for the same bot at the same time. journalctl reads logs; it does not provide an interactive Claude prompt.

5 traps on a production server and how to avoid them

Key points

I collected the traps from a week of production setup runs: Bun isn’t visible to systemd, long polling drops after a long idle period, Max plan limits run out in the middle of the day, --dangerously-skip-permissions can leak, and the allowlist is forgotten after reinstallation. Each can be addressed with a one-line setting, but if you don’t know about them, you’ll run into them in a couple of days.

1. Bun isn’t in systemd’s PATH

systemd starts processes with a minimal environment: it doesn’t see variables from ~/.bashrc. If you installed Bun only in root’s home but the service file has User=claude, the service will not inherit that installation or root’s shell PATH.

Solution. Either install Bun system-wide (/usr/local/bin/bun) or pass PATH explicitly:

Environment="PATH=/home/claude/.bun/bin:/usr/local/bin:/usr/bin:/bin"

2. The session loses its TCP connection to the Telegram API after a long idle period

After 6–12 hours idle, the bot may “go quiet”—messages are sent to Telegram, but the plugin doesn’t receive them. This is a long polling quirk.

Solution. Add a regular restart to systemd (every 24 hours):

Restart=always
RuntimeMaxSec=86400

Or set up a cron job: 0 5 * * * systemctl restart claude-code (restart at 5 a.m.).

3. Claude Max limits run out in the middle of the day

If you use Claude heavily through Telegram, on a Max 5x plan (~$100/month) you may hit the limit in 4–6 hours. Telegram requests are no different from requests in a regular terminal; they draw from the same budget.

Solution. Set a reminder: “Bot isn’t responding—check /stats.” If you hit the limit, either wait for it to reset or upgrade to Max 20x ($200/month). The guide to saving tokens and guide to Sonnet vs Opus models may help.

4. --dangerously-skip-permissions is dangerous even with an allowlist

This flag disables all confirmations. Any command from you in Telegram will run without questions: deleting files, sending external requests, anything. Once, I asked Claude to “remove unnecessary console.log statements,” and in its zeal to clean things up, Claude wiped out half the debug logs in a production script. I restored them through git, but the damage was done.

Solution. Don’t enable --dangerously-skip-permissions if you’re working on a critical project. Instead, use Remote Control to run sessions—permissions come to your phone, and you approve them manually. Channels with --dangerously-skip-permissions is for rough drafts, refactoring, and tests.

5. The allowlist “breaks” after reinstallation

The allowlist is stored in ~/.claude/channels/telegram/. If you move to a new VPS, reinstall Claude, or change users, the old pairing data won’t be picked up. The old sender allowlist is absent; do not assume the new instance has the previous access policy.

Solution. Before moving, back up ~/.claude/channels/telegram/. Afterward, move it back. Or pair again right after reinstallation and don’t leave even a minute between launching the bot and setting policy allowlist.

Channels or Remote Control—which should you choose?

Key points

Channels means your Claude session replies in chat, and you send prompts from your phone. Remote Control means your terminal screen is on your phone, and you operate the session with buttons. Channels is more convenient for “ask and go,” while Remote Control is for critical steps where you need to see what Claude is doing and approve every risky action.

Anthropic released both features almost at the same time: Remote Control on February 25, 2026, and Channels on March 20, 2026. They don’t duplicate each other; they solve different problems.

ScenarioChannelsRemote Control
Ask “what were yesterday’s commits?” while out✅ IdealOverkill—you need the full screen
Approve a file change⚠️ Blind approval through --dangerously-skip-permissions✅ You see what Claude wants to do
Run Claude 24/7✅ VPS + systemd setup⚠️ Requires an open laptop
Just send a couple of prompts from your phone⚠️ Overkill—bot, token, plugin✅ One QR code
Catch a webhook from CI / Sentry✅ Native use case❌ Not for this
Team with several people✅ Allowlist for multiple accounts⚠️ Session owner only
Keep files out of Anthropic’s cloud✅ Text only through MCP✅ Text only too

Here’s how I divide them for myself: Channels for asynchronous work when I’m away from my laptop, CI notifications, and integrations. Remote Control when I need to see what Claude is doing or approve a risky step.

You can use both at the same time. The Telegram bot gives you a quick “ask and get an answer” channel; Remote Control gives you a channel for “controlling critical things.” They use the same Claude limit.

FAQ

Key points

Seven of the most common questions about Channels: connecting multiple bots, what happens when you close the terminal, webhooks from CI, Telegram versus Discord, Team plan limitations, what Claude can see from your phone, and the free plan. More materials are available in the Ailoot documentation.

Can I connect multiple bots at the same time?

Yes. The --channels flag accepts a space-separated list: --channels plugin:telegram@claude-plugins-official plugin:discord@claude-plugins-official. One Claude session replies in both chats.

What happens if I close the terminal?

The session closes, the plugin stops, and the bot goes quiet. On a VPS, the session keeps running in systemd. On a local machine, close the laptop and claude will disconnect with SIGHUP in a few seconds.

Can I receive notifications from CI or Sentry?

Yes. Channels is a two-way channel. You can write your own plugin to forward webhooks into the session using the Channels Reference. Claude will see events in real time and respond.

Is Telegram more limited than Discord in any way?

The basic capabilities are the same. Discord requires Message Content Intent in the bot settings. iMessage works only on macOS and reads the ~/Library/Messages/chat.db database directly. Telegram is universal.

If I’m on a Team plan, what do I need to do?

The organization admin must enable channelsEnabled: true in managed settings or through admin-settings/claude-code. Without this, the plugin will connect, but messages won’t go through—a startup warning will appear in the terminal.

What can Claude see from my phone—the Telegram chat itself?

No. Claude sees only the message you sent to the bot. Your Telegram conversation history, chat list, and contacts are inaccessible. The MCP plugin reads only messages to the bot through the Telegram Bot API.

Can I run Claude through Channels without a Pro/Max subscription?

Yes, an Anthropic Console API key is also supported; API usage is billed to that Console organization. The free claude.ai tier is not the subscription route described here. Team/Enterprise and managed Console organizations must satisfy the channel-enablement settings.

What’s next

Key points

The bot is configured, the allowlist is enabled, and the session is on a VPS. Next, work Channels into your daily routine: connect webhooks from GitHub Actions and Sentry, pair it with Routines for regular tasks, and set up a bot health monitor. Each step takes 15–30 minutes and closes one observability gap.

Once the bot is running reliably, there are a few next steps to get the most out of Channels:

  1. Connect webhooks from CI. If you use GitHub Actions / GitLab CI, you can configure the Channels plugin to forward build results straight into the session. Claude will see “test failed” right after a push and suggest a fix. See the channels-reference documentation.
  2. Pair it with Routines. You can run Routines on the same session for regular tasks. In the morning, the bot sends “good morning, here’s the project summary” on its own, and you reply from your phone, “make a revenue report.”
  3. Set up a bot monitor. If the bot goes quiet, I want to know. A small cron script on the VPS pings the Telegram bot once an hour. If the bot doesn’t reply, it sends an alert to a separate channel. Without this, the bot could die at 4 a.m., and you wouldn’t find out until noon.
  4. Consider hooks. Hooks respond to Claude events (tool started, message finished). Hooks plus Channels mean automatic Telegram notifications like “Claude finished task N.”

Don’t bolt Channels onto everything. It’s a convenient way to catch up on a task while you’re out or at a coffee shop. When you need to really think, open your laptop and sit down. Channels frees your mind from “oh, I still need to ask it this, I have to open my laptop,” when you’re out or on the road.

For more materials on working with tools, see the Ailoot documentation.

More details

Questions about How to Control Claude Code from Your Phone via Telegram in 2026

Why does the Telegram bot work manually but fail as a service?

Compare the service’s Unix user, HOME, workspace, Claude executable path, Bun PATH, and authentication environment with the successful interactive run. Install, configure, and pair under the same service user; root’s plugin and pairing state are a different configuration.

Can a Console API key replace a Pro or Max sign-in for Channels?

Yes. Anthropic Console API-key authentication is supported and uses Console API billing. Check organization channel settings where required, and complete token configuration, pairing, and the sender allowlist under the account that runs the session.

All articles