
1. Claude Code 长任务跑起来后为什么你总在盯屏Claude Code 这类终端里的编码 Agent最舒服的用法是丢一个长任务进去比如重构一个模块、批量补测试、跑一轮依赖升级然后你去干别的事。但现实往往是你每隔两分钟切回终端看一眼怕它卡在权限确认上怕它报错退出怕它其实早就跑完了你还在傻等。这个「盯屏焦虑」在本地开发和自动化脚本场景里特别明显因为 Claude Code 默认不会主动告诉你状态变化它只会在终端里默默输出。我试过把 Claude Code 挂在 tmux 里跑结果还是得手动tmux attach去看。问题的本质是Claude Code 有一套 hooks 机制能在关键事件触发时执行你配置的命令但默认没人去接这些事件。你要做的就是给这些事件挂上一个通知脚本让任务完成、需要确认、执行失败这些时刻主动推送到你眼前。这篇要解决的就是这件事给 Claude Code 装一个通知监控覆盖 Windows Toast 本地弹窗和 Webhook 远程推送两条路。同时把模型通道统一到 TaoToken 的 Key 上这样无论你切哪个模型通知配置都不用改。适合谁适合每天用 Claude Code 跑长任务、又不想一直守着终端的本地开发者以及把 Claude Code 塞进自动化流水线、需要感知每一步结果的脚本党。先说清楚 Claude Code 的 hooks 能接哪些事件这决定了你的通知能覆盖多细。常用的有这几类Stop在 Claude 完成一轮响应时触发对应「任务完成」PermissionRequest在需要你批准某个操作时触发对应「需要确认」PostToolUse可以匹配具体工具名比如EnterPlanMode、AskUserQuestion对应「等待输入」还有TeammateIdle这类团队协作场景的空闲通知。把这些事件映射成通知类型你就能做到不盯屏也知道 Claude 现在卡在哪一步。通知的落地方式分两种。一种是本地弹窗Windows 上用 PowerShell 调 Toast APIMac 上用osascript或terminal-notifier优点是零依赖、即时另一种是 Webhook把事件 POST 到一个 HTTP 端点可以推到飞书、钉钉、企业微信或者你自己的服务优点是跨设备、可留痕。两种可以同时配本地弹窗负责即时提醒Webhook 负责远程和归档。这里有个容易被忽略的点Claude Code 的 hooks 是在 harness 层执行的它不会在执行 hook 前再问你一次权限。也就是说你写进settings.json的 hook 命令会被直接执行。所以 hook 命令里只应该调用你自己信任的通知脚本别塞来源不明的命令。这一点后面排障章节还会展开。2. TaoToken 统一 Key 通道的前置准备在配通知之前先把模型通道理顺。原因很实际通知脚本本身不关心你用哪个模型但你的 Claude Code 会。如果你今天用这个 Key、明天换那个端点settings.json里的环境变量和 hook 配置就会跟着乱。把模型访问统一到 TaoToken 的 Key 通道上好处是 Base URL 和 Key 固定通知配置写一次就不用动。TaoToken 在这里扮演的是统一入口的角色你拿一个 Key就能在 Claude Code 里访问多种模型不用为每个模型单独维护一套凭证。对通知监控这个场景来说这意味着你的settings.json里模型相关的部分和 hooks 部分是解耦的改通知不会碰到模型配置改模型也不会影响通知。前置准备分三步。第一步拿到 API Key。打开 https://taotoken.net/api-keys 创建或复制你的 Key注意这个页面是控制台里的密钥管理入口Key 只显示一次复制后自己存好。第二步确认 Base URL。TaoToken 的 API 端点是 https://taotoken.net/api注意这个地址不带任何查询参数直接作为ANTHROPIC_BASE_URL的值。第三步选一个 Model ID。Claude Code 走的是 Anthropic 兼容协议Model ID 填你实际要用的模型标识比如claude-sonnet-4-5这类具体以你账号下可用的为准。把这三件套写进环境变量Claude Code 启动时就会读。Windows 上可以在 PowerShell 里临时设置也可以写进系统环境变量Mac/Linux 上写进~/.zshrc或~/.bashrc。三件套是Base URL、Key、Model ID缺一不可。很多人只配了 Key 忘了 Base URL结果请求打到默认端点上去报 401 或者连接失败这类问题在排障章节会具体讲。如果你用的是 Claude Code 的配置文件方式可以在~/.claude/settings.json里通过env字段注入这样比系统环境变量更可控也方便和 hooks 放在同一个文件里管理。下面给一个最小示例注意 Key 不要明文提交到 Git{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_AUTH_TOKEN: sk-你的TaoToken密钥, ANTHROPIC_MODEL: claude-sonnet-4-5 } }这里ANTHROPIC_AUTH_TOKEN就是你的 TaoToken KeyANTHROPIC_BASE_URL固定为https://taotoken.net/apiANTHROPIC_MODEL填你要用的 Model ID。三个值确认无误后Claude Code 的模型请求就走通了。这一步做完再去配通知你的注意力就只需要放在 hooks 上。顺便说一句如果你还没决定长期用哪个模型可以先在 https://taotoken.net/models 里对话验证一下确认模型可用、响应正常再写进配置。验证模型和配通知是两件独立的事但顺序上建议先验证模型通道否则通知配好了、模型却报错你会分不清是哪一层的问题。3. 可复制的通知监控配置hooks 加 Webhook 参数这一节是核心给你可以直接抄的配置。整体结构是一个通知脚本负责实际发送settings.json里的 hooks 负责在事件触发时调用这个脚本。脚本同时支持本地 Toast 和 Webhook 两种输出通过参数切换。先建目录结构。Claude Code 的 skill 约定放在~/.claude/skills/下我们建一个notify-monitor~/.claude/skills/notify-monitor/ ├── SKILL.md ├── scripts/ │ ├── notify.ps1 # Windows Toast Webhook │ └── notify.sh # Mac/Linux 版本 └── assets/ └── icon.png # 可选通知图标Windows 版notify.ps1的核心逻辑接收-Type、-Message、-Sound、-Webhook参数先调 Windows Toast API 弹本地通知如果传了-Webhook就再发一个 POST。下面是一个精简可用的版本param( [Parameter(Mandatory$true)][string]$Type, [Parameter(Mandatory$true)][string]$Message, [switch]$Sound, [string]$Webhook , [int]$Duration 5 ) # 本地 Toast 通知 $titleMap { complete 任务完成 confirm 需要确认 wait 等待输入 milestone 关键节点 error 执行失败 } $title $titleMap[$Type] if (-not $title) { $title Claude Code 通知 } $toastParams { Text $Message Title $title AppLogo $PSScriptRoot/../assets/icon.png } if ($Sound) { $toastParams.Sound Notification.Default } # 使用 BurntToast 模块需先 Install-Module BurntToast if (Get-Module -ListAvailable -Name BurntToast) { Import-Module BurntToast New-BurntToastNotification toastParams } else { # 无模块时退化为 msg 命令 msg * $title : $Message } # Webhook 推送 if ($Webhook -ne ) { $payload { type $Type message $Message time (Get-Date).ToString(yyyy-MM-dd HH:mm:ss) } | ConvertTo-Json -Compress try { Invoke-RestMethod -Uri $Webhook -Method Post -Body $payload -ContentType application/json -TimeoutSec 10 } catch { Write-Warning Webhook 推送失败: $_ } }Mac/Linux 版notify.sh用osascript或notify-sendWebhook 部分用curl#!/usr/bin/env bash TYPE$1; MESSAGE$2; WEBHOOK$3 case $TYPE in complete) TITLE任务完成 ;; confirm) TITLE需要确认 ;; wait) TITLE等待输入 ;; milestone) TITLE关键节点 ;; error) TITLE执行失败 ;; *) TITLEClaude Code 通知 ;; esac # 本地通知 if command -v osascript /dev/null 21; then osascript -e display notification \$MESSAGE\ with title \$TITLE\ elif command -v notify-send /dev/null 21; then notify-send $TITLE $MESSAGE fi # Webhook if [ -n $WEBHOOK ]; then curl -s -X POST $WEBHOOK \ -H Content-Type: application/json \ -d {\type\:\$TYPE\,\message\:\$MESSAGE\,\time\:\$(date %F %T)\} \ --max-time 10 || echo Webhook 推送失败 2 fi脚本有了接下来是settings.json里的 hooks 配置。这是最关键的一段直接决定哪些事件会触发通知。下面这份配置覆盖了完成、确认、等待输入、失败四类场景Webhook 地址用占位符你替换成自己的{ hooks: { Stop: [ { matcher: , hooks: [ { type: command, command: powershell -ExecutionPolicy Bypass -File ~/.claude/skills/notify-monitor/scripts/notify.ps1 -Type complete -Message Claude 任务已完成 -Sound -Webhook https://your-webhook.example.com/claude } ] } ], PermissionRequest: [ { matcher: , hooks: [ { type: command, command: powershell -ExecutionPolicy Bypass -File ~/.claude/skills/notify-monitor/scripts/notify.ps1 -Type confirm -Message Claude 需要你的确认 -Sound -Webhook https://your-webhook.example.com/claude } ] } ], PostToolUse: [ { matcher: EnterPlanMode, hooks: [ { type: command, command: powershell -ExecutionPolicy Bypass -File ~/.claude/skills/notify-monitor/scripts/notify.ps1 -Type confirm -Message 请审批 Claude 的计划 -Sound } ] }, { matcher: AskUserQuestion, hooks: [ { type: command, command: powershell -ExecutionPolicy Bypass -File ~/.claude/skills/notify-monitor/scripts/notify.ps1 -Type wait -Message Claude 需要你的输入 -Sound } ] } ] } }几个参数说明。matcher为空字符串表示匹配该事件的所有情况PostToolUse的matcher填具体工具名比如EnterPlanMode、AskUserQuestion只有这些工具被调用时才触发。-Webhook参数只在需要远程推送的事件上加本地弹窗类的事件可以不加减少网络请求。-Sound控制是否播放提示音需要安静环境时去掉即可。如果你不想手动编辑 JSONClaude Code 提供了/update-config这类交互式配置入口可以用自然语言描述你要加的 hooks让它帮你写进settings.json。但无论哪种方式最终落到文件里的结构就是上面这样理解结构比记住命令更重要。Webhook 端点的选择上飞书、钉钉、企业微信的群机器人 Webhook 都能直接收 JSON但它们的字段格式不完全一样。上面脚本发的是通用 JSON如果你要对接特定平台需要在脚本里把 payload 改成对应格式。比如飞书群机器人要的是{msg_type:text,content:{text:...}}这个转换放在脚本里做hooks 配置不用动。4. 验证一次任务完成与失败告警配置写完不验证等于没配。这一节给你两个可复现的验证动作一个测完成通知一个测失败通知都不需要真的跑一个长任务。先测脚本本身能不能弹通知。在 PowerShell 里直接调powershell -ExecutionPolicy Bypass -File ~/.claude/skills/notify-monitor/scripts/notify.ps1 -Type complete -Message 测试通知任务完成 -Sound如果 Windows 右下角弹出「任务完成」的通知说明本地 Toast 通了。如果没弹先看 Windows 设置里的通知开关再看 BurntToast 模块是否安装。这一步是隔离验证排除了 Claude Code 的干扰。再测 Webhook。把-Webhook参数指向你的端点跑一次powershell -ExecutionPolicy Bypass -File ~/.claude/skills/notify-monitor/scripts/notify.ps1 -Type error -Message 测试通知执行失败 -Webhook https://your-webhook.example.com/claude去你的 Webhook 接收端看有没有收到这条 JSON字段应该是type、message、time三个。收到就说明远程通道通了。脚本层验证完再验证 hooks 是否真的被 Claude Code 触发。启动 Claude Code随便给它一个会触发Stop的简单任务比如「列出当前目录的文件」。任务完成后你应该收到「任务已完成」的通知。如果没收到检查settings.json的路径是不是~/.claude/settings.json以及 hook 命令里的脚本路径是不是绝对路径或正确的~展开路径。失败告警的验证稍微绕一点因为 Claude Code 正常跑不会主动报错。你可以构造一个会失败的操作比如让它执行一个不存在的命令或者在 hook 里临时把-Type改成error来模拟。更稳妥的做法是单独写一个测试 hook只在手动触发时调用notify.ps1 -Type error确认失败通知的文案和声音符合预期再把它接到真实事件上。验证通过后你会看到这样的结果Claude Code 在后台跑长任务任务完成时你手机上的群机器人收到一条消息同时电脑弹出 Toast需要你确认权限时通知类型是confirm你能立刻切回去处理如果某一步失败error类型的通知会带上失败信息。整个过程你不需要盯着终端。这里补一个实用技巧通知消息里不要塞敏感信息。比如不要把文件绝对路径、命令原文、密钥片段写进-Message因为 Toast 通知会进 Windows 通知中心其他应用可能读到。用通用描述比如「任务已完成」「需要确认」具体细节回终端看。这个习惯在团队协作或共享电脑上尤其重要。5. 常见报错排查401、local proxy failed、reading choices通知监控配好后报错通常来自两层模型通道层和 hooks 执行层。分开排查别混在一起看。401 Unauthorized。这个几乎都是 Key 或 Base URL 的问题。先确认ANTHROPIC_AUTH_TOKEN是你的 TaoToken Key没有多余空格再确认ANTHROPIC_BASE_URL是https://taotoken.net/api注意结尾没有斜杠、没有多余路径。如果 Key 是对的但还报 401去 https://taotoken.net/api-keys 看这个 Key 是否被禁用或额度耗尽。还有一种情况是环境变量没生效Claude Code 读的是旧值重启终端或重新加载配置文件。local proxy failed / connection refused。这类报错说明请求根本没发出去或者发到了一个本地代理端口。检查你的环境里有没有残留的HTTP_PROXY、HTTPS_PROXY设置指向一个已经关掉的本地端口。Claude Code 会读这些环境变量如果代理不通就会报 local proxy failed。清掉这些变量或者确认代理服务在运行。注意这里说的是环境变量层面的代理配置不是让你去搭什么通道只是排查残留配置。reading choices / unexpected response shape。这个报错通常出现在响应格式不符合预期时常见原因是 Base URL 指向了一个不兼容 Anthropic 协议的端点或者 Model ID 填错了。确认ANTHROPIC_BASE_URL是 TaoToken 的 API 地址ANTHROPIC_MODEL是你账号下真实可用的 Model ID。如果 Model ID 写了一个不存在的名字服务端可能返回一个结构不同的错误响应客户端解析时就报 reading choices 之类的错。OAuth 相关报错。如果你之前用 OAuth 方式登录过 Claude Code配置里可能残留了 OAuth 凭证和现在的 Key 方式冲突。检查~/.claude/下有没有旧的凭证文件必要时清理掉让 Claude Code 走ANTHROPIC_AUTH_TOKEN这条路径。OAuth 和 Key 两种方式不要混用。hooks 不触发。如果模型通道正常但通知不弹问题在 hooks。先确认settings.json的 JSON 语法正确可以用python -m json.tool ~/.claude/settings.json校验。再确认 hook 命令里的脚本路径存在Test-Path一下。Windows 上路径分隔符和~展开容易出问题建议在 hook 命令里用绝对路径比如C:/Users/你的用户名/.claude/skills/notify-monitor/scripts/notify.ps1。另外PostToolUse的matcher大小写敏感工具名要写对。通知弹了但没声音。检查-Sound参数是否传了以及 Windows 的通知声音设置。BurntToast 的Sound参数支持Notification.Default、Notification.Looping.Alarm等值如果系统静音或专注助手开着声音会被抑制。Webhook 收不到。先在脚本层用curl或Invoke-RestMethod单独测端点确认端点可达。再看脚本里的-Webhook参数有没有传对URL 有没有被 shell 转义。如果端点要求特定 header 或签名需要在脚本里补上。超时设 10 秒避免 hook 卡住影响 Claude Code 主流程。排查顺序建议先隔离脚本手动跑 notify.ps1再隔离模型手动发一个请求最后看 hooks 配置。三层分开测比一上来就怀疑 Claude Code 本身高效得多。6. 把通知监控接进你的日常流程配置跑通之后通知监控的价值在于让你敢把长任务丢出去。你可以根据任务类型调整通知粒度短任务只留Stop完成通知涉及权限操作的任务加上PermissionRequest需要你中途决策的任务加上AskUserQuestion。通知太频繁会烦太少又失去意义按自己的节奏调。Webhook 那条路可以玩得更开。把事件推到自己的服务就能做任务历史记录、失败率统计、甚至触发下一步自动化。比如任务完成后自动跑测试失败时自动开一个 issue。这些都在 Webhook 接收端做Claude Code 这边只负责发事件。模型通道统一在 TaoToken 的 Key 上之后你换模型只需要改ANTHROPIC_MODEL一个值通知配置完全不用动。这种解耦在长期使用里省心很多。如果你还在选长期用的模型可以去 https://taotoken.net/models 对话验证如果打算把 Claude Code 接进更重的编码和 Agent 流程可以看看 https://taotoken.net/coding-plan 的长期方案接入细节和参数说明在 https://taotoken.net/doc 里有完整文档。最后留一个我踩过的坑hook 命令里不要写会阻塞很久的操作。通知脚本要快速返回Webhook 超时设短一点否则 Claude Code 会等 hook 执行完才继续长任务反而被拖慢。通知是辅助别让它成为新的瓶颈。