Claude Code Channels: The Complete Guide to Controlling Your AI Agent via Telegram, Discord, and Webhooks
On March 20, 2026, Anthropic quietly shipped one of the most practically useful features Claude Code has ever gotten — and it’s barely two days old. Claude Code Channels lets you send messages from Telegram or Discord directly into a running Claude Code session on your local machine. You ask your AI agent something from your phone. The work happens on your computer, against your real files. The answer comes back in your chat app.
That’s the elevator pitch. The actual depth of what Channels can do goes much further: it’s a push-based event system that lets CI pipelines, error monitors, deploy scripts, and custom webhooks all feed directly into a live Claude Code session that already has your codebase loaded. When a build breaks at 2am, you don’t have to open your laptop — you can ask Claude what broke and approve the fix, all from your phone.
This guide covers everything: what Claude Code Channels is, how it compares to other Claude features, step-by-step setup for Telegram and Discord, building a CI/CD webhook receiver, the permission relay system for approving tool calls remotely, enterprise controls, honest limitations, and real use cases that actually make sense to build for.
Everything here is drawn from the official Anthropic documentation, hands-on reports from the MacStories first-look, and the Hookdeck integration guide. Let’s get into it.
What Are Claude Code Channels?
A channel is an MCP (Model Context Protocol) server that pushes events into your running Claude Code session. The key word is “pushes.” Most Claude Code integrations are pull-based — you type in the terminal, Claude responds. Channels flip that model. External systems push events to Claude, and Claude reacts while you’re away from the terminal.
Channels can be one-way or two-way:
- One-way channel: External system fires an event (CI failure, monitoring alert, webhook). Claude reads it and acts — runs commands, edits files, creates a fix. Nothing is sent back through the channel.
- Two-way channel (chat bridge): Claude reads the inbound message and also replies back through the same channel. You send a message on Telegram, Claude sends a message back. Telegram and Discord are both two-way by default.
The architecture looks like this: your channel plugin runs locally on the same machine as Claude Code. Claude Code spawns it as a subprocess and communicates over stdio. The plugin bridges between your external system and the Claude Code session:
- Chat platforms (Telegram, Discord): The plugin runs locally and polls the platform’s API for new messages. When someone DMs your bot, the plugin receives the message and forwards it to Claude. No public URL needed — the connection is outbound from your machine.
- Webhooks (CI, monitoring): Your channel server listens on a local HTTP port. External systems POST to that port (either directly or via a tunnel like Hookdeck), and the server pushes the payload to Claude.
One important constraint that defines the entire model: events only arrive while the session is open. Claude Code Channels is not a 24/7 background service. For unattended setups, you need to run Claude Code in a persistent background terminal or as a background process. If the session isn’t running, messages queue externally until you start it again.
Channels launched in research preview on March 20, 2026. Telegram and Discord are the two official plugins available now. A plugin architecture means more platforms can follow — the Channels reference documentation already contains instructions for building your own. Channels is part of a much larger shift in how AI tools are being woven into development and business workflows — something covered in depth in the AI in digital marketing guide.
How Channels Compare to Every Other Claude Code Feature
Before setting anything up, it’s worth understanding exactly where Channels fits relative to other ways Claude Code can connect to external systems. The confusion between these options trips a lot of people up.
| Feature | What it does | Who initiates | Session type | Best for |
|---|---|---|---|---|
| Claude Code Channels | External systems push events into your already-running local session | External system (Telegram, webhook, Discord) | Local, already running | Chat bridge from phone, CI alerts, webhook automation |
| Claude Code on the Web | Runs tasks in a fresh cloud sandbox, cloned from GitHub | You (via claude.ai) | Cloud, fresh each time | Delegating self-contained async work you check on later |
| Claude in Slack | Spawns a web session from an @Claude mention in Slack | You (via Slack @mention) | Cloud, spawned per mention | Starting tasks directly from team conversation context |
| Standard MCP Server | Claude queries tools during a task; nothing is pushed to the session | Claude (during a task) | Local or remote | Giving Claude on-demand access to external data or APIs |
| Remote Control | You drive your local session from claude.ai or the Claude mobile app | You (via claude.ai or mobile) | Local, already running | Steering an in-progress session while away from your desk |
The key difference between Channels and Remote Control is who initiates and what the use case is. Remote Control lets you steer an existing session from your phone — it’s you driving. Channels lets external systems push into an existing session — it’s automation driving. They’re complementary, not competing.
The key difference between Channels and standard MCP servers is the direction of communication. An MCP server is passive — Claude queries it when needed. A Channel is active — it pushes events into Claude whether Claude asked or not. This push-based model is what enables the CI-alert-to-auto-fix workflow that makes Channels genuinely interesting.
Requirements: What You Need Before Starting
Channels has some specific prerequisites that aren’t obvious from the headlines. Go through this checklist before attempting any setup. Full requirements are listed in the official Channels documentation.
| Requirement | Details | Where to check |
|---|---|---|
| Claude Code v2.1.80+ | Permission relay requires v2.1.81+ | claude --version |
| claude.ai login | Console and API key auth is NOT supported for Channels | claude auth status |
| Bun runtime | Pre-built channel plugins are Bun scripts. Node and Deno work for custom channels, but not for the official Telegram/Discord plugins. | bun --version |
| Team/Enterprise admin approval | Channels are disabled by default on Team and Enterprise plans. An admin must enable channelsEnabled in managed settings. |
claude.ai → Admin settings → Claude Code → Channels |
| Research preview limitations | Only Anthropic-approved plugins work with --channels. Custom channels require --dangerously-load-development-channels. |
See channels reference docs |
Install Bun if you don’t have it (see the official Bun installation docs for Windows/macOS/Linux specifics):
curl -fsSL https://bun.sh/install | bash
The Bun requirement caught several early users off guard. The official plugins for Telegram and Discord are Bun scripts specifically — they won’t run on a plain Node.js or Deno setup. Anthropic acquired Oven, the company behind Bun, in late 2024, which explains the decision to build the reference plugins on it.
How to Set Up Claude Code Channels with Telegram: Complete Walkthrough
Telegram is the faster of the two official options — no server invites, no guild configuration, just a bot token and a pairing code. The full process from zero to your first working message takes about five minutes. Here is the complete flow covering both the Telegram platform side and the Claude Code side.
Official documentation: Claude Code Channels docs | Telegram plugin source on GitHub
Part A: Set Up the Bot on Telegram (Platform Side)
Step 1: Open BotFather and Create a New Bot
BotFather is Telegram’s official bot-creation service. Open Telegram on any device — phone, desktop, or web — and search for @BotFather in the search bar. Make sure you select the one with the blue verified checkmark. Any account without that checkmark is not the real BotFather.
Once you’re in the BotFather chat, send the command:
/newbot
BotFather responds with two prompts in sequence:
- Display name: This is the name people see when they look at your bot profile. It can be anything — “My Claude Agent”, “Dev Assistant”, “Project Bot”. No uniqueness requirement.
- Username: This is your bot’s @handle and must be globally unique across all of Telegram. It must end in
bot(e.g.,my_claude_agent_botordevclaude_bot). If the username is taken, BotFather will tell you to try another one.
Once you confirm both, BotFather replies with a success message containing your bot token. It looks like this:
7234891234:AAHxyz_abcdefghijklmnopqrstuvwxyz_1234
Copy this token and save it somewhere temporary. You’ll use it in Part B, Step 3. Treat it like a password — anyone with this token can control your bot.
Quick tip: If you need to regenerate the token at any time (for example, if it was accidentally exposed), send /revoke to BotFather and follow the prompts. The old token stops working immediately.
Step 2: (Optional) Configure Bot Privacy Settings
By default, Telegram bots in group chats only receive messages that start with / or that directly mention the bot. For Claude Code Channels, you’ll be DMing the bot directly, so this doesn’t affect the core workflow. But if you ever want to deploy the bot into a group chat, you’ll want to disable privacy mode first.
To check or change this: send /setprivacy to BotFather, select your bot, and choose Disable to let the bot read all messages in group chats it’s added to. For personal/solo use, leave the default setting.
Step 3: Find Your Bot in Telegram
Search for your bot’s username in Telegram’s search bar (e.g., @my_claude_agent_bot). Open the chat. You’ll see an empty chat window with a Start button. Do not press it yet — you need to complete the Claude Code setup first so the bot is actually running and can respond with a pairing code.
Part B: Set Up the Plugin in Claude Code (Claude Code Side)
Step 4: Install the Telegram Plugin
Open a Claude Code session in your terminal. Install the Telegram plugin from the official Anthropic plugin marketplace:
/plugin install telegram@claude-plugins-official
If Claude Code returns a “plugin not found” error, your marketplace index is either missing or outdated. Run this to refresh it:
/plugin marketplace update claude-plugins-official
If the marketplace itself hasn’t been added yet:
/plugin marketplace add anthropics/claude-plugins-official
Then retry the install. After a successful install, reload plugins so that the /telegram:configure command becomes available in your session:
/reload-plugins
You should see confirmation that the telegram plugin is loaded. If you don’t see it in the plugin list, try closing and reopening the Claude Code session.
Step 5: Configure Your Bot Token
Pass the token from BotFather (Step 1) into Claude Code’s configure command:
/telegram:configure 7234891234:AAHxyz_abcdefghijklmnopqrstuvwxyz_1234
Replace the example token with your actual one. Claude Code saves it to ~/.claude/channels/telegram/.env. You only need to run this once — the token persists across sessions.
Alternatively, set it as an environment variable in your shell profile (~/.bashrc, ~/.zshrc, etc.) if you prefer not to store it in the Claude config directory:
export TELEGRAM_BOT_TOKEN="your_actual_token_here"
Step 6: Restart Claude Code with Channels Enabled
Exit your current Claude Code session, then relaunch with the --channels flag pointing to the Telegram plugin:
claude --channels plugin:telegram@claude-plugins-official
When Claude Code starts, you’ll see a startup message confirming the Telegram channel is active and polling for messages. The plugin begins polling the Telegram Bot API immediately. Keep this terminal window open — the bot only functions while this session is running.
Running multiple channels at once: You can pass multiple plugins to --channels, space-separated. For example, to run both Telegram and Discord simultaneously:
claude --channels plugin:telegram@claude-plugins-official plugin:discord@claude-plugins-official
Part C: Pair Your Telegram Account (Final Step)
Step 7: Trigger the Pairing Flow from Telegram
Go back to your bot chat in Telegram (from Step 3). Send any message — it can be literally anything, like “hello”. The bot will reply automatically with a pairing code: a short alphanumeric string like A7K3P.
If the bot doesn’t reply within 10–15 seconds, verify that Claude Code is running with the --channels flag from Step 6. The pairing code is only generated while the channel is active.
Step 8: Approve the Code in Claude Code
Back in your Claude Code terminal, pair your Telegram sender ID with the code:
/telegram:access pair A7K3P
Replace A7K3P with the actual code your bot sent. Claude Code adds your Telegram user ID to the sender allowlist and confirms the pairing.
Step 9: Lock the Allowlist
By default after pairing, the bot may still accept messages from other Telegram users (depending on your bot’s privacy settings). Lock it down so only your paired account can interact with the Claude Code session:
/telegram:access policy allowlist
This is a critical security step. After this command, anyone outside the allowlist who sends a message to the bot gets no response — their message is silently dropped before it ever reaches Claude.
Testing and Verifying the Telegram Setup
Send a test message from Telegram to verify the full loop is working:
What files are in my working directory?
In your Claude Code terminal, you’ll see the inbound channel event arrive as a <channel source="telegram"> tag, followed by Claude’s tool calls (like ls or Read). The reply text does not appear in the terminal — it goes back to Telegram. Check your Telegram chat for the response.
If the terminal shows the event but no reply arrives in Telegram, check that the bot has permission to send messages (it should by default for DMs). If you’re testing in a group chat, make sure Message Content Intent is enabled and the bot has been given Send Messages permission in that channel.
Troubleshooting Common Telegram Issues
| Problem | Likely cause | Fix |
|---|---|---|
| Bot doesn’t reply with a pairing code | Claude Code is not running with --channels |
Restart with claude --channels plugin:telegram@claude-plugins-official |
| “Plugin not found” on install | Marketplace index is outdated or not added | Run /plugin marketplace update claude-plugins-official |
| Messages send but Claude doesn’t respond | Sender not in allowlist, or allowlist policy blocking | Run /telegram:access list to check, re-pair if needed |
| Token error on configure | Token was copied with extra spaces or line breaks | Regenerate token via BotFather /revoke, re-configure |
| “channelsEnabled” org policy error | Team/Enterprise org has Channels disabled | Ask admin to enable: claude.ai → Admin settings → Claude Code → Channels |
How to Set Up Claude Code Channels with Discord: Complete Walkthrough
Discord setup takes about 10–15 minutes — longer than Telegram because you need to configure bot permissions, enable a privileged intent, and invite the bot to a server. The payoff is worth it: Discord gives you message history, server channels, thread support, and much better team-sharing options if you work with others.
Official documentation: Claude Code Channels docs | Discord plugin source on GitHub | Discord Developer docs
Part A: Create and Configure the Bot on Discord (Platform Side)
Step 1: Create a New Application in the Discord Developer Portal
Go to the Discord Developer Portal. You’ll need to be signed in to your Discord account. Click the blue New Application button in the top-right corner.
Give the application a name — this becomes the bot’s default display name in Discord. Something like “Claude Dev Agent” or “My AI Agent” works well. Accept the developer terms if prompted, then click Create.
You’ll land on the application’s General Information page. Take note of the Application ID shown here — you won’t need it for the basic setup, but it’s useful to have if you ever need to debug OAuth scopes or permissions.
Step 2: Create the Bot User
In the left sidebar, click Bot. On the Bot page, you have the option to set a username for the bot (separate from the application name) and upload an avatar if you want one. Do both or neither — it doesn’t affect functionality.
Find the Token section. Click Reset Token. Discord will warn you that this replaces any existing token — confirm. The token appears once. Copy it now and save it somewhere secure. This token is the equivalent of a password for your bot: anyone who has it can make the bot do things.
Your token looks like this:
MTk4NjIyNDgzNDc2MzU4MDY0.GvBe4A.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Step 3: Enable Message Content Intent
Still on the Bot page, scroll down to the Privileged Gateway Intents section. You’ll see three toggles:
- Presence Intent
- Server Members Intent
- Message Content Intent
Enable Message Content Intent. This is the one that matters. Without it, Discord’s API will deliver message events to your bot but strip out the actual text — so the plugin will know a message was sent, but Claude won’t be able to read what it says. Save your changes at the bottom of the page.
Why this is a privileged intent: Discord gates access to message content behind this intent for privacy reasons. For bots in fewer than 100 servers, it’s enabled instantly. For bots in 100+ servers, Discord requires verification. Since this is a personal bot for your own server, instant approval applies.
Step 4: Set Bot Permissions and Generate an Invite URL
In the left sidebar, click OAuth2, then URL Generator. This tool builds the invite URL with the exact permissions your bot needs.
Under Scopes, check the bot scope. A permissions panel appears below. Check every permission the Claude Code Discord plugin requires:
| Permission | Why it’s needed |
|---|---|
| View Channels | Bot needs to see which channels exist to receive messages |
| Send Messages | Bot sends replies back to you in the channel or DM |
| Send Messages in Threads | Bot can reply within thread conversations |
| Read Message History | Bot can read previous messages in a channel, not just new ones |
| Attach Files | Bot can send file attachments (useful for code output or logs) |
| Add Reactions | Bot can react to messages (acknowledgement signals) |
After checking all six permissions, scroll down to the Generated URL section and copy the URL. Open it in a browser. Discord will ask you to select a server to add the bot to — choose your development server or personal server. Click Authorize and complete the CAPTCHA if prompted.
Your bot now appears in your Discord server’s member list, but it’s offline. It will come online when you start Claude Code with the channel enabled.
Part B: Set Up the Plugin in Claude Code (Claude Code Side)
Step 5: Install the Discord Plugin
Open a Claude Code session in your terminal and install the Discord plugin:
/plugin install discord@claude-plugins-official
If you get a “plugin not found” error:
# Refresh the marketplace index first:
/plugin marketplace update claude-plugins-official
# Or add the marketplace if it's not there at all:
/plugin marketplace add anthropics/claude-plugins-official
After a successful install, reload plugins to activate the configure command:
/reload-plugins
Step 6: Configure Your Bot Token
Pass the bot token you copied from the Developer Portal (Step 2) into Claude Code:
/discord:configure YOUR_DISCORD_BOT_TOKEN_HERE
Claude Code saves it to ~/.claude/channels/discord/.env. This persists across sessions — you won’t need to run this command again unless you regenerate your token.
You can also set it via environment variable if you prefer managing credentials in your shell profile:
export DISCORD_BOT_TOKEN="your_actual_token_here"
Step 7: Restart Claude Code with the Discord Channel Enabled
Exit your current session and relaunch with the --channels flag:
claude --channels plugin:discord@claude-plugins-official
Claude Code starts the Discord plugin as a subprocess. The bot connects to Discord’s Gateway API and comes online — you’ll see its status change to “Online” in your server’s member list. The terminal confirms the channel is active.
If your organization has Channels disabled (Team/Enterprise), you’ll see a warning at startup: “channelsEnabled is false — contact your admin.” In that case, an admin needs to enable it at claude.ai → Admin settings → Claude Code → Channels before you can proceed.
Part C: Pair Your Discord Account (Final Step)
Step 8: DM the Bot to Trigger Pairing
In Discord, find your bot in your server’s member list and open a Direct Message with it. Send any message — “hello” works fine. The bot replies with a pairing code: a short string like B2FMX.
If the bot doesn’t reply within 10–15 seconds, confirm Claude Code is running with --channels from Step 7. Pairing only works while the channel is active.
Note: The pairing must be done via DM, not in a server channel. Server channel messages and DMs are treated as separate contexts in Discord’s API.
Step 9: Approve the Code in Claude Code
Back in your Claude Code terminal, enter the pairing command with the code the bot sent you:
/discord:access pair B2FMX
Claude Code adds your Discord user ID to the sender allowlist and confirms the pairing was successful.
Step 10: Lock the Allowlist
/discord:access policy allowlist
This locks the bot so only sender IDs in your allowlist can push messages to Claude. Anyone else — including other members of your Discord server — who messages the bot gets no response. This step is not optional if you care about security.
Adding team members later: Each team member who needs access should DM the bot, get a pairing code, and then you (or they, if they have Claude Code access) run /discord:access pair <code> for their code. Each person’s Discord user ID gets added to the allowlist independently.
Testing and Verifying the Discord Setup
DM your bot a test message:
List the files in my current working directory
In your Claude Code terminal, you’ll see:
- The inbound event arrive as
<channel source="discord"> - Claude’s tool calls executing (e.g., a
Bashcall withls) - A confirmation that the reply tool was called (“sent”)
The reply text itself appears in your Discord DM with the bot — not in the terminal. If you see Claude working in the terminal but no message appears in Discord, check that the bot has permission to send DMs (it does by default) and that your Discord account hasn’t blocked DMs from server members.
Using Discord Server Channels Instead of DMs
One of Discord’s major advantages over Telegram for team setups is the ability to operate through a dedicated server channel rather than DMs. This keeps a shared log of everything you’ve asked Claude and what it answered — useful for teams where multiple people are triggering the same agent.
To use a server channel instead of a DM: invite the bot to your server (already done in Step 4), then simply send messages in any channel the bot has access to. The pairing flow still requires DM initially, but after pairing, you can interact with the bot in server channels. Your messages in that channel will reach Claude provided your Discord user ID is in the allowlist.
A recommended Discord server setup for development teams looks like this:
- #claude-tasks — general task channel, visible to the whole team
- #claude-alerts — where CI webhook alerts from the webhook channel get reported (if you’ve built a two-way custom channel)
- #claude-private — restricted channel for one developer’s personal agent interactions
Troubleshooting Common Discord Issues
| Problem | Likely cause | Fix |
|---|---|---|
| Bot comes online but doesn’t reply to DMs | Message Content Intent not enabled | Developer Portal → Bot → Privileged Gateway Intents → enable Message Content Intent |
| Bot stays offline after starting Claude Code | Wrong token configured, or token not saved | Re-run /discord:configure YOUR_TOKEN with the correct token |
| Bot replies to DM but not server channels | Missing View Channels or Send Messages permission in that specific channel | In Discord: channel settings → Permissions → add the bot with required permissions |
| Pairing code not generated | Session not running with --channels flag |
Restart: claude --channels plugin:discord@claude-plugins-official |
| “Missing Access” error in Discord logs | Bot missing one or more required permissions | Re-invite with correct permissions via OAuth2 URL Generator in Developer Portal |
| Bot visible in server but not responding | Sender not in allowlist after policy was set | Run /discord:access list to verify, re-pair if your ID is missing |
| Works in DM but not in threads | Missing “Send Messages in Threads” permission | Re-invite via URL Generator with the Send Messages in Threads permission checked |
Telegram vs. Discord: Which Should You Use?
Both work. The right choice depends on your workflow:
| Factor | Telegram | Discord |
|---|---|---|
| Setup time | ~5 minutes | ~10–15 minutes |
| Best for | Solo developer, quick personal use | Teams, shared logging, structured channels |
| Message history | Available in DM chat | Full server-side history with search |
| Multi-user access | Possible via allowlist, but purely DM-based | Cleaner — server channels visible to whole team |
| Mobile experience | Excellent Telegram mobile app | Good Discord mobile app |
| Group chat support | Requires disabling privacy mode in BotFather | Native, full server channel support |
| Bot visibility to others | Only you know about it (DM-based) | Visible in server member list |
My recommendation: if you’re the only one using it, start with Telegram — it’s faster and the mobile experience is marginally smoother. If you’re on a team or want a persistent log of what Claude has been asked to do, Discord’s server structure makes it the better long-term choice.
Testing with Fakechat Before Going Live
If you want to understand how Channels works before connecting a real messaging platform, the fakechat demo is the fastest path. It’s an officially supported channel plugin that runs a browser-based chat UI on localhost — no bot account, no external service, no authentication required. See the fakechat quickstart in the official docs for the complete walkthrough.
/plugin install fakechat@claude-plugins-official
# Exit, then restart:
claude --channels plugin:fakechat@claude-plugins-official
Open http://localhost:8787 in your browser. Type a message. It arrives in your Claude Code session as a <channel source="fakechat"> event, Claude processes it, and the reply shows up in the browser. The whole loop takes seconds.
Fakechat is particularly useful for testing permission relay (covered next) without having to set up a real Telegram bot. The fakechat server also demonstrates file attachments and message editing, which are features the pre-built Telegram and Discord plugins also support. The fakechat source code on GitHub is worth reading if you plan to build your own custom channel — it’s the cleanest reference implementation available.
Building a CI/CD Webhook Receiver with Claude Code Channels
This is where Channels goes from “neat phone trick” to “genuinely changes how I debug.” A webhook receiver channel lets any external system — GitHub Actions, Sentry, PagerDuty, your own deploy scripts — push events directly into a Claude Code session that already has your codebase loaded and understands what you’ve been working on. The full protocol reference for building custom channels is at code.claude.com/docs/en/channels-reference.
When your CI pipeline can push a build failure directly into a Claude Code session that already has your code open, the time between “something broke” and “here’s the fix” collapses dramatically. Claude isn’t starting fresh — it already knows your files, your recent changes, your test setup.
The Basic Webhook Receiver
You’ll need Bun and the MCP SDK. Create a project directory:
mkdir webhook-channel && cd webhook-channel
bun add @modelcontextprotocol/sdk
Create webhook.ts:
#!/usr/bin/env bun
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
const mcp = new Server(
{ name: 'webhook', version: '0.0.1' },
{
capabilities: { experimental: { 'claude/channel': {} } },
instructions: 'Events from the webhook channel arrive as <channel source="webhook" ...>. They are one-way: read them and act, no reply expected.',
},
)
await mcp.connect(new StdioServerTransport())
Bun.serve({
port: 8788,
hostname: '127.0.0.1',
async fetch(req) {
const body = await req.text()
await mcp.notification({
method: 'notifications/claude/channel',
params: {
content: body,
meta: { path: new URL(req.url).pathname, method: req.method },
},
})
return new Response('ok')
},
})
Register it in .mcp.json at your project root:
{
"mcpServers": {
"webhook": { "command": "bun", "args": ["./webhook.ts"] }
}
}
Start Claude Code with the development flag (required during the research preview for custom channels):
claude --dangerously-load-development-channels server:webhook
Test it immediately from another terminal:
curl -X POST localhost:8788 -d "build failed on main: https://ci.example.com/run/1234"
In your Claude Code terminal, you’ll see Claude receive the event and start responding.
Receiving Real Webhooks from GitHub with Hookdeck
The webhook server only listens on 127.0.0.1, which means external services like GitHub cannot post to it directly. Hookdeck CLI is the cleanest solution — it gives you a stable public URL that forwards to your local server, and it includes event replay so you can resend any captured webhook without triggering a real GitHub push.
Install Hookdeck CLI:
npm install -g hookdeck-cli
# or
brew install hookdeck/hookdeck/hookdeck
Authenticate and start listening:
hookdeck login --cli-key YOUR_CLI_KEY
hookdeck listen 8788 my-claude-channel
Hookdeck gives you a stable URL like https://hkdk.events/src_xxxxxxxxxx. Go to your GitHub repository → Settings → Webhooks → Add webhook. Set the Payload URL to your Hookdeck URL, Content type to application/json, and select the events you care about (Push, Pull Request, etc.).
Now every GitHub push event flows through: GitHub → Hookdeck public URL → Hookdeck CLI → your local webhook server on port 8788 → Claude Code session. Claude reads the push event and can act on it — check what files changed, run tests, look for regressions — with full access to your codebase.
Customizing Claude’s Response Behavior
Add a CLAUDE.md to your project to give Claude specific instructions for how to handle webhook events:
## Webhook handling
When you receive a GitHub push webhook via the webhook channel:
1. Check which files were changed in the commit
2. If any test files were modified, run the test suite
3. If the commit message mentions "fix" or "bug", review the diff for issues
4. Reply with a one-paragraph summary of what changed and any concerns
The combination of project-specific instructions in CLAUDE.md and real-time webhook events is what makes this genuinely powerful. Claude isn’t just receiving an alert — it’s acting as a context-aware first responder that already understands your codebase.
Permission Relay: Approving Tool Calls from Your Phone
By default, when Claude Code needs permission to run a bash command, write a file, or make an edit, the session pauses and waits for your input at the terminal. This breaks the “work from your phone” use case entirely. Permission relay fixes it.
With permission relay, the permission prompt gets forwarded to you through your channel (Telegram, Discord, or any custom channel that supports it). You can approve or deny directly from your phone. The local terminal dialog stays open simultaneously — whichever response arrives first is applied.
Permission relay requires Claude Code v2.1.81 or later. Your channel plugin must explicitly declare the claude/channel/permission capability. The official Telegram and Discord plugins support it. Full technical details are in the permission relay section of the channels reference.
How the Relay Flow Works
- Claude wants to run a bash command. A permission dialog opens in your terminal.
- Claude Code generates a short five-letter request ID (using letters that can’t be confused for numbers — no ‘l’) and notifies your channel server.
- Your channel server forwards the prompt and the request ID to your phone via Telegram or Discord: “Claude wants to run Bash: git commit -am ‘Fix auth bug’. Reply ‘yes abcde’ or ‘no abcde’.”
- You reply from your phone:
yes abcde - Claude Code applies the approval. The local terminal dialog closes. Claude runs the command.
A reply in the wrong format (like just “yes” without the ID) falls through as a regular message to Claude rather than a permission verdict. This prevents accidental approvals from messages that happen to contain “yes” in normal conversation.
One important security note from the docs: only add senders to your allowlist who you actually trust with permission relay authority. Anyone who can reply through your channel can approve or deny tool use in your session. For personal setups this is fine. For team setups, be intentional about who gets pairing access.
Security and the Sender Allowlist
An ungated channel is a serious security risk. Anyone who can reach your endpoint or send a DM to your bot can put arbitrary text in front of Claude — and Claude will act on it. Anthropic’s design accounts for this with the sender allowlist system.
Every approved channel plugin maintains a sender allowlist. Only sender IDs you’ve explicitly added can push messages. Everyone else is silently dropped — no error, no response.
For Telegram and Discord, the allowlist is bootstrapped through the pairing flow: you DM the bot, it gives you a code, you enter it in Claude Code, your sender ID gets added. After that, you run /telegram:access policy allowlist (or the Discord equivalent) to lock the bot to allowlist-only access.
For custom webhook channels, you implement the gating yourself. Gate on the sender’s identity — specifically the user ID, not the room or channel ID. In group chats, these are different things, and gating on the room would let anyone in that room inject messages into your session. The Channels reference documentation makes this explicit:
“Gate on the sender’s identity, not the chat or room identity: message.from.id in the example, not message.chat.id.”
For webhook receivers receiving events from services like GitHub or Sentry, the standard approach is to validate the x-hookdeck-signature header (if using Hookdeck) or the webhook secret provided by the source platform. Only process events from sources you explicitly trust.
Beyond the allowlist, you also control which channel servers are enabled per session using the --channels flag. Being configured in .mcp.json is not enough for a server to push messages — it also has to be named in --channels at startup. This two-layer design means a misconfigured or compromised MCP server can’t silently push events into your session.
Enterprise and Team Plan Controls
If you’re on a Claude.ai Team or Enterprise plan, Channels don’t just work out of the box. The feature is disabled by default at the organization level. The full admin settings reference is at code.claude.com/docs/en/channels#enterprise-controls.
| Plan | Default behavior | How to enable |
|---|---|---|
| Pro / Max (personal, no org) | Channels available; users opt in per session with --channels |
No admin action needed |
| Team / Enterprise | Channels disabled until admin explicitly enables | Admin → claude.ai Admin settings → Claude Code → Channels → Enable |
Admins can also control this via the channelsEnabled field in managed settings. When disabled at the org level, the MCP server still connects and its tools still work, but channel messages won’t arrive. Claude Code shows a startup warning explaining the situation and directing users to contact their admin.
For teams adopting Channels, the practical recommendation is to start with the fakechat demo for internal testing, use Discord for team-shared access (multiple people can be in the bot’s DM allowlist), and keep Telegram for individual developer setups where one person controls the bot. The allowlist model means multiple people on a team can each have their own pairing — the bot will respond to all of them independently based on their individual allowlist entries.
Real Use Cases Worth Building
The examples in the official docs are deliberately minimal. Here’s a more grounded breakdown of what’s actually worth building with Channels right now — and what’s realistic given the current research preview constraints.
1. Ask-From-Phone Code Assistant
What it does: You’re away from your desk and remember you need to check something in your codebase. You open Telegram, ask your Claude bot, and get an answer in the same chat. No SSH, no VPN, no opening a laptop. The MacStories reviewer used this to compile an iOS project and deploy it wirelessly to their iPhone — all from Telegram, while the Mac handled the heavy lifting.
Realistic for: Individual developers who keep a persistent Claude Code session running during work hours.
Limitation to know: Session must be running. If Claude Code is closed, the bot is silent.
2. CI Failure to Instant Diagnosis
What it does: Your GitHub Actions pipeline fails. Instead of checking GitHub, opening your editor, and re-reading the failing test — your webhook channel pushes the failure directly into Claude Code. Claude already has your repo open. It reads the failure, locates the relevant code, and tells you what broke and why. You respond with an approval from Telegram and Claude commits a fix.
Realistic for: Solo developers or small teams who want faster feedback on CI failures without building a full autonomous fix pipeline.
Limitation to know: Autonomous commits require --dangerously-skip-permissions or permission relay. Be careful about enabling this for production branches.
3. Error Monitoring Alert Handler
What it does: Sentry fires a webhook when a new error hits production. The webhook channel forwards it to your Claude Code session. Claude reads the stack trace, searches your codebase for the relevant function, and reports the most likely cause — before you’ve even opened Sentry.
Realistic for: Backend developers who want context-aware first-pass triage of production errors.
Limitation to know: Still requires you to push the actual fix. Claude can diagnose and draft, but human review before production deploys is strongly advisable.
4. Podcast/Meeting Transcription Pipeline
What it does: The MacStories reviewer ran this exact workflow — they sent an audio file via Telegram, and Claude transcribed it and returned TXT, SRT, and Markdown formats. The reviewer used this with Readwise Reader integration as well, pulling tagged articles and processing them locally.
Realistic for: Developers who already use Claude Code for content processing workflows and want to trigger those workflows from mobile.
Limitation to know: Voice messages from Telegram are not supported. Image and file sharing works; audio from the voice message feature does not.
5. Deploy Status Notifications
What it does: Your deploy script sends a webhook when a deployment completes or fails. Claude receives it, checks whether the relevant tests passed before the deploy, and sends a confirmation or warning message back through Discord to your team channel.
Realistic for: Teams using Discord for communication who want lightweight automated deploy notifications with context.
Limitation to know: Requires a custom webhook channel server, not just the pre-built Discord plugin.
6. AI-Powered Content and SEO Workflows
What it does: Trigger Claude from your phone to run keyword research, draft a content brief, or analyze a competitor’s article as part of an automated publishing pipeline. Combined with scheduled tasks, you can push a topic idea from Telegram and have a structured draft ready by the time you sit back at your desk.
Realistic for: Content marketers and SEO professionals who already use Claude Code as part of their AI-assisted SEO workflow and want to extend it to mobile.
Limitation to know: Long-running tasks (like a full research + write cycle) may trigger multiple permission prompts. Set up permission relay before relying on this for unattended use.
Current Limitations: What Channels Can’t Do Yet
Any honest assessment of a two-day-old research preview feature has to include the real constraints. Here’s what you’ll run into:
- Session must be open: There is no always-on daemon mode. Events only arrive while Claude Code is actively running. For unattended operation, you need to keep Claude Code open in a persistent terminal session — tmux, screen, or a background process.
- No voice message support: Telegram voice messages (the audio clips the app records) cannot be processed. Standard file attachments and images work. If you need voice-to-text, you’ll need to send audio as a file attachment rather than using Telegram’s native voice message feature.
- Permission dialogs block remote operation by default: Without permission relay (v2.1.81+), any bash command that requires approval will pause your session and wait for terminal input. You either need permission relay enabled or
--dangerously-skip-permissions— the latter of which you should only use in trusted environments. - Custom channels still need the development flag: During the research preview, only Anthropic-approved plugins work with
--channels. Custom webhook receivers need--dangerously-load-development-channels. This flag name is deliberately alarming — it’s intended to be temporary, but it’s the current reality. - Team/Enterprise requires admin opt-in: If you’re on a managed plan and Channels don’t seem to work, it’s almost certainly an admin setting, not a bug on your end.
- Reply text doesn’t show in terminal: When Claude replies through a channel, you see the tool call in your terminal but not the reply text. The actual reply only appears in the channel (Telegram/Discord). This is by design but can be disorienting when debugging.
- No simultaneous multi-channel operation (cleanly): You can technically pass multiple plugins to
--channels, space-separated. But managing two active channels simultaneously in a single session can get messy. Most developers stick to one channel per session context.
How to Build Your Own Custom Channel
The official Telegram and Discord plugins cover most personal use cases, but the real power of Channels comes from building your own for systems that don’t have a plugin yet. The protocol is straightforward — an MCP server with a specific capability declaration. Full reference at code.claude.com/docs/en/channels-reference. The MCP SDK on npm is the only required dependency.
Your server needs to do three things:
- Declare the
claude/channelcapability in the Server constructor so Claude Code registers a notification listener - Emit
notifications/claude/channelevents when something happens - Connect over stdio transport (Claude Code spawns your server as a subprocess)
The channel capability declaration looks like this in TypeScript:
const mcp = new Server(
{ name: 'your-channel', version: '0.0.1' },
{
capabilities: {
experimental: { 'claude/channel': {} },
tools: {}, // include if two-way
},
instructions: 'Messages arrive as <channel source="your-channel" ...>. Reply with the reply tool.',
},
)
The instructions string is added to Claude’s system prompt. It tells Claude what events to expect, what the tag attributes mean, and whether to reply. This is how Claude knows to use the reply tool for two-way channels versus just acting silently for one-way alert channels.
Notifications are pushed using mcp.notification():
await mcp.notification({
method: 'notifications/claude/channel',
params: {
content: 'your event body here',
meta: { severity: 'high', source_system: 'sentry' },
},
})
Each key in meta becomes an attribute on the <channel> tag Claude receives. Keys must be identifiers (letters, digits, underscores — no hyphens). The content becomes the tag body.
For a full two-way custom channel with permission relay, the channels reference documentation has a complete working example with reply tools, sender gating, and permission relay all combined. The fakechat plugin on GitHub is also worth reading — it’s the cleanest production example of a full two-way channel with file attachments.
Frequently Asked Questions
Does Claude Code Channels work on Windows?
Yes, with the caveat that Bun must be installed. Bun supports Windows, macOS, and Linux. The setup steps are the same across platforms. If you’re on Windows and Bun isn’t recognized after installation, add %USERPROFILE%\.bun\bin to your PATH environment variable and restart your terminal.
Can I run Claude Code Channels on a remote server so it’s always on?
Yes, and this is actually a good pattern for teams. Run Claude Code in a persistent tmux or screen session on a remote server or a Mac Mini, then use Telegram or Discord as the interface. The MacStories first-look article specifically noted the potential for “remote connections back to the Mac” as a model for mobile development. The key requirement is that the server must be authenticated with a claude.ai account — API key auth is not supported for Channels.
What happens if I send a message while Claude is in the middle of a task?
The message queues at the channel level. Claude Code processes the current task first, then picks up the new channel event. The channel plugin buffers incoming messages while Claude is busy. You won’t lose messages, but you will wait for the current operation to complete before Claude responds to your new prompt.
Is there a rate limit on channel messages?
The official docs don’t specify a rate limit for Channels specifically. The underlying constraint is that Claude Code processes one task at a time — it won’t process a second channel event while still working on the first. For webhook use cases with potentially high event frequency (like push events on a busy repository), you’ll want to add filtering logic in your webhook server to only forward events that require action, rather than forwarding every event.
Can multiple team members use the same Claude Code Channels bot on Discord?
Yes. The sender allowlist supports multiple entries. Each team member goes through the pairing flow with the bot — they DM the bot, get a pairing code, and the code is added to the allowlist by someone who already has access. On Team and Enterprise plans, the org admin must have channelsEnabled set to true first. Every allowlisted sender has equal authority, including permission relay authority — so only add team members who should be able to approve or deny Claude’s tool calls.
What’s the difference between Channels and the Claude mobile app’s Remote Control?
Remote Control (accessed through claude.ai or the Claude mobile app) lets you steer a running local session — you’re the driver. Channels lets external systems push events into a running session — automation is the driver. Remote Control is better for “I want to check in and give Claude direction.” Channels is better for “I want CI failures, Sentry alerts, or other automated events to trigger Claude automatically.” Both features can coexist — you can run a session with Channels enabled and also use Remote Control to check on it.
Where Claude Code Channels Fits in the Bigger Picture
Claude Code Channels is early. Two days old, research preview, custom channels still need a development flag. None of that changes the fact that this is a genuinely different architecture for AI-assisted development.
Every AI coding tool on the market — Cursor, GitHub Copilot, Windsurf — operates on the same pull model. You type, it responds. Channels introduces push. External systems can now talk to Claude directly, in a session that has full context of your codebase, your recent changes, and what you were working on when you left your desk.
The closest analogy I can think of is the difference between checking your email manually and having a smart assistant who reads your email and acts on it while you sleep. The mechanism is simple. The implications compound over time as you build more integrations around it.
The Telegram setup takes five minutes. If you’re already using Claude Code regularly, there’s no good reason not to have it. Start there, see what breaks, and build from what works. The webhook and CI integration patterns are where it gets genuinely interesting — but those are worth building only once you’ve lived with the chat bridge for a few days and understand how the session model actually behaves in practice.
For teams thinking about this from an AI adoption standpoint, Channels fits into a broader pattern of agentic AI workflows — systems where AI takes action based on external triggers rather than just responding to direct prompts. The technical complexity here is low enough that any developer comfortable with Node/Bun can build functional webhook integrations in an afternoon. The strategic value of event-driven AI workflows, though, is something that will compound significantly as the tooling matures.
If you want to go deeper on how AI tooling is reshaping development and marketing workflows, the AI marketing automation guide and the ChatGPT for digital marketing guide cover related territory on the strategy side. And if you’re thinking about what this kind of always-available AI agent means for content and SEO workflows specifically — that’s a topic worth watching closely over the next few months.