首页 › tutorials › Claude Code Channels全实战:通知到双向通信

Claude Code Channels全实战:从通知推送到双向通信

概述

本教程面向有一定Claude Code使用经验的开发者,深入讲解Channels与Hooks通知两大事件驱动机制。你将学会:配置跨平台桌面通知、搭建Telegram/Discord双向通信通道、构建自定义Channel MCP服务器、实现事件溯源工作流。学完后,你的Claude Code将从"被动工具"进化为"主动协作伙伴"——它能主动通知你任务完成,你也能从手机远程操控终端里的Claude。

适用人群:每天使用Claude Code超2小时的中高级开发者,尤其适合需要并行管理多个长任务、或在移动端监控开发进度的团队。

前置条件

条件 说明
Claude Code版本 ≥ v1.0.37(Channels需要v2.1.80+)
操作系统 macOS / Linux / WSL2
Node.js ≥ 18.x
基础知识 熟悉JSON配置、Shell脚本、MCP协议基本概念
可选 Telegram Bot Token 或 Discord Bot Token
## 第一章 理解Claude Code事件体系全景

Claude Code的事件驱动能力由三层构成:

graph TB
    subgraph "外部世界"
        TG[Telegram]
        DC[Discord]
        WH[Webhook/GitHub]
        CI[CI/CD Pipeline]
    end

    subgraph "Claude Code事件层"
        CH[Channels<br/>MCP Server推送]
        HK[Hooks<br/>Shell命令响应]
        NT[Native Notifications<br/>桌面提醒]
    end

    subgraph "Claude Code核心"
        AG[Agent Loop]
        TOOLS[Tool Execution]
        PERM[Permission System]
    end

    TG -->|消息事件| CH
    DC -->|消息事件| CH
    WH -->|HTTP推送| CH
    CI -->|构建状态| CH
    CH -->|event_channel_send| AG

    AG -->|生命周期事件| HK
    HK -->|exit code 2| NT
    HK -->|osascript/notify-send| NT

    style CH fill:#e1f5fe
    style HK fill:#fff3e0
    style NT fill:#e8f5e9

三层分工:

第二章 Hooks通知:30秒配置桌面提醒

2.1 最小化配置

在项目根目录创建 .claude/settings.json:

{
  "hooks": {
    "Stop": [
      {
        "type": "command",
        "command": "printf '\\a'"
      }
    ],
    "Notification": [
      {
        "type": "command",
        "command": "printf '\\a'"
      }
    ]
  }
}

printf '\a' 发送终端响铃(BEL字符),几乎所有终端都支持。配置完成后,Claude完成任务或需要你输入时,你会听到一声"叮"。

2.2 macOS桌面通知(推荐)

{
  "hooks": {
    "Stop": [
      {
        "type": "command",
        "command": "osascript -e 'display notification \"Claude Code任务完成\" with title \"Claude Code\" sound name \"Glass\"'"
      }
    ],
    "Notification": [
      {
        "type": "command",
        "command": "osascript -e 'display notification \"Claude需要你的注意\" with title \"Claude Code\" sound name \"Ping\"'"
      }
    ]
  }
}

2.3 Linux桌面通知

{
  "hooks": {
    "Stop": [
      {
        "type": "command",
        "command": "notify-send -u critical -i utilities-terminal 'Claude Code' '任务已完成' && paplay /usr/share/sounds/freedesktop/stereo/complete.oga"
      }
    ],
    "Notification": [
      {
        "type": "command",
        "command": "notify-send -u normal -i utilities-terminal 'Claude Code' '等待输入' && paplay /usr/share/sounds/freedesktop/stereo/bell.oga"
      }
    ]
  }
}

2.4 解析Hook输入JSON

Hooks的实际价值在于处理结构化数据。每个Hook通过stdin接收JSON:

{
  "session_id": "abc123",
  "hook_event_name": "Stop",
  "input": {
    "stop_hook_active": true,
    "conversation": [
      {"role": "user", "content": "修复登录bug"},
      {"role": "assistant", "content": "已修复src/auth/login.ts中的空指针异常..."}
    ]
  }
}

利用这个数据,可以构建智能通知脚本:

#!/usr/bin/env bash
# ~/.claude/hooks/smart-notify.sh
set -euo pipefail

INPUT=$(cat)
EVENT=$(echo "$INPUT" | jq -r '.hook_event_name')
SESSION=$(echo "$INPUT" | jq -r '.session_id')

# 提取最后一条assistant消息的前100字
LAST_MSG=$(echo "$INPUT" | jq -r '.input.conversation | map(select(.role=="assistant")) | last .content' | head -c 100)

case "$EVENT" in
  Stop)
    osascript -e "display notification \"$LAST_MSG\" with title \"✅ Claude完成\" sound name \"Glass\""
    ;;
  Notification)
    osascript -e "display notification \"需要你的输入\" with title \"🔔 Claude等待\" sound name \"Ping\""
    ;;
  SubagentStop)
    osascript -e "display notification \"子Agent完成\" with title \"🤖 Subagent\" sound name \"Pop\""
    ;;
esac

# 记录事件日志(用于后续事件溯源)
echo "$(date -Iseconds)|$EVENT|$SESSION|${LAST_MSG:0:50}" >> ~/.claude/event-log.csv

在settings.json中引用:

{
  "hooks": {
    "Stop": [{"type": "command", "command": "bash ~/.claude/hooks/smart-notify.sh"}],
    "Notification": [{"type": "command", "command": "bash ~/.claude/hooks/smart-notify.sh"}],
    "SubagentStop": [{"type": "command", "command": "bash ~/.claude/hooks/smart-notify.sh"}]
  }
}

2.5 常见问题

第三章 Channels:让外部世界推送到Claude

3.1 Channels核心概念

Channel本质上是一个MCP服务器,它通过event_channel_send工具向正在运行的Claude Code会话推送消息。整个架构:

sequenceDiagram
    participant User as 用户手机
    participant TG as Telegram Bot API
    participant CH as Channel MCP Server
    participant CC as Claude Code会话
    participant FS as 文件系统/代码

    User->>TG: 发送"/deploy production"
    TG->>CH: Webhook推送消息
    CH->>CC: event_channel_send(payload)
    CC->>CC: 解析指令,执行部署
    CC->>CH: 调用Channel工具(reply_to_chat)
    CH->>TG: 发送回复消息
    TG->>User: "✅ 生产环境已部署完成"

    Note over CC,FS: Claude同时执行本地操作
    CC->>FS: git push / kubectl apply

3.2 官方Telegram Channel配置

第一步:创建Telegram Bot

  1. 在Telegram中搜索 @BotFather
  2. 发送 /newbot,按提示设置名称
  3. 记录得到的Bot Token(格式:123456789:ABCdefGHIjklMNOpqrsTUVwxyz)

第二步:安装官方Telegram插件

# 插件已内置于Claude Code,直接配置即可
# 在项目根目录的 .claude/settings.json 或全局 ~/.claude/settings.json 中添加:
{
  "mcpServers": {
    "telegram": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/claude-code-telegram-channel@latest"
      ],
      "env": {
        "TELEGRAM_BOT_TOKEN": "你的Bot Token"
      }
    }
  }
}

第三步:启动并验证

# 启动Claude Code
claude

# 在Claude Code内部,发送测试消息
# Claude会自动发现telegram MCP server的工具
# 工具列表包括:
#   - reply_to_chat: 回复Telegram消息
#   - react_to_message: 对消息添加表情反应
#   - edit_message: 编辑已发送的消息

在Telegram中给你的Bot发送任意消息,Claude Code会话中将收到推送事件。

3.3 官方Discord Channel配置

第一步:创建Discord Bot

  1. 访问 Discord Developer Portal
  2. 创建New Application → Bot → 记录Token
  3. 开启Message Content Intent(Bot设置页)
  4. 生成OAuth2 URL,添加Bot到你的服务器

第二步:配置MCP Server

{
  "mcpServers": {
    "discord": {
      "command": "npx",
      "args": [
        "-y",
        "@anthropic-ai/claude-code-discord-channel@latest"
      ],
      "env": {
        "DISCORD_BOT_TOKEN": "你的Discord Bot Token"
      }
    }
  }
}

3.4 同时配置多Channel

完整的全球化开发配置示例:

{
  "mcpServers": {
    "telegram": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/claude-code-telegram-channel@latest"],
      "env": {
        "TELEGRAM_BOT_TOKEN": "${TELEGRAM_BOT_TOKEN}"
      }
    },
    "discord": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/claude-code-discord-channel@latest"],
      "env": {
        "DISCORD_BOT_TOKEN": "${DISCORD_BOT_TOKEN}"
      }
    }
  },
  "hooks": {
    "Stop": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/smart-notify.sh"
      }
    ],
    "Notification": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/smart-notify.sh"
      }
    ]
  }
}

注意:Token建议通过环境变量引用,避免硬编码到配置文件中。在~/.bashrc或~/.zshrc中export: bash export TELEGRAM_BOT_TOKEN="your_token_here" export DISCORD_BOT_TOKEN="your_token_here"

第四章 构建自定义Channel MCP Server

当官方插件不满足需求时(比如需要接入企业微信、Slack、或自定义Webhook),你需要构建自己的Channel。

4.1 Channel MCP Server的核心要求

一个Channel MCP Server必须:

  1. 作为MCP服务器运行,通过stdio与Claude Code通信
  2. 实现event_channel_send工具,用于推送事件到Claude Code会话
  3. 实现至少一个"接收工具",让Claude能回复消息

4.2 TypeScript实现:GitHub Webhook Channel

这是一个将GitHub Webhook事件推送到Claude Code的自定义Channel:

// github-webhook-channel/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import http from "http";

const PORT = parseInt(process.env.WEBHOOK_PORT || "3456");

// 创建MCP Server
const server = new Server(
  {
    name: "github-webhook-channel",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {},
    },
  }
);

// 注册Claude可调用的工具
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "reply_to_github",
      description: "通过GitHub API回复评论或创建Issue评论",
      inputSchema: {
        type: "object",
        properties: {
          event_type: {
            type: "string",
            enum: ["pr_comment", "issue_comment", "review_comment"],
          },
          repo: { type: "string", description: "owner/repo" },
          number: { type: "number" },
          body: { type: "string" },
        },
        required: ["event_type", "repo", "number", "body"],
      },
    },
  ],
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "reply_to_github") {
    const { event_type, repo, number, body } = request.params.arguments as any;
    // 调用GitHub API回复
    const response = await fetch(
      `https://api.github.com/repos/${repo}/issues/${number}/comments`,
      {
        method: "POST",
        headers: {
          Authorization: `token ${process.env.GITHUB_TOKEN}`,
          "Content-Type": "application/json",
          "User-Agent": "claude-code-channel",
        },
        body: JSON.stringify({ body }),
      }
    );
    return {
      content: [{ type: "text", text: `已回复 ${repo}#${number}` }],
    };
  }
});

// 启动HTTP服务器接收GitHub Webhook
const webhookServer = http.createServer(async (req, res) => {
  if (req.method === "POST" && req.url === "/webhook") {
    let body = "";
    req.on("data", (chunk) => (body += chunk));
    req.on("end", async () => {
      const payload = JSON.parse(body);
      const event = req.headers["x-github-event"] as string;

      // 构造推送消息
      const message = formatGithubEvent(event, payload);

      // 通过event_channel_send推送到Claude Code
      // 注意:这个工具由Claude Code自动注入,Channel Server可以直接调用
      console.log(
        JSON.stringify({
          jsonrpc: "2.0",
          method: "notifications/tools/list_changed",
        })
      );

      res.writeHead(200);
      res.end("OK");
    });
  }
});

function formatGithubEvent(event: string, payload: any): string {
  switch (event) {
    case "pull_request":
      return `[PR ${payload.action}] ${payload.pull_request.title}\n` +
        `Repo: ${payload.repository.full_name}\n` +
        `Author: ${payload.sender.login}\n` +
        `URL: ${payload.pull_request.html_url}`;
    case "issues":
      return `[Issue ${payload.action}] ${payload.issue.title}\n` +
        `Repo: ${payload.repository.full_name}\n` +
        `Author: ${payload.sender.login}`;
    case "push":
      const commits = payload.commits.map((c: any) => `  - ${c.message}`).join("\n");
      return `[Push] ${payload.ref} → ${payload.repository.full_name}\n${commits}`;
    default:
      return `[${event}] New event from ${payload.repository?.full_name || "GitHub"}`;
  }
}

// 启动
async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  webhookServer.listen(PORT, () => {
    console.error(`Webhook server listening on port ${PORT}`);
  });
}

main().catch(console.error);

4.3 配置自定义Channel

{
  "mcpServers": {
    "github-webhook": {
      "command": "node",
      "args": ["/path/to/github-webhook-channel/index.js"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}",
        "WEBHOOK_PORT": "3456"
      }
    }
  }
}

使用ngrok暴露本地端口以接收GitHub Webhook:

ngrok http 3456
# 将ngrok URL配置到GitHub仓库的Webhook设置中
# Payload URL: https://xxxx.ngrok.io/webhook
# Content type: application/json
# Events: Pull requests, Issues, Pushes

4.4 Channel工作流程

flowchart LR
    subgraph "外部触发源"
        GH[GitHub Webhook]
        TG[Telegram消息]
        CR[Cron定时任务]
        API[内部API调用]
    end

    subgraph "Channel MCP Server"
        HTTP[HTTP接收器]
        POLL[轮询器]
        WS[WebSocket客户端]
    end

    subgraph "Claude Code会话"
        ECS[event_channel_send]
        AGENT[Agent处理]
        REPLY[回复工具]
    end

    GH -->|POST /webhook| HTTP
    CR -->|触发检查| POLL
    API -->|推送事件| WS

    HTTP -->|JSON-RPC| ECS
    POLL -->|JSON-RPC| ECS
    WS -->|JSON-RPC| ECS

    ECS --> AGENT
    AGENT --> REPLY
    REPLY -->|回复消息| HTTP

第五章 事件溯源:让Claude Code工作流可观测

5.1 设计思路

Nick Tune提出的事件溯源模式核心思想:将Claude Code的工作流状态存储为不可变事件序列,而非只关注最终结果。

graph TD
    subgraph "事件采集层"
        H1[PreToolUse Hook]
        H2[PostToolUse Hook]
        H3[Stop Hook]
        H4[Notification Hook]
        H5[SubagentStop Hook]
    end

    subgraph "事件存储"
        EL[event-log.jsonl]
        DB[SQLite事件库]
    end

    subgraph "分析与可视化"
        DASH[实时Dashboard]
        TIME[时间线视图]
        COST[成本追踪]
        AUDIT[审计日志]
    end

    H1 & H2 & H3 & H4 & H5 -->|追加写入| EL
    EL -->|定期归档| DB
    DB --> DASH
    DB --> TIME
    DB --> COST
    DB --> AUDIT

5.2 全生命周期Hook配置

{
  "hooks": {
    "PreToolUse": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ],
    "PostToolUse": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ],
    "Stop": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ],
    "SubagentStop": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ],
    "Notification": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ]
  }
}

5.3 事件记录器脚本

#!/usr/bin/env bash
# ~/.claude/hooks/event-recorder.sh
# 将所有Claude Code生命周期事件记录到JSONL文件

set -euo pipefail

INPUT=$(cat)
EVENT=$(echo "$INPUT" | jq -r '.hook_event_name')
SESSION=$(echo "$INPUT" | jq -r '.session_id')
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")

# 构造事件记录
EVENT_RECORD=$(jq -n \
  --arg ts "$TIMESTAMP" \
  --arg event "$EVENT" \
  --arg session "$SESSION" \
  --argjson input "$(echo "$INPUT" | jq '.input // {}')" \
  '{
    timestamp: $ts,
    event: $event,
    session_id: $session,
    data: $input
  }')

# 写入日期分区的事件日志
LOG_DIR="$HOME/.claude/events/$(date -u +%Y-%m-%d)"
mkdir -p "$LOG_DIR"
echo "$EVENT_RECORD" >> "$LOG_DIR/${SESSION:-default}.jsonl"

# 轻量级桌面通知(仅关键事件)
case "$EVENT" in
  Stop)
    osascript -e 'display notification "任务完成" with title "Claude Code" sound name "Glass"' 2>/dev/null || true
    ;;
  Notification)
    osascript -e 'display notification "等待输入" with title "Claude Code" sound name "Ping"' 2>/dev/null || true
    ;;
esac

5.4 事件分析工具

#!/usr/bin/env bash
# ~/.claude/hooks/event-analytics.sh
# 分析今日Claude Code事件日志

TODAY=$(date -u +%Y-%m-%d)
LOG_DIR="$HOME/.claude/events/$TODAY"

if [ ! -d "$LOG_DIR" ]; then
  echo "今日暂无事件记录"
  exit 0
fi

echo "=== Claude Code 事件日报 $TODAY ==="
echo ""

# 事件类型统计
echo "📊 事件类型分布:"
cat "$LOG_DIR"/*.jsonl | jq -r '.event' | sort | uniq -c | sort -rn
echo ""

# 工具使用频率
echo "🔧 工具调用Top 10:"
cat "$LOG_DIR"/*.jsonl | \
  jq -r 'select(.event == "PreToolUse") | .data.tool_name // "unknown"' | \
  sort | uniq -c | sort -rn | head -10
echo ""

# 会话时间线
echo "⏱ 会话活跃时段:"
cat "$LOG_DIR"/*.jsonl | \
  jq -r '.timestamp' | \
  sed 's/T/ /' | \
  cut -d'.' -f1 | \
  cut -d':' -f1-2 | \
  sort | uniq -c
echo ""

# 活跃会话数
SESSION_COUNT=$(cat "$LOG_DIR"/*.jsonl | jq -r '.session_id' | sort -u | wc -l)
EVENT_COUNT=$(cat "$LOG_DIR"/*.jsonl | wc -l)
echo "📈 今日统计:$EVENT_COUNT 个事件,$SESSION_COUNT 个会话"

运行分析:

bash ~/.claude/hooks/event-analytics.sh

预期输出:

=== Claude Code 事件日报 2026-05-21 ===

📊 事件类型分布:
    142 PreToolUse
    138 PostToolUse
     12 Stop
      8 Notification
      3 SubagentStop

🔧 工具调用Top 10:
     45 Read
     38 Edit
     22 Bash
     12 Glob
      8 Grep
      6 Write
      4 Task
      3 WebSearch
      2 Glob
      2 TodoWrite

⏱ 会话活跃时段:
      1 2026-05-21 09:1
      3 2026-05-21 09:2
     15 2026-05-21 09:3
     42 2026-05-21 10:0
     28 2026-05-21 10:1
     ...

📈 今日统计:303 个事件,4 个会话

第六章 实战项目:全栈监控通知系统

将Hooks、Channels、事件溯源整合为一个完整的监控系统——当代码提交触发CI失败时,Claude Code自动收到通知并尝试修复。

6.1 系统架构

graph TB
    subgraph "触发源"
        GH[GitHub Push]
        CI[CI/CD Pipeline]
        CRON[Cron定时检查]
    end

    subgraph "Channel层"
        GWC[GitHub Webhook Channel]
        CSC[CI Status Channel]
    end

    subgraph "Claude Code"
        AG[Agent Loop]
        HK[Hooks层]
        EV[事件记录器]
    end

    subgraph "通知层"
        TG[Telegram通知]
        DT[桌面通知]
        LOG[事件日志]
    end

    GH -->|Push事件| GWC --> AG
    CI -->|构建失败| CSC --> AG
    CRON -->|定时检查| CSC

    AG -->|生命周期| HK
    HK --> EV --> LOG
    HK --> TG
    HK --> DT
    AG -->|自动修复| GH

    style AG fill:#ffcdd2
    style EV fill:#c8e6c9
    style TG fill:#bbdefb

6.2 CI状态Channel(轮询模式)

// ci-status-channel/index.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

const GITHUB_TOKEN = process.env.GITHUB_TOKEN!;
const REPO = process.env.GITHUB_REPO || "myorg/myrepo";
const POLL_INTERVAL = parseInt(process.env.POLL_INTERVAL || "60000");

const server = new Server(
  { name: "ci-status-channel", version: "1.0.0" },
  { capabilities: { tools: {} } }
);

let lastStatus = "success";

// 注册工具
server.setRequestHandler(ListToolsRequestSchema, async () => ({
  tools: [
    {
      name: "get_ci_status",
      description: "获取最新的CI/CD构建状态",
      inputSchema: {
        type: "object",
        properties: {
          branch: { type: "string", default: "main" },
        },
      },
    },
    {
      name: "rerun_failed_workflow",
      description: "重新运行失败的GitHub Actions workflow",
      inputSchema: {
        type: "object",
        properties: {
          run_id: { type: "number" },
        },
        required: ["run_id"],
      },
    },
  ],
}));

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name === "get_ci_status") {
    const branch = (request.params.arguments as any)?.branch || "main";
    const res = await fetch(
      `https://api.github.com/repos/${REPO}/actions/runs?branch=${branch}&per_page=5`,
      {
        headers: {
          Authorization: `token ${GITHUB_TOKEN}`,
          "User-Agent": "claude-ci-channel",
        },
      }
    );
    const data = await res.json();
    const runs = data.workflow_runs.map((r: any) => ({
      name: r.name,
      status: r.status,
      conclusion: r.conclusion,
      run_number: r.run_number,
      created_at: r.created_at,
    }));
    return { content: [{ type: "text", text: JSON.stringify(runs, null, 2) }] };
  }

  if (request.params.name === "rerun_failed_workflow") {
    const { run_id } = request.params.arguments as any;
    await fetch(
      `https://api.github.com/repos/${REPO}/actions/runs/${run_id}/rerun`,
      {
        method: "POST",
        headers: {
          Authorization: `token ${GITHUB_TOKEN}`,
          "User-Agent": "claude-ci-channel",
        },
      }
    );
    return { content: [{ type: "text", text: `已重新触发workflow #${run_id}` }] };
  }

  throw new Error(`Unknown tool: ${request.params.name}`);
});

// 轮询CI状态并推送到Claude Code
async function pollCIStatus() {
  try {
    const res = await fetch(
      `https://api.github.com/repos/${REPO}/actions/runs?per_page=1&status=completed`,
      {
        headers: {
          Authorization: `token ${GITHUB_TOKEN}`,
          "User-Agent": "claude-ci-channel",
        },
      }
    );
    const data = await res.json();
    const latest = data.workflow_runs?.[0];

    if (latest && latest.conclusion === "failure" && lastStatus !== "failure") {
      lastStatus = "failure";
      // 推送失败事件到Claude Code
      // event_channel_send由Claude Code框架自动处理
      console.error(`[CI FAIL] ${latest.name} #${latest.run_number} failed`);
    } else if (latest?.conclusion === "success") {
      lastStatus = "success";
    }
  } catch (err) {
    console.error("Poll error:", err);
  }
}

// 启动轮询
setInterval(pollCIStatus, POLL_INTERVAL);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error(`CI Status Channel started, polling ${REPO} every ${POLL_INTERVAL}ms`);
}

main().catch(console.error);

6.3 完整配置文件

{
  "mcpServers": {
    "telegram": {
      "command": "npx",
      "args": ["-y", "@anthropic-ai/claude-code-telegram-channel@latest"],
      "env": {
        "TELEGRAM_BOT_TOKEN": "${TELEGRAM_BOT_TOKEN}"
      }
    },
    "github-webhook": {
      "command": "node",
      "args": ["/opt/claude-channels/github-webhook-channel/index.js"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}",
        "WEBHOOK_PORT": "3456"
      }
    },
    "ci-status": {
      "command": "node",
      "args": ["/opt/claude-channels/ci-status-channel/index.js"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}",
        "GITHUB_REPO": "myorg/myrepo",
        "POLL_INTERVAL": "60000"
      }
    }
  },
  "hooks": {
    "PreToolUse": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ],
    "PostToolUse": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ],
    "Stop": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/event-recorder.sh"
      }
    ],
    "Notification": [
      {
        "type": "command",
        "command": "bash ~/.claude/hooks/smart-notify.sh"
      }
    ]
  }
}

6.4 验证整个流水线

# 1. 启动ngrok(用于接收GitHub Webhook)
ngrok http 3456 &

# 2. 配置GitHub Webhook(替换为你的ngrok URL)
# Repository → Settings → Webhooks → Add webhook
# Payload URL: https://xxxx.ngrok-free.app/webhook
# Content type: application/json
# Secret: (可选)

# 3. 启动Claude Code
claude

# 4. 在另一个终端推送代码触发CI
git commit --allow-empty -m "test: trigger CI pipeline"
git push

# 5. 观察事件流
tail -f ~/.claude/events/$(date -u +%Y-%m-%d)/*.jsonl | jq .

预期行为:

  1. git push → GitHub Webhook → github-webhook Channel推送Push事件到Claude Code
  2. CI开始运行,ci-status Channel轮询检测状态
  3. CI失败 → ci-status Channel推送失败事件到Claude Code
  4. Claude Code收到事件后分析日志,尝试修复代码
  5. 修复完成后自动commit + push
  6. Stop Hook触发桌面通知和Telegram消息
  7. 全程事件被记录到JSONL日志

第七章 进阶模式与最佳实践

7.1 Channel安全模型

安全层级 措施
Token保护 使用环境变量,永远不硬编码到配置文件
消息验证 Telegram/Discord消息需验证来源ID
权限控制 Channel工具应限制可执行的操作范围
网络隔离 Webhook Channel建议使用ngrok + IP白名单
日志审计 所有Channel事件记录到事件溯源系统

7.2 性能优化建议

7.3 多Agent协同通知

当使用Subagent模式时,通知策略需要分层:

主Agent (Stop事件)    → 桌面通知 + Telegram通知
Subagent (SubagentStop) → 仅记录日志
所有Agent (错误事件)   → 桌面通知 + Slack告警

在Hook脚本中通过session_id区分主会话和子会话。

7.4 移动端远程操控最佳实践

通过Telegram/Discord Channel,你可以从手机远程操控Claude Code:

指令 用途
/status 查询当前任务进度
/deploy <env> 触发部署到指定环境
/review <PR#> 自动审查指定PR
/test 运行测试套件
/logs <service> 查看服务日志
/rollback 回滚最近部署

建议在Claude Code的CLAUDE.md中定义这些指令的处理规则,确保响应一致性。

延伸阅读

参考来源

  1. Push events into a running session with channels - Claude Code Docs — Anthropic官方Channels功能文档,涵盖核心概念与配置方法
  2. Channels reference - Claude Code Docs — Channel MCP Server的完整构建参考,包含event_channel_send工具规范
  3. Hooks reference - Claude Code Docs — Hook生命周期事件、JSON输入输出Schema、退出码的权威参考
  4. Event-sourced Claude Code workflows - Nick Tune — 事件溯源模式在Claude Code工作流中的开创性实践
  5. Claude Code Notifications - GitHub — 社区维护的跨平台通知方案集,从终端BEL到桌面通知的完整覆盖

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入