Hooks 是使用者定義的 shell 命令,在 Claude Code 生命週期的特定時間點執行。它們提供對 Claude Code 行為的確定性控制,確保某些操作始終發生,而不是依賴 LLM 選擇執行它們。使用 hooks 來強制執行專案規則、自動化重複性任務,並將 Claude Code 與您現有的工具整合。 對於需要判斷而不是確定性規則的決策,您也可以使用基於提示的 hooks 或基於代理的 hooks,它們使用 Claude 模型來評估條件。 有關擴展 Claude Code 的其他方式,請參閱skills以提供 Claude 額外的指令和可執行命令、subagents以在隔離的上下文中執行任務,以及plugins以打包要在專案間共享的擴展。Documentation Index
Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
設定您的第一個 hook
若要建立 hook,請將hooks 區塊新增到設定檔。本逐步解說建立一個桌面通知 hook,因此每當 Claude 等待您的輸入而不是監視終端時,您都會收到警報。
將 hook 新增到您的設定
開啟 如果您的設定檔已經有 您也可以透過在 CLI 中描述您想要的內容,要求 Claude 為您編寫 hook。
~/.claude/settings.json 並新增 Notification hook。下面的範例使用 osascript 進行 macOS;有關 Linux 和 Windows 命令,請參閱當 Claude 需要輸入時收到通知。hooks 鍵,請將 Notification 作為現有事件鍵的同級項目新增,而不是替換整個物件。每個事件名稱是單個 hooks 物件內的鍵:驗證配置
輸入
/hooks 以開啟 hooks 瀏覽器。您將看到所有可用 hook 事件的列表,每個配置了 hooks 的事件旁邊都有一個計數。選擇 Notification 以確認您的新 hook 出現在列表中。選擇 hook 會顯示其詳細資訊:事件、匹配器、類型、來源檔案和命令。您可以自動化的內容
Hooks 讓您在 Claude Code 生命週期的關鍵點執行程式碼:編輯後格式化檔案、在執行前阻止命令、當 Claude 需要輸入時發送通知、在工作階段開始時注入上下文等。有關 hook 事件的完整列表,請參閱 Hooks 參考。 每個範例都包含一個現成可用的配置區塊,您可以將其新增到設定檔。最常見的模式:當 Claude 需要輸入時收到通知
每當 Claude 完成工作並需要您的輸入時收到桌面通知,這樣您可以切換到其他任務而無需檢查終端。 此 hook 使用Notification 事件,當 Claude 等待輸入或權限時觸發。下面的每個標籤使用平台的原生通知命令。將此新增到 ~/.claude/settings.json:
- macOS
- Linux
- Windows (PowerShell)
如果沒有出現通知
如果沒有出現通知
osascript 透過內建的 Script Editor 應用程式路由通知。如果 Script Editor 沒有通知權限,命令會無聲地失敗,macOS 不會提示您授予它。在終端中執行一次以使 Script Editor 出現在您的通知設定中:matcher 會在所有通知類型上觸發。若要僅在特定事件上觸發,請將其設定為以下其中一個值:
| Matcher | 觸發時機 |
|---|---|
permission_prompt | Claude 需要您批准工具使用 |
idle_prompt | Claude 完成並等待您的下一個提示 |
auth_success | 驗證完成 |
elicitation_dialog | MCP 伺服器開啟引導表單 |
elicitation_complete | MCP 引導表單被提交或關閉 |
elicitation_response | MCP 引導回應被發送回伺服器 |
/hooks 並選擇 Notification 以確認 hook 已註冊。有關完整的事件架構,請參閱 Notification 參考。
編輯後自動格式化程式碼
在 Claude 編輯的每個檔案上自動執行 Prettier,以便格式保持一致而無需手動干預。 此 hook 使用PostToolUse 事件搭配 Edit|Write 匹配器,因此它只在檔案編輯工具之後執行。該命令使用 jq 提取編輯的檔案路徑並將其傳遞給 Prettier。將此新增到您的專案根目錄中的 .claude/settings.json:
本頁上的 Bash 範例使用
jq 進行 JSON 解析。使用 brew install jq(macOS)、apt-get install jq(Debian/Ubuntu)安裝它,或參閱 jq 下載。阻止編輯受保護的檔案
防止 Claude 修改敏感檔案,如.env、package-lock.json 或 .git/ 中的任何內容。Claude 會收到解釋編輯被阻止原因的回饋,因此它可以調整其方法。
此範例使用 hook 呼叫的單獨指令檔。該指令檢查目標檔案路徑是否與受保護的模式列表相符,並以代碼 2 退出以阻止編輯。
壓縮後重新注入上下文
當 Claude 的上下文視窗填滿時,壓縮會總結對話以釋放空間。這可能會遺失重要細節。使用帶有compact 匹配器的 SessionStart hook 在每次壓縮後重新注入關鍵上下文。
您的命令寫入 stdout 的任何文字都會新增到 Claude 的上下文中。此範例提醒 Claude 專案慣例和最近的工作。將此新增到您的專案根目錄中的 .claude/settings.json:
echo 替換為任何產生動態輸出的命令,如 git log --oneline -5 以顯示最近的提交。有關在每個工作階段開始時注入上下文,請考慮改用 CLAUDE.md。有關環境變數,請參閱參考中的 CLAUDE_ENV_FILE。
審計配置變更
追蹤工作階段期間設定或 skills 檔案何時變更。ConfigChange 事件在外部程序或編輯器修改配置檔案時觸發,因此您可以記錄變更以進行合規性檢查或阻止未授權的修改。
此範例將每個變更附加到審計日誌。將此新增到 ~/.claude/settings.json:
user_settings、project_settings、local_settings、policy_settings 或 skills。要阻止變更生效,以代碼 2 退出或傳回 {"decision": "block"}。有關完整的輸入架構,請參閱 ConfigChange 參考。
當目錄或檔案變更時重新載入環境
某些專案根據您所在的目錄設定不同的環境變數。direnv 之類的工具在您的 shell 中自動執行此操作,但 Claude 的 Bash 工具不會自行選取這些變更。 配對SessionStart hook 與 CwdChanged hook 可以修復此問題。SessionStart 載入您啟動時所在目錄的變數,CwdChanged 在 Claude 每次變更目錄時重新載入它們。兩者都寫入 CLAUDE_ENV_FILE,Claude Code 在每個 Bash 命令之前執行為指令碼前置。將此新增到 ~/.claude/settings.json:
.envrc 的目錄中執行一次 direnv allow,以便允許 direnv 載入它。如果您使用 devbox 或 nix 而不是 direnv,相同的模式適用於 devbox shellenv 或 devbox global shellenv 代替 direnv export bash。
若要對特定檔案而不是每次目錄變更做出反應,請使用 FileChanged 搭配 matcher 列出要監視的檔案名稱(以 | 分隔)。若要建立監視清單,此值會分割為字面檔案名稱,而不是作為正規表達式進行評估。有關輸入架構、watchPaths 輸出和 CLAUDE_ENV_FILE 詳細資訊,請參閱 FileChanged。此範例監視工作目錄中 .envrc 和 .env 的變更:
watchPaths 輸出和 CLAUDE_ENV_FILE 詳細資訊,請參閱 CwdChanged 和 FileChanged 參考項目。
自動批准特定權限提示
跳過您始終允許的工具呼叫的批准對話。此範例自動批准ExitPlanMode,這是 Claude 在完成呈現計畫並要求繼續時呼叫的工具,因此您不會在每次計畫準備好時被提示。
與上面的退出代碼範例不同,自動批准要求您的 hook 將 JSON 決策寫入 stdout。PermissionRequest hook 在 Claude Code 即將顯示權限對話時觸發,傳回 "behavior": "allow" 會代表您回答它。
匹配器將 hook 的範圍限制為僅 ExitPlanMode,因此不會影響其他提示。將此新增到 ~/.claude/settings.json:
setMode 項目的 updatedPermissions 陣列。mode 值是任何權限模式,如 default、acceptEdits 或 bypassPermissions,destination: "session" 僅將其應用於當前工作階段。
bypassPermissions 只有在工作階段已經啟用了繞過模式時才適用:--dangerously-skip-permissions、--permission-mode bypassPermissions、--allow-dangerously-skip-permissions 或設定中的 permissions.defaultMode: "bypassPermissions",且未被 permissions.disableBypassPermissionsMode 禁用。它永遠不會被持久化為 defaultMode。acceptEdits,您的 hook 會將此 JSON 寫入 stdout:
.* 上進行匹配或留空匹配器會自動批准每個權限提示,包括檔案寫入和 shell 命令。有關決策欄位的完整集合,請參閱 PermissionRequest 參考。
Hooks 如何工作
Hook 事件在 Claude Code 的特定生命週期點觸發。當事件觸發時,所有匹配的 hooks 並行執行,相同的 hook 命令會自動去重。下表顯示每個事件及其觸發時間:| Event | When it fires |
|---|---|
SessionStart | When a session begins or resumes |
Setup | When you start Claude Code with --init-only, or with --init or --maintenance in -p mode. For one-time preparation in CI or scripts |
UserPromptSubmit | When you submit a prompt, before Claude processes it |
UserPromptExpansion | When a user-typed command expands into a prompt, before it reaches Claude. Can block the expansion |
PreToolUse | Before a tool call executes. Can block it |
PermissionRequest | When a permission dialog appears |
PermissionDenied | When a tool call is denied by the auto mode classifier. Return {retry: true} to tell the model it may retry the denied tool call |
PostToolUse | After a tool call succeeds |
PostToolUseFailure | After a tool call fails |
PostToolBatch | After a full batch of parallel tool calls resolves, before the next model call |
Notification | When Claude Code sends a notification |
SubagentStart | When a subagent is spawned |
SubagentStop | When a subagent finishes |
TaskCreated | When a task is being created via TaskCreate |
TaskCompleted | When a task is being marked as completed |
Stop | When Claude finishes responding |
StopFailure | When the turn ends due to an API error. Output and exit code are ignored |
TeammateIdle | When an agent team teammate is about to go idle |
InstructionsLoaded | When a CLAUDE.md or .claude/rules/*.md file is loaded into context. Fires at session start and when files are lazily loaded during a session |
ConfigChange | When a configuration file changes during a session |
CwdChanged | When the working directory changes, for example when Claude executes a cd command. Useful for reactive environment management with tools like direnv |
FileChanged | When a watched file changes on disk. The matcher field specifies which filenames to watch |
WorktreeCreate | When a worktree is being created via --worktree or isolation: "worktree". Replaces default git behavior |
WorktreeRemove | When a worktree is being removed, either at session exit or when a subagent finishes |
PreCompact | Before context compaction |
PostCompact | After context compaction completes |
Elicitation | When an MCP server requests user input during a tool call |
ElicitationResult | After a user responds to an MCP elicitation, before the response is sent back to the server |
SessionEnd | When a session terminates |
type 來決定它如何執行。大多數 hooks 使用 "type": "command",它執行 shell 命令。還有四種其他類型可用:
"type": "http":POST 事件資料到 URL。請參閱 HTTP hooks。"type": "mcp_tool":在已連接的 MCP 伺服器上呼叫工具。請參閱 MCP tool hooks。"type": "prompt":單輪 LLM 評估。請參閱基於提示的 hooks。"type": "agent":具有工具存取的多輪驗證。Agent hooks 是實驗性的,可能會改變。請參閱基於 Agent 的 hooks。
合併來自多個 hooks 的結果
當多個 hooks 相符同一事件時,每個 hook 的命令都會執行到完成,然後 Claude Code 合併結果。一個 hook 傳回deny 不會阻止同級 hooks 執行。不要依賴一個 hook 的 deny 來抑制另一個 hook 中的副作用。
所有匹配的 hooks 完成後,Claude Code 合併它們的輸出。對於 PreToolUse 權限決策,最具限制性的答案獲勝:deny 覆蓋 ask,ask 覆蓋 allow。來自 additionalContext 的文字會從每個 hook 保留並一起傳遞給 Claude。
下面的範例在 Bash 上註冊了兩個 PreToolUse hooks。第一個將每個命令附加到日誌檔案並退出 0。第二個執行一個指令碼,當命令包含 rm -rf 時退出 2 以拒絕:
rm -rf /tmp/build 時,兩個 hooks 並行執行。日誌記錄 hook 將命令寫入 ~/.claude/bash.log 並退出 0,這表示沒有決策。防護欄 hook 退出 2,這拒絕了工具呼叫。拒絕獲勝,所以 Claude Code 阻止命令並向 Claude 顯示防護欄的 stderr。日誌項仍然被寫入,因為日誌記錄 hook 已經執行。
讀取輸入並傳回輸出
Hooks 透過 stdin、stdout、stderr 和退出代碼與 Claude Code 通訊。當事件觸發時,Claude Code 將事件特定的資料作為 JSON 傳遞到您的指令的 stdin。您的指令讀取該資料、執行其工作,並透過退出代碼告訴 Claude Code 接下來要做什麼。Hook 輸入
每個事件都包含常見欄位,如session_id 和 cwd,但每個事件類型都新增不同的資料。例如,當 Claude 執行 Bash 命令時,PreToolUse hook 在 stdin 上接收類似以下內容:
UserPromptSubmit hooks 改為取得 prompt 文字,SessionStart hooks 取得 source(startup、resume、clear、compact),等等。有關共享欄位,請參閱參考中的常見輸入欄位,以及每個事件的部分以了解事件特定的架構。
Hook 輸出
您的指令透過寫入 stdout 或 stderr 並以特定代碼退出來告訴 Claude Code 接下來要做什麼。例如,想要阻止命令的PreToolUse hook:
- Exit 0:操作繼續。對於
UserPromptSubmit、UserPromptExpansion和SessionStarthooks,您寫入 stdout 的任何內容都會新增到 Claude 的上下文中。 - Exit 2:操作被阻止。寫入原因到 stderr,Claude 會收到它作為回饋,以便它可以調整。某些事件無法被阻止:對於
SessionStart、Setup、Notification和其他事件,exit 2 會向使用者顯示 stderr,執行繼續。有關完整清單,請參閱每個事件的 exit code 2 行為。 - 任何其他退出代碼:操作繼續。文字記錄顯示
<hook name> hook error通知,後面跟著 stderr 的第一行;完整的 stderr 進入除錯日誌。
結構化 JSON 輸出
退出代碼給您兩個選項:允許或阻止。為了獲得更多控制,退出 0 並改為將 JSON 物件列印到 stdout。使用 exit 2 以 stderr 訊息阻止,或使用 exit 0 和 JSON 進行結構化控制。不要混合它們:Claude Code 在您退出 2 時忽略 JSON。
PreToolUse hook 可以拒絕工具呼叫並告訴 Claude 為什麼,或將其升級給使用者以獲得批准:
"deny",Claude Code 會取消工具呼叫並將 permissionDecisionReason 回饋給 Claude。這些 permissionDecision 值特定於 PreToolUse:
"allow":跳過互動式權限提示。拒絕和詢問規則,包括企業受管拒絕清單,仍然適用"deny":取消工具呼叫並將原因傳送給 Claude"ask":照常向使用者顯示權限提示
"defer" 在非互動模式中使用 -p 旗標時可用。它以保留的工具呼叫退出程序,以便 Agent SDK 包裝器可以收集輸入並繼續。有關詳細資訊,請參閱參考中的延遲工具呼叫以供稍後使用。
傳回 "allow" 會跳過互動式提示,但不會覆蓋權限規則。如果拒絕規則與工具呼叫相符,即使您的 hook 傳回 "allow",呼叫也會被阻止。如果詢問規則相符,使用者仍會被提示。這意味著來自任何設定範圍(包括受管理的設定)的拒絕規則始終優先於 hook 批准。
其他事件使用不同的決策模式。例如,PostToolUse 和 Stop hooks 使用頂級 decision: "block" 欄位,而 PermissionRequest 使用 hookSpecificOutput.decision.behavior。有關按事件的完整分解,請參閱參考中的摘要表。
對於 UserPromptSubmit hooks,改用 additionalContext 將文字注入到 Claude 的上下文中。基於提示的 hooks(type: "prompt")以不同方式處理輸出:請參閱基於提示的 hooks。
使用匹配器篩選 hooks
沒有匹配器,hook 會在其事件的每次出現時觸發。匹配器讓您縮小範圍。例如,如果您只想在檔案編輯後執行格式化程式(而不是在每次工具呼叫後),請將匹配器新增到您的PostToolUse hook:
"Edit|Write" 匹配器只在 Claude 使用 Edit 或 Write 工具時觸發,而不是在它使用 Bash、Read 或任何其他工具時。請參閱匹配器模式以了解純名稱和正規表達式如何被評估。
Claude 也可以透過
Bash 工具執行 shell 命令來建立或修改檔案。如果您的 hook 必須看到每個檔案變更,例如用於合規掃描或稽核日誌,請新增一個Stop hook,它每輪掃描一次工作樹。為了獲得每次呼叫的覆蓋範圍,也請匹配 Bash 並讓您的指令使用 git status --porcelain 列出修改和未追蹤的檔案。| 事件 | 匹配器篩選的內容 | 範例匹配器值 |
|---|---|---|
PreToolUse、PostToolUse、PostToolUseFailure、PermissionRequest、PermissionDenied | 工具名稱 | Bash、Edit|Write、mcp__.* |
SessionStart | 工作階段如何開始 | startup、resume、clear、compact |
Setup | 哪個 CLI 旗標觸發了設定 | init、maintenance |
SessionEnd | 工作階段為什麼結束 | clear、resume、logout、prompt_input_exit、bypass_permissions_disabled、other |
Notification | 通知類型 | permission_prompt、idle_prompt、auth_success、elicitation_dialog、elicitation_complete、elicitation_response |
SubagentStart | Agent 類型 | general-purpose、Explore、Plan 或自訂 Agent 名稱 |
PreCompact、PostCompact | 什麼觸發了壓縮 | manual、auto |
SubagentStop | Agent 類型 | 與 SubagentStart 相同的值 |
ConfigChange | 配置來源 | user_settings、project_settings、local_settings、policy_settings、skills |
StopFailure | 錯誤類型 | rate_limit、authentication_failed、oauth_org_not_allowed、billing_error、invalid_request、server_error、max_output_tokens、unknown |
InstructionsLoaded | 載入原因 | session_start、nested_traversal、path_glob_match、include、compact |
Elicitation | MCP 伺服器名稱 | 您配置的 MCP 伺服器名稱 |
ElicitationResult | MCP 伺服器名稱 | 與 Elicitation 相同的值 |
FileChanged | 字面檔案名稱以監視(請參閱 FileChanged) | .envrc|.env |
UserPromptExpansion | 命令名稱 | 您的 skill 或命令名稱 |
UserPromptSubmit、PostToolBatch、Stop、TeammateIdle、TaskCreated、TaskCompleted、WorktreeCreate、WorktreeRemove、CwdChanged | 不支援匹配器 | 始終在每次出現時觸發 |
- 記錄每個 Bash 命令
- 匹配 MCP 工具
- 在工作階段結束時清理
只匹配
Bash 工具呼叫並將每個命令記錄到檔案。PostToolUse 事件在命令完成後觸發,因此 tool_input.command 包含執行的內容。hook 在 stdin 上接收事件資料作為 JSON,jq -r '.tool_input.command' 只提取命令字串,>> 將其附加到日誌檔案:使用 if 欄位按工具名稱和引數篩選
if 欄位需要 Claude Code v2.1.85 或更新版本。較早的版本會忽略它並在每次匹配的呼叫上執行 hook。if 欄位使用權限規則語法按工具名稱和引數一起篩選 hooks,因此 hook 程序只在工具呼叫相符時生成,或當 Bash 命令太複雜而無法解析時。這超越了 matcher,它只在工具名稱級別篩選。
例如,若要只在 Claude 使用 git 命令而不是所有 Bash 命令時執行 hook:
git * 相符時生成,或當命令太複雜而無法解析為子命令時。對於複合命令(如 npm test && git push),Claude Code 評估每個子命令並觸發 hook,因為 git push 相符。if 欄位接受與權限規則相同的模式:"Bash(git *)"、"Edit(*.ts)" 等。若要匹配多個工具名稱,請使用每個都有自己的 if 值的單獨處理程式,或在 matcher 級別進行匹配,其中支援管道交替。
if 只適用於工具事件:PreToolUse、PostToolUse、PostToolUseFailure、PermissionRequest 和 PermissionDenied。將其新增到任何其他事件會防止 hook 執行。
配置 hook 位置
您新增 hook 的位置決定了其範圍:
在 Claude Code 中執行
/hooks 以瀏覽按事件分組的所有配置的 hooks。若要一次禁用所有 hooks,請在設定檔中設定 "disableAllHooks": true。受管理的原則設定中配置的 Hooks 仍會執行,除非 disableAllHooks 也在那裡設定。
如果您在 Claude Code 執行時直接編輯設定檔,檔案監視程式通常會自動選取 hook 變更。
基於提示的 hooks
對於需要判斷而不是確定性規則的決策,使用type: "prompt" hooks。Claude Code 不執行 shell 命令,而是將您的提示和 hook 的輸入資料傳送到 Claude 模型(預設為 Haiku)以做出決策。如果您需要更多功能,可以使用 model 欄位指定不同的模型。
模型的唯一工作是傳回 yes/no 決策作為 JSON:
"ok": true:操作繼續"ok": false:發生的情況取決於事件:Stop和SubagentStop:reason被回饋給 Claude,以便它繼續工作PreToolUse:工具呼叫被拒絕,reason作為工具錯誤傳回給 Claude,以便它可以調整並繼續PostToolUse、PostToolBatch、UserPromptSubmit和UserPromptExpansion:回合結束,reason在聊天中顯示為警告行
Stop hook 詢問模型是否所有請求的任務都已完成。如果模型傳回 "ok": false,Claude 會繼續工作並使用 reason 作為其下一個指令:
基於代理的 hooks
當驗證需要檢查檔案或執行命令時,使用type: "agent" hooks。與只進行單個 LLM 呼叫的提示 hooks 不同,代理 hooks 生成一個 subagent,可以讀取檔案、搜尋程式碼和使用其他工具在傳回決策之前驗證條件。
代理 hooks 使用與提示 hooks 相同的 "ok" / "reason" 回應格式,但預設超時時間更長(60 秒)且最多 50 個工具使用輪次。
此範例驗證在允許 Claude 停止之前測試通過:
HTTP hooks
使用type: "http" hooks 將事件資料 POST 到 HTTP 端點,而不是執行 shell 命令。端點接收命令 hook 在 stdin 上接收的相同 JSON,並使用相同的 JSON 格式透過 HTTP 回應主體傳回結果。
HTTP hooks 在您希望 Web 伺服器、雲端函數或外部服務處理 hook 邏輯時很有用:例如,一個共享的審計服務,在整個團隊中記錄工具使用事件。
此範例將每個工具使用 POST 到本機記錄服務:
hookSpecificOutput 欄位。HTTP 狀態代碼本身無法阻止操作。
標頭值支援使用 $VAR_NAME 或 ${VAR_NAME} 語法的環境變數插值。只有在 allowedEnvVars 陣列中列出的變數才會被解析;所有其他 $VAR 參考保持為空。
有關完整的配置選項和回應處理,請參閱參考中的 HTTP hooks。
限制和故障排除
限制
- 命令 hooks 只透過 stdout、stderr 和退出代碼通訊。它們無法觸發
/命令或工具呼叫。透過additionalContext傳回的文字會作為系統提醒注入,Claude 將其讀取為純文字。HTTP hooks 改為透過回應主體通訊。 - Hook 超時因類型而異。透過
timeout欄位(以秒為單位)按 hook 覆寫。command、http、mcp_tool:10 分鐘。UserPromptSubmit將這些降低至 30 秒。prompt:30 秒。agent:60 秒。
PostToolUsehooks 無法撤銷操作,因為工具已經執行。PermissionRequesthooks 在非互動模式(-p)中不觸發。對於自動化權限決策,使用PreToolUsehooks。Stophooks 在 Claude 完成回應時觸發,而不僅在任務完成時。它們在使用者中斷時不觸發。API 錯誤觸發 StopFailure 代替。- 當多個 PreToolUse hooks 傳回
updatedInput以重寫工具的引數時,最後完成的會獲勝。由於 hooks 並行執行,順序是非確定性的。避免有多個 hook 修改同一工具的輸入。
Hooks 和權限模式
PreToolUse hooks 在任何權限模式檢查之前觸發。傳回permissionDecision: "deny" 的 hook 會阻止工具,即使在 bypassPermissions 模式或使用 --dangerously-skip-permissions。這讓您強制執行使用者無法透過變更其權限模式來繞過的原則。
反面不成立:傳回 "allow" 的 hook 不會繞過來自設定的拒絕規則。Hooks 可以加強限制,但不能放寬超過權限規則允許的限制。
Hook 未觸發
Hook 已配置但從不執行。- 執行
/hooks並確認 hook 出現在正確的事件下 - 檢查匹配器模式是否與工具名稱完全相符(匹配器區分大小寫)
- 驗證您觸發的是正確的事件類型(例如,
PreToolUse在工具執行前觸發,PostToolUse在之後觸發) - 如果在非互動模式(
-p)中使用PermissionRequesthooks,改用PreToolUse
Hook 輸出中的錯誤
您在文字記錄中看到類似「PreToolUse hook error: …」的訊息。- 您的指令意外以非零代碼退出。透過管道傳輸範例 JSON 來手動測試它:
- 如果您看到「command not found」,使用絕對路徑或
${CLAUDE_PROJECT_DIR}來參考指令。為了完全避免 shell 引用,添加"args": []以切換到 exec 形式,它直接生成指令而不使用 shell - 如果您看到「jq: command not found」,安裝
jq或使用 Python/Node.js 進行 JSON 解析 - 如果指令根本沒有執行,使其可執行:
chmod +x ./my-hook.sh
/hooks 顯示未配置任何 hooks
您編輯了設定檔但 hooks 未出現在選單中。
- 檔案編輯通常會自動選取。如果在幾秒鐘後仍未出現,檔案監視程式可能已錯過變更:重新啟動您的工作階段以強制重新載入。
- 驗證您的 JSON 有效(不允許尾隨逗號和註解)
- 確認設定檔在正確的位置:
.claude/settings.json用於專案 hooks,~/.claude/settings.json用於全域 hooks
Stop hook 永遠執行
Claude 在無限迴圈中繼續工作而不是停止。 您的 Stop hook 指令需要檢查它是否已經觸發了延續。從 JSON 輸入解析stop_hook_active 欄位,如果為 true 則提前退出:
JSON 驗證失敗
Claude Code 顯示 JSON 解析錯誤,即使您的 hook 指令輸出有效的 JSON。 當 Claude Code 執行 shell 形式的命令 hook(沒有args 的)時,它在 macOS 和 Linux 上生成 sh -c,或在 Windows 上生成 Git Bash。此 shell 是非互動式的,但 Git Bash 和某些配置(例如 BASH_ENV 指向 ~/.bashrc)仍然會來源您的設定檔。如果該設定檔包含無條件的 echo 陳述式,輸出會被前置到您的 hook 的 JSON:
$- 變數包含 shell 旗標,i 表示互動式。Hooks 在非互動式 shell 中執行,因此 echo 被跳過。
除錯技術
文字記錄檢視(使用Ctrl+O 切換)為每個觸發的 hook 顯示一行摘要:成功是無聲的,阻止錯誤顯示 stderr,非阻止錯誤顯示 <hook name> hook error 通知,後面跟著 stderr 的第一行。
有關完整的執行詳細資訊,包括哪些 hooks 相符、它們的退出代碼、stdout 和 stderr,請閱讀除錯日誌。使用 claude --debug-file /tmp/claude.log 啟動 Claude Code 以寫入已知路徑,然後在另一個終端中執行 tail -f /tmp/claude.log。如果您啟動時沒有該旗標,在工作階段中執行 /debug 以啟用記錄並找到日誌路徑。
深入瞭解
- Hooks 參考:完整的事件架構、JSON 輸出格式、非同步 hooks 和 MCP 工具 hooks
- 安全考量:在共享或生產環境中部署 hooks 之前進行檢查
- Bash 命令驗證器範例:完整的參考實現