1. 为什么 Claude Code 跑长任务时你总在反复切窗口用 Claude Code 写代码的人大概率都经历过这个场景让它重构一个模块、跑一遍全量测试、或者批量改十几个文件命令敲下去之后终端就开始刷日志。你不知道它要跑三分钟还是十五分钟于是每隔一会儿就切回终端看一眼——结果它还在跑再切回去写两行代码又忍不住切回来。真正让人抓狂的不是等待本身而是没有反馈。更麻烦的是权限确认。Claude Code 在执行某些 shell 命令或写文件前会停下来等你授权如果你正好在浏览器里查文档它就一直卡在那里十分钟后你回来才发现任务根本没往下走。这种「静默阻塞」比慢更浪费时间。我试过用提示词让模型自己播提示音在~/.claude/CLAUDE.md里写一段「任务完成后执行 afplay」的指令。结果很不稳定有时候响有时候不响长对话里上下文一压缩这条指令直接丢了。原因很简单——提示词是「软请求」模型可以不听Hook 是「硬触发」事件发生就一定执行。这篇就围绕 Claude Code 的 Hook 机制给你一套可复制的settings.json配置让终端在任务结束或需要授权时主动「响铃」同时用 TaoToken 统一 Key 接入省去多平台来回配密钥的麻烦。适合谁看本地用 Claude Code 做开发的工程师、经常跑长任务的 Agent 玩家、以及想把通知做成可复用 SKILL 的人。下面从接入准备讲到配置、验证、排障每一步都能直接抄。2. TaoToken 前置统一 Key 与 API 通道准备在配 Hook 之前先把 Claude Code 的模型通道理顺。Claude Code 默认走 Anthropic 官方通道但很多人手里同时有多个模型的 Key切换起来要改环境变量、改配置很碎。TaoToken 的作用是把这些通道统一成一个 Key、一个 API 入口Claude Code、Coding Agent、脚本调用都走同一套凭证。你需要先拿到两样东西API Key和API 地址。地址固定是https://taotoken.net/api注意这个不带任何查询参数直接作为 base URL 用。Key 在控制台里创建建议单独建一个给 Claude Code 用的 Key方便后面按用途吊销。创建 Key 的入口在这里API Keys 管理页https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite拿到 Key 之后Claude Code 通过环境变量读取。Anthropic 系的工具通常认ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL这两个变量把 base URL 指向 TaoToken 的 API 地址即可。如果你用的是 Claude Code 的配置文件方式也可以写进~/.claude/settings.json的env字段里这样每次启动自动生效不用手动 export。这里有个容易踩的点base URL 不要带/v1后缀也不要自己拼/messages。Claude Code 内部会按 Anthropic 的路径规则拼接你只需要给到https://taotoken.net/api这一层。多写一段路径请求就会 404。配置好之后先用一条最简单的命令验证通道是否通export ANTHROPIC_API_KEY你的_TaoToken_Key export ANTHROPIC_BASE_URLhttps://taotoken.net/api然后启动 Claude Code随便问一句「你好」能正常返回就说明通道没问题。这一步过了再往下配 Hook否则通知响了但任务本身跑不起来排查会混在一起。3. 可复制的 settings.json Hook 配置骨架Claude Code 的 Hook 配置写在~/.claude/settings.json里核心结构是hooks对象里面按事件名分组。我们这篇要用到两个事件Stop任务停止/完成和Notification需要用户注意比如等待输入或权限请求。先给一个最小可用的骨架直接复制{ env: { ANTHROPIC_API_KEY: 你的_TaoToken_Key, ANTHROPIC_BASE_URL: https://taotoken.net/api }, hooks: { Stop: [ { matcher: , hooks: [ { type: command, command: python3 ~/.claude/hooks/notify.py stop } ] } ], Notification: [ { matcher: , hooks: [ { type: command, command: python3 ~/.claude/hooks/notify.py notification } ] } ] } }几个关键字段解释一下。matcher留空表示匹配所有情况如果你只想对特定工具触发可以填工具名。type固定是command表示执行一条 shell 命令。command就是你要跑的通知脚本这里我把它放在~/.claude/hooks/notify.py参数stop/notification用来区分事件类型。接下来写这个notify.py。它从 stdin 读 Claude Code 传进来的 JSON解析出事件类型然后触发终端铃声和系统通知。用纯标准库不装任何依赖#!/usr/bin/env python3 import sys import json import subprocess import platform def ring_bell(): # 终端铃声直接往 stdout 写 BEL 字符 sys.stdout.write(\a) sys.stdout.flush() def system_notify(title, message): os_name platform.system() if os_name Darwin: script fdisplay notification {message} with title {title} subprocess.run([osascript, -e, script], checkFalse) elif os_name Linux: subprocess.run([notify-send, title, message], checkFalse) elif os_name Windows: # Windows 用 PowerShell 弹气泡 ps ( [reflection.assembly]::loadwithpartialname(System.Windows.Forms); [System.Windows.Forms.MessageBox]::Show( f{message}, {title}) ) subprocess.run([powershell, -Command, ps], checkFalse) def main(): event sys.argv[1] if len(sys.argv) 1 else unknown raw sys.stdin.read() try: payload json.loads(raw) if raw.strip() else {} except json.JSONDecodeError: payload {} if event stop: title Claude Code message 任务已完成可以回来看了 else: ntype payload.get(notification_type, ) if ntype permission_prompt: message 需要你授权任务在等你 else: message Claude 在等你输入 title Claude Code 提醒 ring_bell() system_notify(title, message) if __name__ __main__: main()保存后给它执行权限chmod x ~/.claude/hooks/notify.py这套配置的设计思路是「事件驱动 单一脚本分发」。Stop 事件代表一轮任务结束Notification 事件代表需要你介入。两个事件都走同一个脚本靠参数区分维护成本低。铃声用 BEL 字符是最通用的做法任何终端都认系统通知按平台分支macOS 用osascriptLinux 用notify-sendWindows 用 PowerShell。注意Windows 下notify-send不存在脚本里已经按platform.system()做了分支不要手动删掉判断逻辑否则在非 macOS 机器上会报错。如果你想把通知做得更丰富比如同时推到 Telegram 或 Slack可以在system_notify后面再加一个send_remote()函数用urllib.request发 HTTP 请求同样不需要第三方库。但建议先把本地铃声跑通再逐步加渠道一次加太多出问题不好定位。4. 验证请求跑一条耗时命令确认铃铛触发配置写完必须验证。分两步先手动喂 JSON 给脚本确认脚本本身没问题再让 Claude Code 跑真实任务确认 Hook 被正确调用。第一步手动模拟 Stop 事件echo {hook_event_name:Stop} | python3 ~/.claude/hooks/notify.py stop执行后你应该听到终端铃声macOS 上还会弹出系统通知。如果没声音先检查终端是否静音、系统通知权限是否给了终端 App。第二步模拟 Notification 事件里的权限请求echo {notification_type:permission_prompt,message:needs permission} \ | python3 ~/.claude/hooks/notify.py notification这一步应该弹出「需要你授权」的通知。两个都通过说明脚本和系统通知链路没问题。第三步真实场景验证。启动 Claude Code让它执行一条明显耗时的命令比如# 在 Claude Code 里输入这个任务 请执行 sleep 20 echo doneClaude Code 会调用 shell 跑这条命令20 秒后任务结束触发 Stop 事件。这时候你应该听到铃声、看到通知。如果它中途因为权限停下来Notification 事件也会触发。验证成功的标志很明确你不用盯着终端铃声会告诉你什么时候该回来。这一步过了整套 Hook 就真正生效了。如果你还想验证模型通道是否走的是 TaoToken可以在 Claude Code 里问一个需要联网知识的问题同时观察控制台里 API Keys 页面的调用记录能看到请求计数在涨就说明 Key 和 base URL 都配对。5. 本篇常见错排查配 Hook 最容易卡在几个固定位置我按出现频率排一下。铃声不响但脚本手动跑有声音。大概率是 Hook 没被触发或者settings.json格式错了。Claude Code 对 JSON 格式很敏感多一个逗号、少一个引号都会导致整个 hooks 段被忽略。用python3 -m json.tool ~/.claude/settings.json校验一下能正常输出就说明格式没问题。脚本报command not found。检查command字段里的路径是不是绝对路径。~在 Hook 执行环境里不一定被展开建议写成/Users/你的用户名/.claude/hooks/notify.py这种完整路径最稳。macOS 上没弹通知。系统设置 → 通知 → 找到你的终端 AppiTerm / Terminal / VS Code确认允许通知。第一次调用osascript时系统会弹权限请求点了拒绝后面就一直静默。Linux 上notify-send不存在。装一下libnotify-binDebian/Ubuntu或libnotifyFedora。如果服务器没有图形界面系统通知本来就不会弹这时候只保留终端铃声即可把system_notify里的 Linux 分支去掉。Claude Code 报 API 401 或 404。这是通道问题不是 Hook 问题。401 通常是 Key 错了或没生效检查ANTHROPIC_API_KEY有没有拼错404 多半是 base URL 多写了路径确认是https://taotoken.net/api而不是带/v1的版本。改完环境变量要重启 Claude Code 才生效。Hook 触发了但脚本卡住。如果脚本里有网络请求比如推 Telegram网络超时会让 Hook 阻塞进而拖慢 Claude Code。所有远程发送都要设超时urllib.request.urlopen(req, timeout5)这种超时就放弃不要无限等。Stop 事件不触发。确认 Claude Code 版本支持 Stop 事件。老版本可能只有 Notification。升级到较新版本或者在settings.json里同时保留两个事件哪个生效用哪个。排查顺序建议固定先手动喂 JSON 验证脚本 → 再校验 settings.json 格式 → 再看 Claude Code 启动日志里有没有 hook 相关报错 → 最后查通道。按这个顺序走基本十分钟内能定位。6. 把通知做成可复用 SKILL并统一走 TaoToken单次配置能解决眼前问题但如果你同时用 Claude Code、Cursor、Copilot CLI每个平台的 Hook 格式都不一样重复配很烦。更省事的做法是把notify.py封装成一个 SKILL统一事件模型{platform, event, message}各平台 Hook 只负责把原始 JSON 喂进来脚本内部做解析和分发。这样加一个新平台只需要在解析层加一个分支通知渠道完全复用。渠道也可以逐步扩展。本地铃声和系统通知是默认开启的Telegram、Slack、Discord 这类远程渠道按需加用concurrent.futures.ThreadPoolExecutor并发发送单个渠道失败不影响其他渠道错误只打到 stderr。这样即使某个 Webhook 挂了本地该响还是响。通道层面所有 Agent 统一走 TaoToken 的 Key 和 API 地址好处是换模型、加 Agent 都不用重新配密钥控制台里还能看到调用量。Claude Code 的接入文档在这里里面有环境变量和配置文件的完整说明接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite如果你主要做长期编码、想让 Agent 持续跑任务可以看下 Coding Plan配合 Hook 通知基本能做到「派活 → 去干别的 → 铃响回来收结果」Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite想先直观感受模型对话效果或者测试通道是否正常可以从模型对话页进模型对话https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite整套下来你得到的是一个确定性触发的通知系统任务结束一定响需要授权一定提醒不再靠模型「心情」决定。配置一次之后所有长任务都能安心丢后台。