← Claude Code Hub
✦ Tip #088 Jun 1, 2026

Claude Code channels beyond chat: push CI, deploy, and error events into your live session

The best-known use of channels is chat, but at heart it's an event receiver: your CI, Sentry, or a deploy can push a webhook into the Claude Code session you already have open. The chat plugins ship ready-made; the webhook receiver is a ~30-line MCP server.

Channels as an event receiver: a CI, Sentry, or deploy webhook lands in your already-open Claude Code session

TL;DR The best-known use of channels is chat: you text from Telegram and Claude replies. But a channel is really an event receiver: any system — your CI, Sentry, a deploy, a curl — can push an event into the session you already have open, with your files loaded and the context of whatever you were debugging. The chat plugins ship ready-made; the webhook receiver is a ~30-line MCP server you build yourself.

If you've read how to control Claude Code from Telegram or Discord, you know the chat-bridge side: you ask, Claude answers. This tip is the other side of the same engine: a machine fires the message and Claude reacts without you typing anything.

From pull to push

The difference is who starts the conversation:

  • Chat-bridge (the known one): you pull. You text "any failing tests?" and Claude looks.
  • Event receiver (this one): the world pushes. Your CI fails → a webhook lands in your session → Claude, which already had the file open, reads the log and proposes the fix.

A channel can be one-way (forwards alerts or webhooks for Claude to act on, no reply) or two-way (also exposes a reply tool, like chat). For CI or monitoring events, one-way is enough.

What an event receiver looks like

The chat plugins (Telegram, Discord, iMessage) ship ready-made. For webhooks there's no one-click plugin: you build your own channel, which is just a tiny MCP server. This is the whole receiver — it listens on a local HTTP port and pushes every POST to Claude:

#!/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' },
  {
    // this key is what makes it a channel
    capabilities: { experimental: { 'claude/channel': {} } },
    instructions: 'Events arrive as <channel source="webhook" ...>. They are one-way: read them and act.',
  },
)
await mcp.connect(new StdioServerTransport())

Bun.serve({
  port: 8788,
  hostname: '127.0.0.1', // localhost-only: nothing outside can POST
  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 and start with the development flag (custom channels aren't on the research-preview allowlist yet):

claude --dangerously-load-development-channels server:webhook

Now anything that can POST lands in your session. Simulate a CI failure:

curl -X POST localhost:8788 -d "build failed on main: https://ci.example.com/run/1234"

And Claude receives this, mid-session, with your files already open:

<channel source="webhook" path="/" method="POST">build failed on main: https://ci.example.com/run/1234</channel>

The source comes from the server's name; each meta key becomes an attribute on the tag.

Why it matters: it lands in the session you ALREADY have open

Claude Code has several ways to connect to the world outside the terminal. Channels is the only one that pushes an event into your live local session:

Feature What it does Why it's not the same
Claude Code on the web Runs the task in a fresh cloud sandbox New session, none of your local context
Claude in Slack Spawns a web session from an @Claude Another new session, not your open one
Standard MCP Claude queries the system on demand It's pull: nothing is pushed to the session
Remote Control You drive your local session from your phone Manual; you act, it doesn't react to an event
Channels Pushes an external event into your open session Claude reacts with your context and your files

That's the value: the CI webhook doesn't open a fresh clone of the repo — it lands where Claude already remembers what you were debugging.

Bonus: approve permissions from your phone

If you react to events while you're away, what happens when Claude needs to approve a Bash or a Write? A two-way channel can declare the claude/channel/permission capability and relay the permission prompt to you (requires v2.1.81+). You get "Claude wants to run Bash: … reply yes/no" with a short ID; you answer from chat and Claude applies the verdict. The local dialog stays open in parallel — whichever answer arrives first wins. Only enable it if you gate the sender: anyone who can reply can approve commands in your session.

Watch out for

  • The session has to be open. Channels isn't a persistent service; if Claude Code isn't running (or your org blocks it), the event is dropped silently, with no error.
  • Gate the sender. An ungated endpoint is a prompt injection vector: anyone who reaches it puts text in front of Claude. Check the sender's identity (not the room or group) before pushing anything.
  • Events queue. If several arrive while Claude is busy, they're delivered together on the next turn. For independent streams in parallel, use separate sessions.

Reference

Aspect Detail
Types One-way (alerts/webhooks) · Two-way (chat, with a reply tool)
Ready-made plugins Telegram, Discord, iMessage, fakechat (all chat)
Webhook/CI Build-your-own: MCP server with capabilities.experimental['claude/channel']
Inbound event <channel source="..." …>body</channel> (method notifications/claude/channel)
Permission relay claude/channel/permission capability (v2.1.81+) — approve remotely
Test your own claude --dangerously-load-development-channels server:<name>
Runtime @modelcontextprotocol/sdk + Bun, Node, or Deno
Security Gate on sender identity; otherwise, prompt injection

Official docs: Channels · Channels reference — build a webhook receiver

Related: Control Claude Code from Telegram or Discord · the map of autonomous primitives

Free guide

51 tips to master Claude Code.

One page per tip. Five chapters. What I actually use daily in production — no theory, no fluff.

  • I. Getting started 10 tips
  • II. Awareness 3 tips
  • III. Mastery 22 tips
  • IV. Autonomy 10 tips
  • V. Comparison 6 tips
Are you a professional Web developer?

You'll receive the guide by email · You join the Gravitas newsletter · Unsubscribe anytime

of 51
#

Wmedia · 51 Tips
Free guide · 51 tips · 5 chapters

51 tips to master Claude Code.

Are you a professional Web developer? · Unsubscribe anytime