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 裡跳出一條顯眼的錯誤訊息。這就違背了「安靜地待在背景」這個狀態燈本該有的定位。等到這個工具具備自動重新連線的能力,或者能優雅地處理裝置確實不存在的情況時,這個做法就值得重新考慮了。到那時,一個真正持續存在的連線問題,才值得被顯示出來,而不是被默默忽略。