Claude Code Hook 集成
不用自己动手运行命令,灯是怎么知道 Claude Code 正在做什么的。
运行一次 andon-light install-hooks 之后,灯就会自己更新。日常不需要你运行任何命令。这篇讲讲这个设置到底做了什么,为什么这么设计,方便你在遇到奇怪的情况时能有个参考。
Claude Code 支持"hook":在它自身生命周期里的一些节点(比如"会话刚开始"或者"正要等你确认权限之前")可以自动帮你运行一条命令。装好这个集成之后,每个这样的节点都会被接上,调用 andon-light 并传入对应的颜色。
什么时候触发哪种颜色
| 时机 | 颜色 | 原因 |
|---|---|---|
| 新会话开始时 | 空闲(红) | 会话还没被交代要做什么。 |
| 你提交一条提示词时 | 工作中(绿) | 你刚给了它一个任务。 |
| 每次使用工具之前 | 工作中(绿) | 这个会在每一次工具调用前触发,所以在一长串密集调用工具的过程中,灯会一直保持绿色。 |
| 出现一般性通知时 | 等待中(黄) | 有什么事需要你关注了。 |
| 专门在等你授权时 | 等待中(黄) | 比如,正在等你批准执行某条命令。 |
| 内部整理("整理中") | 依次点亮模式 | 内部维护:还在运行,只是在忙别的事。 |
| 一轮对话或会话正常结束时 | 空闲(红) | 回到空闲状态。 |
| 会话因为任何原因结束时 | 空闲(红) | 覆盖那些"正常结束"节点可能漏掉的情况(见下文)。 |
这些命令是一条接一条按顺序执行的,不是放在后台运行:这一点比听起来更重要(详见下面的为什么不放在后台运行)。这套设置会根据你安装时选的范围,合并进 Claude Code 的全局设置,或者某一个项目自己的设置里。它不需要知道 USB 连接另一端接的是什么。只管调用 andon-light,剩下的交给固件处理。如果你编辑了这个文件,需要重启 Claude Code(或者开一个新会话)才会生效。
几个设计上的考虑
为什么"每次使用工具之前"这么重要
上表里的大多数时机都只会发生一次:提交提示词是一次性的,通知也是一次性的。但 Claude Code 的一次回复里,可能会连续调用几十次工具(读文件、跑命令、改代码)。如果没有别的东西在这期间去碰这盏灯,它就会一直没人管。把 hook 挂在"每次工具调用之前",意味着整个过程中灯会持续被刷新,而不会因为中途没人更新而变成"连接中断"的闪烁状态。唯一覆盖不到的情况是一整轮完全没有调用任何工具、纯粹在思考的时候(Claude Code 没有"还在生成文字"这种 hook)。不过这种情况持续的时间通常远短于 30 分钟的看门狗超时,所以实际上不构成问题。
为什么"等待授权"要单独拆出一个 hook,不和普通通知合并
两者最终显示的都是同一种黄色,所以实际上触发哪一个差别不大。不过专门为"正在等待授权"(比如批准一条命令)设一个独立的 hook,能让这个特定时刻处理得更精准,不会和其他各种通知混在一起。
为什么内部整理要有专属的显示效果
如果没有专属的图案,整理期间要么保持之前的颜色不变(如果之前是红色/空闲,容易让人误解),要么就得再加一个 hook,专门用来在整理结束后把颜色改回去。依次点亮模式一眼就能看出"还活着,在做后续整理",而且等下一个 hook 触发时会自然过渡到下一个状态:不需要再加一个"整理完成"的 hook。
为什么会话开始时特意设成空闲
如果不这样做,新会话会直接继承上一个会话结束时留下的颜色。大多数情况下这没问题,因为正常结束的会话本来就会回到空闲状态。但如果上一个会话中途崩溃了,这个假设就不成立了。在会话开始时明确设成空闲,就不用依赖"每次都能正常收尾"这个不一定成立的前提。
为什么会话结束和单轮结束要分开处理
如果你在 Claude Code 工作到一半时中断它(Ctrl+C),这和一轮正常结束是不一样的停止方式,单靠"一轮结束"这个 hook 是覆盖不到的。这样会导致灯卡在最后一个颜色上不再变化。"会话因任何原因结束"这个 hook 不管是什么原因导致的结束都会触发,正好补上这个缺口。而"一轮结束"这个 hook 仍然保留着,这样在最常见的场景(正常结束)下,不用等整个会话收尾就能尽快反映出来。
为什么不放在后台运行
最早的时候,这些命令全部是放在后台运行的,目的是不给真正的工具调用增加任何延迟。后来发现这个取舍并不划算:放在后台运行只能保证每条命令按顺序"开始执行",不能保证它们按顺序"执行完成"。每次调用 andon-light 都是一个独立的短生命周期程序,虽然快,但也不是瞬间完成。所以在负载比较高的情况下(比如工具调用很密集的一轮),后开始的命令有时反而会比先开始的命令更早跑完。实际发生过这样的情况:一个会话正确地以红色(空闲)结束了,但会话中较早触发的一条黄色(等待中)命令因为延迟,恰好在红色命令之后才执行完,悄无声息地把正确的红色又覆盖成了过时的黄色。
改成一条接一条顺序执行之后,Claude Code 会等每条命令执行完再继续,这就保证了灯始终反映事件的真实顺序。每次调用增加的等待时间,相比实际工具调用本身的耗时几乎可以忽略不计。所以放在后台运行本来想省下的那点延迟,并不值得冒顺序出错的风险。
为什么每条命令都被设计成"静默失败"
如果板子被拔掉了,或者这个工具运行在一台根本没接设备的电脑上,没有这个设计的话,每一次提示都会在 Claude Code 里弹出一条显眼的报错。这就违背了"安静地待在后台"这个状态灯本该有的定位。等到这个工具具备自动重连能力,或者能优雅地处理设备确实不存在的情况时,这个做法就值得重新考虑了。到那时,一个真正持续存在的连接问题,才值得被展示出来,而不是被默默忽略。