要把 Claude Code 的通知发到 Telegram、Slack 或 Discord,先在对应应用里创建一个 bot 或 incoming webhook,再添加一个 Claude Code hook,用 curl 向它发一条简短消息。Notification hook 负责“Claude 需要你授权”和“Claude 正在等待”,Stop hook 负责“Claude 已完成”。Telegram 需要 bot token 和你的 chat ID,Slack 和 Discord 只需要一个 webhook URL。同一个脚本在 Mac 和 Linux 上都能用,Windows 则用一个简短的 PowerShell 版本。
01开始之前:消息内容和密钥
每个 hook 都会从标准输入收到 JSON。有用的字段包括 hook_event_name、cwd(项目目录)、Notification 事件中的 message,以及 Stop 事件中的 last_assistant_message。下面的示例会把它们拼成一行,比如 Claude needs you in my-app: Claude needs your permission to use Bash。
Bot token 和 webhook URL 相当于密码:拿到它的人都能以你的 bot 身份发消息。Slack 的文档明确说明不要分享 webhook URL,也不要提交到版本控制中。把它们放在一个只有你能读取的单独文件里:
mkdir -p ~/.claude
touch ~/.claude/chat-notify.env
chmod 600 ~/.claude/chat-notify.env
02Telegram:给你发消息的 bot
- 在 Telegram 中打开与 @BotFather 的对话,发送
/newbot,按提示操作。它会回复一个 token,比如123456789:AA...。 - 打开与新 bot 的对话,随便给它发一条消息,这样它才能给你回消息。
- 找到你的 chat ID。用你的 token 访问这个 URL,在返回内容里找
"chat":{"id"::
curl "https://api.telegram.org/bot<TOKEN>/getUpdates"
- 把这两个值写进
~/.claude/chat-notify.env:
SERVICE=telegram
TELEGRAM_TOKEN=123456789:AA...
TELEGRAM_CHAT_ID=987654321
Telegram 的 sendMessage 方法接收 chat_id 和 text(1 到 4,096 个字符),还支持 disable_notification=true,让消息静音送达。脚本对“已完成”消息使用静音,对授权请求保留提示音。
03Slack:incoming webhook
- 在 api.slack.com/apps 创建一个 Slack 应用(或打开已有应用)。
- 在 Incoming Webhooks 下打开 Activate Incoming Webhooks。
- 点击 Add New Webhook to Workspace,选择频道,然后点 Authorize。
- 复制以
https://hooks.slack.com/services/开头的 URL。
SERVICE=slack
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T000/B000/XXXX
每个 webhook 只能发到创建时选定的一个频道,而且不能按消息修改名称或图标。最好用一个只有你自己的小私有频道,免得提醒被繁忙的频道淹没。
04Discord:频道 webhook
- 在你的服务器中打开 Server Settings,然后依次进入 Integrations、Webhooks。
- 创建一个 webhook,选择频道,复制它的 URL。
SERVICE=discord
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/1234/abcd
Discord 的 execute-webhook 接口接收一个 JSON body,包含 content(最多 2,000 个字符),还可以用可选的 username 覆盖 webhook 的名称。
05Hook 脚本(Mac 和 Linux)
把下面内容保存为 ~/.claude/chat-notify.sh,然后运行 chmod +x ~/.claude/chat-notify.sh。它依赖 curl 和 jq(brew install jq 或 apt install jq)。
#!/bin/sh
. "$HOME/.claude/chat-notify.env"
input=$(cat)
event=$(printf '%s' "$input" | jq -r '.hook_event_name')
project=$(basename "$(printf '%s' "$input" | jq -r '.cwd')")
if [ "$event" = "Stop" ]; then
detail=$(printf '%s' "$input" | jq -r '(.last_assistant_message // "") | .[0:300]')
text="Claude finished in $project. $detail"
quiet=true
else
detail=$(printf '%s' "$input" | jq -r '.message // "Needs your attention"')
text="Claude needs you in $project: $detail"
quiet=false
fi
case "$SERVICE" in
telegram)
curl -s "https://api.telegram.org/bot$TELEGRAM_TOKEN/sendMessage" \
--data-urlencode "chat_id=$TELEGRAM_CHAT_ID" \
--data-urlencode "text=$text" \
--data-urlencode "disable_notification=$quiet" > /dev/null ;;
slack)
jq -n --arg t "$text" '{text: $t}' | curl -s -X POST \
-H 'Content-Type: application/json' --data @- "$SLACK_WEBHOOK_URL" > /dev/null ;;
discord)
jq -n --arg t "$text" '{content: $t, username: "Claude Code"}' | curl -s -X POST \
-H 'Content-Type: application/json' --data @- "$DISCORD_WEBHOOK_URL" > /dev/null ;;
esac
exit 0
用 jq -n --arg 构造 JSON 很关键:Claude 的回复里有引号、反斜杠和换行,手动拼进 JSON 字符串会导致请求出错。
接入之前先测试一下:
echo '{"hook_event_name":"Notification","cwd":"/tmp/demo","message":"Test"}' | ~/.claude/chat-notify.sh
06添加 hook
在 ~/.claude/settings.json 中添加(如果已有 hooks 对象,就加在里面):
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt|idle_prompt",
"hooks": [{ "type": "command", "command": "~/.claude/chat-notify.sh" }]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "~/.claude/chat-notify.sh", "async": true }]
}
]
}
}
新开一个 Claude Code 会话,让 hook 生效。idle_prompt 和 Stop 有重叠:Stop 在 Claude 完成时立即触发,而 idle_prompt 在你约一分钟没输入后触发。两个都保留或只留一个都行;ntfy 指南里解释了其中的取舍。
07Windows(PowerShell)
保存为 %USERPROFILE%\.claude\chat-notify.ps1。这个版本发到 Discord;如果用 Slack,把 body 改成 @{ text = $text } 并更换 URL。
$url = 'https://discord.com/api/webhooks/1234/abcd'
$in = [Console]::In.ReadToEnd() | ConvertFrom-Json
$project = Split-Path $in.cwd -Leaf
if ($in.hook_event_name -eq 'Stop') { $text = "Claude finished in $project." }
else { $text = "Claude needs you in ${project}: $($in.message)" }
$json = @{ content = $text; username = 'Claude Code' } | ConvertTo-Json
Invoke-RestMethod -Method Post -Uri $url -ContentType 'application/json; charset=utf-8' `
-Body ([Text.Encoding]::UTF8.GetBytes($json)) | Out-Null
Hook 配置:
{
"type": "command",
"shell": "powershell",
"command": "powershell -NoProfile -ExecutionPolicy Bypass -File \"$HOME\\.claude\\chat-notify.ps1\""
}
在 WSL 中请使用 Mac 和 Linux 版脚本。
08用聊天应用做通知需要注意的地方
- 发送的内容会离开你的电脑。“已完成”消息里包含 Claude 回复的开头部分。在共享的 Slack 或 Discord 频道里,所有成员都能看到。如果代码是私有的,就去掉
$detail。 - 聊天应用会合并和静音通知。繁忙的工作区或被静音的服务器可能让提醒被忽略。专门的推送应用(比如 ntfy,见 ntfy 指南)更不容易漏掉。
- Hook 不知道你是否在电脑前。
Stop每次都会发消息。idle_prompt和permission_prompt是最接近“离开时才提醒”的内置过滤方式。
09Claude Code Notifier 的定位
Webhook 很适合记录 Claude 做了什么,对团队来说也可能正合适。但如果你是一个人、想直接处理提醒,它就不够用了:你看到 Claude 需要授权,还得走回 terminal 去批准。Telegram bot 理论上可以接收回复,但等待回复并返回决定的 hook 得你自己写。
Claude Code Notifier 就是做这部分的。配对手机后,你可以直接在手机上对授权请求选择允许一次、本次会话允许或拒绝,回答 Claude 的选择题,并在 Claude 完成时发送后续指令。如果你在最近 30 秒内有输入,terminal 会照常询问,手机上不会有等待中的请求。它是独立产品,并非 Anthropic 出品,ccn 支持 Mac、Windows 和 Linux。参见方案对比、ccn 页面和价格。
10常见问题
Claude Code 能不用脚本直接发到 Slack 吗?
Claude Code 有 http hook,可以把 hook 的 JSON POST 到某个 URL,但 Slack 和 Discord 的 webhook 需要各自的 body 格式(text 或 content),所以直接用 http hook 发过去会失败。中间需要一个小脚本或中转服务。
怎么找到我的 Telegram chat ID?
先给你的 bot 发一条消息,然后打开 https://api.telegram.org/bot<TOKEN>/getUpdates。"chat":{"id": 后面的数字就是 chat ID。如果是群组,先把 bot 拉进群,并在群里发一条消息。
可以在 Slack 或 Discord 里回复 Claude Code 吗?
用 incoming webhook 不行,它只能发消息。要回复,需要一个能等待你的答复并返回决定的 hook,这正是远程审批工具要做的事。
这个 hook 会拖慢 Claude Code 吗?
Stop 配置使用了 "async": true,所以会在后台发送。Notification hook 本来就与 Claude 并行运行,不会阻塞它。