resources

Claude Channels: Deep Dive

architecture

Claude Channels: Deep Dive

How Claude Code routes work across channels. Slack, GitHub, Linear, terminal: the surfaces that make Claude omnipresent.

Architecture · 9 min

Claude Channels: Deep Dive

How Claude Code routes work across channels. Slack, GitHub, Linear, terminal: the surfaces that make Claude omnipresent.

Claude Code Channels make the model omnipresent: terminal, Slack, GitHub, Linear, Telegram, or a web client. Every surface follows the same routing model: a channel plugin runs as an MCP server on your machine, polls or listens for incoming messages, and pushes events into Claude's idle loop. Nothing lives in the cloud. Nothing requires a relay. The channel is just a text bridge.

The Full Picture

Channel Model Overview

A channel plugin is an MCP server. It registers tools with Claude (e.g. send_telegram_message) and pushes incoming messages as events. Claude treats channel tools exactly like Attio, Notion, or any other MCP server: just callable tools. The distinction is directionality: regular MCP is pull-based (Claude decides when to call), channels are push-based (the plugin fires events into Claude's idle loop).

Regular MCP: Pull

  • · Claude decides when to call the tool
  • · Server waits passively
  • · You type "check Attio" in terminal
  • · Claude calls the Attio MCP tool

Channel MCP: Push

  • · Plugin pushes events TO Claude
  • · Plugin actively polls for messages
  • · You text from your phone
  • · Plugin pushes event; Claude reacts

The 6 Channels

Each channel implements the same MCP interface with a different transport.

The default channel. You type directly into the Claude Code REPL. No plugin, no polling; input arrives synchronously. Every other channel wraps this primitive.

The Slack MCP plugin connects via the Slack Bolt SDK and a bot token. Messages in a designated channel or DM are polled (or received via socket mode). Responses are posted back usingchat.postMessage. Ideal for team commands that don't require terminal access.

GitHub channels trigger on PR events via a webhook or the GitHub App API. Claude receives the diff, runs its review skill, and posts comments directly on the PR. Can also respond to@claude review mentions in PR comments.

The Linear channel polls for issues assigned to a bot user or labeled withclaude. When one is found, Claude reads the issue body, executes the task (write code, open a PR, update docs), and comments the result back on the Linear issue.

The Telegram plugin pollsapi.telegram.org/getUpdatesevery 2-3 seconds via a bot token. Incoming messages are checked against an allowlist (paired via a 5-letter code flow). Approved messages become events in Claude's idle loop. Replies go back viasendMessage. Permission prompts are forwarded to your phone for yes/no approval.

A local HTTP server (or Next.js app) connects to the Claude Code session via the Chat SDK. The browser sends prompts and streams responses over a WebSocket or SSE connection. The web channel is the surface for custom dashboards and cockpit UIs.

Routing Rules

Every message, regardless of channel, passes through the same routing logic before it reaches Claude's model context.

  • 1Allowlist checkSender identity is validated against the channel's allowlist. Messages from unknown senders are silently dropped: no error, no acknowledgement.

Allowlist check

Sender identity is validated against the channel's allowlist. Messages from unknown senders are silently dropped: no error, no acknowledgement.

  • 2Event constructionThe plugin wraps the raw message in a channel event:{ type: "channel_message", text, reply_tool, chat_id }

Event construction

The plugin wraps the raw message in a channel event:{ type: "channel_message", text, reply_tool, chat_id }

  • 3Idle loop injectionThe event is pushed into Claude's event queue. Claude picks it up during its idle state, when it has finished its current task and is waiting for input. If Claude is busy, the event waits in the queue.

Idle loop injection

The event is pushed into Claude's event queue. Claude picks it up during its idle state, when it has finished its current task and is waiting for input. If Claude is busy, the event waits in the queue.

  • 4Permission relay (if needed)When Claude needs approval for a destructive action, the permission prompt fires simultaneously in the terminal and in the originating channel. The first answer (yes/no + request ID) wins; the second is discarded.

Permission relay (if needed)

When Claude needs approval for a destructive action, the permission prompt fires simultaneously in the terminal and in the originating channel. The first answer (yes/no + request ID) wins; the second is discarded.

  • 5Reply dispatchClaude calls the reply tool registered by the channel plugin (e.g.send_telegram_message). The plugin forwards the response back to the originating surface.

Reply dispatch

Claude calls the reply tool registered by the channel plugin (e.g.send_telegram_message). The plugin forwards the response back to the originating surface.

No queue persistence

State Sync

Claude Code sessions maintain a single shared context. When a Telegram message arrives, Claude has the same CLAUDE.md, the same files, the same open MCP connections as if you typed the prompt in the terminal. There is no per-channel session isolation; all channels share one model context.

  • CLAUDE.md context
  • Open files & git state
  • Active MCP connections
  • Skill registry
  • Conversation history

Per-channel

  • Reply tool reference
  • Chat / channel ID
  • Sender identity
  • Allowlist config
  • Permission request IDs

Not synced

  • Queued messages (offline)
  • Cross-session history
  • Channel-to-channel routing

Real Example: PR Review Across Channels

A PR is opened on GitHub. Claude reviews it, posts inline comments, and notifies Slack. The flow touches three channels sequentially.

GitHub webhook delivers a pull_request event to the GitHub channel plugin. Plugin checks: is the repo in the allowlist? Yes. Constructs channel event with diff payload.

Event lands in the idle loop. Claude reads CLAUDE.md, fetches the diff via the GitHub MCP, runs the /review skill, checks for security issues with /audit.

Claude calls the reply tool with structured review comments. Plugin posts them as GitHub review comments on the PR diff.

Claude calls the Slack reply tool to post a summary in #engineering. The Slack plugin POSTs to chat.postMessage.

What stays on your machine

Only the text of the review comments and the Slack message leave your Mac. The diff, your codebase, credentials, and all tool data stay local. Channels are text bridges, nothing more.

claude -p vs claude --channels

claude -p

  • · One-shot execution: run, print, exit
  • · Used by /scheduler and launchd cron jobs
  • · No event loop, no idle state
  • · Cannot receive Channel messages
  • · Perfect for scheduled, headless tasks

claude --channels

  • · Long-running session with event loop
  • · Starts channel plugins as MCP servers
  • · Listens for terminal AND channel input
  • · Stays alive until you close it
  • · Pair with launchd KeepAlive for 24/7 bot

Want this running in your stack?

ManasFlow builds agent systems, RAG pipelines, and Claude Code setups for production teams.

Hooks Setup: From Zero to Production

Custom Subagents: Build Your Own

Ready to transform your business?

Let’s turn your next automation opportunity into a system that works.

Book a Free Strategy Call