1. Claude Code 干完活不出声,盯屏等待到底有多折磨
Claude Code 这个工具用起来是真香,但有个细节特别反人类:它干完活从来不吭声。你让它重构一个模块、跑一遍测试、生成一堆文件,它就在那儿默默跑,跑完了也不告诉你。结果就是你每隔十几秒切回终端看一眼,发现还在转圈,再切回去干别的,过一会儿又忍不住看——一上午下来,正事没干多少,眼睛倒是快盯瞎了。
这个痛点在做长任务的时候尤其明显。比如你让 Claude Code 去处理一个跨十几个文件的批量改动,或者跑一个耗时几分钟的代码分析,中间你根本不知道它是在思考、在等工具返回、还是已经卡住了。没有反馈的等待是最消耗注意力的,因为你没法真正把注意力转移到别的事情上,总惦记着「它好了没」。
解决办法其实很直接:让 Claude Code 在关键节点「出声」。任务完成时响一声,需要你确认权限时响另一声,新会话开始时再换一个音效。这样你完全可以去泡杯咖啡、回个消息,听到声音再回来处理。这就是 hook 机制 + afplay 脚本要干的事。
Claude Code 的 hook 本质上是一套事件回调系统。它在执行流程的特定节点会触发事件,你可以在配置文件里声明「当某个事件发生时,去执行某条命令」。这条命令可以是一个 shell 脚本,脚本里调用 macOS 自带的 afplay 播放音频文件。整套链路是:Claude Code 触发事件 → 执行你配置的命令 → 命令调用脚本 → 脚本用 afplay 播放 mp3。理解了这个链路,后面配置起来就不会迷糊。
适合谁看这篇?如果你满足下面任意一条,这篇就是写给你的:用 macOS 跑 Claude Code,经常让它做耗时任务,受够了反复切窗口查看进度,愿意花十分钟做一次性配置。Windows 用户思路一样,只是播放命令要换成 PowerShell 的[console]::beep()或者调用系统播放器,本文以 macOS 的 afplay 为主线。
需要提前说清楚一个容易踩的坑:不同版本的 Claude Code 支持的 hook 事件名不完全一样。网上很多教程直接甩一段配置让你复制,结果你复制完发现根本不触发,原因就是事件名对不上你的版本。所以本文会先教你查自己版本支持哪些事件,再动手写配置,而不是上来就贴代码。
另外,hook 配置里除了音频播放,通常还会带上模型接入相关的环境变量。如果你还没配好 Claude Code 的模型来源,可以先去 TaoToken 的接入文档看一眼标准写法,把 Base URL、Key、Model ID 三件套对齐,再回来加 hook,这样排查问题时变量更少。文档地址在 https://taotoken.net/doc ,里面有各客户端的配置示例。
2. 前置准备:查清 hook 事件名,别让配置白写
动手之前必须先做一件事:确认你当前 Claude Code 版本支持哪些 hook 事件。这一步看着不起眼,但它是后面所有配置能不能生效的前提。我见过太多人配置写完、脚本也测通了,就是不响,最后发现是事件名写错了。
查事件名的方法很简单,在 Claude Code 的交互界面里输入斜杠命令:
/help然后找到 hooks 相关的说明,或者直接输入:
/hooks终端底部会列出当前版本支持的全部 hook 事件。以 Claude Code v1.0.72 为例,实际支持的事件大致是这几个:
| 事件名 | 触发时机 | 适合用来做什么 |
|---|---|---|
| PreToolUse | 工具执行前 | 记录即将执行的操作、做前置校验 |
| PostToolUse | 工具执行后 | 任务完成提示音、结果日志 |
| Notification | 发送通知时 | 权限确认提醒、异常告警 |
| UserPromptSubmit | 用户提交提示时 | 提交确认音、输入记录 |
| SessionStart | 新会话开始时 | 启动提示音、环境初始化 |
这里要重点区分 PostToolUse 和 Notification。PostToolUse 是「工具执行完之后」触发,也就是 Claude 完成一次工具调用(比如写完文件、跑完命令)就会响,适合做「干完活提醒」。Notification 更多是在需要你介入的时候触发,比如它要请求权限、要你确认某个操作,这时候响一声提醒你回来点确认。两个事件配合起来用,体验最好。
如果你想让「每次我发消息」也有个反馈音,那就用 UserPromptSubmit。想让「新开一个会话」有提示,用 SessionStart。事件选对了,后面脚本和配置才有意义。
选好事件之后,准备音频文件。音效来源随意,自己录、用系统自带、或者用剪辑软件导出都行。建议准备两到三个不同的音,方便区分状态:任务完成用一个偏轻快的,权限确认用一个偏急促的,会话启动用一个短的。文件格式用 mp3 或 wav 都可以,afplay 都支持。
把音频文件统一放到一个目录里,比如:
mkdir -p ~/hooks然后把你的音频文件丢进去,假设命名为done.mp3、notify.mp3、start.mp3。路径记清楚,后面配置里要写绝对路径,不能用~简写,因为 hook 执行时的环境不一定能正确展开波浪号。
还有一点:确认你的系统音量不是静音,afplay 播放走的是系统默认输出设备。如果你外接了显示器带音箱、或者用了蓝牙耳机,确认当前输出设备是你能听到的那个。这个听起来像废话,但真有人排查半天发现是输出设备切错了。
前置准备做到这里就够了:事件名查清、音频文件就位、路径确认。接下来写脚本。
3. 可复制配置:afplay 脚本 + settings.json hook 片段
这一节是核心,分两步走:先写播放脚本,再写 settings.json 配置。两步都给你可直接复制的片段,路径换成你自己的就行。
3.1 写一个通用的播放脚本
脚本的作用很简单:接收一个音频文件路径作为参数,用 afplay 播放它,同时记一行日志方便调试。先建目录和文件:
mkdir -p ~/.local/bin nano ~/.local/bin/claude-beep.sh脚本内容如下:
#!/bin/bash # 记录触发时间和传入的音频路径,方便排查 echo "Hook triggered at $(date): $1" >> /tmp/claude-hook.log # 播放传入的音频文件 afplay "$1"保存退出后,给它加上执行权限:
chmod +x ~/.local/bin/claude-beep.sh手动测一下脚本能不能出声:
~/.local/bin/claude-beep.sh ~/hooks/done.mp3听到声音就说明脚本没问题。如果没声音,先直接用 afplay 测音频本身:
afplay ~/hooks/done.mp3afplay 能响但脚本不响,检查脚本权限和路径;afplay 也不响,检查音频文件是否损坏、系统音量、输出设备。日志文件/tmp/claude-hook.log里会记录每次触发,后面排查 hook 有没有被调用时非常有用。
3.2 配置 settings.json 的 hooks 段
Claude Code 的配置文件是.claude/settings.json,注意它必须在.claude目录的根下,放错位置会读不到。完整配置结构如下,路径记得全部换成你自己的:
{ "env": { "ANTHROPIC_AUTH_TOKEN": "sk-你的Key", "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_MODEL": "claude-sonnet-4-5", "CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": 1, "API_TIMEOUT_MS": 600000 }, "permissions": { "allow": [], "deny": [] }, "hooks": { "PostToolUse": [ { "matcher": "", "hooks": [ { "type": "command", "command": "/Users/你的用户名/.local/bin/claude-beep.sh /Users/你的用户名/hooks/done.mp3" } ] } ], "UserPromptSubmit": [ { "matcher": "", "hooks": [ { "type": "command", "command": "/Users/你的用户名/.local/bin/claude-beep.sh /Users/你的用户名/hooks/start.mp3" } ] } ], "Notification": [ { "matcher": "permission", "hooks": [ { "type": "command", "command": "/Users/你的用户名/.local/bin/claude-beep.sh /Users/你的用户名/hooks/notify.mp3" } ] } ] } }几个关键点解释一下。env段里的ANTHROPIC_BASE_URL和ANTHROPIC_AUTH_TOKEN是模型接入配置,如果你用的是 TaoToken 的 API,Base URL 填https://taotoken.net/api,Key 去控制台生成,Model ID 按你实际要用的填。这三件套必须对齐,否则 Claude Code 连模型都连不上,hook 配得再对也没机会触发。
hooks段里每个事件对应一个数组,数组元素里有matcher和hooks。matcher用来过滤触发条件,空字符串表示全部匹配。Notification那里我写了"matcher": "permission",意思是只在权限请求类通知时触发,避免所有通知都响。
command字段必须是绝对路径,脚本路径和音频路径都要写全。macOS 上用户目录一般是/Users/你的用户名/,别用~。
配置改完,重启 Claude Code 让它重新加载 settings.json。重启方式就是退出当前会话再重新进入。
如果你同时用多个客户端(比如 Cline、Codex),建议把 Base URL、Key、Model ID 这三件套在各自配置里保持一致,避免出现「这个客户端能连、那个连不上」的混乱。TaoToken 的 API Keys 管理页在 https://taotoken.net/api-keys ,生成和轮换 Key 都在那里。
4. 验证请求:确认任务完成时真的会出声
配置写完不算完,必须验证。验证分三层:脚本层、hook 触发层、端到端层。一层层过,出问题好定位。
第一层,脚本层。前面已经手动测过claude-beep.sh能出声,这层过了。
第二层,hook 触发层。重启 Claude Code 后,随便发一条消息,比如「你好」。如果UserPromptSubmit配对了,你应该立刻听到start.mp3。听到了说明 hook 机制通了,配置被正确读取。没听到的话,先看日志:
tail -f /tmp/claude-hook.log再发一条消息,观察日志有没有新增行。有新增行说明 hook 被调用了,问题在 afplay 或音频路径;没有新增行说明 hook 根本没触发,问题在事件名或配置位置。
第三层,端到端层。让 Claude Code 干一件会调用工具的事,比如「在当前目录创建一个 test.txt 文件」。它执行写文件这个工具后,PostToolUse应该触发,你听到done.mp3。这一步成功,说明整条链路完全打通。
验证时可以故意做个对照:把done.mp3和start.mp3换成明显不同的音效,这样你能清楚区分是哪个事件在响。如果两个事件响的是同一个音,你会误以为配置生效了,其实可能只有一个事件在工作。
再补一个验证技巧:观察日志的时间戳。日志里会记录每次触发的精确时间,你可以对照 Claude Code 界面上的操作时间,确认响应对不对得上。比如你 10:00:05 提交消息,日志里 10:00:05 有一条记录,那就对上了。
端到端验证通过后,你就可以放心把注意力从屏幕上移开了。长任务跑起来,听到done.mp3再回来。权限确认的时候notify.mp3会提醒你,不会让你干等着。
如果你在验证过程中发现模型请求本身有问题(比如一直转圈不出结果),那可能是接入配置的问题,跟 hook 无关。这时候去 TaoToken 的模型对话页面单独测一下模型能不能正常返回,地址是 https://taotoken.net/models ,能返回说明 Key 和 Base URL 没问题,问题在 Claude Code 客户端侧。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth
配置 hook 的过程中,报错基本集中在几类。下面按真实报错对照着排查。
401 未授权。这个报错跟 hook 没关系,是模型接入的 Key 有问题。表现是 Claude Code 一发请求就报 401,日志里能看到401 Unauthorized。排查顺序:先确认ANTHROPIC_AUTH_TOKEN填的是有效 Key,没有多余空格;再确认ANTHROPIC_BASE_URL写对了,TaoToken 的地址是https://taotoken.net/api,结尾不要多加斜杠;最后确认 Key 没有过期或被禁用。去 https://taotoken.net/api-keys 重新生成一个换上试试。
local proxy failed。这个报错通常出现在客户端尝试走本地代理但代理没起来的时候。如果你在配置里写了代理相关设置,先去掉,直连试试。Claude Code 的 settings.json 里不要保留任何代理字段。如果系统层面有代理环境变量,临时 unset 掉再测:
unset HTTP_PROXY HTTPS_PROXY ALL_PROXYreading choices 相关报错。这类报错一般是响应格式不符合预期,常见于 Base URL 指向的端点不兼容 Anthropic 协议。确认你用的 Base URL 是 Anthropic 兼容端点,TaoToken 的https://taotoken.net/api是兼容的。如果 Model ID 填错,也可能导致返回结构异常,检查ANTHROPIC_MODEL是不是有效模型名。
OAuth 相关报错。如果你用的是需要 OAuth 登录的客户端(比如某些版本的 Codex),报 OAuth 错误说明登录态失效或配置冲突。这时候检查auth.json里的凭据是否有效,Base URL、Key、Model ID 三件套是否齐全。三件套缺任何一个都可能触发认证流程异常。
hook 不触发但没有任何报错。这是最隐蔽的一类。排查顺序:第一,确认 settings.json 在.claude根目录下,不是子目录;第二,确认事件名跟/hooks列出来的一致;第三,确认command是绝对路径且脚本有执行权限;第四,看/tmp/claude-hook.log有没有记录。四步走完基本能定位。
脚本触发了但没声音。日志有记录但听不到,检查音频文件路径是否正确、文件是否损坏、系统输出设备是否是当前在用的那个。afplay 直接测音频文件,能响就是脚本参数问题,不能响就是音频或设备问题。
权限确认不响。Notification事件的matcher写的是permission,如果你希望所有通知都响,把 matcher 改成空字符串。但要注意,改成空字符串后所有通知都会触发,可能比较吵,建议还是保留permission过滤。
排查的核心思路就一条:把链路拆成「事件触发 → 命令执行 → 脚本运行 → 音频播放」四段,用日志确认卡在哪一段。日志文件是/tmp/claude-hook.log,这是你最好的朋友。
6. 把提示音接进你的日常编码流
配置跑通之后,真正有价值的是把它融进日常习惯。我自己的用法是这样:PostToolUse用done.mp3,Notification的 permission 用notify.mp3,SessionStart用start.mp3。三个音效区分度拉满,闭着眼都知道现在是什么状态。
长任务场景收益最大。比如让 Claude Code 批量重构、跑全量测试、生成文档,这些动辄几分钟起步。以前我得反复切窗口,现在提交完就去干别的,听到done.mp3再回来验收。注意力不再被切碎,效率提升是实打实的。
如果你经常用 Coding Plan 跑 Agent 类的长任务,提示音的价值会更高,因为 Agent 任务链路长、中间状态多,没有声音反馈你根本不知道它跑到哪一步了。Coding Plan 的入口在 https://taotoken.net/coding-plan ,配合 hook 提示音用,体验会顺很多。
再给几个实用小技巧。音效别选太长的,一两秒足够,太长会烦。音量别太大,能听到就行,突然一声巨响会吓到人。如果你在办公室,建议用耳机或者把音量调低,别打扰同事。音频文件统一放~/hooks,脚本统一放~/.local/bin,路径规范了以后换机器也好迁移。
最后,hook 机制不止能播声音。你完全可以在脚本里加更多动作:任务完成时发一条系统通知、写一行记录到日志文件、甚至触发一个自动化流程。脚本是你的,想加什么加什么。afplay 只是最直观的那个用法。
整套配置一次性做好,后面就是纯收益。Claude Code 干活会出声了,你的眼睛就解放了。