90 秒總覽
Hooks 系統讓使用者在 Claude Code 的事件節點上掛載自動化行為:可以是 shell 命令、LLM 提示、HTTP 呼叫,或完整的代理驗證迴圈。所有掛鉤透過 settings.json 配置,以「事件 → 匹配器 → 掛鉤」三層管線運作。匹配器重用權限規則語法,掛鉤支援同步、非同步、一次性等執行模式。掌握這套管線,就能在不修改核心程式碼的前提下擴充任何工作流。
執行路徑(主骨架)
input: 事件觸發(例如 PreToolUse)
載入 settings.json 中對應事件的 matcher 列表
for each matcher:
if matcher.if 條件匹配當前工具/參數:
for each hook in matcher.hooks:
依 hook 類型執行:
command → 執行 shell 命令(含 timeout)
prompt → 送 LLM 提示($ARGUMENTS 展開)
http → POST 至指定 URL(含 headers)
agent → 啟動完整代理驗證迴圈
回傳結果供主流程決策
flowchart TD
A[事件觸發] --> B[載入 Matcher 列表]
B --> C{條件匹配?}
C -->|否| D[跳過]
C -->|是| E[執行 Hook]
E --> F{Hook 類型}
F -->|command| G[Shell 命令]
F -->|prompt| H[LLM 提示]
F -->|http| I[HTTP POST]
F -->|agent| J[代理驗證]
G --> K[回傳結果]
H --> K
I --> K
J --> K
// settings.json 掛鉤配置範例
// "if" 使用權限規則語法:Bash(git *) 表示匹配所有以 git 開頭的 Bash 指令
{
"hooks": {
"PreToolUse": [
{
"if": "Bash(git *)",
"hooks": [
{
"type": "command",
"command": "echo '即將執行 git 指令'",
"timeout": 5000
}
]
}
]
}
}
三層管線的關鍵:事件決定「何時」、匹配器決定「對誰」、掛鉤決定「做什麼」。
flowchart LR
subgraph 三層管線
E[Event
何時觸發] --> M[Matcher
對誰觸發]
M --> H[Hook
做什麼]
end
路徑判讀重點
- 事件名稱固定(PreToolUse、PostToolUse、PreMessage、PostMessage 等),不可自訂。
- 匹配器
if欄位重用權限規則語法,例如Bash(git *)。 - 每個匹配器可掛載多個 hook,按陣列順序依次執行。
- hook 執行結果回傳主流程,可影響後續工具調用決策。
關鍵決策(為什麼這樣設計)
決策 1:事件-匹配器-掛鉤三層架構
原因:將「何時」、「對誰」、「做什麼」三個關注點分離。使用者可以在同一事件上掛載多組匹配器,每組匹配器再各自掛載多個掛鉤,組合彈性極高。
代價:配置結構比扁平陣列深一層,初次接觸需要理解巢狀邏輯。
決策 2:使用權限規則語法做條件匹配
原因:權限系統已有一套成熟的 pattern-matching 語法(如 Bash(git *))。掛鉤匹配器直接重用,降低使用者學習成本,也減少程式碼重複。
代價:匹配器的能力受限於權限語法的表達力;若需要更複雜的條件(如多欄位交叉比對),現有語法不夠用。
決策 3:非同步與一次性模式
原因:async: true 讓耗時掛鉤不阻塞主流程;once: true 讓僅需執行一次的初始化掛鉤自動移除,避免重複觸發。asyncRewake: true 則在背景完成後透過 exit code 2 喚醒模型,兼顧效能與回饋。
代價:非同步掛鉤的執行結果無法同步影響當前決策;一次性掛鉤在配置檔中被自動移除,可能讓不知情的使用者困惑。
替代方案與取捨
| 方案 | 優點 | 缺點 | 為何未採用/何時可採用 |
|---|---|---|---|
| 外掛系統(Plugin System) | 能力更強,可注入任意邏輯 | 安全邊界複雜,載入管理成本高 | 適合需要深度整合的場景;目前掛鉤已覆蓋多數自動化需求 |
| 全觸發(Always-fire)無匹配器 | 配置簡單,不需學習匹配語法 | 每個事件都觸發所有掛鉤,效能浪費且難以精準控制 | 掛鉤數量極少時可行,規模增長後匹配器必不可少 |
| 純同步執行(Sync-only) | 執行順序可預測,除錯容易 | 耗時掛鉤阻塞主流程,使用體驗變差 | 所有掛鉤都很快時可行,但實務中常需背景執行 |
| 環境變數全開放(無 allowlist) | 配置更簡單,不需逐一宣告 | HTTP hook 可能洩漏敏感環境變數 | 安全性考量下不可採用;顯式 allowlist 是必要防護 |
失敗路徑與防護
Failure 1:Hook 超時阻塞主流程
症狀:同步掛鉤執行時間超過預期,使用者操作卡頓或無回應。
防護:為 command hook 設定合理的 timeout 值;對可能耗時的操作使用 async: true,避免阻塞主線程。利用 statusMessage 顯示自訂 spinner 文字,讓使用者知道系統仍在運作。
Failure 2:HTTP hook 洩漏環境變數
症狀:HTTP hook 在 POST 請求中帶出未預期的環境變數,導致機密外洩。
防護:環境變數插值僅限顯式 allowlist 中列出的變數;HTTP hook 預設受限,不允許存取任意環境變數。配置審查時確認 allowlist 只包含必要項目。
Failure 3:非同步 hook 狀態污染
症狀:背景執行的掛鉤修改了共享狀態(如檔案系統或全域變數),導致後續回合行為不可預測。
防護:非同步掛鉤應設計為無副作用或僅操作隔離的資源。使用 asyncRewake: true 時,透過 exit code 控制是否需要模型介入,避免靜默污染。
實作驗證(你改完要怎麼確認)
- 在
settings.json新增一個 PreToolUse command hook:確認對應工具被呼叫時掛鉤確實觸發。 - 測試匹配器條件:修改
if條件,確認只有符合 pattern 的工具調用才觸發掛鉤。 - 驗證
async: true:確認非同步掛鉤不阻塞主流程,主回合正常推進。 - 驗證
once: true:確認掛鉤第一次觸發後自動從配置中移除,不再重複執行。 - 測試 HTTP hook allowlist:故意引用未列入 allowlist 的環境變數,確認被拒絕。
- 模擬 hook 超時:設定極短
timeout,確認超時後主流程仍正常繼續。
這六步涵蓋「觸發、匹配、非同步、一次性、安全、容錯」,是掛鉤配置的最低可接受驗證集。