- 阻止危險操作在執行前,例如破壞性的 shell 命令或未授權的檔案存取
- 記錄和稽核工具呼叫以進行合規性、除錯或分析
- 轉換輸入和輸出以清理資料、注入認證或重定向檔案路徑
- 要求人工批准敏感操作,例如資料庫寫入或 API 呼叫
- 追蹤會話生命週期以管理狀態、清理資源或傳送通知
Hook 如何運作
1
事件觸發
agent 執行期間發生某事,SDK 觸發事件:工具即將被呼叫(
PreToolUse)、工具返回結果(PostToolUse)、subagent 啟動或停止、agent 閒置或執行完成。請參閱完整事件列表。2
SDK 收集已註冊的 hook
SDK 檢查為該事件類型註冊的 hook。這包括您在
options.hooks 中傳遞的回呼 hook,以及當相應的 settingSources 或 setting_sources 項目啟用時(預設 query() 選項即為啟用)來自設定檔的 shell 命令 hook。3
matcher 篩選哪些 hook 執行
如果 hook 有
matcher 模式(例如 "Write|Edit"),SDK 會針對事件的目標(例如工具名稱)測試它。沒有 matcher 的 hook 會針對該類型的每個事件執行。4
回呼函式執行
每個相符 hook 的回呼函式會接收有關正在發生之事的輸入:工具名稱、其引數、工作階段 ID 以及其他事件特定的詳細資訊。
5
您的回呼返回決定
執行任何操作(日誌、API 呼叫、驗證)後,您的回呼會返回輸出物件,告訴 agent 該做什麼:允許操作、阻止它、修改輸入或將上下文注入對話。
PreToolUse hook(步驟 1),帶有 "Write|Edit" matcher(步驟 3),因此回呼會針對 Write 和 Edit 工具觸發。觸發時,回呼接收工具的輸入(步驟 4),檢查檔案路徑是否指向 .env 檔案,並返回 permissionDecision: "deny" 以阻止操作(步驟 5):
file_path 以 /.env 結尾的 Write 或 Edit 呼叫,不分大小寫。在 Windows 上,file_path 使用反斜線,例如 C:\project\.env,因此此 hook 會允許對 C:\project\.env 的 Write 或 Edit 呼叫。
可用的 hooks
SDK 為代理執行的不同階段提供 hooks。某些 hooks 在兩個 SDK 中都可用,而其他則僅限 TypeScript。設定 hook
要設定 hook,請在 agent 選項的hooks 欄位中傳遞它(Python 中的 ClaudeAgentOptions,TypeScript 中的 options 物件)。此程式碼片段假設您已經定義了 hook 回調,例如上面範例中 Python 的 protect_env_files 或 TypeScript 的 protectEnvFiles:
hooks 選項是一個字典(Python)或物件(TypeScript),其中:
Matcher
使用 matcher 篩選您的回調何時觸發。matcher 欄位根據 hook 事件類型比對不同的值。例如,工具型 hook 比對工具名稱,而 Notification hook 比對通知類型。
SDK matcher 遵循與設定檔中的 matcher 相同的規則。該部分記錄了精確字串和正規表達式評估路徑、其版本要求,以及每個事件類型的 matcher 值。
盡可能使用
matcher 模式來針對特定工具。帶有 'Bash' 的 matcher 只針對 Bash 命令執行,而省略模式會針對事件的每次出現執行您的回調。
回調函數
輸入
每個 hook 回調接收三個引數:- 輸入資料: 一個包含事件詳細資訊的類型物件。每個 hook 類型都有自己的輸入形狀。例如,
PreToolUseHookInput包括tool_name和tool_input,而NotificationHookInput包括message。請參閱 TypeScript 和 Python SDK 參考中的完整類型定義。- 所有 hook 輸入共享
session_id、cwd和hook_event_name。 - 當 hook 在 subagent 內觸發時,
agent_id和agent_type會被填充。在 TypeScript 中,這些在基本 hook 輸入上,可供所有 hook 類型使用。在 Python 中,它們是PreToolUse、PostToolUse、PostToolUseFailure和PermissionRequest上的可選欄位,以及SubagentStart和SubagentStop上的必需欄位。
- 所有 hook 輸入共享
- 工具使用 ID(
str | None/string | undefined):關聯同一工具呼叫的PreToolUse和PostToolUse事件。 - 上下文: 在 TypeScript 中,包含用於取消的
signal屬性(AbortSignal)。在 Python 中,此引數保留供將來使用。
輸出
您的回調返回一個具有兩類欄位的物件:- 頂級欄位在每個事件上被接受:
systemMessage向使用者顯示訊息,continue(Python 中的continue_)決定此 hook 後 agent 是否繼續執行。某些事件會捨棄它們或將它們傳遞到其他地方。每個事件的部分在 hook 頁面上說明它們的位置。 hookSpecificOutput控制目前操作。內部的欄位取決於 hook 事件類型:- 對於
PreToolUsehook,這是您設定permissionDecision("allow"、"deny"、"ask"或"defer")、permissionDecisionReason和updatedInput的地方。如果您返回"defer",該回合會以一則stop_reason為"tool_deferred"的結果訊息結束,以便您可以稍後繼續該呼叫。 - 對於
PostToolUsehook,您可以設定additionalContext以將資訊附加到工具結果。要在 Claude 看到之前替換工具的輸出,請設定updatedToolOutput,這適用於兩個 SDK 中的任何工具。較舊的updatedMCPToolOutput欄位僅替換 MCP 工具輸出。 - 在 TypeScript SDK 中,
PostToolUse回調也可以返回classifierContext,這是關於工具呼叫結果的簡短說明,用於自動模式權限分類器。因為您的回調在您應用程式自己的程序中執行,分類器可能會將您在說明中轉達的使用者陳述視為使用者意圖。該欄位需要 TypeScript Agent SDK v0.3.236 或更新版本。為自動模式分類器註解結果涵蓋長度上限、僅同步規則,以及不要在說明中放入的內容。
- 對於
{} 以允許操作而不進行變更。SDK 回調 hook 使用與 Claude Code shell 命令 hook 相同的 JSON 輸出格式,其記錄每個欄位和事件特定選項。對於 SDK 類型定義,請參閱 TypeScript 和 Python SDK 參考。
當多個
PreToolUse hook 返回不同的決策時,deny 優先於 defer,defer 優先於 ask,ask 優先於 allow。非同步輸出
預設情況下,agent 在您的 hook 返回前等待。如果您的 hook 執行副作用,例如日誌記錄或傳送 webhook,並且不需要影響 agent 的行為,您可以改為返回非同步輸出。這告訴 agent 立即繼續,無需等待 hook 完成。在此程式碼片段中,Python 中的send_to_logging_service 和 TypeScript 中的 sendToLoggingService 代表您定義的任何日誌記錄函數:
非同步輸出無法阻止、修改或將上下文注入操作,因為 agent 已經繼續。僅將它們用於副作用,例如日誌記錄、指標或通知。
範例
本節中的幾個範例僅顯示回調函數。若要執行其中一個,請在您的選項的hooks 欄位中的匹配事件下註冊回調,如 設定 hooks 中所示。
修改工具輸入
此範例攔截 Write 工具呼叫並重寫file_path 引數以預先加上 /sandbox。回調返回帶有修改路徑的 updatedInput 和 permissionDecision: 'allow' 以自動批准重寫的操作:
將
updatedInput 與 permissionDecision: 'allow' 配對以自動批准修改的輸入,或使用 permissionDecision: 'ask' 以將其顯示給使用者。如果您省略 permissionDecision,修改的輸入仍然適用並流經正常的權限評估。使用 'defer' 時,updatedInput 會被忽略。始終返回新物件,而不是改變原始 tool_input。./sandbox 或 /tmp/sandbox(macOS 不允許建立根層級的 /sandbox 目錄),然後要求代理寫入檔案:Write 工具在訊息流中的結果會顯示帶有您的沙箱前綴的路徑,而不是 Claude 要求的路徑。
新增上下文並阻止工具
此範例拒絕file_path 以 /etc 開頭的工具呼叫,並向模型和使用者解釋原因:
permissionDecision: 'deny'停止工具呼叫。permissionDecisionReason告訴模型原因。systemMessage向使用者顯示發生了什麼。
PreToolUse 下使用 Write|Edit 匹配器註冊回調,並要求代理在 /etc 下建立檔案:Write 工具在訊息流中的結果包含 Writing to /etc is not allowed,且不會建立任何檔案。
自動批准特定工具
預設情況下,agent 可能在使用某些工具前提示權限。此範例透過返回permissionDecision: 'allow' 自動批准唯讀檔案系統工具(Read、Glob、Grep),讓它們無需使用者確認即可執行(從網路路徑讀取除外),同時讓所有其他工具受到正常權限檢查:
註冊多個 hooks
當事件觸發時,符合的 hook 會並行執行。對於權限決定,以最嚴格的結果為準。任一 hook 的deny 都會阻止工具呼叫。由於完成順序是不確定的,請編寫每個 hook 以獨立運作,而不是依賴另一個 hook 已先執行。
下面的範例註冊三個獨立檢查,每個都省略 matcher。範例中的 hook 名稱,例如 Python 中的 audit_logger 或 TypeScript 中的 auditLogger,代表您定義的回調:
使用多工具匹配器篩選
使用多工具匹配器在相關工具間共享一個回調。此範例註冊三個具有不同範圍的匹配器,每個 hook 它命名代表您定義的回調:- 管道分隔的精確列表(
Write|Edit|NotebookEdit)針對 Write、Edit 和 NotebookEdit 工具觸發file_security_hook。 - 正規表達式(
^mcp__)針對任何名稱以mcp__開頭的 MCP 工具觸發mcp_audit_hook。 - 省略的 matcher 觸發
global_logger,不依工具名稱篩選。
追蹤子代理活動
使用SubagentStop hooks 監控子代理何時完成其工作。請參閱 TypeScript 和 Python SDK 參考中的完整輸入類型。此範例在每次子代理完成時記錄摘要:
[SUBAGENT] Completed: 行,其中包含子代理的 ID 和文字記錄路徑。
從 hooks 發出 HTTP 請求
Hooks 可以執行非同步操作,例如 HTTP 請求。在您的 hook 內捕捉錯誤,而不是讓它們傳播。 此範例在每個工具完成後傳送 webhook,記錄哪個工具執行以及何時執行。hook 捕捉來自失敗 webhook 的錯誤:將通知轉發到 Slack
使用Notification hooks 接收來自代理的系統通知並將其轉發到外部服務。在 SDK 工作階段中,Claude Code 為以下通知類型執行此 hook:
permission_prompt一旦權限請求在您的canUseTool回調 上等待約六秒。需要 TypeScript Agent SDK v0.3.233 或更新版本,或 Python Agent SDK v0.2.139 或更新版本elicitation_complete和elicitation_response用於使用者提示引導流程
idle_prompt、auth_success 和 elicitation_dialog。
每個通知都包括帶有人類可讀描述的 message 欄位,以及可選的 title。
此範例將每個通知轉發到 Slack 頻道。它需要 Slack 傳入 webhook URL,您可以通過將應用程式新增到 Slack 工作區並啟用傳入 webhooks 來建立:
Notification 事件觸發時,hook 會將通知的 message(前綴為 Agent status:)發佈到您的 webhook 目標的頻道。
修復常見問題
Hook 未觸發
- 驗證 hook 事件名稱正確且區分大小寫(
PreToolUse,而不是preToolUse) - 檢查您的 matcher 模式是否與工具名稱完全匹配
- 確保 hook 在
options.hooks中的正確事件類型下 - 對於支援 matcher 的非工具 hook,如
Notification和SubagentStop,matcher 匹配不同的欄位,而Stop完全忽略 matcher(請參閱 matcher 模式) - 當 agent 達到
max_turns限制時,hook 可能不會觸發,因為工作階段在 hook 可以執行前結束
Matcher 未按預期篩選
Matcher 只匹配工具名稱,不匹配檔案路徑或其他引數。要按檔案路徑篩選,請在您的 hook 內檢查tool_input.file_path:
Hook 逾時
Claude Code 以逾時時間執行每個回調,您可以在其HookMatcher 上使用 timeout 欄位以秒為單位設定。當您未設定時,Claude Code 使用事件的預設值:大多數事件為 600 秒,UserPromptSubmit、PreModelSwitch 和 PostModelSwitch 為 30 秒,MessageDisplay 為 10 秒。Claude Code 在關閉期間執行 SessionEnd 回調,使用較短的 SessionEnd 逾時預算,預設為 1.5 秒。
當回調超過其逾時時間時,Claude Code 取消它並捨棄其輸出,工作階段繼續而不是掛起。接下來發生的情況取決於事件:
PreToolUse:Claude Code 阻止工具呼叫。取而代之的是,Claude 收到工具結果,說明 hook 未在逾時前回應,回合繼續。在 v2.1.210 之前,Claude Code 將逾時報告給 Claude 作為使用者拒絕,這使無人值守工作階段停止並等待輸入。PostToolUse和PostToolUseFailure:Claude Code 保留工具結果,回合繼續。UserPromptSubmit和UserPromptExpansion:Claude Code 以指出 hook 名稱和逾時的訊息阻止提示詞,工作階段繼續。在 v2.1.208 之前,當這些事件上的回調逾時時,Claude Code 以error_during_execution結束查詢。Stop和SubagentStop:逾時的回調計為不返回任何決定。Agent 或 subagent 停止,如同該回調已允許它,而您其他 hook 在該事件上的決定仍然適用。在 Claude Code v2.1.273 之前,逾時的Stop或SubagentStop回調計為失敗的 hook 執行,Claude Code 捨棄您其他 hook 在該事件上的決定。SessionStart:逾時的回調計為不返回任何輸出,工作階段繼續,使用您其他SessionStarthook 的輸出。PreModelSwitch:Claude Code 阻止模型切換。未回答的 hook 尚未核准切換。- 其他事件,如
Notification、PreCompact和PostModelSwitch:Claude Code 記錄失敗並繼續。
Stop 或 SessionStart 回調首次逾時時,Claude Code 也會新增 SDKInformationalMessage 到訊息流,說明驅動工作階段的應用程式未回應。稍後的逾時在您的應用程式保持無回應時不會重複該訊息。
如果您在回調待處理時中斷查詢,Claude Code 取消待處理的工具呼叫。在 v2.1.208 之前,如果您在待處理的 PreToolUse 回調期間中斷,工具呼叫仍可能繼續進行。
如果您的回調需要更多時間,請在其 HookMatcher 上設定更高的 timeout。在 TypeScript 中,使用第三個回調引數中的 AbortSignal 以在逾時觸發時優雅地處理取消。
工具意外被阻止
- 檢查所有
PreToolUsehook 是否返回permissionDecision: 'deny' - 將日誌新增到您的 hook 以查看它們返回的
permissionDecisionReason - 驗證 matcher 模式不會太寬泛:空 matcher 匹配所有工具
修改的輸入未應用
-
確保
updatedInput在hookSpecificOutput內,而不是在頂級: -
不要將
updatedInput與permissionDecision: 'defer'配對,這會捨棄修改的輸入。省略permissionDecision是可以的:修改的輸入仍通過正常權限評估應用。您也可以返回'allow'以自動核准修改的輸入或'ask'以向使用者顯示以供核准 -
在
hookSpecificOutput中包括hookEventName以識別輸出適用於哪個 hook 類型
Python 中不可用工作階段 hook
SessionStart 和 SessionEnd 可以在 TypeScript 中註冊為 SDK 回調 hook,但在 Python SDK 中不可用,因為其 HookEvent 類型省略它們。在 Python 中,它們僅作為shell 命令 hook在設定檔中定義,例如 .claude/settings.json。您的 SDK 應用程式載入哪些設定檔取決於 setting_sources 或 settingSources。如果您設定了該選項,請包括存放 hook 的來源:
client.receive_response() 的第一條訊息作為您的觸發器。
Subagent 權限提示倍增
生成多個 subagent 時,每個 subagent 可能會分別請求其自身工具呼叫的權限。要避免重複提示,請使用PreToolUse hook 自動核准特定工具,或設定權限規則,subagent 會從父對話繼承這些規則。
Subagent 的遞迴 hook 迴圈
生成 subagent 的UserPromptSubmit hook 如果這些 subagent 觸發相同的 hook,可能會建立無限迴圈。要防止這種情況:
- 使用共享變數或工作階段狀態來追蹤您是否已在 subagent 內
- 將 hook 範圍限制為僅針對頂級 agent 工作階段執行
systemMessage 未出現在輸出中
systemMessage 欄位向使用者顯示訊息,而不是模型。在 Claude Code v2.1.227 或更新版本上,hook 的 systemMessage 可以在訊息流中呈現為 SDKInformationalMessage。它是否呈現取決於事件。hooks 頁面上每個事件的部分說明輸出如何呈現。要改為將上下文傳遞給模型,請返回 additionalContext。
在 v2.1.227 之前,SDK 僅針對 SessionStart 和 Setup hook 在訊息流中呈現 hook 輸出。對於任何其他事件,輸出僅出現在 includeHookEvents(Python 中的 include_hook_events)新增的生命週期事件中。該選項的條目涵蓋每個 hook 事件產生的生命週期事件。
如果您需要可靠地將 hook 決定呈現給您的應用程式,請分別記錄它們或使用專用輸出頻道。
相關資源
- Claude Code hooks 參考:完整的 JSON 輸入/輸出架構、事件文件和匹配器模式
- Claude Code hooks 指南:shell 命令 hook 範例和逐步解說
- TypeScript SDK 參考:hook 類型、輸入/輸出定義和配置選項
- Python SDK 參考:hook 類型、輸入/輸出定義和配置選項
- 權限:控制您的代理可以做什麼
- 自訂工具:建立工具以擴展代理功能