757 Hook 輸入和輸出757 Hook 輸入和輸出
758</h2>758</h2>
759 759
760命令 hooks 通過 stdin 接收 JSON 資料,並通過退出代碼、stdout 和 stderr 傳回結果。HTTP hooks 接收相同的 JSON 作為 POST 請求正文,並通過 HTTP 回應正文傳回結果。本部分涵蓋所有事件通用的欄位和行為。每個事件在 [Hook 事件](#hook-events) 下的部分包括其特定的輸入架構和決定控制選項。760命令 hook 透過 stdin 接收 JSON 資料,並透過退出碼、stdout 和 stderr 傳回結果。HTTP hook 接收相同的 JSON 作為 POST 請求正文,並透過 HTTP 回應正文傳回結果。本部分涵蓋所有事件通用的欄位和行為。每個事件在 [Hook 事件](#hook-events) 下的部分包括其特定的輸入 schema 和決定控制選項。
761 761
762在 macOS 和 Linux 上,命令 hooks 在沒有控制終端的自己的工作階段中執行。Hook 程序和任何子程序無法開啟 `/dev/tty` 或直接向 Claude Code 介面發送逃逸序列。Windows 沒有 `/dev/tty`。762在 macOS 和 Linux 上,命令 hook 在沒有控制終端機的自己的工作階段中執行。Hook 程序和任何子程序無法開啟 `/dev/tty` 或直接向 Claude Code 介面發送逃逸序列。Windows 沒有 `/dev/tty`。
763 763
764要在任何平台上向使用者顯示訊息,請在 JSON 輸出中返回 [`systemMessage`](#json-output)。某些事件會捨棄它或將其傳遞到其他地方,每個 [事件的部分](#hook-events) 都會說明。要觸發桌面通知、設定視窗標題或響鈴,請改為返回 [`terminalSequence`](#emit-terminal-notifications)。764要在任何平台上向使用者顯示訊息,請在 JSON 輸出中返回 [`systemMessage`](#json-output)。某些事件會捨棄它或將其傳遞到其他地方,每個 [事件的部分](#hook-events) 都會說明。要觸發桌面通知、設定視窗標題或響鈴,請改為返回 [`terminalSequence`](#emit-terminal-notifications)。
765 765
767 通用輸入欄位767 通用輸入欄位
768</h3>768</h3>
769 769
770Hook 事件接收這些欄位作為 JSON,除了每個 [hook 事件](#hook-events) 部分中記錄的事件特定欄位。對於命令 hooks,此 JSON 通過 stdin 到達。對於 HTTP hooks,它作為 POST 請求正文到達。770Hook 事件接收這些欄位作為 JSON,除了每個 [hook 事件](#hook-events) 部分中記錄的事件特定欄位。對於命令 hook,此 JSON 透過 stdin 到達。對於 HTTP hook,它作為 POST 請求正文到達。
771 771
772| 欄位 | 描述 |772| 欄位 | 描述 |
773| :- | :- |773| :- | :- |
774| `session_id` | 目前工作階段識別碼 |774| `session_id` | 目前工作階段識別碼 |
775| `prompt_id` | 識別目前正在處理的使用者提示詞的 UUID。與 [OpenTelemetry 事件上的 `prompt.id` 屬性](/docs/zh-TW/monitoring-usage#event-correlation-attributes) 相符,因此您可以將 hook 輸出與單一提示詞的遙測相關聯。在第一個使用者輸入之前不存在 |775| `prompt_id` | 識別目前正在處理的使用者提示詞的 UUID。與 [OpenTelemetry 事件上的 `prompt.id` 屬性](/docs/zh-TW/monitoring-usage#event-correlation-attributes) 相符,因此您可以將 hook 輸出與單一提示詞的遙測相關聯。在第一個使用者輸入之前不存在 |
776| `transcript_path` | 對話 JSON 的路徑。成績單檔案以非同步方式寫入,可能滯後於記憶體中的對話,因此當 hook 觸發時,它可能尚未包含目前回合的最新訊息。需要目前回合最後助手文字的 Hooks 應在 [Stop](#stop) 和 [SubagentStop](#subagentstop) 上使用 `last_assistant_message`,而不是讀取成績單 |776| `transcript_path` | 對話 JSON 的路徑。逐字稿檔案以非同步方式寫入,可能滯後於記憶體中的對話,因此當 hook 觸發時,它可能尚未包含目前回合的最新訊息。需要目前回合最後助手文字的 hook 應在 [Stop](#stop) 和 [SubagentStop](#subagentstop) 上使用 `last_assistant_message`,而不是讀取逐字稿 |
777| `cwd` | 叫用 hook 時的目前工作目錄 |777| `cwd` | 叫用 hook 時的目前工作目錄 |
778| `scratchpad_dir` | 工作階段的 [暫存目錄](/docs/zh-TW/claude-directory#session-scratchpad-directory) 的路徑,Claude 在其中保存臨時工作檔案。當工作階段沒有暫存或臨時目錄不可用時不存在。需要 Claude Code v2.1.257 或更新版本 |778| `scratchpad_dir` | 工作階段的 [暫存目錄](/docs/zh-TW/claude-directory#session-scratchpad-directory) 的路徑,Claude 在其中保存臨時工作檔案。當工作階段沒有暫存或臨時目錄不可用時不存在。需要 Claude Code v2.1.257 或更新版本 |
779| `permission_mode` | 目前 [權限模式](/docs/zh-TW/permissions#permission-modes):`"default"`、`"plan"`、`"acceptEdits"`、`"auto"`、`"dontAsk"` 或 `"bypassPermissions"`。標記為**手動**的模式以 `"default"` 到達,永遠不會以 `"manual"` 到達,因此匹配 `"default"` 的指令碼繼續工作。並非所有事件都接收此欄位。檢查每個 [hook 事件](#hook-events) 部分中的 JSON 範例 |779| `permission_mode` | 目前 [權限模式](/docs/zh-TW/permissions#permission-modes):`"default"`、`"plan"`、`"acceptEdits"`、`"auto"`、`"dontAsk"` 或 `"bypassPermissions"`。標記為**手動**的模式以 `"default"` 到達,永遠不會以 `"manual"` 到達,因此匹配 `"default"` 的指令碼繼續工作。並非所有事件都接收此欄位。檢查每個 [hook 事件](#hook-events) 部分中的 JSON 範例 |
780| `effort` | 物件,其 `level` 欄位保存執行 hook 時生效的 [努力等級](/docs/zh-TW/model-config#adjust-effort-level):`"low"`、`"medium"`、`"high"`、`"xhigh"` 或 `"max"`。如果您設定的等級是活躍模型不支援的,`level` 會報告 Claude Code 實際執行的等級;[調整努力等級](/docs/zh-TW/model-config#adjust-effort-level) 說明它如何選擇該等級。該物件與 [狀態行](/docs/zh-TW/statusline#available-data) `effort` 欄位相符。存在於在工具使用上下文中觸發的事件,例如 `PreToolUse`、`PostToolUse`、`Stop` 和 `SubagentStop`,當目前模型支援努力參數時。該等級也可作為 `$CLAUDE_EFFORT` 環境變數提供給 hook 命令和 Bash 工具。 |780| `effort` | 物件,其 `level` 欄位保存執行 hook 時生效的 [effort 等級](/docs/zh-TW/model-config#adjust-effort-level):`"low"`、`"medium"`、`"high"`、`"xhigh"` 或 `"max"`。如果您設定的等級是活躍模型不支援的,`level` 會報告 Claude Code 實際執行的等級;[調整 effort 等級](/docs/zh-TW/model-config#adjust-effort-level) 說明它如何選擇該等級。該物件與 [狀態列](/docs/zh-TW/statusline#available-data) `effort` 欄位相符。存在於在工具使用上下文中觸發的事件,例如 `PreToolUse`、`PostToolUse`、`Stop` 和 `SubagentStop`,當目前模型支援 effort 參數時。該等級也可作為 `$CLAUDE_EFFORT` 環境變數提供給 hook 命令和 Bash 工具。 |
781| `hook_event_name` | 觸發的事件名稱 |781| `hook_event_name` | 觸發的事件名稱 |
782 782
783使用 `--agent` 執行或在 subagent 內執行時,包括兩個額外欄位:783使用 `--agent` 執行或在 subagent 內執行時,包括兩個額外欄位:
785| 欄位 | 描述 |785| 欄位 | 描述 |
786| :- | :- |786| :- | :- |
787| `agent_id` | Subagent 的唯一識別碼。僅當 hook 在 subagent 呼叫內觸發時出現。使用此項來區分 subagent hook 呼叫與主執行緒呼叫。 |787| `agent_id` | Subagent 的唯一識別碼。僅當 hook 在 subagent 呼叫內觸發時出現。使用此項來區分 subagent hook 呼叫與主執行緒呼叫。 |
788| `agent_type` | 代理名稱(例如 `"Explore"` 或 `"security-reviewer"`)。當工作階段使用 `--agent` 或 hook 在 subagent 內觸發時出現。對於 subagents,subagent 的類型優先於工作階段的 `--agent` 值。請參閱 [SubagentStart](#subagentstart) 以了解自訂和 plugin subagents 報告的值,以及如何針對 plugin 範圍名稱編寫匹配器。 |788| `agent_type` | Agent 名稱(例如 `"Explore"` 或 `"security-reviewer"`)。當工作階段使用 `--agent` 或 hook 在 subagent 內觸發時出現。對於 subagent,subagent 的類型優先於工作階段的 `--agent` 值。請參閱 [SubagentStart](#subagentstart) 以了解自訂和外掛 subagent 報告的值,以及如何針對外掛範圍名稱編寫 matcher。 |
789 789
790只有 [`SessionStart`](#sessionstart) hooks 可以接收 `model` 欄位,且 Claude Code 不一定包含它。[`PreModelSwitch`](#premodelswitch) 和 [`PostModelSwitch`](#postmodelswitch) hooks 接收 `from_model` 和 `to_model` 代替,因此使用 PostModelSwitch hook 來追蹤模型在工作階段期間的變化。790只有 [`SessionStart`](#sessionstart) hook 可以接收 `model` 欄位,且 Claude Code 不一定包含它。[`PreModelSwitch`](#premodelswitch) 和 [`PostModelSwitch`](#postmodelswitch) hook 改為接收 `from_model` 和 `to_model`,因此使用 PostModelSwitch hook 來追蹤模型在工作階段期間的變化。
791 791
792沒有 `$CLAUDE_MODEL` 環境變數。如果您在 shell 中設定了 `$ANTHROPIC_MODEL`,hook 可以讀取它,但當您在工作階段期間使用 `/model` 切換模型時,該值不會改變。792沒有 `$CLAUDE_MODEL` 環境變數。如果您在 shell 中設定了 `$ANTHROPIC_MODEL`,hook 可以讀取它,但當您在工作階段期間使用 `/model` 切換模型時,該值不會改變。
793 793
818`tool_name`、`tool_input` 和 `tool_use_id` 欄位是事件特定的。每個 [hook 事件](#hook-events) 部分記錄了該事件的額外欄位。818`tool_name`、`tool_input` 和 `tool_use_id` 欄位是事件特定的。每個 [hook 事件](#hook-events) 部分記錄了該事件的額外欄位。
819 819
820<h3 id="exit-code-output">820<h3 id="exit-code-output">
821 退出代碼輸出821 退出碼輸出
822</h3>822</h3>
823 823
824來自您的 hook 命令的退出代碼告訴 Claude Code 該操作是應該進行、被阻止還是被忽略。退出代碼不單獨起作用。Claude Code 在每個退出代碼上從 stdout 讀取 [JSON 輸出欄位](#json-output),而不僅僅是 0,對於使用標準決定模型的事件,通過架構驗證的已解析物件與代碼一起生效。Exit 2 的阻止是 JSON 無法覆蓋的唯一結果。824來自您的 hook 命令的退出碼告訴 Claude Code 該操作是應該進行、被阻止還是被忽略。退出碼不單獨起作用。Claude Code 在每個退出碼上從 stdout 讀取 [JSON 輸出欄位](#json-output),而不僅僅是 0,對於使用標準決定模型的事件,通過 schema 驗證的已解析物件與退出碼一起生效。Exit 2 的阻止是 JSON 無法覆寫的唯一結果。
825 825
826兩個表格擁有每個事件的例外:[每個事件的退出代碼 2 行為](#exit-code-2-behavior-per-event) 說明每個事件的退出代碼做什麼,[決定控制](#decision-control) 說明每個事件接受哪些決定欄位。通用欄位(如 `systemMessage`)在大多數事件中工作,並列在 [JSON 輸出](#json-output) 表格中。826兩個表格負責每個事件的例外:[每個事件的退出碼 2 行為](#exit-code-2-behavior-per-event) 說明每個事件的退出碼做什麼,[決定控制](#decision-control) 說明每個事件接受哪些決定欄位。通用欄位(如 `systemMessage`)在大多數事件中工作,並列在 [JSON 輸出](#json-output) 表格中。
827 827
828<h4 id="exit-code-0">828<h4 id="exit-code-0">
829 退出代碼 0829 退出碼 0
830</h4>830</h4>
831 831
832退出 0 表示成功,是當您列印 JSON 進行結構化控制時的預期退出代碼。832退出 0 表示成功,是當您列印 JSON 進行結構化控制時的預期退出碼。
833 833
834對於大多數事件,Claude Code 將 stdout 寫入詳細日誌,不在成績單中顯示。例外是 `UserPromptSubmit`、`UserPromptExpansion`、`SessionStart` 和 `PostModelSwitch`,其中 Claude Code 將純文字 stdout 新增為 Claude 可以看到和作用的上下文。834對於大多數事件,Claude Code 將 stdout 寫入偵錯日誌,不在逐字稿中顯示。例外是 `UserPromptSubmit`、`UserPromptExpansion`、`SessionStart` 和 `PostModelSwitch`,其中 Claude Code 將純文字 stdout 新增為 Claude 可以看到並據以行動的上下文。
835 835
836Claude Code 是否將您的 stdout 讀取為 [JSON 輸出](#json-output) 或純文字取決於它如何開始和結束,忽略周圍的空白:836Claude Code 是否將您的 stdout 讀取為 [JSON 輸出](#json-output) 或純文字取決於它如何開始和結束,忽略周圍的空白:
837 837
838* **以 `{` 開始並以 `}` 結束**:Claude Code 將其解析為 JSON。當輸出是兩行或更多行,每行本身都解析為 JSON,且沒有行是設定欄位的 [JSON 輸出](#json-output) 物件時,Claude Code 將整個輸出視為純文字。當其中一行確實設定欄位時,整個輸出是解析失敗,如下所述。838* **以 `{` 開始並以 `}` 結束**:Claude Code 將其解析為 JSON。當輸出是兩行或更多行,每行本身都解析為 JSON,且沒有任何一行是設定欄位的 [JSON 輸出](#json-output) 物件時,Claude Code 將整個輸出視為純文字。當其中一行確實設定欄位時,整個輸出是解析失敗,如下所述。
839* **以 `{` 開始但不以 `}` 結束**:Claude Code 將其視為純文字。839* **以 `{` 開始但不以 `}` 結束**:Claude Code 將其視為純文字。
840* **以其他任何內容開始**:Claude Code 將其視為純文字,即使它是 JSON 陣列或帶引號的 JSON 字串也是如此。840* **以其他任何內容開始**:Claude Code 將其視為純文字,即使它是 JSON 陣列或帶引號的 JSON 字串也是如此。
841 841
842對於使用標準決定模型的事件,以已解析物件退出 0 但未通過架構驗證是非阻止性錯誤:操作進行,成績單顯示 `<hook name> hook error` 通知,帶有驗證訊息。在任何退出代碼上都會發生相同情況,除了 2,而 [exit 2 仍然阻止](#exit-code-2)。842對於使用標準決定模型的事件,以已解析物件退出 0 但未通過 schema 驗證是非阻止性錯誤:操作進行,逐字稿顯示 `<hook name> hook error` 通知,帶有驗證訊息。在除 2 以外的任何退出碼上都會發生相同情況,而 [exit 2 仍然阻止](#exit-code-2)。
843 843
844對於使用標準決定模型的事件,當 Claude Code 嘗試將您的 stdout 解析為 JSON 且無法時,它在除 2 以外的每個退出代碼上報告非阻止性錯誤。成績單顯示 `<hook name> hook error` 通知,帶有解析訊息。在新增純文字 stdout 作為上下文的事件上,Claude Code 不新增文字。在 v2.1.248 之前,Claude Code 將該 stdout 視為純文字。844對於使用標準決定模型的事件,當 Claude Code 嘗試將您的 stdout 解析為 JSON 且無法時,它在除 2 以外的每個退出碼上報告非阻止性錯誤。逐字稿顯示 `<hook name> hook error` 通知,帶有解析訊息。在新增純文字 stdout 作為上下文的事件上,Claude Code 不新增文字。在 v2.1.248 之前,Claude Code 將該 stdout 視為純文字。
845 845
846來自以 0 退出的 hook 的 Stderr 僅進入詳細日誌,永遠不進入成績單,Claude 永遠看不到它。要自己讀取它,請啟用 [詳細日誌](#debug-hooks)。要從 `PostToolUse` 或 `PostToolUseFailure` hook 向 Claude 顯示警告,請改為退出 2,以便 [Claude 看到 stderr](#exit-code-2-behavior-per-event),儘管工具已執行。846來自以 0 退出的 hook 的 stderr 僅進入偵錯日誌,永遠不進入逐字稿,Claude 永遠看不到它。要自己讀取它,請啟用 [偵錯日誌](#debug-hooks)。要從 `PostToolUse` 或 `PostToolUseFailure` hook 向 Claude 顯示警告,請改為退出 2,以便 [Claude 看到 stderr](#exit-code-2-behavior-per-event),儘管工具已執行。
847 847
848<h4 id="exit-code-2">848<h4 id="exit-code-2">
849 退出代碼 2849 退出碼 2
850</h4>850</h4>
851 851
852退出 2 表示阻止性錯誤。在 [可以阻止的事件](#exit-code-2-behavior-per-event) 上,退出 2 無論您是否列印 JSON 都會阻止:即使 JSON `permissionDecision` 為 `"allow"` 也無法覆蓋它。Claude Code 仍然在 stdout 上讀取任何有效的 [JSON 輸出](#json-output)。在 `Elicitation` 和 `ElicitationResult` 上,exit-2 hook 的 `hookSpecificOutput` 被忽略。852退出 2 表示阻止性錯誤。在 [可以阻止的事件](#exit-code-2-behavior-per-event) 上,退出 2 無論您是否列印 JSON 都會阻止:即使 JSON `permissionDecision` 為 `"allow"` 也無法覆寫它。Claude Code 仍然讀取 stdout 上任何有效的 [JSON 輸出](#json-output)。在 `Elicitation` 和 `ElicitationResult` 上,exit-2 hook 的 `hookSpecificOutput` 被忽略。
853 853
854阻止訊息是您的 JSON 的阻止決定的原因(當它做出決定時),否則是您的 stderr 文字。阻止做什麼因事件而異:`PreToolUse` 阻止工具呼叫,`UserPromptSubmit` 拒絕提示,等等。[每個事件的退出代碼 2 行為](#exit-code-2-behavior-per-event) 列出每個事件的效果,每個事件的部分說明訊息去哪裡。854阻止訊息是您的 JSON 的阻止決定的原因(當它做出阻止決定時),否則是您的 stderr 文字。阻止做什麼因事件而異:`PreToolUse` 阻止工具呼叫,`UserPromptSubmit` 拒絕提示詞,等等。[每個事件的退出碼 2 行為](#exit-code-2-behavior-per-event) 列出每個事件的效果,每個事件的部分說明訊息去哪裡。
855 855
856在列印未通過 [JSON 輸出](#json-output) 架構驗證的 JSON 時退出 2 的 hook 仍然阻止:Claude Code 使用 stderr 作為阻止原因,並在詳細日誌中記錄驗證失敗。在 v2.1.214 之前,Claude Code 將該組合視為非阻止性錯誤,操作進行。856在列印未通過 [JSON 輸出](#json-output) schema 驗證的 JSON 時退出 2 的 hook 仍然阻止:Claude Code 使用 stderr 作為阻止原因,並在偵錯日誌中記錄驗證失敗。在 v2.1.214 之前,Claude Code 將該組合視為非阻止性錯誤,操作進行。
857 857
858此指令碼通過退出 2 阻止 `rm` 命令,並將每個其他命令留給正常權限流程:858此指令碼透過退出 2 阻止 `rm` 命令,並將每個其他命令留給正常權限流程:
859 859
860```bash theme={null}860```bash theme={null}
861#!/bin/bash861#!/bin/bash
872```872```
873 873
874<h4 id="other-exit-codes">874<h4 id="other-exit-codes">
875 其他退出代碼875 其他退出碼
876</h4>876</h4>
877 877
878任何其他退出代碼對於大多數 hook 事件本身不會阻止。發生的情況取決於您的 stdout:878任何其他退出碼對於大多數 hook 事件本身不會阻止。發生的情況取決於您的 stdout:
879 879
880* 使用通過架構驗證的已解析物件,對於使用標準決定模型的事件,Claude Code 忽略退出代碼,JSON 單獨決定結果:880* 使用通過 schema 驗證的已解析物件,對於使用標準決定模型的事件,Claude Code 忽略退出碼,JSON 單獨決定結果:
881 * 事件支援的每個欄位都被接受,包括 `permissionDecision`、`additionalContext`、`updatedInput` 和 `systemMessage`,hook 不被報告為錯誤。881 * 事件支援的每個欄位都被接受,包括 `permissionDecision`、`additionalContext`、`updatedInput` 和 `systemMessage`,hook 不被報告為錯誤。
882 * [決定控制](#decision-control) 列出每個事件的決定欄位;通用欄位如 `systemMessage` 遵循 [JSON 輸出](#json-output) 表格。882 * [決定控制](#decision-control) 列出每個事件的決定欄位;通用欄位如 `systemMessage` 遵循 [JSON 輸出](#json-output) 表格。
883* 使用未通過架構驗證的已解析物件,對於使用標準決定模型的事件,它與 [exit 0 上](#exit-code-0) 相同的非阻止性錯誤:操作進行,`<hook name> hook error` 通知帶有驗證訊息。883* 使用未通過 schema 驗證的已解析物件,對於使用標準決定模型的事件,它是與 [exit 0 上](#exit-code-0) 相同的非阻止性錯誤:操作進行,`<hook name> hook error` 通知帶有驗證訊息。
884* 使用 Claude Code [嘗試解析為 JSON](#exit-code-0) 且無法的 stdout,Claude Code 對於使用標準決定模型的事件報告與 exit 0 上相同的非阻止性錯誤。操作進行,通知帶有解析訊息。884* 使用 Claude Code [嘗試解析為 JSON](#exit-code-0) 且無法的 stdout,Claude Code 對於使用標準決定模型的事件報告與 exit 0 上相同的非阻止性錯誤。操作進行,通知帶有解析訊息。
885* 使用 Claude Code [視為純文字](#exit-code-0) 的 stdout,或使用空 stdout,對於大多數 hook 事件是非阻止性錯誤:操作進行,成績單顯示 `<hook name> hook error` 通知,後跟 stderr 的第一行,前綴為 `Failed with non-blocking status code:`。要捕獲完整 stderr,請啟用 [詳細日誌](#debug-hooks)。885* 使用 Claude Code [視為純文字](#exit-code-0) 的 stdout,或使用空 stdout,對於大多數 hook 事件是非阻止性錯誤:操作進行,逐字稿顯示 `<hook name> hook error` 通知,後跟 stderr 的第一行,前綴為 `Failed with non-blocking status code:`。要擷取完整 stderr,請啟用 [偵錯日誌](#debug-hooks)。
886 886
887標準決定模型之外的事件在 [每個事件表](#exit-code-2-behavior-per-event) 中保持自己的行:`WorktreeCreate` 在任何非零退出時失敗建立,無論您的 JSON 說什麼,事件完全捨棄 hook 輸出(如 `StopFailure`)除了副作用欄位(如 `terminalSequence`)在每個退出代碼上忽略您的 JSON,除了副作用欄位(如 `terminalSequence`),它仍然觸發。887標準決定模型之外的事件在 [每個事件表](#exit-code-2-behavior-per-event) 中保有自己的列:`WorktreeCreate` 在任何非零退出時都會使建立失敗,無論您的 JSON 說什麼;而完全捨棄 hook 輸出的事件(如 `StopFailure`)在每個退出碼上都忽略您的 JSON,但 `terminalSequence` 等副作用欄位仍會觸發。
888 888
889無法啟動的 hook 落入相同的非阻止性桶。當指令碼路徑不存在或不可執行時,shell 以代碼(如 127)退出,您看到相同的通知,帶有解釋器的訊息,例如 `Failed with non-blocking status code: /bin/sh: /path/to/hook.sh: No such file or directory`。對於大多數 hook 事件,操作進行。當您設定原則 hook 時,在其第一次執行時監視此通知:`settings.json` 中的拼寫錯誤路徑使閘門無聲地禁用。889無法啟動的 hook 落入相同的非阻止性類別。當指令碼路徑不存在或不可執行時,shell 以代碼(如 127)退出,您看到相同的通知,帶有解譯器的訊息,例如 `Failed with non-blocking status code: /bin/sh: /path/to/hook.sh: No such file or directory`。對於大多數 hook 事件,操作進行。當您設定原則 hook 時,請在其第一次執行時留意此通知:`settings.json` 中拼寫錯誤的路徑會使閘門無聲地停用。
890 890
891<Warning>891<Warning>
892 對於大多數 hook 事件,退出代碼 2 是唯一通過代碼單獨阻止的退出代碼。沒有 stdout 上的有效 JSON,Claude Code 將退出代碼 1 視為非阻止性錯誤並繼續操作,儘管 1 是傳統的 Unix 失敗代碼。如果您的 hook 旨在強制執行原則,請使用 `exit 2`。Worktree 事件不同:來自 `WorktreeCreate` 的任何非零退出代碼都會中止 worktree 建立,來自 `WorktreeRemove` 的任何非零退出代碼會在目錄仍然存在後使 worktree 移除失敗。892 對於大多數 hook 事件,退出碼 2 是唯一單靠退出碼就能阻止的退出碼。沒有 stdout 上的有效 JSON,Claude Code 將退出碼 1 視為非阻止性錯誤並繼續操作,儘管 1 是傳統的 Unix 失敗代碼。如果您的 hook 旨在強制執行原則,請使用 `exit 2`。Worktree 事件不同:來自 `WorktreeCreate` 的任何非零退出碼都會中止 worktree 建立,來自 `WorktreeRemove` 的任何非零退出碼會在目錄之後仍然存在時使 worktree 移除失敗。
893</Warning>893</Warning>
894 894
895<h4 id="timeouts">895<h4 id="timeouts">
896 逾時896 逾時
897</h4>897</h4>
898 898
899除了您使用 [`async: true`](#run-hooks-in-the-background) 執行的命令 hook,Claude Code 取消達到其 [`timeout`](#common-fields) 的 `command`、`http` 或 `mcp_tool` hook,捨棄 hook 的輸出,因此在大多數事件上,逾時的 hook 不呈現決定。899除了您使用 [`async: true`](#run-hooks-in-the-background) 執行的命令 hook,Claude Code 會取消達到其 [`timeout`](#common-fields) 的 `command`、`http` 或 `mcp_tool` hook,並捨棄 hook 的輸出,因此在大多數事件上,逾時的 hook 不會做出決定。
900 900
901在 [`PreModelSwitch`](#premodelswitch) 上,在其逾時時取消的 hook 阻止模型切換。在 `PreToolUse` 上,兩個 hook 系列不同:901在 [`PreModelSwitch`](#premodelswitch) 上,在其逾時時被取消的 hook 會阻止模型切換。在 `PreToolUse` 上,兩個 hook 系列不同:
902 902
903* 逾時的 `command`、`http` 或 `mcp_tool` hook 不阻止工具呼叫。呼叫通過正常 [權限流程](/docs/zh-TW/permissions) 繼續,因此不要指望停滯的 hook 充當閘門。903* 逾時的 `command`、`http` 或 `mcp_tool` hook 不阻止工具呼叫。呼叫透過正常 [權限流程](/docs/zh-TW/permissions) 繼續,因此不要指望停滯的 hook 充當閘門。
904* 超過其逾時的 [Agent SDK 回調 hook](/docs/zh-TW/agent-sdk/hooks) [阻止工具呼叫](#pretooluse)。904* 超過其逾時的 [Agent SDK 回呼 hook](/docs/zh-TW/agent-sdk/hooks) [阻止工具呼叫](#pretooluse)。
905 905
906<h4 id="exit-code-2-behavior-per-event">906<h4 id="exit-code-2-behavior-per-event">
907 每個事件的退出代碼 2 行為907 每個事件的退出碼 2 行為
908</h4>908</h4>
909 909
910退出代碼 2 是 hook 發出「停止,不要這樣做」的方式。效果取決於事件,因為某些事件代表可以被阻止的操作(例如尚未發生的工具呼叫),而其他事件代表已經發生或無法防止的事情。910退出碼 2 是 hook 發出「停止,不要這樣做」的方式。效果取決於事件,因為某些事件代表可以被阻止的操作(例如尚未發生的工具呼叫),而其他事件代表已經發生或無法防止的事情。
911 911
912| Hook 事件 | 可以阻止? | 退出 2 時發生的情況 |912| Hook 事件 | 可以阻止? | 退出 2 時發生的情況 |
913| :- | :- | :- |913| :- | :- | :- |
914| `PreToolUse` | 是 | 阻止工具呼叫 |914| `PreToolUse` | 是 | 阻止工具呼叫 |
915| `PermissionRequest` | 否 | 此事件不接受退出代碼 2,權限流程保持不變。改為通過 [`decision` 物件](#permissionrequest-decision-control) 拒絕 |915| `PermissionRequest` | 否 | 此事件不接受退出碼 2,權限流程保持不變。改為透過 [`decision` 物件](#permissionrequest-decision-control) 拒絕 |
916| `UserPromptSubmit` | 是 | 阻止提示,所以它永遠不會到達 Claude。請參閱 [被阻止的提示留下什麼](#what-a-blocked-prompt-leaves-behind) |916| `UserPromptSubmit` | 是 | 阻止提示詞,所以它永遠不會到達 Claude。請參閱 [被阻止的提示詞留下什麼](#what-a-blocked-prompt-leaves-behind) |
917| `UserPromptExpansion` | 是 | 阻止擴展 |917| `UserPromptExpansion` | 是 | 阻止擴展 |
918| `Stop` | 是 | 防止 Claude 停止,繼續對話 |918| `Stop` | 是 | 防止 Claude 停止,繼續對話 |
919| `SubagentStop` | 是 | 防止 subagent 停止 |919| `SubagentStop` | 是 | 防止 subagent 停止 |
920| `TeammateIdle` | 是 | 防止隊友閒置,所以它繼續工作 |920| `TeammateIdle` | 是 | 防止隊友閒置,所以它繼續工作 |
921| `TaskCreated` | 是 | 回滾任務建立 |921| `TaskCreated` | 是 | 回滾任務建立 |
922| `TaskCompleted` | 是 | 防止任務被標記為已完成 |922| `TaskCompleted` | 是 | 防止任務被標記為已完成 |
923| `ConfigChange` | 是 | 阻止配置變更生效(除了 `policy_settings`) |923| `ConfigChange` | 是 | 阻止設定變更生效(除了 `policy_settings`) |
924| `StopFailure` | 否 | 輸出和退出代碼被忽略,除了 `terminalSequence` |924| `StopFailure` | 否 | 輸出和退出碼被忽略,除了 `terminalSequence` |
925| `PostToolUse` | 否 | 向 Claude 顯示 stderr;工具已執行 |925| `PostToolUse` | 否 | 向 Claude 顯示 stderr;工具已執行 |
926| `PostToolUseFailure` | 否 | 向 Claude 顯示 stderr;工具已失敗 |926| `PostToolUseFailure` | 否 | 向 Claude 顯示 stderr;工具已失敗 |
927| `PostToolBatch` | 是 | 在下一個模型呼叫之前停止代理迴圈 |927| `PostToolBatch` | 是 | 在下一個模型呼叫之前停止代理式迴圈 |
928| `PermissionDenied` | 否 | 退出代碼和 stderr 被忽略,因為拒絕已發生。使用 JSON `hookSpecificOutput.retry: true` 告訴模型它可能重試;Claude Code 忽略 [no-verdict denials](#permissiondenied-decision-control) 的 `retry: true` |928| `PermissionDenied` | 否 | 退出碼和 stderr 被忽略,因為拒絕已發生。使用 JSON `hookSpecificOutput.retry: true` 告訴模型它可以重試;Claude Code 對於 [no-verdict denials](#permissiondenied-decision-control) 會忽略 `retry: true` |
929| `Notification` | 否 | 退出代碼和 stderr 被忽略 |929| `Notification` | 否 | 退出碼和 stderr 被忽略 |
930| `SubagentStart` | 否 | 僅向使用者顯示 stderr |930| `SubagentStart` | 否 | 僅向使用者顯示 stderr |
931| `SessionStart` | 否 | 僅向使用者顯示 stderr |931| `SessionStart` | 否 | 僅向使用者顯示 stderr |
932| `Setup` | 否 | 退出代碼和 stderr 被忽略 |932| `Setup` | 否 | 退出碼和 stderr 被忽略 |
933| `SessionEnd` | 否 | 僅向使用者顯示 stderr |933| `SessionEnd` | 否 | 僅向使用者顯示 stderr |
934| `CwdChanged` | 否 | 僅向使用者顯示 stderr |934| `CwdChanged` | 否 | 僅向使用者顯示 stderr |
935| `DirectoryAdded` | 否 | Stderr 進入詳細日誌;目錄已新增 |935| `DirectoryAdded` | 否 | Stderr 進入偵錯日誌;目錄已新增 |
936| `FileChanged` | 否 | 僅向使用者顯示 stderr |936| `FileChanged` | 否 | 僅向使用者顯示 stderr |
937| `PreCompact` | 是 | 阻止壓縮 |937| `PreCompact` | 是 | 阻止壓縮 |
938| `PostCompact` | 否 | 僅向使用者顯示 stderr |938| `PostCompact` | 否 | 僅向使用者顯示 stderr |
939| `PreModelSwitch` | 是 | 阻止模型切換並向使用者顯示 stderr |939| `PreModelSwitch` | 是 | 阻止模型切換並向使用者顯示 stderr |
940| `PostModelSwitch` | 否 | 僅向使用者顯示 stderr;模型已切換 |940| `PostModelSwitch` | 否 | 僅向使用者顯示 stderr;模型已切換 |
941| `Elicitation` | 是 | 拒絕徵詢 |941| `Elicitation` | 是 | 拒絕請求,且不會出現對話框 |
942| `ElicitationResult` | 是 | 阻止回應(操作變為拒絕) |942| `ElicitationResult` | 是 | 阻止回應(操作變為拒絕) |
943| `WorktreeCreate` | 是 | 任何非零退出代碼都會導致 worktree 建立失敗 |943| `WorktreeCreate` | 是 | 任何非零退出碼都會導致 worktree 建立失敗 |
944| `WorktreeRemove` | 是 | 任何非零退出代碼會在目錄仍然存在後使 worktree 移除失敗。請參閱 [WorktreeRemove](#worktreeremove) 以了解目錄發生的情況 |944| `WorktreeRemove` | 是 | 任何非零退出碼會在目錄之後仍然存在時使 worktree 移除失敗。請參閱 [WorktreeRemove](#worktreeremove) 以了解目錄發生的情況 |
945| `InstructionsLoaded` | 否 | 退出代碼被忽略 |945| `InstructionsLoaded` | 否 | 退出碼被忽略 |
946| `MessageDisplay` | 否 | 原始文字被顯示 |946| `MessageDisplay` | 否 | 原始文字被顯示 |
947 947
948對於 `SessionStart`、`SubagentStart` 和 `PostModelSwitch`,Claude Code 在成績單中呈現退出代碼 2 stderr 作為 `<hook name> hook error` 通知,與 [非阻止性錯誤](#exit-code-output) 相同的方式。Claude 看不到它,工作階段或 subagent 繼續進行。對於 `SubagentStart`,通知出現在 subagent 自己的成績單中,而不是在父對話中。948對於 `SessionStart`、`SubagentStart` 和 `PostModelSwitch`,Claude Code 在逐字稿中將退出碼 2 的 stderr 呈現為 `<hook name> hook error` 通知,與 [非阻止性錯誤](#exit-code-output) 相同的方式。Claude 看不到它,工作階段或 subagent 繼續進行。對於 `SubagentStart`,通知出現在 subagent 自己的逐字稿中,而不是在父對話中。
949 949
950<h3 id="http-response-handling">950<h3 id="http-response-handling">
951 HTTP 回應處理951 HTTP 回應處理
952</h3>952</h3>
953 953
954HTTP hooks 使用 HTTP 狀態代碼和回應正文,而不是退出代碼和 stdout。下面的結果適用於大多數事件;在 [每個事件表](#exit-code-2-behavior-per-event) 中有自己的失敗合約的事件(如 `WorktreeCreate`)將該合約應用於失敗的 HTTP hook:954HTTP hook 使用 HTTP 狀態碼和回應正文,而不是退出碼和 stdout。下面的結果適用於大多數事件;在 [每個事件表](#exit-code-2-behavior-per-event) 中有自己的失敗約定的事件(如 `WorktreeCreate`)也會將該約定套用於失敗的 HTTP hook:
955 955
956* **2xx 且正文為空**:成功,等同於退出代碼 0 且無輸出956* **2xx 且正文為空**:成功,等同於退出碼 0 且無輸出
957* **2xx 且 JSON 物件正文**:使用與命令 hooks 相同的 [JSON 輸出](#json-output) 架構進行解析。未通過架構驗證的正文是非阻止性錯誤957* **2xx 且 JSON 物件正文**:使用與命令 hook 相同的 [JSON 輸出](#json-output) schema 進行解析。未通過 schema 驗證的正文是非阻止性錯誤
958* **2xx 且任何其他正文,如純文字**:非阻止性錯誤,處理方式與非 2xx 狀態相同。Claude Code 不將文字新增到 Claude 的上下文958* **2xx 且任何其他正文,如純文字**:非阻止性錯誤,處理方式與非 2xx 狀態相同。Claude Code 不將文字新增到 Claude 的上下文
959* **非 2xx 狀態**:非阻止性錯誤,執行繼續959* **非 2xx 狀態**:非阻止性錯誤,執行繼續
960* **連線失敗**:非阻止性錯誤,執行繼續960* **連線失敗**:非阻止性錯誤,執行繼續
961* **逾時**:hook 被取消,如 [逾時](#timeouts) 下所述961* **逾時**:hook 被取消,如 [逾時](#timeouts) 下所述
962 962
963與命令 hooks 不同,HTTP hooks 無法僅通過狀態代碼發出阻止性錯誤信號。要阻止工具呼叫或拒絕權限,請返回 2xx 回應,其 JSON 正文包含適當的決定欄位。963與命令 hook 不同,HTTP hook 無法僅透過狀態碼發出阻止性錯誤信號。要阻止工具呼叫或拒絕權限,請返回 2xx 回應,其 JSON 正文包含適當的決定欄位。
964 964
965<h3 id="json-output">965<h3 id="json-output">
966 JSON 輸出966 JSON 輸出
967</h3>967</h3>
968 968
969退出代碼只讓您阻止或保持沉默,但 JSON 輸出提供更細粒度的控制。與其以代碼 2 退出來阻止,不如退出 0 並將 JSON 物件列印到 stdout。Claude Code 從該 JSON 讀取特定欄位以控制行為,包括 [決定控制](#decision-control) 以阻止、允許或升級給使用者。969退出碼只讓您阻止或保持沉默,但 JSON 輸出提供更細緻的控制。與其以代碼 2 退出來阻止,不如退出 0 並將 JSON 物件列印到 stdout。Claude Code 從該 JSON 讀取特定欄位以控制行為,包括用於阻止、允許或升級給使用者的 [決定控制](#decision-control)。
970 970
971<Note>971<Note>
972 為每個 hook 選擇一種方法:要麼單獨使用退出代碼進行信號傳遞,要麼退出 0 並列印 JSON 進行結構化控制。如果您混合它們,退出 2 保持其 [阻止效果](#exit-code-2-behavior-per-event),Claude Code 仍然讀取 JSON 欄位,除了 [Exit code 2](#exit-code-2) 下記錄的一個徵詢例外。972 為每個 hook 選擇一種方法:要麼單獨使用退出碼進行信號傳遞,要麼退出 0 並列印 JSON 進行結構化控制。如果您混合它們,退出 2 保持其 [阻止效果](#exit-code-2-behavior-per-event),Claude Code 仍然讀取 JSON 欄位,但 [Exit code 2](#exit-code-2) 下記錄的一個 elicitation 例外除外。
973</Note>973</Note>
974 974
975您的 hook 的 stdout 必須僅包含 JSON 物件。如果您的 shell 設定檔在啟動時列印文字,它可能會干擾 JSON 解析。請參閱故障排除指南中的 [Hook JSON 無效](/docs/zh-TW/hooks-guide#hook-json-has-no-effect)。975您的 hook 的 stdout 必須僅包含 JSON 物件。如果您的 shell 設定檔在啟動時列印文字,它可能會干擾 JSON 解析。請參閱疑難排解指南中的 [Hook JSON 無效](/docs/zh-TW/hooks-guide#hook-json-has-no-effect)。
976 976
977Hook 的 `additionalContext`、`systemMessage` 和 `initialUserMessage` 字串,以及其純 stdout,上限為 10,000 個字元:977Hook 的 `additionalContext`、`systemMessage` 和 `initialUserMessage` 字串,以及其純 stdout,上限為 10,000 個字元:
978 978
979* **範圍**:Claude Code 分別測量每個字串,即使多個 hooks 為同一事件執行。對於 JSON 輸出,每個欄位分別測量;純 stdout 整體測量。979* **範圍**:Claude Code 分別測量每個字串,即使多個 hook 為同一事件執行。對於 JSON 輸出,每個欄位分別測量;純 stdout 整體測量。
980* **超過限制**:Claude Code 將輸出儲存到工作階段目錄中的檔案,並將其替換為檔案路徑和最多前 2,000 個字元的預覽。大型有效 Bash 結果的處理方式相同,如 [輸出限制](/docs/zh-TW/tools-reference#output-limits) 下所述。與該 Bash 上限不同,此上限沒有設定或環境變數來提高它。980* **超過限制**:Claude Code 將輸出儲存到工作階段目錄中的檔案,並將其替換為檔案路徑和最多前 2,000 個字元的預覽。大型有效 Bash 結果的處理方式相同,如 [輸出限制](/docs/zh-TW/tools-reference#output-limits) 下所述。與該 Bash 上限不同,此上限沒有可提高它的設定或環境變數。
981* **讀取檔案**:Claude Code 不要求 Claude 讀取檔案,因此將 Claude 必須始終看到的任何內容保持在上限內。981* **讀取檔案**:Claude Code 不要求 Claude 讀取檔案,因此將 Claude 必須始終看到的任何內容保持在上限內。
982 982
983JSON 物件支援三種欄位:983JSON 物件支援三種欄位:
984 984
985* **通用欄位**,如 `continue`,列在下表中。每個事件都接受它們,但某些事件捨棄它們或將 `systemMessage` 傳遞到成績單以外的地方。每個事件的部分都說明。`terminalSequence` 在這些事件上也工作,除了 [發出終端通知](#emit-terminal-notifications) 下列出的例外。985* **通用欄位**,如 `continue`,列在下表中。每個事件都接受它們,但某些事件捨棄它們或將 `systemMessage` 傳遞到逐字稿以外的地方。每個事件的部分都會說明。`terminalSequence` 在這些事件上也有效,但 [發出終端機通知](#emit-terminal-notifications) 下列出的例外除外。
986* **頂層 `decision` 和 `reason`** 由某些事件用來阻止或提供反饋。986* **頂層 `decision` 和 `reason`** 由某些事件用來阻止或提供回饋。
987* **`hookSpecificOutput`** 是一個嵌套物件,用於需要更豐富控制的事件。它需要一個設定為事件名稱的 `hookEventName` 欄位。987* **`hookSpecificOutput`** 是一個巢狀物件,用於需要更豐富控制的事件。它需要一個設定為事件名稱的 `hookEventName` 欄位。
988 988
989| 欄位 | 預設 | 描述 |989| 欄位 | 預設 | 描述 |
990| :- | :- | :- |990| :- | :- | :- |
991| `continue` | `true` | 如果為 `false`,Claude 在 hook 執行後完全停止處理。優先於任何事件特定的決定欄位 |991| `continue` | `true` | 如果為 `false`,Claude 在 hook 執行後完全停止處理。優先於任何事件特定的決定欄位 |
992| `stopReason` | 無 | 當 `continue` 為 `false` 時向使用者顯示的訊息。它停留在對話中,因此如果對話繼續,Claude 會看到它 |992| `stopReason` | 無 | 當 `continue` 為 `false` 時向使用者顯示的訊息。它停留在對話中,因此如果對話繼續,Claude 會看到它 |
993| `suppressOutput` | `false` | 無效果:Claude Code 接受欄位但不作用。成功的 hook 的 stdout 永遠不在成績單中顯示,並在詳細日誌中記錄 |993| `suppressOutput` | `false` | 無效果:Claude Code 接受該欄位但不據以行動。成功的 hook 的 stdout 永遠不在逐字稿中顯示,並記錄在偵錯日誌中 |
994| `systemMessage` | 無 | 向使用者顯示的警告訊息。在 [Agent SDK](/docs/zh-TW/agent-sdk/overview) 和 [`--output-format stream-json`](/docs/zh-TW/headless) 輸出中,它可以作為 [`SDKInformationalMessage`](/docs/zh-TW/agent-sdk/typescript#sdkinformationalmessage) 到達 |994| `systemMessage` | 無 | 向使用者顯示的警告訊息。在 [Agent SDK](/docs/zh-TW/agent-sdk/overview) 和 [`--output-format stream-json`](/docs/zh-TW/headless) 輸出中,它可以作為 [`SDKInformationalMessage`](/docs/zh-TW/agent-sdk/typescript#sdkinformationalmessage) 到達 |
995| `terminalSequence` | 無 | Claude Code 代表您發出的終端逃逸序列,例如桌面通知、視窗標題或響鈴。限制為 OSC `0`/`1`/`2`/`9`/`99`/`777` 和 BEL。如果值包含允許清單外的任何內容,該欄位將被忽略。使用此項而不是寫入 `/dev/tty`,後者對 hooks 不可用 |995| `terminalSequence` | 無 | Claude Code 代表您發出的終端機逃逸序列,例如桌面通知、視窗標題或響鈴。限制為 OSC `0`/`1`/`2`/`9`/`99`/`777` 和 BEL。如果值包含允許清單外的任何內容,該欄位將被忽略。使用此項而不是寫入 `/dev/tty`,後者對 hook 不可用 |
996 996
997要完全停止 Claude:997要完全停止 Claude:
998 998
1000{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }1000{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }
1001```1001```
1002 1002
1003對於 `PreToolUse` 和 `PostToolUse` hooks,停止適用,即使工具呼叫失敗或在 Claude 仍在串流回應時完成。1003對於 `PreToolUse` 和 `PostToolUse` hook,即使工具呼叫在 Claude 仍在串流回應時失敗或完成,停止仍然適用。
1004 1004
1005<h4 id="emit-terminal-notifications">1005<h4 id="emit-terminal-notifications">
1006 發出終端通知1006 發出終端機通知
1007</h4>1007</h4>
1008 1008
1009Hooks 在沒有控制終端的情況下執行,因此直接寫入逃逸序列到 `/dev/tty` 會失敗。相反,在 `terminalSequence` 欄位中返回逃逸序列,Claude Code 通過其自己的終端寫入路徑為您發出它。這是無競爭的,在 tmux 和 GNU screen 內工作,並在沒有 `/dev/tty` 的 Windows 上工作。1009Hook 在沒有控制終端機的情況下執行,因此直接將逃逸序列寫入 `/dev/tty` 會失敗。相反,在 `terminalSequence` 欄位中返回逃逸序列,Claude Code 會透過其自己的終端機寫入路徑為您發出它。這不會產生競爭狀況,在 tmux 和 GNU screen 內有效,並在沒有 `/dev/tty` 的 Windows 上有效。
1010 1010
1011該欄位接受一個或多個允許清單逃逸序列的字串:1011該欄位接受由一個或多個允許清單中逃逸序列組成的字串:
1012 1012
1013* OSC `0`、`1`、`2`:視窗和圖示標題1013* OSC `0`、`1`、`2`:視窗和圖示標題
1014* OSC `9`:iTerm2、ConEmu、Windows Terminal 和 WezTerm 通知,包括 `9;4` 工作列進度1014* OSC `9`:iTerm2、ConEmu、Windows Terminal 和 WezTerm 通知,包括 `9;4` 工作列進度
1015* OSC `99`:Kitty 通知1015* OSC `99`:Kitty 通知
1016* OSC `777`:urxvt、Ghostty 和 Warp 通知1016* OSC `777`:urxvt、Ghostty 和 Warp 通知
1017* 裸 BEL1017* 單獨的 BEL
1018 1018
1019序列可以用 BEL 或 ST 終止。允許清單外的任何內容,包括 CSI 游標和顏色序列、OSC 調色板序列、OSC 8 超連結、OSC 52 剪貼簿寫入和 OSC 1337,都會被拒絕,該欄位將被忽略。1019序列可以用 BEL 或 ST 終止。允許清單外的任何內容,包括 CSI 游標和顏色序列、OSC 調色盤序列、OSC 8 超連結、OSC 52 剪貼簿寫入和 OSC 1337,都會被拒絕,該欄位將被忽略。
1020 1020
1021Claude Code 在處理您的 hook 輸出時寫入序列本身,因此該欄位在捨棄 `systemMessage` 和 `continue` 的事件上工作,例如 `Notification` 和 `StopFailure`。它有兩個限制:1021Claude Code 在處理您的 hook 輸出時自行寫入序列,因此該欄位在捨棄 `systemMessage` 和 `continue` 的事件上也有效,例如 `Notification` 和 `StopFailure`。它有兩個限制:
1022 1022
1023* Claude Code 僅在互動式工作階段中寫入序列,且僅在其介面在螢幕上時。在使用 `-p` 旗標的非互動式模式和 Agent SDK 中,它忽略該欄位。1023* Claude Code 僅在互動式工作階段中寫入序列,且僅在其介面顯示於螢幕上時。在使用 `-p` 旗標的非互動模式和 Agent SDK 中,它忽略該欄位。
1024* `WorktreeCreate` 命令 hook 無法返回 JSON,因為 Claude Code 將其 stdout 讀取為 worktree 路徑。HTTP `WorktreeCreate` hook 返回 JSON 並可以包含該欄位。1024* `WorktreeCreate` 命令 hook 無法返回 JSON,因為 Claude Code 將其 stdout 讀取為 worktree 路徑。HTTP `WorktreeCreate` hook 返回 JSON 並可以包含該欄位。
1025 1025
1026下面的範例從 `Notification` hook 觸發桌面通知。逃逸序列使用 `printf` 八進位逃逸構建,因此控制位元組永遠不會出現在 shell 命令行上,`jq -n --arg` 構建 JSON 輸出,因此通知訊息中的引號、反斜線和換行符被正確逃逸:1026下面的範例從 `Notification` hook 觸發桌面通知。逃逸序列使用 `printf` 八進位逃逸建立,因此控制位元組永遠不會出現在 shell 命令列上,並以 `jq -n --arg` 建立 JSON 輸出,因此通知訊息中的引號、反斜線和換行符號會被正確逃逸:
1027 1027
1028```bash theme={null}1028```bash theme={null}
1029#!/bin/bash1029#!/bin/bash
1035jq -nc --arg seq "$seq" '{terminalSequence: $seq}'1035jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
1036```1036```
1037 1037
1038`{ "terminalSequence": "..." }` 形狀在任何 shell 或語言中都相同。1038`{ "terminalSequence": "..." }` 形式在任何 shell 或語言中都相同。
1039 1039
1040<h4 id="add-context-for-claude">1040<h4 id="add-context-for-claude">
1041 為 Claude 新增上下文1041 為 Claude 新增上下文
1042</h4>1042</h4>
1043 1043
1044`additionalContext` 欄位將字串從您的 hook 傳遞到 Claude 的上下文視窗。Claude Code 將字串包裝在 [系統提醒](/docs/zh-TW/glossary#system-reminder) 中,並將其插入到 hook 觸發的對話點。Claude 在下一個模型請求時讀取提醒,但它不會在介面中顯示為聊天訊息。1044`additionalContext` 欄位將字串從您的 hook 傳遞到 Claude 的上下文視窗。Claude Code 將字串包裝在 [系統提醒](/docs/zh-TW/glossary#system-reminder) 中,並將其插入到 hook 觸發時的對話位置。Claude 在下一個模型請求時讀取提醒,但它不會在介面中顯示為聊天訊息。
1045 1045
1046在 `hookSpecificOutput` 中返回 `additionalContext` 以及事件名稱:1046在 `hookSpecificOutput` 中將 `additionalContext` 與事件名稱一起返回:
1047 1047
1048```json theme={null}1048```json theme={null}
1049{1049{
1056 1056
1057提醒出現的位置取決於事件:1057提醒出現的位置取決於事件:
1058 1058
1059* [SessionStart](#sessionstart) 和 [SubagentStart](#subagentstart):在對話開始,在第一個提示之前1059* [SessionStart](#sessionstart) 和 [SubagentStart](#subagentstart):在對話開始時,在第一個提示詞之前
1060* [UserPromptSubmit](#userpromptsubmit) 和 [UserPromptExpansion](#userpromptexpansion):與提交的提示一起1060* [UserPromptSubmit](#userpromptsubmit) 和 [UserPromptExpansion](#userpromptexpansion):與提交的提示詞一起
1061* [PreToolUse](#pretooluse)、[PostToolUse](#posttooluse)、[PostToolUseFailure](#posttoolusefailure) 和 [PostToolBatch](#posttoolbatch):在工具結果旁邊1061* [PreToolUse](#pretooluse)、[PostToolUse](#posttooluse)、[PostToolUseFailure](#posttoolusefailure) 和 [PostToolBatch](#posttoolbatch):在工具結果旁邊
1062* [Stop](#stop) 和 [SubagentStop](#subagentstop):在回合結束。對話繼續,以便 Claude 可以對反饋採取行動。請參閱 [Stop 決定控制](#stop-decision-control)1062* [Stop](#stop) 和 [SubagentStop](#subagentstop):在回合結束時。對話繼續,以便 Claude 可以對回饋採取行動。請參閱 [Stop 決定控制](#stop-decision-control)
1063* [PostModelSwitch](#postmodelswitch):與切換後的下一個請求一起。請參閱 [PostModelSwitch 決定控制](#postmodelswitch-decision-control) 以了解時機1063* [PostModelSwitch](#postmodelswitch):與切換後的下一個請求一起。請參閱 [PostModelSwitch 決定控制](#postmodelswitch-decision-control) 以了解時機
1064 1064
1065當多個 hooks 為同一事件返回 `additionalContext` 時,Claude 接收所有值。1065當多個 hook 為同一事件返回 `additionalContext` 時,Claude 接收所有值。
1066 1066
1067如果值超過 10,000 個字元,Claude Code 會將文字寫入工作階段目錄中的檔案,並將檔案路徑與最多前 2,000 個字元的預覽傳遞給 Claude。Claude 可以讀取檔案,但 Claude Code 不要求它。1067如果值超過 10,000 個字元,Claude Code 會將文字寫入工作階段目錄中的檔案,並改為將檔案路徑與最多前 2,000 個字元的預覽傳遞給 Claude。Claude 可以讀取檔案,但 Claude Code 不要求它這樣做。
1068 1068
1069使用 `additionalContext` 來提供 Claude 應該知道的有關您環境目前狀態或剛剛執行的操作的資訊:1069使用 `additionalContext` 來提供 Claude 應該知道的有關您環境目前狀態或剛剛執行的操作的資訊:
1070 1070
1071* **環境狀態**:目前分支、部署目標或活躍的功能旗標1071* **環境狀態**:目前分支、部署目標或啟用中的功能旗標
1072* **條件專案規則**:哪個測試命令適用於剛編輯的檔案,此 worktree 中哪些目錄是唯讀的1072* **條件式專案規則**:哪個測試命令適用於剛編輯的檔案,此 worktree 中哪些目錄是唯讀的
1073* **外部資料**:分配給您的開放問題、最近的 CI 結果、從內部服務擷取的內容1073* **外部資料**:指派給您的未解決問題、最近的 CI 結果、從內部服務擷取的內容
1074 1074
1075對於永遠不會改變的指示,優先使用 [CLAUDE.md](/docs/zh-TW/memory)。它無需執行指令碼即可載入,是靜態專案約定的標準位置。1075對於永遠不會改變的指示,優先使用 [CLAUDE.md](/docs/zh-TW/memory)。它無需執行指令碼即可載入,是靜態專案慣例的標準位置。
1076 1076
1077將文字寫成事實陳述,而不是命令式系統指示。「部署目標是生產」或「此儲存庫使用 `bun test`」之類的措辭讀起來像專案資訊。框架為帶外系統命令的文字可能會觸發 Claude 的提示注入防禦,這會導致 Claude 將文字呈現給您,而不是將其視為上下文。1077將文字寫成事實陳述,而不是命令式系統指示。「部署目標是 production」或「此儲存庫使用 `bun test`」之類的措辭讀起來像專案資訊。以帶外系統命令形式呈現的文字可能會觸發 Claude 的提示詞注入防禦,這會導致 Claude 將文字呈現給您,而不是將其視為上下文。
1078 1078
1079Claude Code 在工作階段成績單中儲存注入的文字。對於 `PostToolUse` 或 `UserPromptSubmit` 等中期事件,當您使用 `--continue` 或 `--resume` 繼續時,Claude Code 重播儲存的文字,而不是為過去的回合重新執行 hook,因此時間戳或提交 SHA 等值變得陳舊。`SessionStart` hooks 在使用 `source` 設定為 `"resume"` 的 `--resume` 時再次執行,或如果您新增了 `--fork-session` 則為 `"fork"`,因此它們可以刷新其上下文。1079Claude Code 在工作階段逐字稿中儲存注入的文字。對於 `PostToolUse` 或 `UserPromptSubmit` 等工作階段中途的事件,當您使用 `--continue` 或 `--resume` 繼續時,Claude Code 會重播儲存的文字,而不是為過去的回合重新執行 hook,因此時間戳記或提交 SHA 等值會變得過時。`SessionStart` hook 會在繼續時再次執行,其 `source` 設定為 `"resume"`,或在您新增了 `--fork-session` 時設定為 `"fork"`,因此它們可以重新整理其上下文。
1080 1080
1081<h4 id="decision-control">1081<h4 id="decision-control">
1082 決定控制1082 決定控制
1083</h4>1083</h4>
1084 1084
1085並非每個事件都支援阻止或通過 JSON 控制行為。支援的事件各自使用不同的欄位集來表達該決定。在編寫 hook 之前,使用此表作為快速參考:1085並非每個事件都支援透過 JSON 阻止或控制行為。支援的事件各自使用不同的欄位集來表達該決定。在編寫 hook 之前,使用此表作為快速參考:
1086 1086
1087| 事件 | 決定模式 | 關鍵欄位 |1087| 事件 | 決定模式 | 關鍵欄位 |
1088| :- | :- | :- |1088| :- | :- | :- |
1089| UserPromptSubmit、UserPromptExpansion、PostToolUse、PostToolUseFailure、PostToolBatch、Stop、SubagentStop、ConfigChange、PreCompact | 頂層 `decision` | `decision: "block"`、`reason`。Stop 和 SubagentStop 也接受 `hookSpecificOutput.additionalContext` 用於 [繼續對話的非錯誤反饋](#stop-decision-control) |1089| UserPromptSubmit、UserPromptExpansion、PostToolUse、PostToolUseFailure、PostToolBatch、Stop、SubagentStop、ConfigChange、PreCompact | 頂層 `decision` | `decision: "block"`、`reason`。Stop 和 SubagentStop 也接受 `hookSpecificOutput.additionalContext` 用於 [繼續對話的非錯誤回饋](#stop-decision-control) |
1090| TeammateIdle、TaskCompleted | 退出代碼或 `continue: false` | 退出代碼 2 使用 stderr 反饋阻止操作。JSON `{"continue": false, "stopReason": "..."}` 也會完全停止隊友,匹配 `Stop` hook 行為;[TaskCompleted 在 `TaskUpdate` 工具觸發事件時忽略它](#taskcompleted-decision-control) |1090| TeammateIdle、TaskCompleted | 退出碼或 `continue: false` | 退出碼 2 以 stderr 回饋阻止操作。JSON `{"continue": false, "stopReason": "..."}` 也會完全停止隊友,與 `Stop` hook 行為一致;[TaskCompleted 在 `TaskUpdate` 工具觸發事件時忽略它](#taskcompleted-decision-control) |
1091| TaskCreated | 退出代碼或頂層 `decision` | 退出代碼 2 或 `decision: "block"` [取消任務](#taskcreated-decision-control) 並將訊息返回給 Claude。`continue: false` 被忽略 |1091| TaskCreated | 退出碼或頂層 `decision` | 退出碼 2 或 `decision: "block"` [取消任務](#taskcreated-decision-control) 並將訊息返回給 Claude。`continue: false` 被忽略 |
1092| PreToolUse | `hookSpecificOutput` | `permissionDecision`(allow/deny/ask/defer)、`permissionDecisionReason` |1092| PreToolUse | `hookSpecificOutput` | `permissionDecision`(allow/deny/ask/defer)、`permissionDecisionReason` |
1093| PreModelSwitch | `hookSpecificOutput` 或頂層 `decision` | `permissionDecision`(allow/deny/ask)、`permissionDecisionReason`。`decision: "block"` 也 [取消切換](#premodelswitch-decision-control) |1093| PreModelSwitch | `hookSpecificOutput` 或頂層 `decision` | `permissionDecision`(allow/deny/ask)、`permissionDecisionReason`。`decision: "block"` 也會 [取消切換](#premodelswitch-decision-control) |
1094| PermissionRequest | `hookSpecificOutput` | `decision.behavior`(allow/deny) |1094| PermissionRequest | `hookSpecificOutput` | `decision.behavior`(allow/deny) |
1095| PermissionDenied | `hookSpecificOutput` | `retry: true` 告訴模型它可能重試被拒絕的工具呼叫;Claude Code 忽略 [no-verdict denials](#permissiondenied-decision-control) 的 `retry: true` |1095| PermissionDenied | `hookSpecificOutput` | `retry: true` 告訴模型它可以重試被拒絕的工具呼叫;Claude Code 對於 [no-verdict denials](#permissiondenied-decision-control) 會忽略它 |
1096| WorktreeCreate | 路徑返回 | 命令 hook 在 stdout 上列印路徑;HTTP hook 通過 `hookSpecificOutput.worktreePath` 返回。Hook 失敗或缺少路徑會導致建立失敗 |1096| WorktreeCreate | 路徑返回 | 命令 hook 在 stdout 上列印路徑;HTTP hook 返回 `hookSpecificOutput.worktreePath`。Hook 失敗或缺少路徑會導致建立失敗 |
1097| WorktreeRemove | 退出代碼 | 任何非零退出代碼會在目錄仍然存在後使移除失敗。JSON 輸出被捨棄 |1097| WorktreeRemove | 退出碼 | 任何非零退出碼會在目錄之後仍然存在時使移除失敗。JSON 輸出被捨棄 |
1098| Elicitation | `hookSpecificOutput` | `action`(accept/decline/cancel)、`content`(accept 的表單欄位值) |1098| Elicitation、ElicitationResult | `hookSpecificOutput` 或頂層 `decision` | `action`(accept/decline/cancel)、`content`(表單欄位值)。`decision: "block"` 也會 [拒絕](#other-ways-to-decline-an-elicitation) |
1099| ElicitationResult | `hookSpecificOutput` | `action`(accept/decline/cancel)、`content`(覆蓋表單欄位值) |1099| MessageDisplay | `hookSpecificOutput` | `displayContent` 替換螢幕上顯示的文字。僅影響顯示:逐字稿和 Claude 看到的內容保持原樣 |
1100| MessageDisplay | `hookSpecificOutput` | `displayContent` 替換螢幕上顯示的文字。僅顯示:成績單和 Claude 看到的內容保持原始 |
1101| SessionStart、SubagentStart、PostModelSwitch | 僅上下文 | `hookSpecificOutput.additionalContext` 為 Claude 新增上下文。SessionStart 也接受 [`initialUserMessage`、`watchPaths`、`sessionTitle` 和 `reloadSkills`](#sessionstart-decision-control)。無阻止或決定控制 |1100| SessionStart、SubagentStart、PostModelSwitch | 僅上下文 | `hookSpecificOutput.additionalContext` 為 Claude 新增上下文。SessionStart 也接受 [`initialUserMessage`、`watchPaths`、`sessionTitle` 和 `reloadSkills`](#sessionstart-decision-control)。無阻止或決定控制 |
1102| Setup、Notification、SessionEnd、PostCompact、InstructionsLoaded、StopFailure、CwdChanged、DirectoryAdded、FileChanged | 無 | 無決定控制。用於副作用,如記錄或清理 |1101| Setup、Notification、SessionEnd、PostCompact、InstructionsLoaded、StopFailure、CwdChanged、DirectoryAdded、FileChanged | 無 | 無決定控制。用於副作用,如日誌記錄或清理 |
1103 1102
1104一些事件也可以重寫內容,而不僅僅是允許或阻止它:1103一些事件也可以重寫內容,而不僅僅是允許或阻止它:
1105 1104
1106* `PreToolUse`:`updatedInput` 直接在 `hookSpecificOutput` 下替換工具的引數,然後執行。請參閱 [PreToolUse 決定控制](#pretooluse-decision-control) 以取得完整的選項集。1105* `PreToolUse`:直接位於 `hookSpecificOutput` 下的 `updatedInput` 會在工具執行前替換其引數。請參閱 [PreToolUse 決定控制](#pretooluse-decision-control)
1107* `PermissionRequest`:`updatedInput` 在 `decision` 物件內。請參閱 [PermissionRequest 決定控制](#permissionrequest-decision-control) 以取得完整的選項集。1106* `PermissionRequest`:`decision` 物件內的 `updatedInput`。請參閱 [PermissionRequest 決定控制](#permissionrequest-decision-control)
1108* `PostToolUse`:`updatedToolOutput` 替換工具的結果。請參閱 [PostToolUse 決定控制](#posttooluse-decision-control) 以取得完整的選項集。1107* `PostToolUse`:`updatedToolOutput` 替換工具的結果。請參閱 [PostToolUse 決定控制](#posttooluse-decision-control)
1109* `UserPromptSubmit`:無法替換提示;僅在其旁邊注入 `additionalContext`1108* `UserPromptSubmit`:無法替換提示詞;僅在其旁邊注入 `additionalContext`
1110 1109
1111對於編輯或轉換使用案例,在 `PreToolUse` 攔截出站工具輸入,在 `PostToolUse` 攔截入站工具結果。1110對於遮蔽或轉換使用案例,在 `PreToolUse` 攔截外送的工具輸入,在 `PostToolUse` 攔截傳入的工具結果。
1112 1111
1113以下是每種模式的實際範例:1112以下是每種模式的實際範例:
1114 1113
1139 </Tab>1138 </Tab>
1140 1139
1141 <Tab title="PermissionRequest">1140 <Tab title="PermissionRequest">
1142 使用 `hookSpecificOutput` 代表使用者允許或拒絕權限請求。允許時,您還可以修改工具的輸入或應用權限規則,以便使用者不會再次被提示。有關完整的選項集,請參閱 [PermissionRequest 決定控制](#permissionrequest-decision-control)。1141 使用 `hookSpecificOutput` 代表使用者允許或拒絕權限請求。允許時,您還可以修改工具的輸入或套用權限規則,以便使用者不會再次收到權限提示。有關完整的選項集,請參閱 [PermissionRequest 決定控制](#permissionrequest-decision-control)。
1143 1142
1144 ```json theme={null}1143 ```json theme={null}
1145 {1144 {
1157 </Tab>1156 </Tab>
1158</Tabs>1157</Tabs>
1159 1158
1160有關擴展範例,包括 Bash 命令驗證、提示篩選和自動批准指令碼,請參閱指南中的 [您可以自動化的內容](/docs/zh-TW/hooks-guide#what-you-can-automate) 和 [Bash 命令驗證器參考實現](https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py)。1159有關延伸範例,包括 Bash 命令驗證、提示詞篩選和自動核准指令碼,請參閱指南中的 [您可以自動化的內容](/docs/zh-TW/hooks-guide#what-you-can-automate) 和 [Bash 命令驗證器參考實作](https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py)。
1161 1160
1162<h2 id="hook-events">1161<h2 id="hook-events">
1163 Hook 事件1162 Hook 事件
1164</h2>1163</h2>
1165 1164
1166每個事件對應 Claude Code 生命週期中可執行 hook 的一個時間點。以下各節依生命週期排序:從工作階段設定,經過代理式迴圈,直到工作階段結束。每一節說明事件何時觸發、支援哪些 matcher、接收的 JSON 輸入,以及如何透過輸出控制行為。1165每個事件都對應到 Claude Code 生命週期中可以執行 hook 的一個時間點。以下各節依照生命週期的順序排列:從工作階段設定、經過代理式迴圈,到工作階段結束。每一節都說明事件何時觸發、支援哪些 matcher、接收的 JSON 輸入,以及如何透過輸出來控制行為。
1167 1166
1168<h3 id="sessionstart">1167<h3 id="sessionstart">
1169 SessionStart1168 SessionStart
1170</h3>1169</h3>
1171 1170
1172在 Claude Code 啟動新工作階段或繼續現有工作階段時執行。適合用來載入開發上下文,例如現有的 issue 或程式碼庫的近期變更,或設定環境變數。若是不需要指令碼的靜態上下文,請改用 [CLAUDE.md](/docs/zh-TW/memory)。1171在 Claude Code 啟動新工作階段或恢復既有工作階段時執行。適合用來載入開發上下文,例如既有的 issue 或程式碼庫的近期變更,或是設定環境變數。若是不需要指令碼的靜態上下文,請改用 [CLAUDE.md](/docs/zh-TW/memory)。
1173 1172
1174SessionStart 會在每個工作階段執行,因此請讓這些 hook 保持快速。僅支援 `type: "command"` 與 `type: "mcp_tool"` hook。關於 `mcp_tool` hook 何時執行,請參閱 [MCP tool hook 欄位](#mcp-tool-hook-fields)。1173SessionStart 會在每個工作階段執行,因此請讓這些 hook 保持快速。僅支援 `type: "command"` 和 `type: "mcp_tool"` hook。關於 `mcp_tool` hook 何時執行,請參閱 [MCP 工具 hook 欄位](#mcp-tool-hook-fields)。
1175 1174
1176matcher 值對應工作階段的啟動方式:1175matcher 值對應工作階段的啟動方式:
1177 1176
1181| `resume` | `--resume`、`--continue` 或 `/resume` |1180| `resume` | `--resume`、`--continue` 或 `/resume` |
1182| `clear` | `/clear` |1181| `clear` | `/clear` |
1183| `compact` | 自動或手動壓縮 |1182| `compact` | 自動或手動壓縮 |
1184| `fork` | 從現有工作階段分叉出的新工作階段:搭配 `--resume` 或 `--continue` 使用的 `--fork-session`、`/fork` 背景副本、`/branch`,或您[移至背景](/docs/zh-TW/agent-view#from-inside-a-session)的對話 |1183| `fork` | 從既有工作階段分岔出的新工作階段:搭配 `--resume` 或 `--continue` 的 `--fork-session`、`/fork` 背景副本、`/branch`,或是您[移至背景](/docs/zh-TW/agent-view#from-inside-a-session)的對話 |
1185 1184
1186在 v2.1.214 之前,分叉的工作階段回報的 source 為 `"resume"`。1185在 v2.1.214 之前,分岔的工作階段回報的 source 為 `"resume"`。
1187 1186
1188當您啟動互動式工作階段、在啟動時以 `--continue` 或 `--resume` 繼續對話,或執行 `/clear` 時,SessionStart hook 會在背景執行。您可以立即開始輸入,而您繼續的對話也會直接顯示,不必等待 hook。Claude 的第一個回應仍會等待 hook 完成,讓其上下文能傳達給 Claude。1187當您啟動互動式工作階段、在啟動時使用 `--continue` 或 `--resume` 恢復對話,或執行 `/clear` 時,SessionStart hook 會在背景執行。您可以立即輸入,而您恢復的對話也會直接出現,無須等待 hook。Claude 的第一個回應仍會等待 hook 完成,讓其上下文能傳達給 Claude。
1189 1188
1190若您在工作階段內以 `/resume` 切換對話,切換動作則會等待 hook 完成。如果您在背景 hook 仍在執行時執行 `/clear` 或切換到另一個對話,它們回傳的任何內容都不會套用到該工作階段。1189當您在工作階段內使用 `/resume` 切換對話時,切換動作則會等待 hook 完成。如果您在背景 hook 仍在執行時執行 `/clear` 或切換到另一個對話,它們傳回的任何內容都不會套用到該工作階段。
1191 1190
1192啟動時也適用相同的等待,包括繼續的工作階段:在 SessionStart hook 仍在執行時送出的提示詞,要等到 hook 完成後才會傳達給 Claude。1191啟動時(包括恢復的工作階段)也適用同樣的等待:在 SessionStart hook 仍在執行時送出的提示詞,會等到它們完成後才傳達給 Claude。
1193 1192
1194在上述任一種等待期間,按下 `Esc` 可將提示詞收回輸入框而不送出。hook 會繼續執行。1193在上述任一等待期間,按下 `Esc` 可將提示詞取回輸入框而不送出。hook 會繼續執行。
1195 1194
1196<h4 id="sessionstart-input">1195<h4 id="sessionstart-input">
1197 SessionStart 輸入1196 SessionStart 輸入
1198</h4>1197</h4>
1199 1198
1200除了[通用輸入欄位](#common-input-fields)之外,SessionStart hook 還會接收 `source`,以及選擇性的 `model`、`agent_type` 與 `session_title`:1199除了[通用輸入欄位](#common-input-fields)之外,SessionStart hook 還會接收 `source`,以及選擇性的 `model`、`agent_type` 和 `session_title`:
1201 1200
1202| 欄位 | 說明 |1201| 欄位 | 說明 |
1203| :- | :- |1202| :- | :- |
1204| `source` | 工作階段的啟動方式:新工作階段為 `"startup"`,繼續的工作階段為 `"resume"`,`/clear` 之後為 `"clear"`,壓縮之後為 `"compact"`,從現有工作階段分叉出的新工作階段則為 `"fork"` |1203| `source` | 工作階段的啟動方式:新工作階段為 `"startup"`、恢復的工作階段為 `"resume"`、`/clear` 之後為 `"clear"`、壓縮之後為 `"compact"`,或從既有工作階段分岔出的新工作階段為 `"fork"` |
1205| `model` | 目前使用中的模型識別碼。此欄位可能被省略,例如在 `/clear` 之後,或工作階段透過對話復原而還原時,因此讀取前請先檢查該欄位是否存在 |1204| `model` | 目前使用中的模型識別碼。此欄位可能被省略,例如在 `/clear` 之後,或工作階段透過對話復原而還原時,因此讀取前請先檢查欄位是否存在 |
1206| `agent_type` | agent 名稱,當您以 `claude --agent <name>` 啟動 Claude Code 時才會出現 |1205| `agent_type` | agent 名稱,在您以 `claude --agent <name>` 啟動 Claude Code 時出現 |
1207| `session_title` | 工作階段的自訂標題,僅在已設定時出現,例如透過 `--name`、`/rename`、hook 的 `sessionTitle` 輸出,或 Agent SDK 的 `renameSession()` 設定。輸出 `sessionTitle` 的 hook 可以先檢查此欄位,以避免覆寫既有的自訂標題 |1206| `session_title` | 工作階段的自訂標題,在已設定時出現,例如透過 `--name`、`/rename`、hook 的 `sessionTitle` 輸出,或 Agent SDK 的 `renameSession()` 設定。會輸出 `sessionTitle` 的 hook 可以先檢查此欄位,以避免覆寫既有的自訂標題 |
1208 1207
1209您尚未命名的工作階段仍可能有[自動產生的標題](/docs/zh-TW/sessions#name-your-sessions)。該標題並非自訂標題,不會出現在 `session_title` 中。1208您尚未命名的工作階段仍可能有[自動產生的標題](/docs/zh-TW/sessions#name-your-sessions)。該標題不是自訂標題,也不會出現在 `session_title` 中。
1210 1209
1211當 `source` 為 `"resume"` 或 `"fork"`,且逐字稿中至少包含一則 Claude 的回應時,SessionStart hook 也會接收以下四個欄位。您的 hook 可以用它們在第一個請求之前回報繼續一個陳舊對話的成本,例如透過 [`systemMessage`](#json-output)。這些欄位需要 Claude Code v2.1.251 或更新版本。1210當 `source` 為 `"resume"` 或 `"fork"`,且逐字稿中至少包含一則 Claude 的回應時,SessionStart hook 也會接收下列四個欄位。您的 hook 可以使用它們,在第一個請求之前回報恢復一個過時對話的成本,例如透過 [`systemMessage`](#json-output)。這些欄位需要 Claude Code v2.1.251 或更新版本。
1212 1211
1213| 欄位 | 說明 |1212| 欄位 | 說明 |
1214| :- | :- |1213| :- | :- |
1215| `seconds_since_last_response` | 自繼續的逐字稿中最後一則回應以來經過的實際秒數 |1214| `seconds_since_last_response` | 自恢復之逐字稿中最後一則回應以來經過的實際秒數 |
1216| `context_tokens` | 繼續的工作階段的第一個請求作為提示詞重新傳送的 token 數 |1215| `context_tokens` | 恢復之工作階段的第一個請求重新傳送作為提示詞的 token 數 |
1217| `prompt_cache_likely_expired` | 當最後一則回應早於工作階段的[提示快取存留期](/docs/zh-TW/prompt-caching#cache-lifetime),或後續的壓縮取代了已快取的對話時,為 `true` |1216| `prompt_cache_likely_expired` | 當最後一則回應早於工作階段的[提示快取存留時間](/docs/zh-TW/prompt-caching#cache-lifetime),或之後的壓縮取代了已快取的對話時為 `true` |
1218| `estimated_cache_write_usd` | 在工作階段的模型上將 `context_tokens` 寫入提示快取的預估成本(美元),不含回應 |1217| `estimated_cache_write_usd` | 在工作階段的模型上將 `context_tokens` 寫入提示快取的預估成本(美元),不含回應 |
1219 1218
1220此範例顯示在最後一則回應 90 分鐘後繼續的工作階段的輸入:1219此範例顯示在最後一則回應 90 分鐘後恢復的工作階段的輸入:
1221 1220
1222```json theme={null}1221```json theme={null}
1223{1222{
1238 SessionStart 決策控制1237 SessionStart 決策控制
1239</h4>1238</h4>
1240 1239
1241Claude Code 會將其[視為純文字](#exit-code-0)的 stdout 加入 Claude 的上下文。除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,您還可以回傳下列事件專屬欄位:1240Claude Code 會將其[視為純文字](#exit-code-0)的 stdout 加入 Claude 的上下文。除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,您還可以傳回下列事件專屬欄位:
1242 1241
1243| 欄位 | 說明 |1242| 欄位 | 說明 |
1244| :- | :- |1243| :- | :- |
1245| `additionalContext` | 在對話開始時、第一個提示詞之前加入 Claude 上下文的字串。關於文字的傳遞方式以及應放入的內容,請參閱[為 Claude 加入上下文](#add-context-for-claude) |1244| `additionalContext` | 在對話開始時、第一個提示詞之前加入 Claude 上下文的字串。關於文字如何傳遞以及應放入什麼內容,請參閱[為 Claude 加入上下文](#add-context-for-claude) |
1246| `initialUserMessage` | 作為工作階段第一則使用者訊息的字串。適用於使用 `-p` 旗標的[非互動模式](/docs/zh-TW/headless),即使未提供提示詞,它也會成為第一個回合。若有提供提示詞,該提示詞會作為下一個回合接續。與附加到既有回合的 `additionalContext` 不同,此欄位會建立回合 |1245| `initialUserMessage` | 用作工作階段第一則使用者訊息的字串。適用於使用 `-p` 旗標的[非互動模式](/docs/zh-TW/headless),即使未提供提示詞,它也會成為第一個回合。如果提供了提示詞,提示詞會作為下一個回合接續。與附加到既有回合的 `additionalContext` 不同,此欄位會建立該回合 |
1247| `sessionTitle` | 設定工作階段標題,效果與 `/rename` 相同。可用來依據啟動資料夾、git 分支或 worktree 名稱自動為工作階段命名。在 `source` 為 `"startup"`、`"resume"` 或 `"fork"` 時套用;在 `"clear"` 與 `"compact"` 時忽略 |1246| `sessionTitle` | 設定工作階段標題,效果與 `/rename` 相同。可用來依據啟動資料夾、git 分支或 worktree 名稱自動命名工作階段。在 `source` 為 `"startup"`、`"resume"` 或 `"fork"` 時套用;在 `"clear"` 和 `"compact"` 時忽略 |
1248| `watchPaths` | 在此工作階段中要監看 [FileChanged](#filechanged) 事件的絕對路徑陣列 |1247| `watchPaths` | 在此工作階段期間要監看 [FileChanged](#filechanged) 事件的絕對路徑陣列 |
1249| `reloadSkills` | 布林值。為 `true` 時,Claude Code 會在 SessionStart hook 完成後重新掃描 [skill](/docs/zh-TW/skills) 與命令目錄,讓 hook 安裝的 skill 能在同一個工作階段中使用,從第一個提示詞開始即可使用 |1248| `reloadSkills` | 布林值。為 `true` 時,Claude Code 會在 SessionStart hook 完成後重新掃描 [skill](/docs/zh-TW/skills) 和命令目錄,讓 hook 安裝的 skill 從第一個提示詞開始就能在同一個工作階段中使用 |
1250 1249
1251```json theme={null}1250```json theme={null}
1252{1251{
1258}1257}
1259```1258```
1260 1259
1261由於此事件的純 stdout 已會傳達給 Claude,只載入上下文的 hook 可以直接輸出到 stdout,不必建構 JSON。當您需要將上下文與其他欄位(例如 `sessionTitle`)結合時,請使用 JSON 形式。1260由於此事件的純 stdout 已會傳達給 Claude,只載入上下文的 hook 可以直接輸出到 stdout,無須建構 JSON。當您需要將上下文與 `sessionTitle` 等其他欄位結合時,請使用 JSON 格式。
1262 1261
1263當 SessionStart hook 安裝或更新 skill 時,請使用 `reloadSkills`。skill 探索通常在 SessionStart hook 完成之前就已執行,因此 hook 寫入 `~/.claude/skills/` 或 `.claude/skills/` 的檔案,否則要到下一個工作階段才會出現。此範例會同步一個共用的 skill 儲存庫並要求重新掃描:1262當 SessionStart hook 會安裝或更新 skill 時,請使用 `reloadSkills`。skill 探索通常會在 SessionStart hook 完成之前執行,因此 hook 寫入 `~/.claude/skills/` 或 `.claude/skills/` 的檔案,否則只會在下一個工作階段中出現。此範例會同步共用的 skill 儲存庫並請求重新掃描:
1264 1263
1265```bash theme={null}1264```bash theme={null}
1266#!/bin/bash1265#!/bin/bash
1271echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'1270echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'
1272```1271```
1273 1272
1274儲存庫 URL 只是預留位置;請將它替換為您自己的 skill 儲存庫。使用預留位置時,clone 會失敗並將 `fatal:` 訊息輸出到 stderr。以退出碼 0 結束的 SessionStart hook 的 stderr 僅供參考,因此 `reloadSkills` 請求仍會套用。1273儲存庫 URL 只是預留位置,請替換為您自己的 skill 儲存庫。使用預留位置時,clone 會失敗並在 stderr 輸出 `fatal:` 訊息。以 0 結束的 SessionStart hook 的 stderr 僅供參考,因此 `reloadSkills` 請求仍會套用。
1275 1274
1276<h4 id="persist-environment-variables">1275<h4 id="persist-environment-variables">
1277 保存環境變數1276 保存環境變數
1293exit 01292exit 0
1294```1293```
1295 1294
1296若要擷取設定命令造成的所有環境變更,請比較執行前後匯出的變數:1295若要擷取設定命令造成的所有環境變更,請比較前後匯出的變數:
1297 1296
1298```bash theme={null}1297```bash theme={null}
1299#!/bin/bash1298#!/bin/bash
1313```1312```
1314 1313
1315<Note>1314<Note>
1316 `CLAUDE_ENV_FILE` 可供 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 與 [FileChanged](#filechanged) hook 使用。其他 hook 類型無法存取此變數。1315 `CLAUDE_ENV_FILE` 可用於 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hook。其他 hook 類型無法存取此變數。
1317</Note>1316</Note>
1318 1317
1319<h3 id="setup">1318<h3 id="setup">
1320 Setup1319 Setup
1321</h3>1320</h3>
1322 1321
1323僅在您以 `--init-only` 啟動 Claude Code,或在使用 `-p` 旗標的[非互動模式](/docs/zh-TW/headless)中搭配 `--init` 或 `--maintenance` 啟動時觸發。一般啟動時不會觸發。可用於一次性的相依套件安裝,或您從 CI 或指令碼明確觸發的排程清理,與一般工作階段啟動分開。若是每個工作階段的初始化,請改用 [SessionStart](#sessionstart)。1322僅在您以 `--init-only` 啟動 Claude Code,或在使用 `-p` 旗標的[非互動模式](/docs/zh-TW/headless)中搭配 `--init` 或 `--maintenance` 啟動時觸發。一般啟動時不會觸發。可用於您從 CI 或指令碼明確觸發的一次性相依套件安裝或排程清理,與一般工作階段啟動分開。若是每個工作階段的初始化,請改用 [SessionStart](#sessionstart)。
1324 1323
1325matcher 值對應觸發該 hook 的 CLI 旗標:1324matcher 值對應觸發 hook 的 CLI 旗標:
1326 1325
1327| Matcher | 觸發時機 |1326| Matcher | 觸發時機 |
1328| :- | :- |1327| :- | :- |
1329| `init` | `claude --init-only` 或 `claude -p --init` |1328| `init` | `claude --init-only` 或 `claude -p --init` |
1330| `maintenance` | `claude -p --maintenance` |1329| `maintenance` | `claude -p --maintenance` |
1331 1330
1332當您執行 `claude --init-only` 時,Claude Code 會執行 Setup hook 以及 matcher 為 `startup` 的 `SessionStart` hook,然後在不啟動對話的情況下結束。1331當您執行 `claude --init-only` 時,Claude Code 會執行 Setup hook 以及具有 `startup` matcher 的 `SessionStart` hook,然後在不啟動對話的情況下結束。
1333 1332
1334當您以 `-p` 開始或繼續對話時,還需要提供提示詞,作為引數或透過 stdin 傳入。當 `SessionStart` hook 提供 [`initialUserMessage`](#sessionstart-decision-control),或您繼續一個帶有[延後工具呼叫](#defer-a-tool-call-for-later)的工作階段時,可以省略提示詞。1333當您使用 `-p` 啟動或繼續對話時,也需要提供提示詞,可以作為引數或透過 stdin 管道傳入。當 `SessionStart` hook 提供了 [`initialUserMessage`](#sessionstart-decision-control),或您恢復的是具有[延後之工具呼叫](#defer-a-tool-call-for-later)的工作階段時,可以省略提示詞。
1335 1334
1336成功時,`--init-only` 不會在終端機輸出任何內容。若要確認 hook 已執行,請以 `claude --debug-file <path> --init-only` 啟動,將 `<path>` 替換為日誌檔案位置,並在日誌中檢查 Setup 與 SessionStart hook 的項目。1335成功時,`--init-only` 不會在終端機輸出任何內容。若要確認 hook 已執行,請以 `claude --debug-file <path> --init-only` 啟動,將 `<path>` 替換為日誌檔案位置,並在日誌中檢查 Setup 和 SessionStart hook 的項目。
1337 1336
1338由於 Setup 不會在每次啟動時觸發,需要安裝相依套件的外掛無法僅依賴 Setup。實務上的做法是在首次使用時檢查相依套件,缺少時再安裝,例如由 hook 或 skill 檢查 `${CLAUDE_PLUGIN_DATA}/node_modules`,若不存在則執行 `npm install`。關於已安裝相依套件的存放位置,請參閱[持久性資料目錄](/docs/zh-TW/plugins/components#path-variables-and-persistent-data)。如果您透過市集發布外掛,可能不需要此做法:Claude Code 在快取外掛時會[自動安裝符合條件的 Node.js 套件相依性](/docs/zh-TW/plugins/loading#node-js-package-dependencies)。1337由於 Setup 不會在每次啟動時觸發,需要安裝相依套件的外掛不能只依賴 Setup。實務上的做法是在首次使用時檢查相依套件,缺少時再安裝,例如以 hook 或 skill 檢測 `${CLAUDE_PLUGIN_DATA}/node_modules`,若不存在則執行 `npm install`。關於已安裝之相依套件的存放位置,請參閱[持久資料目錄](/docs/zh-TW/plugins/components#path-variables-and-persistent-data)。如果您透過市集發布外掛,可能不需要這種做法:Claude Code 在快取外掛時會[自動安裝符合條件的 Node.js 套件相依性](/docs/zh-TW/plugins/loading#node-js-package-dependencies)。
1339 1338
1340<h4 id="setup-input">1339<h4 id="setup-input">
1341 Setup 輸入1340 Setup 輸入
1357 Setup 決策控制1356 Setup 決策控制
1358</h4>1357</h4>
1359 1358
1360Setup hook 無法阻擋;無論退出碼為何,執行都會繼續。無論退出碼為何,Claude Code 都會捨棄 Setup hook 的 [JSON 輸出欄位](#json-output),例如 `systemMessage`、`continue` 與 `hookSpecificOutput.additionalContext`。使用 `-p` 時,Setup hook 的 stdout、stderr 與退出碼只有在您以 `--output-format stream-json --verbose` 啟動時,才會以 [`hook_response` 事件](/docs/zh-TW/headless#read-session-metadata)的形式出現在執行輸出中。1359Setup hook 無法阻擋;無論退出碼為何,執行都會繼續。在任何退出碼下,Claude Code 都會捨棄 Setup hook 的 [JSON 輸出欄位](#json-output),例如 `systemMessage`、`continue` 和 `hookSpecificOutput.additionalContext`。使用 `-p` 時,只有在您以 `--output-format stream-json --verbose` 啟動的情況下,Setup hook 的 stdout、stderr 和退出碼才會以 [`hook_response` 事件](/docs/zh-TW/headless#read-session-metadata)的形式出現在執行的輸出中。
1361 1360
1362Setup hook 可以存取 `CLAUDE_ENV_FILE`。寫入該檔案的變數會保存到該工作階段後續的 Bash 命令中,與 [SessionStart hook](#persist-environment-variables) 相同。`Setup` 上只會執行 `type: "command"` hook。`Setup` 上的 `type: "mcp_tool"` hook 一律會被略過,如 [MCP 工具 hook 欄位](#mcp-tool-hook-fields)中所述。1361Setup hook 可以存取 `CLAUDE_ENV_FILE`。寫入該檔案的變數會保存到工作階段中後續的 Bash 命令,與 [SessionStart hook](#persist-environment-variables) 相同。`Setup` 上只會執行 `type: "command"` hook。`Setup` 上的 `type: "mcp_tool"` hook 一律會被略過,如 [MCP 工具 hook 欄位](#mcp-tool-hook-fields)所述。
1363 1362
1364<h3 id="instructionsloaded">1363<h3 id="instructionsloaded">
1365 InstructionsLoaded1364 InstructionsLoaded
1366</h3>1365</h3>
1367 1366
1368當 `CLAUDE.md` 或 `.claude/rules/*.md` 檔案載入上下文時觸發。此事件會在工作階段開始時針對立即載入的檔案觸發,之後在檔案延遲載入時再次觸發,例如當 Claude 存取包含巢狀 `CLAUDE.md` 的子目錄時,或具有 `paths:` frontmatter 的條件式規則符合時。此 hook 不支援阻擋或決策控制。它以非同步方式執行,用於可觀察性目的。1367在 `CLAUDE.md` 或 `.claude/rules/*.md` 檔案載入上下文時觸發。此事件會在工作階段開始時針對預先載入的檔案觸發,之後在檔案延遲載入時再次觸發,例如當 Claude 存取包含巢狀 `CLAUDE.md` 的子目錄時,或具有 `paths:` frontmatter 的條件式規則相符時。此 hook 不支援阻擋或決策控制。它以非同步方式執行,用於可觀測性用途。
1369 1368
1370當 Claude 透過 **Project instructions** 設定[直接讀取 `AGENTS.md`](/docs/zh-TW/memory#agents-md) 時,此事件不會觸發。當 `CLAUDE.md` 匯入您的 `AGENTS.md` 時,此事件會觸發,且 `load_reason` 與其他任何匯入的檔案一樣設為 `include`;當 `CLAUDE.md` 是指向它的符號連結時,也會以一般的 `CLAUDE.md` 載入觸發。1369當 Claude 透過 **Project instructions** 設定[直接讀取 `AGENTS.md`](/docs/zh-TW/memory#agents-md) 時,此事件不會觸發。當 `CLAUDE.md` 匯入您的 `AGENTS.md` 時會觸發,`load_reason` 與其他任何匯入的檔案一樣設為 `include`;當 `CLAUDE.md` 是指向它的符號連結時也會觸發,視為一般的 `CLAUDE.md` 載入。
1371 1370
1372matcher 會比對 `load_reason`。例如,使用 `"matcher": "session_start"` 只針對工作階段開始時載入的檔案觸發,或使用 `"matcher": "path_glob_match|nested_traversal"` 只針對延遲載入觸發。1371matcher 會比對 `load_reason`。例如,使用 `"matcher": "session_start"` 可僅針對工作階段開始時載入的檔案觸發,或使用 `"matcher": "path_glob_match|nested_traversal"` 僅針對延遲載入觸發。
1373 1372
1374<h4 id="instructionsloaded-input">1373<h4 id="instructionsloaded-input">
1375 InstructionsLoaded 輸入1374 InstructionsLoaded 輸入
1376</h4>1375</h4>
1377 1376
1378除了[通用輸入欄位](#common-input-fields)之外,InstructionsLoaded hook 還會接收以下欄位:1377除了[通用輸入欄位](#common-input-fields)之外,InstructionsLoaded hook 還會接收下列欄位:
1379 1378
1380| 欄位 | 說明 |1379| 欄位 | 說明 |
1381| :- | :- |1380| :- | :- |
1382| `file_path` | 已載入的指令檔案的絕對路徑 |1381| `file_path` | 已載入之指令檔案的絕對路徑 |
1383| `memory_type` | 檔案的範圍:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |1382| `memory_type` | 檔案的範圍:`"User"`、`"Project"`、`"Local"` 或 `"Managed"` |
1384| `load_reason` | 檔案載入的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值會在壓縮事件後重新載入指令檔案時觸發 |1383| `load_reason` | 檔案載入的原因:`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值會在壓縮事件後重新載入指令檔案時觸發 |
1385| `globs` | 檔案 `paths:` frontmatter 中的路徑 glob 模式(若有)。僅在 `path_glob_match` 載入時出現 |1384| `globs` | 來自檔案 `paths:` frontmatter 的路徑 glob 模式(若有)。僅在 `path_glob_match` 載入時出現 |
1386| `trigger_file_path` | 對於延遲載入,其存取觸發此次載入的檔案路徑 |1385| `trigger_file_path` | 延遲載入時,其存取觸發此次載入的檔案路徑 |
1387| `parent_file_path` | 對於 `include` 載入,包含此檔案的上層指令檔案路徑 |1386| `parent_file_path` | `include` 載入時,包含此檔案的上層指令檔案路徑 |
1388 1387
1389```json theme={null}1388```json theme={null}
1390{1389{
1402 InstructionsLoaded 決策控制1401 InstructionsLoaded 決策控制
1403</h4>1402</h4>
1404 1403
1405InstructionsLoaded hook 沒有決策控制。它們無法阻擋或修改指令載入。Claude Code 會捨棄它們的 [JSON 輸出欄位](#json-output),例如 `systemMessage` 與 `continue`。請將此事件用於稽核日誌、合規追蹤或可觀察性。1404InstructionsLoaded hook 沒有決策控制。它們無法阻擋或修改指令載入。Claude Code 會捨棄它們的 [JSON 輸出欄位](#json-output),例如 `systemMessage` 和 `continue`。請將此事件用於稽核日誌、合規追蹤或可觀測性。
1406 1405
1407<h3 id="userpromptsubmit">1406<h3 id="userpromptsubmit">
1408 UserPromptSubmit1407 UserPromptSubmit
1409</h3>1408</h3>
1410 1409
1411在提示詞送出後、Claude 處理之前執行。這可讓您1410在提交提示詞時、Claude 處理之前執行。這讓您可以
1412根據提示詞或對話加入額外情境、驗證提示詞,或1411根據提示詞/對話加入額外的上下文、驗證提示詞,或
1413封鎖特定類型的提示詞。1412阻擋特定類型的提示詞。
1414 1413
1415`UserPromptSubmit` hook 不只會在您輸入的提示詞上觸發。Claude Code 也會在下列情況執行它們:1414`UserPromptSubmit` hook 不只會在您輸入的提示詞上觸發。Claude Code 也會在下列情況執行它們:
1416 1415
1418* [背景 subagent](/docs/zh-TW/sub-agents#run-subagents-in-foreground-or-background) 向啟動它的工作階段回報時1417* [背景 subagent](/docs/zh-TW/sub-agents#run-subagents-in-foreground-or-background) 向啟動它的工作階段回報時
1419* [另一個工作階段傳送訊息](/docs/zh-TW/cross-session-messaging)到您的主要對話時1418* [另一個工作階段傳送訊息](/docs/zh-TW/cross-session-messaging)到您的主要對話時
1420 1419
1421`UserPromptSubmit` hook 對於 `command`、`http` 與 `mcp_tool` 類型的預設逾時為 30 秒,比這些類型在其他大多數事件上的 600 秒預設值更短。由於此 hook 會在每個提示詞之前執行,並在完成前阻擋模型處理,卡住的 hook 會讓工作階段停滯。如果您的 hook 需要更多時間,請在 hook 項目中設定 `timeout` 欄位。1420`UserPromptSubmit` hook 對 `command`、`http` 和 `mcp_tool` 類型的預設逾時為 30 秒,短於大多數其他事件上這些類型的 600 秒預設值。由於此 hook 會在每個提示詞之前執行,並在完成前阻擋模型處理,卡住的 hook 會使工作階段停滯。如果您的 hook 需要更多時間,請在 hook 項目中設定 `timeout` 欄位。
1422 1421
1423除了您以 [`async: true`](#run-hooks-in-the-background) 執行的 command hook 之外,達到逾時的 `UserPromptSubmit` command、HTTP 或 MCP tool hook 會被取消,其輸出(包括任何 `additionalContext`)都會被捨棄。提示詞仍會傳達給 Claude,只是不含該上下文。逐字稿會顯示一則通知,指出該 hook 名稱、觸發的逾時,以及輸出已被捨棄。1422除了您以 [`async: true`](#run-hooks-in-the-background) 執行的命令 hook 之外,達到逾時的 `UserPromptSubmit` 命令、HTTP 或 MCP 工具 hook 會被取消,其輸出(包括任何 `additionalContext`)會被捨棄。提示詞仍會在沒有該上下文的情況下傳達給 Claude。逐字稿會顯示一則通知,說明該 hook 的名稱、觸發的逾時,以及輸出已被捨棄。
1424 1423
1425`UserPromptSubmit` 上達到逾時的 [Agent SDK 回呼 hook](/docs/zh-TW/agent-sdk/hooks) 會以指出 hook 名稱與逾時的訊息阻擋提示詞,因為該處的回呼可能充當不得在失敗時放行的政策關卡。工作階段會繼續。在 v2.1.208 之前,該事件上的回呼逾時會以執行錯誤結束該回合。1424`UserPromptSubmit` 上達到逾時的 [Agent SDK 回呼 hook](/docs/zh-TW/agent-sdk/hooks) 會阻擋該提示詞,並顯示說明該 hook 和逾時的訊息,因為該處的回呼可能作為不得在失敗時放行的政策關卡。工作階段會繼續。在 v2.1.208 之前,該事件上的回呼逾時會以執行錯誤結束該回合。
1426 1425
1427<h4 id="userpromptsubmit-input">1426<h4 id="userpromptsubmit-input">
1428 UserPromptSubmit 輸入1427 UserPromptSubmit 輸入
1429</h4>1428</h4>
1430 1429
1431除了[通用輸入欄位](#common-input-fields)之外,UserPromptSubmit hook 還會接收包含所送出文字的 `prompt` 欄位。摺疊為 `[Pasted text #N]` 預留位置的貼上內容,會在原位置展開後送達。在 Claude Code [為 Claude 標記貼上文字](/docs/zh-TW/terminal-config#how-claude-treats-pasted-text)的工作階段中,展開的內容位於 `<pasted_content id="…">` 行與 `</pasted_content id="…">` 行之間,因此如果您的 hook 會剖析提示詞,請將這些行納入考量。1430除了[通用輸入欄位](#common-input-fields)之外,UserPromptSubmit hook 還會接收包含所提交文字的 `prompt` 欄位。折疊成 `[Pasted text #N]` 預留位置的貼上內容會在原位置展開後傳入。在 Claude Code [為 Claude 標記貼上文字](/docs/zh-TW/terminal-config#how-claude-treats-pasted-text)的工作階段中,展開的內容會位於 `<pasted_content id="…">` 行與 `</pasted_content id="…">` 行之間,因此如果您的 hook 會剖析提示詞,請將這些行納入考量。
1432 1431
1433當工作階段具有自訂標題時,UserPromptSubmit hook 也會接收 `session_title`,其意義與 [SessionStart 的 `session_title` 欄位](#sessionstart-input)相同。1432當工作階段有自訂標題時,UserPromptSubmit hook 也會接收 `session_title`,其意義與 [SessionStart 的 `session_title` 欄位](#sessionstart-input)相同。
1434 1433
1435```json theme={null}1434```json theme={null}
1436{1435{
1447 UserPromptSubmit 決策控制1446 UserPromptSubmit 決策控制
1448</h4>1447</h4>
1449 1448
1450`UserPromptSubmit` hook 可以控制是否處理已送出的提示詞,並可加入情境。所有 [JSON 輸出欄位](#json-output)皆可使用。1449`UserPromptSubmit` hook 可以控制是否處理已提交的提示詞,並加入上下文。所有 [JSON 輸出欄位](#json-output)皆可使用。
1451 1450
1452在退出碼 0 時,有兩種方式可以將上下文加入對話:1451在退出碼 0 時,有兩種方式可以將上下文加入對話:
1453 1452
1454* **純文字 stdout**:Claude Code 會將其[視為純文字](#exit-code-0)的 stdout 加入 Claude 的上下文1453* **純文字 stdout**:Claude Code 會將其[視為純文字](#exit-code-0)的 stdout 加入 Claude 的上下文
1455* **帶有 `additionalContext` 的 JSON**:使用下方的 JSON 格式以獲得更多控制。`additionalContext` 欄位會作為上下文加入1454* **含 `additionalContext` 的 JSON**:使用下方的 JSON 格式以獲得更多控制。`additionalContext` 欄位會作為上下文加入
1456 1455
1457兩種管道都不會產生可見的逐字稿項目。純 stdout 與 `additionalContext` 值會各自以開頭為 hook 名稱的系統提醒注入;Claude 兩者都會讀取。若要確認已傳遞,請檢查[偵錯日誌](#debug-hooks)。1456這兩個管道都不會產生可見的逐字稿項目。純 stdout 和 `additionalContext` 值各自會以開頭為 hook 名稱的系統提醒注入;Claude 兩者都會讀取。若要確認已傳遞,請查看[除錯日誌](#debug-hooks)。
1458 1457
1459若要阻擋提示詞,請回傳 `decision` 設為 `"block"` 的 JSON 物件:1458若要阻擋提示詞,請傳回 `decision` 設為 `"block"` 的 JSON 物件:
1460 1459
1461| 欄位 | 說明 |1460| 欄位 | 說明 |
1462| :- | :- |1461| :- | :- |
1463| `decision` | `"block"` 會在提示詞傳達給 Claude 之前將其停止。省略則允許提示詞繼續 |1462| `decision` | `"block"` 會在提示詞傳達給 Claude 之前將其停止。省略則允許提示詞繼續 |
1464| `reason` | 當 `decision` 為 `"block"` 時向使用者顯示。不會加入上下文 |1463| `reason` | 當 `decision` 為 `"block"` 時顯示給使用者。不會加入上下文 |
1465| `additionalContext` | 與送出的提示詞一同加入 Claude 上下文的字串。請參閱[為 Claude 加入上下文](#add-context-for-claude) |1464| `additionalContext` | 與已提交之提示詞一同加入 Claude 上下文的字串。請參閱[為 Claude 加入上下文](#add-context-for-claude) |
1466| `sessionTitle` | 設定工作階段標題。可用來依據提示詞內容自動為工作階段命名 |1465| `sessionTitle` | 設定工作階段標題。可用來依據提示詞內容自動命名工作階段 |
1467| `suppressOriginalPrompt` | 若在 hook 阻擋提示詞時為 `true`,則會從阻擋訊息中省略提示詞文字。請參閱[被阻擋的提示詞會留下什麼](#what-a-blocked-prompt-leaves-behind) |1466| `suppressOriginalPrompt` | 若在 hook 阻擋提示詞時為 `true`,則會將提示詞文字排除在阻擋訊息之外。請參閱[被阻擋的提示詞會留下什麼](#what-a-blocked-prompt-leaves-behind) |
1468 1467
1469以退出碼 2 阻擋的 hook 與 `reason` 的處理方式相同:阻擋訊息會向使用者顯示 stderr 文字,且不會加入上下文。1468以退出碼 2 阻擋的 hook 與 `reason` 的處理方式相同:阻擋訊息會向使用者顯示 stderr 文字,且不會加入上下文。
1470 1469
1485 被阻擋的提示詞會留下什麼1484 被阻擋的提示詞會留下什麼
1486</h4>1485</h4>
1487 1486
1488被阻擋的提示詞永遠不會傳達給 Claude,但其文字並不會從各處移除。預設情況下,顯示給使用者的阻擋訊息會以 `Original prompt:` 加上送出的文字結尾,且 Claude Code 會將該訊息寫入磁碟上的工作階段逐字稿檔案。若要在訊息中省略該文字,請在 `hookSpecificOutput` 內輸出含 `"suppressOriginalPrompt": true` 的 JSON。無論 hook 是以 `decision: "block"` 阻擋,還是以退出碼 2 阻擋,此設定皆有效。1487被阻擋的提示詞永遠不會傳達給 Claude,但其文字並不會從所有地方移除。預設情況下,顯示給使用者的阻擋訊息結尾會是 `Original prompt:` 加上所提交的文字,而 Claude Code 會將該訊息寫入磁碟上工作階段的逐字稿檔案。若要將文字排除在訊息之外,請在 `hookSpecificOutput` 中輸出含 `"suppressOriginalPrompt": true` 的 JSON。無論 hook 是以 `decision: "block"` 還是以退出碼 2 阻擋,此設定都有效。
1489 1488
1490`suppressOriginalPrompt` 只會變更阻擋訊息。送出的文字仍可能出現在本機檔案中,例如工作階段逐字稿與您的提示詞歷史記錄,因此阻擋 hook 並不是讓機密不落入磁碟的方法。若要限制或移除這些檔案,請參閱[純文字儲存](/docs/zh-TW/claude-directory#plaintext-storage)與[清除本機資料](/docs/zh-TW/claude-directory#clear-local-data)。1489`suppressOriginalPrompt` 只會改變阻擋訊息。所提交的文字仍可能出現在本機檔案中,例如工作階段逐字稿和您的提示詞歷史記錄,因此阻擋 hook 並不是讓機密不寫入磁碟的方法。若要限制或移除這些檔案,請參閱[純文字儲存](/docs/zh-TW/claude-directory#plaintext-storage)和[清除本機資料](/docs/zh-TW/claude-directory#clear-local-data)。
1491 1490
1492<h3 id="userpromptexpansion">1491<h3 id="userpromptexpansion">
1493 UserPromptExpansion1492 UserPromptExpansion
1494</h3>1493</h3>
1495 1494
1496在使用者輸入的命令展開為提示詞、傳達給 Claude 之前執行。可用來阻擋特定命令被直接呼叫、為特定 skill 注入上下文,或記錄使用者呼叫了哪些命令。例如,比對 `deploy` 的 hook 可以在核准檔案不存在時阻擋 `/deploy`,或比對審查 skill 的 hook 可以將團隊的審查檢查清單作為 `additionalContext` 附加。1495在使用者輸入的命令展開為提示詞、傳達給 Claude 之前執行。可用來阻擋特定命令被直接呼叫、為特定 skill 注入上下文,或記錄使用者呼叫了哪些命令。例如,比對 `deploy` 的 hook 可以在核准檔案不存在時阻擋 `/deploy`,或比對審查 skill 的 hook 可以將團隊的審查清單附加為 `additionalContext`。
1497 1496
1498此事件涵蓋 `PreToolUse` 未涵蓋的路徑:比對 `Skill` 工具的 `PreToolUse` hook 只會在 Claude 呼叫該工具時觸發,但直接輸入 `/skillname` 會繞過 `PreToolUse`。`UserPromptExpansion` 會在該直接路徑上觸發。1497此事件涵蓋了 `PreToolUse` 所沒有涵蓋的路徑:比對 `Skill` 工具的 `PreToolUse` hook 只會在 Claude 呼叫該工具時觸發,但直接輸入 `/skillname` 會略過 `PreToolUse`。`UserPromptExpansion` 會在這條直接路徑上觸發。
1499 1498
1500比對 `command_name`。將 matcher 留空即可在每個提示詞類型的命令上觸發。1499比對 `command_name`。將 matcher 留空即可在每個提示詞類型的命令上觸發。
1501 1500
1503 UserPromptExpansion 輸入1502 UserPromptExpansion 輸入
1504</h4>1503</h4>
1505 1504
1506除了[通用輸入欄位](#common-input-fields)之外,UserPromptExpansion hook 還會接收 `expansion_type`、`command_name`、`command_args`、`command_source`,以及原始的 `prompt` 字串。`expansion_type` 欄位對於 skill 與自訂命令為 `slash_command`,對於 MCP 伺服器提示詞則為 `mcp_prompt`。1505除了[通用輸入欄位](#common-input-fields)之外,UserPromptExpansion hook 還會接收 `expansion_type`、`command_name`、`command_args`、`command_source` 以及原始的 `prompt` 字串。`expansion_type` 欄位對於 skill 和自訂命令為 `slash_command`,對於 MCP 伺服器提示詞則為 `mcp_prompt`。
1507 1506
1508```json theme={null}1507```json theme={null}
1509{1508{
1524 UserPromptExpansion 決策控制1523 UserPromptExpansion 決策控制
1525</h4>1524</h4>
1526 1525
1527`UserPromptExpansion` hook 可以阻擋展開或加入上下文。所有 [JSON 輸出欄位](#json-output)都可使用。1526`UserPromptExpansion` hook 可以阻擋展開或加入上下文。所有 [JSON 輸出欄位](#json-output)皆可使用。
1528 1527
1529| 欄位 | 說明 |1528| 欄位 | 說明 |
1530| :- | :- |1529| :- | :- |
1531| `decision` | `"block"` 會阻止命令展開。省略則允許其繼續 |1530| `decision` | `"block"` 會阻止命令展開。省略則允許其繼續 |
1532| `reason` | 當 `decision` 為 `"block"` 時向使用者顯示 |1531| `reason` | 當 `decision` 為 `"block"` 時顯示給使用者 |
1533| `additionalContext` | 與展開後的提示詞一同加入 Claude 上下文的字串。請參閱[為 Claude 加入上下文](#add-context-for-claude) |1532| `additionalContext` | 與展開後之提示詞一同加入 Claude 上下文的字串。請參閱[為 Claude 加入上下文](#add-context-for-claude) |
1534 1533
1535以退出碼 2 阻擋的 hook 與 `reason` 的處理方式相同:阻擋訊息會向使用者顯示 stderr 文字。1534以退出碼 2 阻擋的 hook 與 `reason` 的處理方式相同:阻擋訊息會向使用者顯示 stderr 文字。
1536 1535
1549 MessageDisplay1548 MessageDisplay
1550</h3>1549</h3>
1551 1550
1552在助理訊息串流到螢幕上時執行。Claude Code 會分段顯示訊息:每當一批新完成的行準備好呈現時,hook 就會以這些行執行一次,而 Claude Code 會在其位置呈現 hook 的替換文字。長訊息會產生多次呼叫;短訊息可能只產生一次。1551在助理訊息串流到畫面上時執行。Claude Code 會逐步顯示訊息:每當一批新完成的行準備好要呈現時,hook 就會以這些行執行一次,而 Claude Code 會在其位置呈現 hook 的替換文字。較長的訊息會產生多次呼叫;較短的訊息可能只產生一次。
1553 1552
1554使用 MessageDisplay 來:1553MessageDisplay 可用於:
1555 1554
1556* 移除 markdown 以精簡顯示1555* 移除 markdown 以呈現精簡的畫面
1557* 轉換 Agent SDK 應用程式向其使用者顯示的文字1556* 轉換 Agent SDK 應用程式向其使用者顯示的文字
1558* 從 Claude 的回應中遮蔽 API 金鑰或內部主機名稱1557* 從 Claude 的回應中遮蔽 API 金鑰或內部主機名稱
1559 1558
1560Claude Code 會保留每一批內容直到您的 hook 回傳,因此請讓 hook 保持快速。如果 hook 失敗或逾時,Claude Code 會顯示原始文字。此事件的預設逾時為 10 秒;如果您的 hook 需要更多時間,請在 hook 項目中設定 `timeout` 欄位。1559Claude Code 會保留每一批內容直到您的 hook 傳回,因此請讓 hook 保持快速。如果 hook 失敗或逾時,Claude Code 會顯示原始文字。此事件的預設逾時為 10 秒;如果您的 hook 需要更多時間,請在 hook 項目中設定 `timeout` 欄位。
1561 1560
1562MessageDisplay 僅影響顯示:替換文字只會改變螢幕上呈現的內容。逐字稿與 Claude 看到的內容會保留原始文字,因此 Claude 永遠不會看到替換內容,而詳細模式會顯示原始內容。hook 只接收助理訊息文字,因此工具結果與您輸入的文字會原樣呈現。1561MessageDisplay 僅影響顯示:替換文字只會改變畫面上呈現的內容。逐字稿以及 Claude 看到的內容會保留原始文字,因此 Claude 永遠不會看到替換內容,而詳細模式也會顯示原始文字。hook 只會接收助理訊息文字,因此工具結果和您輸入的文字會原樣呈現。
1563 1562
1564MessageDisplay 不支援 matcher,會對每一則串流文字的助理訊息觸發;沒有文字的訊息,例如只有工具呼叫的回應,不會觸發它。1563MessageDisplay 不支援 matcher,並會針對每則串流文字的助理訊息觸發;沒有文字的訊息(例如僅含工具呼叫的回應)不會觸發它。
1565 1564
1566在非互動式執行中,包括 Agent SDK 查詢與 `claude -p`,MessageDisplay 會針對每則助理訊息執行一次,而非每批行執行一次。這次單一呼叫會在訊息完成後送達,並攜帶完整的訊息文字:`index` 為 `0`、`final` 為 `true`,而 `delta` 包含整則訊息。為每則訊息收集 `delta` 文字的 hook,在兩種模式下都會接收到相同的完整文字。1565在非互動式執行中,包括 Agent SDK 查詢和 `claude -p`,MessageDisplay 會針對每則助理訊息執行一次,而不是每批行執行一次。這次單一呼叫會在訊息完成後到達,並攜帶完整的訊息文字:`index` 為 `0`、`final` 為 `true`,而 `delta` 包含整則訊息。收集每則訊息之 `delta` 文字的 hook,在兩種模式下都會收到相同的完整文字。
1567 1566
1568<h4 id="messagedisplay-input">1567<h4 id="messagedisplay-input">
1569 MessageDisplay 輸入1568 MessageDisplay 輸入
1570</h4>1569</h4>
1571 1570
1572除了[通用輸入欄位](#common-input-fields)之外,MessageDisplay hook 還會接收回合與訊息的識別碼、此次呼叫在訊息中的位置,以及 `delta` 中的新文字。批次邊界取決於文字的串流方式,因此請使用 `index` 與 `final` 追蹤訊息的進度,而不要預期行會以特定方式分組。1571除了[通用輸入欄位](#common-input-fields)之外,MessageDisplay hook 還會接收回合和訊息的識別碼、此次呼叫在訊息中的位置,以及 `delta` 中的新文字。批次邊界取決於文字的串流方式,因此請使用 `index` 和 `final` 追蹤訊息的進度,而不要預期行會以特定方式分組。
1573 1572
1574| 欄位 | 說明 |1573| 欄位 | 說明 |
1575| :- | :- |1574| :- | :- |
1576| `turn_id` | 目前回合的 UUID |1575| `turn_id` | 目前回合的 UUID |
1577| `message_id` | 正在顯示的助理訊息的 UUID。在同一則訊息的每一批中保持不變。這不是 API 的 `msg_…` id,因此無法與逐字稿的訊息 id 對應 |1576| `message_id` | 正在顯示之助理訊息的 UUID。在同一則訊息的每一批中都保持不變。這不是 API 的 `msg_…` id,因此無法與逐字稿的訊息 id 對應 |
1578| `index` | 此批次在訊息中從零起算的索引 |1577| `index` | 此批次在訊息中從零開始的索引 |
1579| `final` | 在訊息的最後一批時為 `true`。每則訊息恰好有一個最後批次 |1578| `final` | 在訊息的最後一批時為 `true`。每則訊息恰好有一個最終批次 |
1580| `delta` | 自前一批以來新完成的行,包含結尾的換行字元。一律為完整的行,但最後一批可能在行中間結束。在互動式執行中,當訊息以換行字元結束時,最後一批的 delta 為空,因此請將 `final`(而非非空的 delta)視為訊息結束的訊號。在 Agent SDK 與 `claude -p` 執行中,單一呼叫會攜帶整則訊息 |1579| `delta` | 自上一批以來新完成的行,包含結尾的換行字元。一律為完整的行,但最終批次可能在行中間結束。在互動式執行中,當訊息以換行結尾時,最終批次的 delta 為空,因此請將 `final`(而非非空的 delta)視為訊息結束的訊號。在 Agent SDK 和 `claude -p` 執行中,單一呼叫會攜帶整則訊息 |
1581 1580
1582```json theme={null}1581```json theme={null}
1583{1582{
1597 MessageDisplay 輸出1596 MessageDisplay 輸出
1598</h4>1597</h4>
1599 1598
1600除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,MessageDisplay hook 還可以回傳 `displayContent`,以在螢幕上替換 delta:1599除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,MessageDisplay hook 還可以傳回 `displayContent`,以取代畫面上的 delta:
1601 1600
1602| 欄位 | 說明 |1601| 欄位 | 說明 |
1603| :- | :- |1602| :- | :- |
1604| `displayContent` | 取代 delta 顯示的文字。省略則顯示原始內容 |1603| `displayContent` | 取代 delta 顯示的文字。省略則顯示原始內容 |
1605 1604
1606MessageDisplay hook 沒有決策控制。它們無法阻擋訊息,也無法變更儲存在逐字稿中或傳送給 Claude 的內容。Claude Code 會依據其 JSON 輸出中的 `displayContent` 採取動作,並捨棄 `systemMessage` 與 `continue`。1605MessageDisplay hook 沒有決策控制。它們無法阻擋訊息,也無法改變儲存在逐字稿中或傳送給 Claude 的內容。Claude Code 會採用其 JSON 輸出中的 `displayContent`,並捨棄 `systemMessage` 和 `continue`。
1607 1606
1608此範例會從 Claude 的回應中移除 markdown 格式,以純文字顯示。指令碼從 stdin 讀取每一批內容,從 `delta` 中移除粗體標記與行內程式碼反引號,並將結果以 `displayContent` 回傳。1607此範例會從 Claude 的回應中移除 markdown 格式,以純文字方式顯示。指令碼會從 stdin 讀取每一批內容,從 `delta` 中移除粗體標記和行內程式碼的反引號,並將結果作為 `displayContent` 傳回。
1609 1608
1610<Tabs>1609<Tabs>
1611 <Tab title="macOS/Linux">1610 <Tab title="macOS/Linux">
1612 在您的設定檔中為此事件註冊 command hook:1611 在您的設定檔中為此事件註冊命令 hook:
1613 1612
1614 ```json theme={null}1613 ```json theme={null}
1615 {1614 {
1638 </Tab>1637 </Tab>
1639 1638
1640 <Tab title="Windows (PowerShell)">1639 <Tab title="Windows (PowerShell)">
1641 註冊透過 PowerShell 執行指令碼的 command hook:1640 註冊透過 PowerShell 執行指令碼的命令 hook:
1642 1641
1643 ```json theme={null}1642 ```json theme={null}
1644 {1643 {
1664 }1663 }
1665 ```1664 ```
1666 1665
1667 `-NoProfile` 旗標會略過載入您的 PowerShell 設定檔,讓 hook 快速啟動,而 `-ExecutionPolicy Bypass` 讓 PowerShell 能執行本機指令碼檔案。1666 `-NoProfile` 旗標會略過載入您的 PowerShell 設定檔,讓 hook 快速啟動,而 `-ExecutionPolicy Bypass` 則讓 PowerShell 可以執行本機指令碼檔案。
1668 1667
1669 將此指令碼儲存至專案中的 `.claude/hooks/plain-display.ps1`:1668 將此指令碼儲存至專案中的 `.claude/hooks/plain-display.ps1`:
1670 1669
1681 </Tab>1680 </Tab>
1682</Tabs>1681</Tabs>
1683 1682
1684不含 markdown 的批次會原樣通過。如果指令碼失敗,例如因為缺少 `jq`,Claude Code 會顯示原始文字,且只在[偵錯輸出](#debug-hooks)中記錄失敗,而不會在工作階段中顯示。1683沒有 markdown 的批次會原樣通過。如果指令碼失敗,例如因為缺少 `jq`,Claude Code 會顯示原始文字,並只在[除錯輸出](#debug-hooks)中記錄失敗,不會在工作階段中顯示。
1685 1684
1686<h3 id="pretooluse">1685<h3 id="pretooluse">
1687 PreToolUse1686 PreToolUse
1688</h3>1687</h3>
1689 1688
1690在 Claude 建立工具參數之後、處理工具呼叫之前執行。比對 `EndConversation` 以外的任何工具名稱:內建工具,例如 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`WebFetch`、`WebSearch`、`AskUserQuestion` 與 `ExitPlanMode`,以及任何 [MCP 工具名稱](#match-mcp-tools)。1689在 Claude 建立工具參數之後、處理工具呼叫之前執行。比對除了 `EndConversation` 以外的任何工具名稱:內建工具,例如 `Bash`、`PowerShell`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`Workflow`、`WebFetch`、`WebSearch`、`AskUserQuestion` 和 `ExitPlanMode`,以及任何 [MCP 工具名稱](#match-mcp-tools)。
1691 1690
1692若要在特定檔案於磁碟上變更時執行 hook(無論由誰寫入),請使用 [FileChanged](#filechanged),而不要依名稱比對編輯檔案的工具。與 PreToolUse 不同,Claude Code 會在變更之後執行 FileChanged hook,且它們沒有決策控制,因此無法阻擋寫入。1691若要在特定檔案於磁碟上變更時執行 hook(無論是由誰寫入),請使用 [FileChanged](#filechanged),而不是依名稱比對編輯檔案的工具。與 PreToolUse 不同,Claude Code 會在變更之後執行 FileChanged hook,而且它們沒有決策控制,因此無法阻擋寫入。
1693 1692
1694<Warning>1693<Warning>
1695 PreToolUse 只會在 Claude 呼叫工具時執行。您[在提示詞中以 `@` 參照](/docs/zh-TW/common-workflows#reference-files-and-directories)的檔案會在沒有任何工具呼叫的情況下加入:Claude Code 在建構提示詞時插入其內容,因此不會為它們觸發任何 PreToolUse hook,包括比對 `Read` 的 hook。若要阻擋特定路徑被 `@` 參照,請改用 [`Read` 拒絕規則](/docs/zh-TW/permissions#read-and-edit)。1694 PreToolUse 只在 Claude 呼叫工具時執行。您[在提示詞中以 `@` 參照](/docs/zh-TW/common-workflows#reference-files-and-directories)的檔案不經任何工具呼叫即被加入:Claude Code 在建構提示詞時插入其內容,因此不會為它們觸發任何 PreToolUse hook,包括比對 `Read` 的 hook。若要阻擋 `@` 參照特定路徑,請改用 [`Read` 拒絕規則](/docs/zh-TW/permissions#read-and-edit)。
1696 1695
1697 PreToolUse 也不會為 [`EndConversation`](/docs/zh-TW/tools-reference#endconversation-tool-behavior) 觸發。1696 PreToolUse 也不會針對 [`EndConversation`](/docs/zh-TW/tools-reference#endconversation-tool-behavior) 觸發。
1698</Warning>1697</Warning>
1699 1698
1700使用 [PreToolUse 決策控制](#pretooluse-decision-control)來允許、拒絕、詢問或延後工具呼叫。1699使用 [PreToolUse 決策控制](#pretooluse-decision-control)來允許、拒絕、詢問或延後工具呼叫。
1701 1700
1702`PreToolUse` 上超過逾時的 [Agent SDK 回呼 hook](/docs/zh-TW/agent-sdk/hooks) 會阻擋工具呼叫,而 Claude 會收到指出該逾時的錯誤結果。其他 hook 回傳的明確拒絕仍優先於此。1701`PreToolUse` 上超過逾時的 [Agent SDK 回呼 hook](/docs/zh-TW/agent-sdk/hooks) 會阻擋工具呼叫,而 Claude 會收到說明該逾時的錯誤結果。其他 hook 傳回的明確拒絕仍然優先。
1703 1702
1704<h4 id="pretooluse-input">1703<h4 id="pretooluse-input">
1705 PreToolUse 輸入1704 PreToolUse 輸入
1706</h4>1705</h4>
1707 1706
1708除了[通用輸入欄位](#common-input-fields)之外,PreToolUse hook 還會接收 `tool_name`、`tool_input` 與 `tool_use_id`。1707除了[通用輸入欄位](#common-input-fields)之外,PreToolUse hook 還會接收 `tool_name`、`tool_input` 和 `tool_use_id`。
1709 1708
1710對於 [MCP 工具](#match-mcp-tools),輸入還會攜帶 `mcp_server`,這是一個包含伺服器 `name` 以及 `source` 的物件,`source` 說明伺服器的定義來自何處。`source` 值包括 `plugin`、`sdk`,以及 `user` 與 `project` 等設定範圍。Agent SDK 參考文件中的 [`McpServerProvenance`](/docs/zh-TW/agent-sdk/typescript#mcpserverprovenance) 列出了所有值,並說明如何處理無法辨識的值。請依據 `source` 而非 `name` 或 `mcp__<server>__` 工具名稱前綴做出信任決策。`mcp_server` 欄位需要 Claude Code v2.1.274 或更新版本。1709對於 [MCP 工具](#match-mcp-tools),輸入還會攜帶 `mcp_server`,這是一個包含伺服器 `name` 以及說明伺服器定義來源之 `source` 的物件。`source` 的值包括 `plugin`、`sdk`,以及 `user` 和 `project` 等設定範圍。Agent SDK 參考文件中的 [`McpServerProvenance`](/docs/zh-TW/agent-sdk/typescript#mcpserverprovenance) 列出了所有值,並說明如何處理無法辨識的值。請依據 `source` 做出信任決策,而不是依據 `name` 或 `mcp__<server>__` 工具名稱前綴。`mcp_server` 欄位需要 Claude Code v2.1.274 或更新版本。
1711 1710
1712對於檔案工具 `Write`、`Edit` 與 `Read`,`tool_input.file_path` 一律為絕對路徑:1711對於檔案工具 `Write`、`Edit` 和 `Read`,`tool_input.file_path` 一律為絕對路徑:
1713 1712
1714* Claude Code 會在 hook 執行之前展開 `~` 與相對路徑,因此比對路徑的 hook 無法透過 `~` 或同一路徑的相對寫法被繞過1713* Claude Code 會在 hook 執行前展開 `~` 和相對路徑,因此比對路徑的 hook 無法透過 `~` 或同一路徑的相對寫法繞過
1715* 在 Windows 上,路徑會以反斜線分隔符號傳入,即使您的 hook 在 Git Bash 下執行、其中 `$PWD` 看起來像 `/c/project` 也是如此1714* 在 Windows 上,路徑會以反斜線分隔符號傳入,即使您的 hook 在 `$PWD` 看起來像 `/c/project` 的 Git Bash 下執行也是如此
1716* 以正斜線撰寫的比較,例如 `/src/` 檢查,永遠不會與反斜線路徑相符,工具呼叫會如同 hook 沒有可阻擋的內容般繼續1715* 以正斜線撰寫的比較(例如 `/src/` 檢查)永遠不會比對到反斜線路徑,工具呼叫會像 hook 沒有任何可阻擋的內容一樣繼續進行
1717* 請在比較前將分隔符號正規化:在 Bash 中使用 `FILE_PATH="${FILE_PATH//\\//}"`,在 Python 中使用 `file_path.replace("\\", "/")`,然後比對路徑片段,例如 `/src/`,而不要以 `^` 錨定,因為路徑是絕對路徑1716* 比較前請先正規化分隔符號:在 Bash 中使用 `FILE_PATH="${FILE_PATH//\\//}"`,或在 Python 中使用 `file_path.replace("\\", "/")`,然後比對路徑片段(例如 `/src/`),而不是以 `^` 錨定,因為路徑是絕對路徑
1718 1717
1719Windows 上的 `Write` 呼叫會傳遞:1718在 Windows 上的 `Write` 呼叫會傳入:
1720 1719
1721```json theme={null}1720```json theme={null}
1722{1721{
1730}1729}
1731```1730```
1732 1731
1733`tool_input` 欄位取決於工具:1732`tool_input` 的欄位取決於工具:
1734 1733
1735<a id="bash" />1734<a id="bash" />
1736 1735
1743| 欄位 | 類型 | 範例 | 說明 |1742| 欄位 | 類型 | 範例 | 說明 |
1744| :- | :- | :- | :- |1743| :- | :- | :- | :- |
1745| `command` | string | `"npm test"` | 要執行的 shell 命令 |1744| `command` | string | `"npm test"` | 要執行的 shell 命令 |
1746| `description` | string | `"Run test suite"` | 選擇性的命令用途說明 |1745| `description` | string | `"Run test suite"` | 選用的命令用途說明 |
1747| `timeout` | number | `120000` | 選擇性的逾時(毫秒)。超過[上限](/docs/zh-TW/tools-reference#bash-tool-behavior)的值會被降為上限,而不會被拒絕 |1746| `timeout` | number | `120000` | 選用的逾時(毫秒)。超過[上限](/docs/zh-TW/tools-reference#bash-tool-behavior)的值會被降為上限,而不會被拒絕 |
1748| `run_in_background` | boolean | `false` | 是否在背景執行命令 |1747| `run_in_background` | boolean | `false` | 是否在背景執行命令 |
1749 1748
1750當 Bash 命令變更 Git 儲存庫中的檔案時,Claude Code 可以記錄變更內容。當 [`bashEditDiffEnabled`](/docs/zh-TW/settings-reference#basheditdiffenabled) 設定開啟記錄時,它會在每種權限模式下記錄變更;該設定的項目說明了哪些檔案可以設定它。否則,它只會在自動模式與 `bypassPermissions` 模式下記錄,且僅在 Claude Code 指示 Claude 透過 Bash 編輯檔案時記錄。將 `bashEditDiffEnabled` 設為 `false` 即可關閉記錄。背景命令與唯讀命令不會攜帶差異。1749當 Bash 命令變更 Git 儲存庫中的檔案時,Claude Code 可以記錄變更的內容。當 [`bashEditDiffEnabled`](/docs/zh-TW/settings-reference#basheditdiffenabled) 設定開啟記錄時,它會在每種權限模式下記錄變更;該設定的項目說明了哪些檔案可以設定它。否則,它只會在自動模式和 `bypassPermissions` 模式下記錄變更,而且只在 Claude Code 指示 Claude 透過 Bash 編輯檔案時記錄。將 `bashEditDiffEnabled` 設為 `false` 可關閉記錄。背景命令和唯讀命令不會攜帶差異。
1751 1750
1752接著,您的 [PostToolUse hook](#posttooluse) 會在 `tool_response.bashEditDiff` 中接收已變更的檔案。清單涵蓋命令執行期間儲存庫下的變更。Git 忽略的檔案與子模組中的檔案不會列出。需要 Claude Code v2.1.269 或更新版本。1751接著,您的 [PostToolUse hook](#posttooluse) 會在 `tool_response.bashEditDiff` 中接收變更的檔案。此清單涵蓋命令執行期間儲存庫下變更的內容。Git 忽略的檔案以及子模組中的檔案不會列出。需要 Claude Code v2.1.269 或更新版本。
1753 1752
1754<Note>1753<Note>
1755 此清單為盡力而為,且處於公開測試版。Claude Code 可能遺漏變更、包含同時被其他程序變更的檔案,或在達到大小限制時停止。欄位結構可能會變更。請使用此清單找出需要審查的內容,而不要用來強制執行政策。1754 此清單為盡力而為,目前處於公開測試版。Claude Code 可能遺漏變更、包含另一個程序同時變更的檔案,或在達到大小限制時停止。欄位結構可能會變更。請使用此清單來找出需要審查的內容,而不是用來強制執行政策。
1756</Note>1755</Note>
1757 1756
1758`changedFiles` 與 `files` 列出命令變更的內容;其餘欄位說明該清單的完整程度與可靠程度。1757`changedFiles` 和 `files` 列出命令變更的內容;其餘欄位說明該清單的完整度和可靠度。
1759 1758
1760| 欄位 | 類型 | 範例 | 說明 |1759| 欄位 | 類型 | 範例 | 說明 |
1761| :- | :- | :- | :- |1760| :- | :- | :- | :- |
1762| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令變更的檔案絕對路徑,最多 200 個。只要 `files` 包含差異或 `moreFiles` 大於零就會出現 |1761| `changedFiles` | array | `["/path/to/src/app.ts"]` | 命令變更之檔案的絕對路徑,最多 200 個。只要 `files` 包含差異或 `moreFiles` 大於零就會出現 |
1763| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 個已變更檔案的差異,供顯示用。對於命令新增或移除的檔案,`created` 或 `deleted` 為 `true` |1762| `files` | array | `[{"filePath": "/path/to/src/app.ts", "hunks": [...]}]` | 最多 5 個變更檔案的差異,供顯示用。對於命令新增或移除的檔案,`created` 或 `deleted` 為 `true` |
1764| `moreFiles` | number | `2` | 在 `files` 中沒有差異的已變更檔案數 |1763| `moreFiles` | number | `2` | 在 `files` 中沒有差異的變更檔案數量 |
1765| `unavailable` | boolean | `true` | 當差異不完整或無法取得時設定 |1764| `unavailable` | boolean | `true` | 當差異不完整或無法取得時設定 |
1766| `skipped` | boolean | `true` | 針對會移動工作樹的 Git 命令設定,例如 `git checkout` 或 `git stash`,因此 Claude Code 不會取得差異 |1765| `skipped` | boolean | `true` | 針對會移動工作樹的 Git 命令(例如 `git checkout` 或 `git stash`)設定,此時 Claude Code 不會取得差異 |
1767| `shared` | boolean | `true` | 當另一個 Bash 工具呼叫(例如 subagent 的呼叫)同時在同一個儲存庫中執行時設定,因此部分列出的變更可能來自該命令 |1766| `shared` | boolean | `true` | 當另一個 Bash 工具呼叫(例如 subagent 的呼叫)同時在同一個儲存庫中執行時設定,因此部分列出的變更可能來自該命令 |
1768 1767
1769<a id="powershell" />1768<a id="powershell" />
1772 PowerShell1771 PowerShell
1773</h5>1772</h5>
1774 1773
1775執行 PowerShell 命令。關於各平台的可用性,請參閱 [PowerShell 工具](/docs/zh-TW/tools-reference#powershell-tool)。1774執行 PowerShell 命令。各平台的可用性請參閱 [PowerShell 工具](/docs/zh-TW/tools-reference#powershell-tool)。
1776 1775
1777欄位與 Bash 工具相同,命令字串位於 `command`:1776欄位與 Bash 工具相同,命令字串位於 `command`:
1778 1777
1779| 欄位 | 類型 | 範例 | 說明 |1778| 欄位 | 類型 | 範例 | 說明 |
1780| :- | :- | :- | :- |1779| :- | :- | :- | :- |
1781| `command` | string | `"Get-ChildItem -Recurse"` | 要執行的 PowerShell 命令 |1780| `command` | string | `"Get-ChildItem -Recurse"` | 要執行的 PowerShell 命令 |
1782| `description` | string | `"List files recursively"` | 選擇性的命令用途說明 |1781| `description` | string | `"List files recursively"` | 選用的命令用途說明 |
1783| `timeout` | number | `120000` | 選擇性的逾時(毫秒) |1782| `timeout` | number | `120000` | 選用的逾時(毫秒) |
1784| `run_in_background` | boolean | `false` | 是否在背景執行命令 |1783| `run_in_background` | boolean | `false` | 是否在背景執行命令 |
1785 1784
1786在檢查 shell 命令的 hook 中請比對 `Bash|PowerShell`,以涵蓋兩種工具:1785在檢查 shell 命令的 hook 中比對 `Bash|PowerShell`,以涵蓋兩種工具:
1787 1786
1788* 在 Windows 上,只要啟用了 PowerShell 工具,Claude 就會將 PowerShell 視為主要 shell,並透過它執行 shell 命令。1787* 在 Windows 上,只要啟用了 PowerShell 工具,Claude 就會將 PowerShell 視為主要 shell,並透過它路由 shell 命令。
1789* 在沒有 Git Bash 的 Windows 上,該工具會自動啟用,而 Claude Code 完全不會註冊 Bash 工具。1788* 在沒有 Git Bash 的 Windows 上,該工具會自動啟用,且 Claude Code 完全不會註冊 Bash 工具。
1790* 只比對 `Bash` 的 hook 在那裡永遠不會觸發。1789* 只比對 `Bash` 的 hook 在該處永遠不會觸發。
1791 1790
1792<h5 id="write">1791<h5 id="write">
1793 Write1792 Write
1797 1796
1798| 欄位 | 類型 | 範例 | 說明 |1797| 欄位 | 類型 | 範例 | 說明 |
1799| :- | :- | :- | :- |1798| :- | :- | :- | :- |
1800| `file_path` | string | `"/path/to/file.txt"` | 要寫入的檔案絕對路徑 |1799| `file_path` | string | `"/path/to/file.txt"` | 要寫入之檔案的絕對路徑 |
1801| `content` | string | `"file content"` | 要寫入檔案的內容 |1800| `content` | string | `"file content"` | 要寫入檔案的內容 |
1802 1801
1803<h5 id="edit">1802<h5 id="edit">
1804 Edit1803 Edit
1805</h5>1804</h5>
1806 1805
1807取代現有檔案中的字串。1806取代既有檔案中的字串。
1808 1807
1809| 欄位 | 類型 | 範例 | 說明 |1808| 欄位 | 類型 | 範例 | 說明 |
1810| :- | :- | :- | :- |1809| :- | :- | :- | :- |
1811| `file_path` | string | `"/path/to/file.txt"` | 要編輯的檔案絕對路徑 |1810| `file_path` | string | `"/path/to/file.txt"` | 要編輯之檔案的絕對路徑 |
1812| `old_string` | string | `"original text"` | 要尋找並取代的文字 |1811| `old_string` | string | `"original text"` | 要尋找並取代的文字 |
1813| `new_string` | string | `"replacement text"` | 取代文字 |1812| `new_string` | string | `"replacement text"` | 取代文字 |
1814| `replace_all` | boolean | `false` | 是否取代所有出現處 |1813| `replace_all` | boolean | `false` | 是否取代所有出現處 |
1821 1820
1822| 欄位 | 類型 | 範例 | 說明 |1821| 欄位 | 類型 | 範例 | 說明 |
1823| :- | :- | :- | :- |1822| :- | :- | :- | :- |
1824| `file_path` | string | `"/path/to/file.txt"` | 要讀取的檔案絕對路徑 |1823| `file_path` | string | `"/path/to/file.txt"` | 要讀取之檔案的絕對路徑 |
1825| `offset` | number | `10` | 選擇性的起始讀取行號 |1824| `offset` | number | `10` | 選用的起始讀取行號 |
1826| `limit` | number | `50` | 選擇性的讀取行數 |1825| `limit` | number | `50` | 選用的讀取行數 |
1827 1826
1828<h5 id="glob">1827<h5 id="glob">
1829 Glob1828 Glob
1834| 欄位 | 類型 | 範例 | 說明 |1833| 欄位 | 類型 | 範例 | 說明 |
1835| :- | :- | :- | :- |1834| :- | :- | :- | :- |
1836| `pattern` | string | `"**/*.ts"` | 用來比對檔案的 glob 模式 |1835| `pattern` | string | `"**/*.ts"` | 用來比對檔案的 glob 模式 |
1837| `path` | string | `"/path/to/dir"` | 選擇性的搜尋目錄。預設為目前工作目錄 |1836| `path` | string | `"/path/to/dir"` | 選用的搜尋目錄。預設為目前工作目錄 |
1838 1837
1839<h5 id="grep">1838<h5 id="grep">
1840 Grep1839 Grep
1841</h5>1840</h5>
1842 1841
1843以規則運算式搜尋檔案內容。1842以正規表示式搜尋檔案內容。
1844 1843
1845| 欄位 | 類型 | 範例 | 說明 |1844| 欄位 | 類型 | 範例 | 說明 |
1846| :- | :- | :- | :- |1845| :- | :- | :- | :- |
1847| `pattern` | string | `"TODO.*fix"` | 要搜尋的規則運算式模式 |1846| `pattern` | string | `"TODO.*fix"` | 要搜尋的正規表示式模式 |
1848| `path` | string | `"/path/to/dir"` | 選擇性的搜尋檔案或目錄 |1847| `path` | string | `"/path/to/dir"` | 選用的搜尋檔案或目錄 |
1849| `glob` | string | `"*.ts"` | 選擇性的檔案篩選 glob 模式 |1848| `glob` | string | `"*.ts"` | 選用的 glob 模式,用於篩選檔案 |
1850| `output_mode` | string | `"content"` | `"content"`、`"files_with_matches"` 或 `"count"`。預設為 `"files_with_matches"` |1849| `output_mode` | string | `"content"` | `"content"`、`"files_with_matches"` 或 `"count"`。預設為 `"files_with_matches"` |
1851| `-i` | boolean | `true` | 不區分大小寫搜尋 |1850| `-i` | boolean | `true` | 不區分大小寫搜尋 |
1852| `multiline` | boolean | `false` | 啟用多行比對 |1851| `multiline` | boolean | `false` | 啟用多行比對 |
1860| 欄位 | 類型 | 範例 | 說明 |1859| 欄位 | 類型 | 範例 | 說明 |
1861| :- | :- | :- | :- |1860| :- | :- | :- | :- |
1862| `url` | string | `"https://example.com/api"` | 要擷取內容的 URL |1861| `url` | string | `"https://example.com/api"` | 要擷取內容的 URL |
1863| `prompt` | string | `"Extract the API endpoints"` | 要對擷取內容執行的提示詞 |1862| `prompt` | string | `"Extract the API endpoints"` | 要在擷取內容上執行的提示詞 |
1864 1863
1865<h5 id="websearch">1864<h5 id="websearch">
1866 WebSearch1865 WebSearch
1871| 欄位 | 類型 | 範例 | 說明 |1870| 欄位 | 類型 | 範例 | 說明 |
1872| :- | :- | :- | :- |1871| :- | :- | :- | :- |
1873| `query` | string | `"react hooks best practices"` | 搜尋查詢 |1872| `query` | string | `"react hooks best practices"` | 搜尋查詢 |
1874| `allowed_domains` | array | `["docs.example.com"]` | 選擇性:只包含來自這些網域的結果 |1873| `allowed_domains` | array | `["docs.example.com"]` | 選用:只包含來自這些網域的結果 |
1875| `blocked_domains` | array | `["spam.example.com"]` | 選擇性:排除來自這些網域的結果 |1874| `blocked_domains` | array | `["spam.example.com"]` | 選用:排除來自這些網域的結果 |
1876 1875
1877<h5 id="agent">1876<h5 id="agent">
1878 Agent1877 Agent
1879</h5>1878</h5>
1880 1879
1881產生一個 [subagent](/docs/zh-TW/sub-agents)。1880產生 [subagent](/docs/zh-TW/sub-agents)。
1882 1881
1883| 欄位 | 類型 | 範例 | 說明 |1882| 欄位 | 類型 | 範例 | 說明 |
1884| :- | :- | :- | :- |1883| :- | :- | :- | :- |
1885| `prompt` | string | `"Find all API endpoints"` | agent 要執行的任務 |1884| `prompt` | string | `"Find all API endpoints"` | agent 要執行的任務 |
1886| `description` | string | `"Find API endpoints"` | 任務的簡短說明 |1885| `description` | string | `"Find API endpoints"` | 任務的簡短說明 |
1887| `subagent_type` | string | `"Explore"` | 要使用的專門 agent 類型 |1886| `subagent_type` | string | `"Explore"` | 要使用的專門 agent 類型 |
1888| `model` | string | `"sonnet"` | 選擇性的模型別名,用以覆寫預設值 |1887| `model` | string | `"sonnet"` | 選用的模型別名,用於覆寫預設值 |
1889 1888
1890當前景 Agent 呼叫完成時,您的 [PostToolUse hook](#posttooluse) 會在 `tool_response` 中接收 subagent 的結果與執行遙測。請讀取這些欄位來檢視執行情況;若要彙總各 subagent 的 token 與成本,請使用以 `query_source` `"subagent"` 篩選的 [token 與成本計數器](/docs/zh-TW/monitoring-usage#token-counter),因為 `totalTokens` 與 `usage` 只涵蓋最後一個請求:1889當前景 Agent 呼叫完成時,您的 [PostToolUse hook](#posttooluse) 會在 `tool_response` 中接收 subagent 的結果和執行遙測。讀取這些欄位以檢查該次執行;若要彙總跨 subagent 的 token 和成本,請使用篩選 `query_source` 為 `"subagent"` 的 [token 和成本計數器](/docs/zh-TW/monitoring-usage#token-counter),因為 `totalTokens` 和 `usage` 只涵蓋最後一個請求:
1891 1890
1892| 欄位 | 類型 | 範例 | 說明 |1891| 欄位 | 類型 | 範例 | 說明 |
1893| :- | :- | :- | :- |1892| :- | :- | :- | :- |
1894| `status` | string | `"completed"` | 前景 subagent 為 `"completed"`,背景 subagent 為 `"async_launched"`。subagent 預設在背景執行,因此省略 `run_in_background` 的 Agent 呼叫也會產生 `"async_launched"` |1893| `status` | string | `"completed"` | 前景 subagent 為 `"completed"`,背景 subagent 為 `"async_launched"`。subagent 預設在背景執行,因此省略 `run_in_background` 的 Agent 呼叫也會產生 `"async_launched"` |
1895| `agentId` | string | `"a4d2c8f1e0b3a297"` | subagent 執行的識別碼 |1894| `agentId` | string | `"a4d2c8f1e0b3a297"` | subagent 執行的識別碼 |
1896| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | subagent 最終的文字區塊;若 subagent 的報告是透過 `SubagentHandback` 傳遞,則改為關於該交回的簡短說明 |1895| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | subagent 的最終文字區塊;對於透過 `SubagentHandback` 提交報告的 subagent,則以一則關於該移交的簡短說明取代 |
1897| `resolvedModel` | string | `"claude-sonnet-4-5"` | subagent 開始時使用的模型,可能與所請求的模型不同 |1896| `resolvedModel` | string | `"claude-sonnet-4-5"` | subagent 啟動時使用的模型,可能與請求的模型不同 |
1898| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 依序使用的模型,連續重複的項目會合併;僅在執行途中切換模型時設定。需要 Claude Code v2.1.212 或更新版本 |1897| `modelsUsed` | array | `["claude-sonnet-4-5", "claude-haiku-4-5"]` | 依序使用的模型,連續重複者會合併;只在執行途中切換模型時設定。需要 Claude Code v2.1.212 或更新版本 |
1899| `totalTokens` | number | `12450` | subagent 最後一個 API 請求的 token 數:輸入、輸出與快取 token 的總和。這並非整個執行的總計 |1898| `totalTokens` | number | `12450` | subagent 最後一個 API 請求的 token 數:輸入、輸出和快取 token 的合計。這不是整次執行的總計 |
1900| `totalDurationMs` | number | `48211` | subagent 執行的實際時間長度 |1899| `totalDurationMs` | number | `48211` | subagent 執行的實際持續時間 |
1901| `totalToolUseCount` | number | `7` | subagent 進行的工具呼叫次數 |1900| `totalToolUseCount` | number | `7` | subagent 進行的工具呼叫次數 |
1902| `usage` | object | `{"input_tokens": 8320, ...}` | 最後一個 API 請求依類型的 token 明細:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |1901| `usage` | object | `{"input_tokens": 8320, ...}` | 最後一個 API 請求依類型區分的 token 明細:`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens` |
1903 1902
1904在 Claude Code v2.1.271 或更新版本中,使用 [`SubagentHandback`](/docs/zh-TW/tools-reference) 工具(Claude Code 在[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)中提供)執行的 subagent,會透過該工具傳遞其報告,而非以文字回傳。此時其 `completed` 結果的 `content` 欄位攜帶的是關於該交回的簡短說明,而非報告本身。若要讀取報告,請讓 `PreToolUse` 或 `PostToolUse` hook 比對 `SubagentHandback`,並讀取 `tool_input.message`。1903在 Claude Code v2.1.271 或更新版本中,使用 [`SubagentHandback`](/docs/zh-TW/tools-reference) 工具(Claude Code 在[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)中提供)執行的 subagent,會透過該工具提交報告,而不是以文字傳回。其 `completed` 結果的 `content` 欄位此時攜帶的是關於該移交的簡短說明,而非報告本身。若要讀取報告,請讓 `PreToolUse` 或 `PostToolUse` hook 比對 `SubagentHandback`,並讀取 `tool_input.message`。
1905 1904
1906對於背景 subagent,工具會在任務移至背景時回傳,因此 `tool_response` 不攜帶使用量欄位:背景啟動會立即回傳,而 Claude Code 在執行途中移至背景的前景任務則會在該轉換時回傳。它包含 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 與 `resolvedModel`。1905對於背景 subagent,工具會在任務移至背景時傳回,因此 `tool_response` 不會攜帶用量欄位:背景啟動會立即傳回,而被 Claude Code 在執行途中移至背景的前景任務會在轉換時傳回。它包含 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。
1907 1906
1908在 `completed` 回應中,`resolvedModel` 指出 subagent 開始時使用的模型,可能與 `tool_input` 中的 `model` 值不同,例如套用了 `availableModels` 或其他覆寫時。在 `async_launched` 回應中,`resolvedModel` 指出 agent 移至背景時使用中的模型,因此在移至背景之前發生的切換會反映在此。`modelsUsed` 以及移至背景時的 `resolvedModel` 行為需要 Claude Code v2.1.212 或更新版本。1907在 `completed` 回應中,`resolvedModel` 指出 subagent 啟動時使用的模型,可能與 `tool_input` 中的 `model` 值不同,例如當 `availableModels` 或其他覆寫套用時。在 `async_launched` 回應中,`resolvedModel` 指出 agent 移至背景時使用中的模型,因此在移至背景之前發生的切換會反映在其中。`modelsUsed` 以及移至背景時的 `resolvedModel` 行為需要 Claude Code v2.1.212 或更新版本。
1909 1908
1910<a id="askuserquestion" />1909<a id="askuserquestion" />
1911 1910
1913 AskUserQuestion1912 AskUserQuestion
1914</h5>1913</h5>
1915 1914
1916向使用者詢問一到四個選擇題。1915向使用者提出一到四個選擇題。
1917 1916
1918| 欄位 | 類型 | 範例 | 說明 |1917| 欄位 | 類型 | 範例 | 說明 |
1919| :- | :- | :- | :- |1918| :- | :- | :- | :- |
1920| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React", "description": "Component library"}, {"label": "Vue", "description": "Progressive framework"}], "multiSelect": false}]` | 要呈現的問題,每個問題包含 `question` 字串、簡短的 `header`、`options` 陣列,以及選用的 `multiSelect` 旗標 |1919| `questions` | array | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React", "description": "Component library"}, {"label": "Vue", "description": "Progressive framework"}], "multiSelect": false}]` | 要呈現的問題,每個問題包含 `question` 字串、簡短的 `header`、`options` 陣列,以及選用的 `multiSelect` 旗標 |
1921| `answers` | object | `{"Which framework?": "React"}` | 選擇性。將問題文字對應到所選選項的標籤。多選答案會以逗號連接標籤。Claude 不會設定此欄位;請透過 `updatedInput` 提供,以程式化方式作答 |1920| `answers` | object | `{"Which framework?": "React"}` | 選用。將問題文字對應到所選選項的標籤。多選答案會以逗號連接標籤。Claude 不會設定此欄位;請透過 `updatedInput` 提供以程式化方式回答 |
1922 1921
1923<h5 id="exitplanmode">1922<h5 id="exitplanmode">
1924 ExitPlanMode1923 ExitPlanMode
1925</h5>1924</h5>
1926 1925
1927在 Claude 離開 [plan mode](/docs/zh-TW/permission-modes#analyze-before-you-edit-with-plan-mode) 之前呈現計畫並請使用者核准。Claude 在呼叫工具之前會將計畫寫入磁碟上的檔案,因此來自模型的原始 `tool_input` 通常為空。Claude Code 會在將輸入傳遞給 hook 之前注入計畫內容與檔案路徑。1926呈現計畫並請使用者核准,之後 Claude 才會離開 [plan mode](/docs/zh-TW/permission-modes#analyze-before-you-edit-with-plan-mode)。Claude 會在呼叫工具之前將計畫寫入磁碟上的檔案,因此模型提供的原始 `tool_input` 通常是空的。Claude Code 會在將輸入傳給 hook 之前注入計畫內容和檔案路徑。
1928 1927
1929| 欄位 | 類型 | 範例 | 說明 |1928| 欄位 | 類型 | 範例 | 說明 |
1930| :- | :- | :- | :- |1929| :- | :- | :- | :- |
1931| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 格式的計畫內容。從磁碟上的計畫檔案注入 |1930| `plan` | string | `"## Refactor auth\n1. Extract..."` | Markdown 格式的計畫內容。從磁碟上的計畫檔案注入 |
1932| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 計畫檔案的路徑。為注入值 |1931| `planFilePath` | string | `"/Users/.../plans/refactor-auth.md"` | 計畫檔案的路徑。注入 |
1933| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已棄用。Claude Code 接受此欄位但會忽略它。在 v2.1.205 之前,它攜帶 Claude 為實作計畫而請求的提示詞式權限 |1932| `allowedPrompts` | array | `[{"tool": "Bash", "prompt": "run tests"}]` | 已棄用。Claude Code 接受此欄位但會忽略它。在 v2.1.205 之前,它攜帶 Claude 為實作計畫而請求的基於提示詞的權限 |
1934 1933
1935在 `PostToolUse` 中,`tool_response` 是一個物件,包含存放已核准計畫的 `plan` 與 `filePath` 欄位,以及內部狀態旗標。請讀取 `tool_response.plan` 取得計畫內容,而不要從磁碟重新讀取檔案。1934在 `PostToolUse` 中,`tool_response` 是一個物件,其 `plan` 和 `filePath` 欄位包含已核准的計畫,另外還有內部狀態旗標。請讀取 `tool_response.plan` 以取得計畫內容,而不要從磁碟重新讀取檔案。
1936 1935
1937<h4 id="pretooluse-decision-control">1936<h4 id="pretooluse-decision-control">
1938 PreToolUse 決策控制1937 PreToolUse 決策控制
1939</h4>1938</h4>
1940 1939
1941`PreToolUse` hook 可以控制工具呼叫是否繼續。與其他使用頂層 `decision` 欄位的 hook 不同,PreToolUse 會在 `hookSpecificOutput` 物件內回傳其決策。這賦予它更豐富的控制:四種結果(允許、拒絕、詢問或延後),以及在執行前修改工具輸入的能力。1940`PreToolUse` hook 可以控制工具呼叫是否繼續。與其他使用頂層 `decision` 欄位的 hook 不同,PreToolUse 會在 `hookSpecificOutput` 物件內傳回其決策。這讓它擁有更豐富的控制:四種結果(允許、拒絕、詢問或延後),以及在執行前修改工具輸入的能力。
1942 1941
1943| 欄位 | 說明 |1942| 欄位 | 說明 |
1944| :- | :- |1943| :- | :- |
1945| `permissionDecision` | `"allow"` 會略過權限提示,但[任何模式都不會自動核准的動作](/docs/zh-TW/permission-modes#actions-no-mode-auto-approves),以及需要[搭配 `updatedInput`](#allow-with-updatedinput) 的 `AskUserQuestion` 與 `ExitPlanMode` 除外。`"deny"` 會阻止工具呼叫。`"ask"` 會提示使用者確認。`"defer"` 會正常結束,以便稍後繼續執行該工具。無論 hook 回傳什麼,[拒絕與詢問規則](/docs/zh-TW/permissions#manage-permissions)仍會被評估 |1944| `permissionDecision` | `"allow"` 會略過權限提示,但[沒有任何模式會自動核准的動作](/docs/zh-TW/permission-modes#actions-no-mode-auto-approves)以及 `AskUserQuestion` 和 `ExitPlanMode` 除外,後兩者需要[搭配 `updatedInput`](#allow-with-updatedinput)。`"deny"` 會阻止工具呼叫。`"ask"` 會提示使用者確認。`"defer"` 會正常結束,以便稍後恢復該工具。無論 hook 傳回什麼,[拒絕和詢問規則](/docs/zh-TW/permissions#manage-permissions)仍會被評估 |
1946| `permissionDecisionReason` | 對於 `"ask"`,會在權限提示中向使用者顯示。當 Claude Code 在無人能回應該提示的 `-p` 執行中[拒絕呼叫](/docs/zh-TW/headless#turn-off-permission-prompts-in-unattended-runs)時,Claude 會改在工具結果中讀取該原因。對於 `"deny"`,會向 Claude 顯示。對於 `"allow"` 與 `"defer"`,只會寫入[偵錯日誌](#debug-hooks) |1945| `permissionDecisionReason` | 對於 `"ask"`,會在權限提示中顯示給使用者。當 Claude Code 在無人能回應該提示的 `-p` 執行中[拒絕呼叫](/docs/zh-TW/headless#turn-off-permission-prompts-in-unattended-runs)時,Claude 會改在工具結果中讀取該原因。對於 `"deny"`,會顯示給 Claude。對於 `"allow"` 和 `"defer"`,只會寫入[除錯日誌](#debug-hooks) |
1947| `updatedInput` | 在執行前修改工具的輸入參數。會取代整個輸入物件,因此請將未變更的欄位與修改後的欄位一併包含。Claude Code 會針對您的 hook 回傳的輸入(而非 Claude 傳送的輸入)評估權限規則以及 Bash 命令的[自動移至背景資格](/docs/zh-TW/tools-reference#foreground-commands-that-move-to-the-background)。與 `"allow"` 搭配可自動核准,或與 `"ask"` 搭配以向使用者顯示修改後的輸入。對於 `"defer"` 則會被忽略 |1946| `updatedInput` | 在執行前修改工具的輸入參數。會取代整個輸入物件,因此請將未變更的欄位與修改過的欄位一併包含。Claude Code 會依據您的 hook 傳回的輸入(而非 Claude 傳送的輸入)評估權限規則以及 Bash 命令的[自動移至背景資格](/docs/zh-TW/tools-reference#foreground-commands-that-move-to-the-background)。搭配 `"allow"` 可自動核准,或搭配 `"ask"` 向使用者顯示修改後的輸入。對於 `"defer"` 會被忽略 |
1948| `additionalContext` | 與工具結果一同加入 Claude 上下文的字串。當 `permissionDecision` 為 `"defer"` 時會被忽略。請參閱[為 Claude 加入上下文](#add-context-for-claude) |1947| `additionalContext` | 與工具結果一同加入 Claude 上下文的字串。當 `permissionDecision` 為 `"defer"` 時會被忽略。請參閱[為 Claude 加入上下文](#add-context-for-claude) |
1949 1948
1950當多個 PreToolUse hook 回傳不同決策時,優先順序為 `deny` > `defer` > `ask` > `allow`。1949當多個 PreToolUse hook 傳回不同的決策時,優先順序為 `deny` > `defer` > `ask` > `allow`。
1951 1950
1952以退出碼 2 阻擋的 hook 與 `"deny"` 的處理方式相同:Claude 會將 stderr 訊息視為拒絕原因。1951以退出碼 2 阻擋的 hook 與 `"deny"` 的處理方式相同:Claude 會將 stderr 訊息視為拒絕原因。
1953 1952
1954當 hook 回傳 `"ask"` 時,向使用者顯示的權限提示會包含一個標籤,標示該 hook 的來源:來自任何設定檔或 agent frontmatter 的 hook 為 `[settings]`,外掛的 hook 為 `[plugin:<name>]`,來自 skill frontmatter 的 hook 則為 `[skill]`。這有助於使用者了解是哪個設定來源在請求確認。1953當 hook 傳回 `"ask"` 時,顯示給使用者的權限提示會包含一個標示 hook 來源的標籤:來自任何設定檔或 agent frontmatter 的 hook 為 `[settings]`,外掛的 hook 為 `[plugin:<name>]`,來自 skill frontmatter 的 hook 則為 `[skill]`。這可協助使用者了解是哪個設定來源在請求確認。
1955 1954
1956hook 的 `"ask"` 也會在[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)中強制顯示權限提示:分類器仍可拒絕工具呼叫,但無法在無提示的情況下核准該呼叫。在 v2.1.211 之前,分類器可以在不顯示 hook 所請求之提示的情況下,核准在[沙箱](/docs/zh-TW/sandboxing)外執行的 Bash 命令;分類器仍會對該命令套用其自身的安全規則,而 hook 的 `"deny"` 一律會被遵守。1955hook 的 `"ask"` 也會在[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)中強制顯示權限提示:分類器仍可拒絕工具呼叫,但無法在不提示的情況下核准該呼叫。在 v2.1.211 之前,分類器可以在不顯示 hook 所請求之提示的情況下,核准在[沙箱](/docs/zh-TW/sandboxing)外執行的 Bash 命令;分類器仍會對該命令套用自己的安全規則,而 hook 的 `"deny"` 一律會被遵守。
1957 1956
1958```json theme={null}1957```json theme={null}
1959{1958{
1970```1969```
1971 1970
1972<Note>1971<Note>
1973 PreToolUse 以前使用頂層的 `decision` 與 `reason` 欄位,但這些欄位在此事件中已棄用。請改用 `hookSpecificOutput.permissionDecision` 與 `hookSpecificOutput.permissionDecisionReason`。已棄用的值 `"approve"` 與 `"block"` 分別對應到 `"allow"` 與 `"deny"`。PostToolUse 與 Stop 等其他事件則繼續以頂層 `decision` 與 `reason` 作為目前的格式。1972 PreToolUse 先前使用頂層的 `decision` 和 `reason` 欄位,但這些欄位在此事件中已棄用。請改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。已棄用的值 `"approve"` 和 `"block"` 分別對應到 `"allow"` 和 `"deny"`。PostToolUse 和 Stop 等其他事件仍以頂層的 `decision` 和 `reason` 作為目前的格式。
1974</Note>1973</Note>
1975 1974
1976<h4 id="allow-with-updatedinput">1975<h4 id="allow-with-updatedinput">
1977 需要使用者互動的工具1976 需要使用者互動的工具
1978</h4>1977</h4>
1979 1978
1980`AskUserQuestion` 與 `ExitPlanMode` 需要使用者互動。在搭配 `-p` 旗標的[非互動模式](/docs/zh-TW/headless)中,只有當執行有可接收提示的[權限主機](/docs/zh-TW/headless#turn-off-permission-prompts-in-unattended-runs)(例如 Agent SDK 的 `canUseTool` 回呼)時,Claude Code 才會提供這些工具。1979`AskUserQuestion` 和 `ExitPlanMode` 需要使用者互動。在使用 `-p` 旗標的[非互動模式](/docs/zh-TW/headless)中,只有在執行具有可接收提示的[權限主機](/docs/zh-TW/headless#turn-off-permission-prompts-in-unattended-runs)(例如 Agent SDK 的 `canUseTool` 回呼)時,Claude Code 才會提供這些工具。
1981 1980
1982當 `PreToolUse` hook 執行下列動作時,即可滿足該需求:1981當 `PreToolUse` hook 執行下列動作時,即可滿足該需求:
1983 1982
1987 1986
1988對這些工具而言,僅傳回 `"allow"` 是不夠的。1987對這些工具而言,僅傳回 `"allow"` 是不夠的。
1989 1988
1990對於 `AskUserQuestion`,請回傳原始的 `questions` 陣列,並新增一個 [`answers`](#askuserquestion) 物件,將每個問題的文字對應到所選答案。此輸出以 `React` 回答一個問題:1989對於 `AskUserQuestion`,請回傳原始的 `questions` 陣列,並加入一個 [`answers`](#askuserquestion) 物件,將每個問題的文字對應到所選答案。此輸出以 `React` 回答一個問題:
1991 1990
1992```json theme={null}1991```json theme={null}
1993{1992{
2009}2008}
2010```2009```
2011 2010
2012伺服器以 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-TW/mcp#require-approval-for-a-specific-tool) 標記的 MCP 工具則更為嚴格:hook 無法以 `"allow"` 略過其核准提示,無論是否搭配 `updatedInput`,因為 Claude Code 無法確認 hook 已收集該工具所需的互動。2011伺服器以 [`_meta["anthropic/requiresUserInteraction"]`](/docs/zh-TW/mcp#require-approval-for-a-specific-tool) 標記的 MCP 工具則更為嚴格:無論是否搭配 `updatedInput`,hook 都無法以 `"allow"` 略過其核准提示,因為 Claude Code 無法確認 hook 已收集到該工具所需的互動。
2013 2012
2014<h4 id="defer-a-tool-call-for-later">2013<h4 id="defer-a-tool-call-for-later">
2015 延後工具呼叫2014 延後工具呼叫
2016</h4>2015</h4>
2017 2016
2018`"defer"` 適用於以子程序執行 `claude -p` 並讀取其 JSON 輸出的整合,例如 Agent SDK 應用程式或建立在 Claude Code 之上的自訂 UI。它讓呼叫端程序可以在工具呼叫處暫停 Claude、透過自己的介面收集輸入,並從中斷處繼續。Claude Code 只在使用 `-p` 旗標的[非互動模式](/docs/zh-TW/headless)中遵守此值。在互動式工作階段中,它會記錄警告並忽略 hook 結果。2017`"defer"` 適用於以子程序方式執行 `claude -p` 並讀取其 JSON 輸出的整合,例如 Agent SDK 應用程式或建構在 Claude Code 之上的自訂 UI。它讓呼叫端程序可以在工具呼叫處暫停 Claude、透過自己的介面收集輸入,然後從中斷處恢復。Claude Code 只在使用 `-p` 旗標的[非互動模式](/docs/zh-TW/headless)中採用此值。在互動式工作階段中,它會記錄警告並忽略 hook 結果。
2019 2018
2020`AskUserQuestion` 工具是典型的情況:Claude 想向使用者詢問某件事,但沒有可供回答的終端機。`-p` 執行只有在具有[權限主機](/docs/zh-TW/headless#turn-off-permission-prompts-in-unattended-runs)(例如您以 `--permission-prompt-tool` 傳入的 MCP 工具)時才會提供 `AskUserQuestion`,因此請以權限主機啟動執行。往返流程如下:2019`AskUserQuestion` 工具是典型的情況:Claude 想詢問使用者某件事,但沒有終端機可以回答。`-p` 執行只有在具有[權限主機](/docs/zh-TW/headless#turn-off-permission-prompts-in-unattended-runs)(例如您以 `--permission-prompt-tool` 傳入的 MCP 工具)時才會提供 `AskUserQuestion`,因此請以權限主機啟動執行。往返流程如下:
2021 2020
20221. Claude 呼叫 `AskUserQuestion`。`PreToolUse` hook 觸發。20211. Claude 呼叫 `AskUserQuestion`。`PreToolUse` hook 觸發。
20232. hook 回傳 `permissionDecision: "defer"`。工具不會執行。程序以 `stop_reason: "tool_deferred"` 結束,待處理的工具呼叫會保留在逐字稿中。20222. hook 傳回 `permissionDecision: "defer"`。工具不會執行。程序以 `stop_reason: "tool_deferred"` 結束,待處理的工具呼叫保留在逐字稿中。
20243. 呼叫端程序從 SDK 結果讀取 `deferred_tool_use`,在自己的 UI 中呈現問題,並等待答案。20233. 呼叫端程序從 SDK 結果中讀取 `deferred_tool_use`,在自己的 UI 中呈現問題,並等待答案。
20254. 呼叫端程序以相同的權限主機執行 `claude -p --resume <session-id>`。同一個工具呼叫會再次觸發 `PreToolUse`。20244. 呼叫端程序以相同的權限主機執行 `claude -p --resume <session-id>`。同一個工具呼叫再次觸發 `PreToolUse`。
20265. hook 回傳 `permissionDecision: "allow"`,並在 `updatedInput` 中附上答案。工具執行,Claude 繼續。20255. hook 傳回 `permissionDecision: "allow"`,並在 `updatedInput` 中附上答案。工具執行,Claude 繼續。
2027 2026
2028`deferred_tool_use` 欄位攜帶工具的 `id`、`name` 與 `input`。`input` 是 Claude 為該工具呼叫產生的參數,在執行前擷取:2027`deferred_tool_use` 欄位攜帶工具的 `id`、`name` 和 `input`。`input` 是 Claude 為工具呼叫產生的參數,在執行前擷取:
2029 2028
2030```json theme={null}2029```json theme={null}
2031{2030{
2041}2040}
2042```2041```
2043 2042
2044沒有逾時或重試次數限制。工作階段會保留在磁碟上直到您繼續它,但受 [`cleanupPeriodDays`](/docs/zh-TW/settings-reference#cleanupperioddays) 保留清理的限制,該清理預設會在 30 天後刪除工作階段檔案,並遵循[保留清理規則](/docs/zh-TW/claude-directory#cleaned-up-automatically)。如果繼續時答案尚未準備好,hook 可以再次回傳 `"defer"`,程序會以相同方式結束。呼叫端程序藉由最終從 hook 回傳 `"allow"` 或 `"deny"` 來控制何時跳出迴圈。2043沒有逾時或重試次數限制。工作階段會保留在磁碟上直到您恢復它,但受 [`cleanupPeriodDays`](/docs/zh-TW/settings-reference#cleanupperioddays) 保留清理的約束,該清理預設會在 30 天後依照[保留清理規則](/docs/zh-TW/claude-directory#cleaned-up-automatically)刪除工作階段檔案。如果在您恢復時答案尚未準備好,hook 可以再次傳回 `"defer"`,程序會以相同方式結束。呼叫端程序最終透過 hook 傳回 `"allow"` 或 `"deny"` 來決定何時結束迴圈。
2045 2044
2046`"defer"` 只在 Claude 於該回合中只進行一次工具呼叫時有效。如果 Claude 同時進行多個工具呼叫,`"defer"` 會被忽略並發出警告,工具會透過一般的權限流程繼續。此限制的原因在於繼續時只能重新執行一個工具:無法在不讓其他呼叫懸而未決的情況下,延後批次中的其中一個呼叫。2045`"defer"` 只在 Claude 於該回合中進行單一工具呼叫時有效。如果 Claude 一次進行多個工具呼叫,`"defer"` 會被忽略並發出警告,工具則透過一般權限流程繼續進行。此限制的存在是因為恢復時只能重新執行一個工具:無法在不讓其他呼叫處於未解決狀態的情況下,延後一批呼叫中的某一個。
2047 2046
2048如果繼續時延後的工具已不可用,程序會在 hook 觸發之前以 `stop_reason: "tool_deferred_unavailable"` 與 `is_error: true` 結束。當提供該工具的 MCP 伺服器在繼續的工作階段中未連線時,就會發生這種情況。`deferred_tool_use` payload 仍會包含在內,讓您能識別遺失的是哪個工具。2047如果在您恢復時延後的工具已無法使用,程序會在 hook 觸發前以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 結束。當提供該工具的 MCP 伺服器未在恢復的工作階段中連線時,就會發生這種情況。`deferred_tool_use` payload 仍會包含在內,讓您可以識別是哪個工具遺失了。
2049 2048
2050<Note>2049<Note>
2051 若要在 plan mode 中繼續已延後的工作階段,請將 [`--permission-prompt-tool`](/docs/zh-TW/cli-reference#cli-flags) 與 `--resume` 一併傳入,讓 Claude Code 能呈現計畫以供核准。如果您傳入某些其他啟動旗標,繼續的執行不會回到 plan mode;請參閱[使用 `-p` 在 plan mode 中繼續](/docs/zh-TW/sessions#resume-in-plan-mode-with-p)。需要 Claude Code v2.1.246 或更新版本。2050 若要在 plan mode 中恢復延後的工作階段,請將 [`--permission-prompt-tool`](/docs/zh-TW/cli-reference#cli-flags) 與 `--resume` 一起傳入,讓 Claude Code 可以呈現計畫以供核准。如果您傳入某些其他啟動旗標,恢復的執行不會返回 plan mode;請參閱[以 `-p` 在 plan mode 中恢復](/docs/zh-TW/sessions#resume-in-plan-mode-with-p)。需要 Claude Code v2.1.246 或更新版本。
2052 2051
2053 當您以 `-p` 繼續時,Claude Code 不會還原任何其他已儲存的權限模式。它會以新的 `claude -p` 執行所使用的權限模式啟動執行,因此如果延後的工作階段使用了 `--permission-mode` 或 `--dangerously-skip-permissions`,請再次傳入。當您不使用 `-p` 而以 `claude --resume <session-id>` 繼續時,Claude Code 會還原已儲存的權限模式,例外情況列於[繼續時的權限模式](/docs/zh-TW/sessions#permission-mode-on-resume)。2052 當您以 `-p` 恢復時,Claude Code 不會還原任何其他已儲存的權限模式。它會以新的 `claude -p` 執行所使用的權限模式啟動執行,因此如果延後的工作階段使用了 `--permission-mode` 或 `--dangerously-skip-permissions`,請再次傳入。當您以不含 `-p` 的 `claude --resume <session-id>` 恢復時,Claude Code 會還原已儲存的權限模式,例外情況列於[恢復時的權限模式](/docs/zh-TW/sessions#permission-mode-on-resume)。
2054</Note>2053</Note>
2055 2054
2056<h3 id="permissionrequest">2055<h3 id="permissionrequest">
2057 PermissionRequest2056 PermissionRequest
2058</h3>2057</h3>
2059 2058
2060在 Claude Code 即將向您請求使用工具的權限時執行。在無法顯示提示的工作階段中,例如[非互動模式](/docs/zh-TW/headless)中的背景 subagent,Claude Code 仍會執行這些 hook,而如果沒有任何 hook 回傳決策,它就會拒絕該工具呼叫。對於到達 `--permission-prompt-tool` 或 Agent SDK 的 [`canUseTool` 回呼](/docs/zh-TW/agent-sdk/permissions)的呼叫,hook 會與您的主機並行執行,以先做出決定者為準。2059在 Claude Code 即將向您請求使用工具的權限時執行。在無法顯示提示的工作階段中,例如[非互動模式](/docs/zh-TW/headless)中的背景 subagent,Claude Code 仍會執行這些 hook,而如果沒有任何 hook 傳回決策,它會拒絕該工具呼叫。對於送達 `--permission-prompt-tool` 或 Agent SDK [`canUseTool` 回呼](/docs/zh-TW/agent-sdk/permissions)的呼叫,hook 會與您的主機並行執行,以先做出決定者為準。
2061使用 [PermissionRequest 決策控制](#permissionrequest-decision-control)代表使用者允許或拒絕。2060使用 [PermissionRequest 決策控制](#permissionrequest-decision-control)代表使用者允許或拒絕。
2062 2061
2063當您需要在 Claude 請求使用工具權限的當下取得訊號時,請使用此事件。Claude Code 只有在提示已等待約六秒後,才會執行類型為 `permission_prompt` 的 [Notification](#notification) hook。2062當您需要在 Claude 請求使用工具權限的當下取得訊號時,請使用此事件。Claude Code 只會在提示等待約六秒之後,才執行 `permission_prompt` 類型的 [Notification](#notification) hook。
2064 2063
2065Claude Code 不會為沙箱化命令的[網路請求](/docs/zh-TW/sandboxing#network-isolation)執行 PermissionRequest hook。若要取得該提示的訊號,請使用 `permission_prompt` 通知類型。2064Claude Code 不會針對沙箱化命令的[網路請求](/docs/zh-TW/sandboxing#network-isolation)執行 PermissionRequest hook。若要取得該提示的訊號,請使用 `permission_prompt` 通知類型。
2066 2065
2067比對工具名稱,值與 PreToolUse 相同。2066比對工具名稱,值與 PreToolUse 相同。
2068 2067
2070 PermissionRequest 輸入2069 PermissionRequest 輸入
2071</h4>2070</h4>
2072 2071
2073PermissionRequest hook 會像 PreToolUse hook 一樣接收 `tool_name` 與 `tool_input` 欄位,但不含 `tool_use_id`。對於 MCP 工具,它們也會接收 [`mcp_server`](#pretooluse-input) 物件。選擇性的 `permission_suggestions` 陣列包含 Claude Code 為此請求建議的[權限更新](#permission-update-entries),例如新增允許規則或變更權限模式。2072PermissionRequest hook 與 PreToolUse hook 一樣會接收 `tool_name` 和 `tool_input` 欄位,但沒有 `tool_use_id`。對於 MCP 工具,它們也會接收 [`mcp_server`](#pretooluse-input) 物件。選用的 `permission_suggestions` 陣列包含 Claude Code 針對此請求建議的[權限更新](#permission-update-entries),例如新增允許規則或變更權限模式。
2074 2073
2075`permission_suggestions` 陣列並非您所看到選項的精確清單,因為每個權限對話框會建構自己的選項。有些對話框(例如檔案編輯的對話框)完全不讀取此陣列,而是從請求本身衍生選項。會讀取此陣列的對話框,仍可能隱藏其建議保留在陣列中的選項,例如當 [`allowManagedPermissionRulesOnly`](/docs/zh-TW/settings-reference#allowmanagedpermissionrulesonly) 隱藏儲存規則的選項時。它也可能提供沒有對應建議項目的選項,例如 [**Yes, and switch to auto mode**](/docs/zh-TW/permission-modes#switch-permission-modes),它會直接變更權限模式,而非透過權限更新。2074`permission_suggestions` 陣列並不是您所看到選項的確切清單,因為每個權限對話方塊都會建立自己的選項。某些對話方塊(例如檔案編輯的對話方塊)完全不讀取此陣列,而是從請求本身衍生選項。會讀取此陣列的對話方塊仍可能隱藏某個其建議仍保留在陣列中的選項,例如當 [`allowManagedPermissionRulesOnly`](/docs/zh-TW/settings-reference#allowmanagedpermissionrulesonly) 隱藏儲存規則的選項時。它也可能提供沒有對應建議項目的選項,例如 [**Yes, and switch to auto mode**](/docs/zh-TW/permission-modes#switch-permission-modes),它會直接變更權限模式,而不是透過權限更新。
2076 2075
2077PreToolUse hook 會在每次工具呼叫之前執行,無論是否需要權限。PermissionRequest hook 只在 Claude Code 即將向您請求權限時執行,或在它原本會自動拒絕一個無法提示的呼叫時執行。兩個事件都不會為 [`EndConversation`](/docs/zh-TW/tools-reference#endconversation-tool-behavior) 觸發。2076PreToolUse hook 會在每次工具呼叫之前執行,無論是否需要權限。PermissionRequest hook 只在 Claude Code 即將向您請求權限時執行,或在它原本會自動拒絕無法提示的呼叫時執行。這兩個事件都不會針對 [`EndConversation`](/docs/zh-TW/tools-reference#endconversation-tool-behavior) 觸發。
2078 2077
2079```json theme={null}2078```json theme={null}
2080{2079{
2103 PermissionRequest 決策控制2102 PermissionRequest 決策控制
2104</h4>2103</h4>
2105 2104
2106`PermissionRequest` hook 可以允許或拒絕權限請求。除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,您的 hook 指令碼還可以回傳包含下列事件專屬欄位的 `decision` 物件:2105`PermissionRequest` hook 可以允許或拒絕權限請求。除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,您的 hook 指令碼還可以傳回包含下列事件專屬欄位的 `decision` 物件:
2107 2106
2108| 欄位 | 說明 |2107| 欄位 | 說明 |
2109| :- | :- |2108| :- | :- |
2110| `behavior` | `"allow"` 授予權限,`"deny"` 拒絕權限。[拒絕與詢問規則](/docs/zh-TW/permissions#manage-permissions)仍會被評估,因此回傳 `"allow"` 的 hook 不會覆寫相符的拒絕規則 |2109| `behavior` | `"allow"` 授予權限,`"deny"` 拒絕權限。[拒絕和詢問規則](/docs/zh-TW/permissions#manage-permissions)仍會被評估,因此傳回 `"allow"` 的 hook 不會覆寫相符的拒絕規則 |
2111| `updatedInput` | 僅適用於 `"allow"`:在執行前修改工具的輸入參數。會取代整個輸入物件,因此請將未變更的欄位與修改後的欄位一併包含。修改後的輸入會重新針對拒絕與詢問規則評估 |2110| `updatedInput` | 僅適用於 `"allow"`:在執行前修改工具的輸入參數。會取代整個輸入物件,因此請將未變更的欄位與修改過的欄位一併包含。修改後的輸入會再次依據拒絕和詢問規則評估 |
2112| `updatedPermissions` | 僅適用於 `"allow"`:要套用的[權限更新項目](#permission-update-entries)陣列,例如新增允許規則或變更工作階段權限模式 |2111| `updatedPermissions` | 僅適用於 `"allow"`:要套用的[權限更新項目](#permission-update-entries)陣列,例如新增允許規則或變更工作階段權限模式 |
2113| `message` | 僅適用於 `"deny"`:告訴 Claude 權限被拒絕的原因 |2112| `message` | 僅適用於 `"deny"`:告訴 Claude 權限被拒絕的原因 |
2114| `interrupt` | 僅適用於 `"deny"`:若為 `true`,則停止 Claude |2113| `interrupt` | 僅適用於 `"deny"`:若為 `true`,則停止 Claude |
2115 2114
2116以退出碼 2 結束但沒有 `decision` 物件的 hook 不會改變權限流程,其 stderr 會被捨棄。只有 `decision` 物件能授予或拒絕請求。2115以退出碼 2 結束但沒有 `decision` 物件的 hook 不會改變權限流程,其 stderr 也會被捨棄。只有 `decision` 物件能授予或拒絕請求。
2117 2116
2118```json theme={null}2117```json theme={null}
2119{2118{
2133 權限更新項目2132 權限更新項目
2134</h4>2133</h4>
2135 2134
2136`updatedPermissions` 輸出欄位與 [`permission_suggestions` 輸入欄位](#permissionrequest-input)都使用相同的項目物件陣列。每個項目都有一個決定其他欄位的 `type`,以及一個控制變更寫入位置的 `destination`。2135`updatedPermissions` 輸出欄位與 [`permission_suggestions` 輸入欄位](#permissionrequest-input)都使用相同的項目物件陣列。每個項目都有一個 `type`,用來決定其他欄位,以及一個 `destination`,用來控制變更寫入的位置。
2137 2136
2138| `type` | 欄位 | 效果 |2137| `type` | 欄位 | 效果 |
2139| :- | :- | :- |2138| :- | :- | :- |
2140| `addRules` | `rules`、`behavior`、`destination` | 新增權限規則。`rules` 是 `{toolName, ruleContent?}` 物件的陣列。省略 `ruleContent` 即可比對整個工具。`behavior` 為 `"allow"`、`"deny"` 或 `"ask"` |2139| `addRules` | `rules`、`behavior`、`destination` | 新增權限規則。`rules` 是由 `{toolName, ruleContent?}` 物件組成的陣列。省略 `ruleContent` 即可比對整個工具。`behavior` 為 `"allow"`、`"deny"` 或 `"ask"` |
2141| `replaceRules` | `rules`、`behavior`、`destination` | 以提供的 `rules` 取代 `destination` 中所有指定 `behavior` 的規則 |2140| `replaceRules` | `rules`、`behavior`、`destination` | 以提供的 `rules` 取代 `destination` 中指定 `behavior` 的所有規則 |
2142| `removeRules` | `rules`、`behavior`、`destination` | 移除指定 `behavior` 的相符規則 |2141| `removeRules` | `rules`、`behavior`、`destination` | 移除指定 `behavior` 中相符的規則 |
2143| `setMode` | `mode`、`destination` | 變更權限模式。有效模式為 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan`,以及作為 `default` 別名的 `manual` |2142| `setMode` | `mode`、`destination` | 變更權限模式。有效的模式為 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan`,以及作為 `default` 別名的 `manual` |
2144| `addDirectories` | `directories`、`destination` | 新增工作目錄。`directories` 是路徑字串的陣列 |2143| `addDirectories` | `directories`、`destination` | 新增工作目錄。`directories` 是由路徑字串組成的陣列 |
2145| `removeDirectories` | `directories`、`destination` | 移除工作目錄 |2144| `removeDirectories` | `directories`、`destination` | 移除工作目錄 |
2146 2145
2147<Note>2146<Note>
2148 只有在啟動工作階段時已可使用略過模式的情況下,搭配 `bypassPermissions` 的 `setMode` 才會生效:`--dangerously-skip-permissions`、`--permission-mode bypassPermissions`、`--allow-dangerously-skip-permissions`,或在[使用者設定、`--settings` 或受管設定](/docs/zh-TW/settings-reference#permissions-defaultmode)中設定 `permissions.defaultMode: "bypassPermissions"`。否則此更新不會產生任何作用。當 [`permissions.disableBypassPermissionsMode`](/docs/zh-TW/permissions#managed-settings) 停用此模式,或工作階段以[受限模式](/docs/zh-TW/cli-reference#cli-flags)啟動時,此更新同樣不會產生任何作用。2147 只有在啟動工作階段時已可使用略過模式的情況下,帶有 `bypassPermissions` 的 `setMode` 才會生效:`--dangerously-skip-permissions`、`--permission-mode bypassPermissions`、`--allow-dangerously-skip-permissions`,或是在[使用者設定、`--settings` 或受管設定](/docs/zh-TW/settings-reference#permissions-defaultmode)中設定 `permissions.defaultMode: "bypassPermissions"`。否則此更新不會產生任何作用。當 [`permissions.disableBypassPermissionsMode`](/docs/zh-TW/permissions#managed-settings) 停用該模式,或工作階段以[受限模式](/docs/zh-TW/cli-reference#cli-flags)啟動時,此更新同樣不會產生任何作用。
2149 2148
2150 無論 `destination` 為何,`bypassPermissions` 都不會被保存為 `defaultMode`。2149 無論 `destination` 為何,`bypassPermissions` 都不會被保存為 `defaultMode`。
2151</Note>2150</Note>
2152 2151
2153每個項目上的 `destination` 欄位決定變更是保留在記憶體中,還是保存到設定檔。2152每個項目上的 `destination` 欄位決定變更是僅保留在記憶體中,還是保存到設定檔。
2154 2153
2155| `destination` | 寫入位置 |2154| `destination` | 寫入位置 |
2156| :- | :- |2155| :- | :- |
2157| `session` | 僅存在記憶體中,工作階段結束時捨棄 |2156| `session` | 僅存在於記憶體中,工作階段結束時捨棄 |
2158| `localSettings` | `.claude/settings.local.json` |2157| `localSettings` | `.claude/settings.local.json` |
2159| `projectSettings` | `.claude/settings.json` |2158| `projectSettings` | `.claude/settings.json` |
2160| `userSettings` | `~/.claude/settings.json` |2159| `userSettings` | `~/.claude/settings.json` |
2161 2160
2162hook 可以將其收到的某個 `permission_suggestions` 原樣作為自己的 `updatedPermissions` 輸出傳回。2161hook 可以將收到的其中一個 `permission_suggestions` 原樣回傳,作為自己的 `updatedPermissions` 輸出。
2163 2162
2164<h3 id="posttooluse">2163<h3 id="posttooluse">
2165 PostToolUse2164 PostToolUse
2169 2168
2170依工具名稱比對,可用值與 PreToolUse 相同。2169依工具名稱比對,可用值與 PreToolUse 相同。
2171 2170
2172當工具名稱不是合適的篩選條件時,可以更廣泛地比對:2171當工具名稱不是適合的篩選條件時,可以更廣泛地比對:
2173 2172
2174* 若要在任何工具成功完成後執行 hook,請省略 `matcher` 或將其設為 `"*"`。您的 hook 接著可以自行找出變更內容,例如執行 `git status --porcelain`,它也會列出 `git diff` 遺漏的未追蹤檔案。對於失敗的工具呼叫,請在 [PostToolUseFailure](#posttoolusefailure) 下新增相同的 hook。2173* 若要在任何工具成功完成後執行 hook,請省略 `matcher` 或將其設為 `"*"`。接著您的 hook 可以自行找出變更內容,例如執行 `git status --porcelain`,它也會列出 `git diff` 遺漏的未追蹤檔案。對於失敗的工具呼叫,請在 [PostToolUseFailure](#posttoolusefailure) 下新增相同的 hook。
2175* 若要在特定檔案於磁碟上變更時執行 hook(無論由誰寫入),請使用 [FileChanged](#filechanged)。當 `Bash` 命令或 Claude Code 以外的程序改寫同一個檔案時,Claude Code 不會執行比對 `Edit|Write` 的 `PostToolUse` hook。2174* 若要在特定檔案於磁碟上變更時執行 hook(無論是誰寫入的),請使用 [FileChanged](#filechanged)。當 `Bash` 命令或 Claude Code 之外的程序重寫同一個檔案時,Claude Code 不會執行比對 `Edit|Write` 的 `PostToolUse` hook。
2176 2175
2177<h4 id="posttooluse-input">2176<h4 id="posttooluse-input">
2178 PostToolUse 輸入2177 PostToolUse 輸入
2179</h4>2178</h4>
2180 2179
2181`PostToolUse` hook 會在工具已成功執行後觸發。輸入同時包含 `tool_input`(傳送給工具的引數)與 `tool_response`(工具傳回的結果)。兩者的確切 schema 取決於工具。檔案工具的 `tool_input` 路徑格式與 [PreToolUse](#pretooluse-input) 相同:一律為絕對路徑,並使用平台原生的分隔符號,因此在 Windows 上為反斜線。對於 MCP 工具,輸入也會帶有 [`mcp_server`](#pretooluse-input) 物件。2180`PostToolUse` hook 會在工具已成功執行後觸發。輸入同時包含 `tool_input`(傳送給工具的引數)與 `tool_response`(工具回傳的結果)。兩者的確切 schema 取決於工具。檔案工具的 `tool_input` 路徑格式與 [PreToolUse](#pretooluse-input) 相同:一律為絕對路徑,並使用平台原生的分隔符號,因此在 Windows 上為反斜線。若為 MCP 工具,輸入中也會帶有 [`mcp_server`](#pretooluse-input) 物件。
2182 2181
2183```json theme={null}2182```json theme={null}
2184{2183{
2203 2202
2204| 欄位 | 說明 |2203| 欄位 | 說明 |
2205| :- | :- |2204| :- | :- |
2206| `duration_ms` | 選用。工具執行時間(毫秒)。不包含花在權限提示與 PreToolUse hook 上的時間 |2205| `duration_ms` | 選用。工具執行時間(毫秒)。不包含權限提示與 PreToolUse hook 所花費的時間 |
2207 2206
2208<h4 id="posttooluse-decision-control">2207<h4 id="posttooluse-decision-control">
2209 PostToolUse 決策控制2208 PostToolUse 決策控制
2210</h4>2209</h4>
2211 2210
2212`PostToolUse` hook 可以在工具執行後向 Claude 提供回饋。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)之外,您的 hook 指令碼還可以傳回以下事件專屬欄位:2211`PostToolUse` hook 可以在工具執行後向 Claude 提供回饋。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)外,您的 hook 指令碼還可以回傳下列事件專屬欄位:
2213 2212
2214| 欄位 | 說明 |2213| 欄位 | 說明 |
2215| :- | :- |2214| :- | :- |
2216| `decision` | `"block"` 會將 `reason` 附加在工具結果旁。Claude 仍會看到原始輸出;若要取代輸出,請使用 `updatedToolOutput` |2215| `decision` | `"block"` 會將 `reason` 附加在工具結果旁。Claude 仍會看到原始輸出;若要取代它,請使用 `updatedToolOutput` |
2217| `reason` | 當 `decision` 為 `"block"` 時向 Claude 顯示的說明 |2216| `reason` | 當 `decision` 為 `"block"` 時向 Claude 顯示的說明 |
2218| `additionalContext` | 與工具結果一併加入 Claude 上下文的字串。請參閱[為 Claude 新增上下文](#add-context-for-claude) |2217| `additionalContext` | 與工具結果一起加入 Claude 上下文的字串。請參閱[為 Claude 新增上下文](#add-context-for-claude) |
2219| `classifierContext` | 關於此次呼叫結果的簡短註記,提供給[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)分類器而非 Claude。請參閱[為自動模式分類器註記結果](#annotate-a-result-for-the-auto-mode-classifier)。需要 Claude Code v2.1.236 或更新版本 |2218| `classifierContext` | 針對此次呼叫結果的簡短註記,提供給[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)分類器而非 Claude。請參閱[為自動模式分類器註記結果](#annotate-a-result-for-the-auto-mode-classifier)。需要 Claude Code v2.1.236 或更新版本 |
2220| `updatedToolOutput` | 在傳送給 Claude 之前,以提供的值取代工具的輸出。該值必須符合工具的輸出結構 |2219| `updatedToolOutput` | 在工具輸出傳送給 Claude 之前,以提供的值取代該輸出。此值必須符合工具的輸出結構 |
2221| `updatedMCPToolOutput` | 僅取代 [MCP 工具](#match-mcp-tools)的輸出。建議改用適用於所有工具的 `updatedToolOutput` |2220| `updatedMCPToolOutput` | 僅取代 [MCP 工具](#match-mcp-tools)的輸出。建議改用適用於所有工具的 `updatedToolOutput` |
2222 2221
2223以下範例取代 `Bash` 呼叫的輸出。取代值符合 `Bash` 工具的輸出結構:2222以下範例會取代 `Bash` 呼叫的輸出。取代值符合 `Bash` 工具的輸出結構:
2224 2223
2225```json theme={null}2224```json theme={null}
2226{2225{
2238```2237```
2239 2238
2240<Warning>2239<Warning>
2241 `updatedToolOutput` 只會改變 Claude 看到的內容。hook 觸發時工具已經執行完畢,因此任何已寫入的檔案、已執行的命令或已送出的網路請求都已生效。OpenTelemetry 工具 span 與分析事件等遙測資料,也會在 hook 執行前擷取原始輸出。若要在工具呼叫執行前阻止或修改它,請改用 [PreToolUse](#pretooluse) hook。2240 `updatedToolOutput` 只會改變 Claude 看到的內容。hook 觸發時工具已經執行完畢,因此任何已寫入的檔案、已執行的命令或已傳送的網路請求都已經生效。OpenTelemetry 工具 span 與分析事件等遙測資料也會在 hook 執行前擷取原始輸出。若要在工具呼叫執行前阻止或修改它,請改用 [PreToolUse](#pretooluse) hook。
2242 2241
2243 取代值必須符合工具的輸出結構。內建工具傳回的是結構化物件,而非純字串。例如,`Bash` 會傳回包含 `stdout`、`stderr`、`interrupted` 與 `isImage` 欄位的物件。對於內建工具,不符合工具輸出 schema 的值會被忽略,並改用原始輸出。MCP 工具的輸出則會直接傳遞,不進行 schema 驗證。移除 Claude 所需的錯誤細節,可能導致它依據錯誤的假設繼續進行。2242 取代值必須符合工具的輸出結構。內建工具回傳的是結構化物件,而非純字串。例如,`Bash` 回傳的物件包含 `stdout`、`stderr`、`interrupted` 與 `isImage` 欄位。對於內建工具,不符合工具輸出 schema 的值會被忽略,並改用原始輸出。MCP 工具的輸出則會直接傳遞,不經 schema 驗證。移除 Claude 需要的錯誤細節,可能導致它基於錯誤的假設繼續進行。
2244</Warning>2243</Warning>
2245 2244
2246<h4 id="annotate-a-result-for-the-auto-mode-classifier">2245<h4 id="annotate-a-result-for-the-auto-mode-classifier">
2247 為自動模式分類器註記結果2246 為自動模式分類器註記結果
2248</h4>2247</h4>
2249 2248
2250傳回 `classifierContext`,即可將關於工具呼叫結果的簡短註記傳送給[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)分類器,而非傳送給 Claude。分類器[永遠不會收到工具結果本身](/docs/zh-TW/permission-modes#how-the-classifier-evaluates-actions),因此在它審查後續動作之前,此欄位是告知它某次呼叫傳回內容的官方支援方式。此欄位需要 Claude Code v2.1.236 或更新版本。2249回傳 `classifierContext`,即可將關於工具呼叫結果的簡短註記傳送給[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)分類器,而非傳送給 Claude。分類器[永遠不會收到工具結果本身](/docs/zh-TW/permission-modes#how-the-classifier-evaluates-actions),因此這個欄位是在分類器審查後續動作之前,告知它某次呼叫回傳了什麼的受支援方式。此欄位需要 Claude Code v2.1.236 或更新版本。
2251 2250
2252以下範例告訴分類器某個查詢的輸出來源:2251以下範例告知分類器某個查詢輸出的來源:
2253 2252
2254```json theme={null}2253```json theme={null}
2255{2254{
2260}2259}
2261```2260```
2262 2261
2263分類器對註記的重視程度,取決於您在何處設定該 hook:2262分類器對此註記的重視程度,取決於您在何處設定該 hook:
2264 2263
2265* **在 Claude Code 中設定的 hook**:對於來自設定檔、外掛、skill 與 agent frontmatter 的 hook,分類器會將註記視為未經驗證、由應用程式提供的上下文。註記永遠無法確立使用者意圖;若註記聲稱您核准或要求了某件事,分類器會以您在對話中的訊息查核該聲明2264* **在 Claude Code 中設定的 hook**:對於來自設定檔、外掛、skill 與 agent frontmatter 的 hook,分類器會將註記視為未經驗證、由應用程式提供的上下文。註記永遠不會確立使用者意圖;若註記聲稱您核准或要求了某件事,分類器會將該聲明與您在對話中的實際訊息進行核對
2266* **行程內 Agent SDK 回呼**:當嵌入 Claude Code 的應用程式將 hook 註冊為 [TypeScript SDK 回呼](/docs/zh-TW/agent-sdk/hooks),並在即時工作階段中傳回註記時,分類器可能會將註記中轉述的使用者陳述視為使用者意圖。此類陳述可以滿足分類器原本會接受您傳送訊息來滿足的同意要求,但永遠無法解除您自己的訊息也無法解除的封鎖。工作階段恢復後,Claude Code 會將還原的註記視為未經驗證的上下文。當兩組來源的 hook 都為同一次呼叫加上註記時,分類器會將合併後的註記視為未經驗證2265* **程序內的 Agent SDK 回呼**:當嵌入 Claude Code 的應用程式將 hook 註冊為 [TypeScript SDK 回呼](/docs/zh-TW/agent-sdk/hooks),並在即時工作階段期間回傳註記時,分類器可能會將註記中轉述的使用者陳述視為使用者意圖。這類陳述可以滿足分類器原本會接受來自您訊息的同意要求,但它永遠無法解除您自己的訊息也無法解除的封鎖。工作階段恢復後,Claude Code 會將還原的註記視為未經驗證的上下文。當兩類來源的 hook 都為同一次呼叫加上註記時,分類器會將合併後的註記視為未經驗證
2267 2266
2268Claude Code 在傳遞註記時會套用以下限制:2267Claude Code 在傳遞註記時會套用下列限制:
2269 2268
2270* **長度**:Claude Code 將單次工具呼叫的註記上限設為 2,000 個字元,超出部分會被截斷。此上限由回應該次呼叫的所有 hook 共用2269* **長度**:Claude Code 將單一工具呼叫的註記上限設為 2,000 個字元,超出部分會被截斷。此上限由回應該呼叫的所有 hook 共用
2271* **僅限同步回應**:對於[在背景執行](#run-hooks-in-the-background)的 hook,Claude Code 會忽略其回應中的此欄位,因為該回應會在 Claude Code 記錄工具結果之後才抵達2270* **僅限同步回應**:對於[在背景執行](#run-hooks-in-the-background)的 hook,Claude Code 會忽略其回應中的此欄位,因為該回應會在 Claude Code 記錄工具結果之後才抵達
2272* **分類器未記錄的呼叫**:分類器的逐字稿會省略唯讀查詢,例如檔案讀取與搜尋。附加在這類呼叫上的註記會被 Claude Code 捨棄2271* **分類器不記錄的呼叫**:分類器的逐字稿會省略唯讀查詢,例如檔案讀取與搜尋。附加在這類呼叫上的註記會被 Claude Code 捨棄
2273* **與改寫的互動**:當註記描述的是您正以 `updatedToolOutput` 取代的輸出時,請在同一個 hook 回應中同時傳回這兩個欄位。若該改寫遭到拒絕,或被另一個 hook 的改寫取代,Claude Code 會捨棄該註記。若您傳回註記但未改寫,即使另一個 hook 改寫了輸出,Claude Code 仍會傳遞您的註記2272* **與改寫的互動**:當註記描述的是您以 `updatedToolOutput` 取代的輸出時,請在同一個 hook 回應中回傳這兩個欄位。若該改寫遭到拒絕,或被另一個 hook 的改寫取代,Claude Code 會捨棄該註記。若您回傳註記時未搭配改寫,即使另一個 hook 改寫了輸出,Claude Code 仍會傳遞該註記
2274 2273
2275<Warning>2274<Warning>
2276 分類器會將您放入 `classifierContext` 的內容視為來自託管工作階段之應用程式的資訊,因此請勿將不受信任的工具輸出或第三方文字複製到其中。請將註記限制為關於這一次呼叫的簡短陳述,例如其來源的相關事實,或使用者對其的陳述;請勿使用此欄位傳遞無關的訊息或一連串事件。2275 分類器會將您放在 `classifierContext` 中的內容視為來自託管該工作階段之應用程式的資訊,因此請勿將不受信任的工具輸出或第三方文字複製到其中。請將註記限定為關於這一次呼叫的簡短斷言,例如關於其來源的事實,或使用者對此呼叫的陳述;請勿使用此欄位傳遞無關的訊息或一連串事件。
2277</Warning>2276</Warning>
2278 2277
2279<h3 id="posttoolusefailure">2278<h3 id="posttoolusefailure">
2280 PostToolUseFailure2279 PostToolUseFailure
2281</h3>2280</h3>
2282 2281
2283當已開始執行的工具失敗時執行:工具擲出錯誤,或 MCP 工具傳回錯誤結果。可用來記錄失敗、傳送警示,或向 Claude 提供修正回饋。2282在已開始執行的工具失敗時執行:工具拋出錯誤,或 MCP 工具回傳錯誤結果。可用來記錄失敗、傳送警示,或向 Claude 提供修正性回饋。
2284 2283
2285依工具名稱比對,可用值與 PreToolUse 相同。2284依工具名稱比對,可用值與 PreToolUse 相同。
2286 2285
2287<Note>2286<Note>
2288 對於在執行前即遭拒絕的工具呼叫,此事件不會觸發:未知的工具名稱、未通過 schema 或工具專屬驗證的輸入,或權限遭拒。驗證拒絕會以 `tool_use_error` 結果傳回,且發生在 hook 執行之前,因此既不會觸發 `PreToolUse`,也不會觸發 `PostToolUseFailure`。權限遭拒會觸發 `PreToolUse`,但不會觸發此事件;請參閱 [PermissionDenied](#permissiondenied)。2287 對於在執行前就被拒絕的工具呼叫,此事件不會觸發:未知的工具名稱、未通過 schema 或工具專屬驗證的輸入,或權限遭拒。驗證拒絕會以 `tool_use_error` 結果回傳,且發生在 hook 執行之前,因此既不會觸發 `PreToolUse`,也不會觸發 `PostToolUseFailure`。權限遭拒會觸發 `PreToolUse`,但不會觸發此事件;請參閱 [PermissionDenied](#permissiondenied)。
2289</Note>2288</Note>
2290 2289
2291<h4 id="posttoolusefailure-input">2290<h4 id="posttoolusefailure-input">
2292 PostToolUseFailure 輸入2291 PostToolUseFailure 輸入
2293</h4>2292</h4>
2294 2293
2295PostToolUseFailure hook 會收到與 PostToolUse 相同的 `tool_name` 與 `tool_input` 欄位,以及作為頂層欄位的錯誤資訊。對於 MCP 工具,它們也會收到 [`mcp_server`](#pretooluse-input) 物件。例如,失敗的 `npm test` 命令可能會傳遞:2294PostToolUseFailure hook 會收到與 PostToolUse 相同的 `tool_name` 與 `tool_input` 欄位,以及作為頂層欄位的錯誤資訊。若為 MCP 工具,還會收到 [`mcp_server`](#pretooluse-input) 物件。例如,失敗的 `npm test` 命令可能會傳遞:
2296 2295
2297```json theme={null}2296```json theme={null}
2298{2297{
2315 2314
2316| 欄位 | 說明 |2315| 欄位 | 說明 |
2317| :- | :- |2316| :- | :- |
2318| `error` | 描述錯誤內容的字串。格式取決於失敗的工具 |2317| `error` | 描述問題的字串。格式取決於失敗的工具 |
2319| `is_interrupt` | 選用布林值。當失敗是以中止的形式傳到 Claude Code,而非工具回報的錯誤時為 true。取消正在執行的工具不會觸發此 hook;工具結果會改為帶有中斷訊息 |2318| `is_interrupt` | 選用的布林值。當失敗是以中止的形式傳達給 Claude Code,而非由工具回報的錯誤時為 true。取消執行中的工具不會觸發此 hook;工具結果會改為帶有中斷訊息 |
2320| `duration_ms` | 選用。工具執行時間(毫秒)。不包含花在權限提示與 PreToolUse hook 上的時間 |2319| `duration_ms` | 選用。工具執行時間(毫秒)。不包含權限提示與 PreToolUse hook 所花費的時間 |
2321 2320
2322`error` 字串通常與 Claude 收到的失敗工具結果文字相同。其格式因工具與失敗情況而異。請讓您的 hook 依據 `tool_name`、`is_interrupt` 以及第一行的 `Exit code N` 判斷;字串的其餘部分請視為顯示用文字,而非穩定的格式。2321`error` 字串通常與 Claude 收到的失敗工具結果文字相同。其格式因工具與失敗情況而異。請讓您的 hook 依據 `tool_name`、`is_interrupt` 以及第一行的 `Exit code N` 來判斷;字串的其餘部分請視為顯示文字,而非穩定的格式。
2323 2322
2324* 對於 Bash 與 PowerShell,已執行並結束的命令會產生第一行 `Exit code N`,接著是命令產生的任何輸出,以 stdout 與 stderr 交錯的單一區塊呈現2323* 對於 Bash 與 PowerShell,已執行並結束的命令會產生第一行 `Exit code N`,接著是命令產生的所有輸出,stdout 與 stderr 交錯成一個區塊
2325* 當 Claude Code 無法啟動 shell 程序本身時,payload 也可能只帶有單純的失敗訊息,沒有退出碼那一行2324* 當 Claude Code 無法啟動 shell 程序本身時,payload 也可能只帶有一則沒有退出碼行的失敗訊息
2326* Claude Code 會在 `... [N characters truncated] ...` 標記周圍截斷長字串的中間部分,也可能插入自己的文字行,例如 `Command timed out after 2m 0s`2325* Claude Code 會在 `... [N characters truncated] ...` 標記周圍對長字串進行中段截斷,並可能插入自己的行,例如 `Command timed out after 2m 0s`
2327 2326
2328<h4 id="posttoolusefailure-decision-control">2327<h4 id="posttoolusefailure-decision-control">
2329 PostToolUseFailure 決策控制2328 PostToolUseFailure 決策控制
2330</h4>2329</h4>
2331 2330
2332`PostToolUseFailure` hook 可以在工具失敗後向 Claude 提供上下文。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)之外,您的 hook 指令碼還可以傳回以下事件專屬欄位:2331`PostToolUseFailure` hook 可以在工具失敗後向 Claude 提供上下文。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)外,您的 hook 指令碼還可以回傳下列事件專屬欄位:
2333 2332
2334| 欄位 | 說明 |2333| 欄位 | 說明 |
2335| :- | :- |2334| :- | :- |
2336| `additionalContext` | 與錯誤一併加入 Claude 上下文的字串。請參閱[為 Claude 新增上下文](#add-context-for-claude) |2335| `additionalContext` | 與錯誤一起加入 Claude 上下文的字串。請參閱[為 Claude 新增上下文](#add-context-for-claude) |
2337 2336
2338```json theme={null}2337```json theme={null}
2339{2338{
2348 PostToolBatch2347 PostToolBatch
2349</h3>2348</h3>
2350 2349
2351在批次中的每個工具呼叫都已解決後執行一次,時間點在 Claude Code 將下一個請求傳送給模型之前。`PostToolUse` 會針對每個工具觸發一次,這表示當 Claude 進行平行工具呼叫時,它會同時觸發。`PostToolBatch` 則會帶著完整批次恰好觸發一次,因此適合用來注入取決於已執行工具集合、而非任何單一工具的上下文。此事件沒有 matcher。2350在一個批次中的每個工具呼叫都處理完畢後執行一次,時間點在 Claude Code 向模型傳送下一個請求之前。`PostToolUse` 會針對每個工具觸發一次,這表示當 Claude 進行平行工具呼叫時,它會同時觸發多次。`PostToolBatch` 則會以完整批次恰好觸發一次,因此適合用來注入取決於所執行工具集合、而非任何單一工具的上下文。此事件沒有 matcher。
2352 2351
2353<h4 id="posttoolbatch-input">2352<h4 id="posttoolbatch-input">
2354 PostToolBatch 輸入2353 PostToolBatch 輸入
2355</h4>2354</h4>
2356 2355
2357除了[通用輸入欄位](#common-input-fields)之外,PostToolBatch hook 還會收到 `tool_calls`,這是描述批次中每個工具呼叫的陣列:2356除了[共通輸入欄位](#common-input-fields)外,PostToolBatch hook 還會收到 `tool_calls`,這是一個描述批次中每個工具呼叫的陣列:
2358 2357
2359```json theme={null}2358```json theme={null}
2360{2359{
2380}2379}
2381```2380```
2382 2381
2383`tool_response` 包含與模型在對應 `tool_result` 區塊中收到的相同內容。其值為序列化字串或內容區塊陣列,與工具輸出時完全相同。對於 `Read`,這表示是帶有行號前綴的文字,而非原始檔案內容。回應可能很大,因此請只解析您需要的欄位。2382`tool_response` 包含的內容與模型在對應 `tool_result` 區塊中收到的內容相同。其值為序列化字串或內容區塊陣列,與工具產生時完全一致。以 `Read` 為例,這代表帶有行號前綴的文字,而非原始檔案內容。回應可能很大,因此請只解析您需要的欄位。
2384 2383
2385<Note>2384<Note>
2386 `tool_response` 的結構與 `PostToolUse` 的不同。`PostToolUse` 傳遞的是工具的結構化 `Output` 物件,例如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 傳遞的則是模型看到的序列化 `tool_result` 內容。2385 `tool_response` 的結構與 `PostToolUse` 的不同。`PostToolUse` 傳遞的是工具的結構化 `Output` 物件,例如 `Write` 的 `{filePath: "...", type: "create"}`;`PostToolBatch` 傳遞的則是模型看到的序列化 `tool_result` 內容。
2390 PostToolBatch 決策控制2389 PostToolBatch 決策控制
2391</h4>2390</h4>
2392 2391
2393`PostToolBatch` hook 可以為 Claude 注入上下文。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)之外,您的 hook 指令碼還可以傳回以下事件專屬欄位:2392`PostToolBatch` hook 可以為 Claude 注入上下文。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)外,您的 hook 指令碼還可以回傳下列事件專屬欄位:
2394 2393
2395| 欄位 | 說明 |2394| 欄位 | 說明 |
2396| :- | :- |2395| :- | :- |
2397| `additionalContext` | 在下一次模型呼叫之前注入一次的上下文字串。關於傳遞細節、應放入的內容,以及恢復的工作階段如何處理過去的值,請參閱[為 Claude 新增上下文](#add-context-for-claude) |2396| `additionalContext` | 在下一次模型呼叫前注入一次的上下文字串。關於傳遞細節、應放入的內容,以及恢復的工作階段如何處理過去的值,請參閱[為 Claude 新增上下文](#add-context-for-claude) |
2398 2397
2399```json theme={null}2398```json theme={null}
2400{2399{
2405}2404}
2406```2405```
2407 2406
2408傳回 `decision: "block"` 或 `continue: false` 會在下一次模型呼叫之前停止代理式迴圈。封鎖訊息來自 JSON 的 `reason` 或 `stopReason`,或在退出碼 2 時來自 stderr。您會在逐字稿中看到它以警告形式呈現,且它會保留在對話中,因此對話繼續時 Claude 會看到它。2407回傳 `decision: "block"` 或 `continue: false` 會在下一次模型呼叫前停止代理式迴圈。封鎖訊息來自 JSON 的 `reason` 或 `stopReason`,或在退出碼 2 時來自 stderr。您會在逐字稿中看到它以警告形式顯示,且它會保留在對話中,因此對話繼續時 Claude 也會看到它。
2409 2408
2410<h3 id="permissiondenied">2409<h3 id="permissiondenied">
2411 PermissionDenied2410 PermissionDenied
2412</h3>2411</h3>
2413 2412
2414當[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)拒絕工具呼叫時執行,包括因[與自動模式分開的安全檢查拒絕了分類器本身的請求](/docs/zh-TW/errors#auto-mode-cannot-determine-the-safety-of-an-action)或其回應無法解析,而在沒有分類器判定的情況下拒絕時。此 hook 只在自動模式下觸發:當您手動拒絕權限對話框、`PreToolUse` hook 封鎖呼叫,或 `deny` 規則相符時,它都不會執行。可用來記錄拒絕情況、調整設定,或告知模型可以重試該工具呼叫。2413在[自動模式](/docs/zh-TW/permission-modes#eliminate-prompts-with-auto-mode)拒絕工具呼叫時執行,包括在沒有分類器判定的情況下拒絕,原因是[與自動模式分開的安全檢查拒絕了分類器本身的請求](/docs/zh-TW/errors#auto-mode-cannot-determine-the-safety-of-an-action),或分類器的回應無法解析。此 hook 只會在自動模式下觸發:當您手動拒絕權限對話方塊、`PreToolUse` hook 封鎖呼叫,或 `deny` 規則相符時,它都不會執行。可用來記錄拒絕、調整設定,或告知模型它可以重試該工具呼叫。
2415 2414
2416依工具名稱比對,可用值與 PreToolUse 相同。2415依工具名稱比對,可用值與 PreToolUse 相同。
2417 2416
2419 PermissionDenied 輸入2418 PermissionDenied 輸入
2420</h4>2419</h4>
2421 2420
2422除了[通用輸入欄位](#common-input-fields)之外,PermissionDenied hook 還會收到 `tool_name`、`tool_input`、`tool_use_id` 與 `reason`。對於 MCP 工具,它們也會收到 [`mcp_server`](#pretooluse-input) 物件。2421除了[共通輸入欄位](#common-input-fields)外,PermissionDenied hook 還會收到 `tool_name`、`tool_input`、`tool_use_id` 與 `reason`。若為 MCP 工具,還會收到 [`mcp_server`](#pretooluse-input) 物件。
2423 2422
2424```json theme={null}2423```json theme={null}
2425{2424{
2440 2439
2441| 欄位 | 說明 |2440| 欄位 | 說明 |
2442| :- | :- |2441| :- | :- |
2443| `reason` | 拒絕原因。對於分類器判定,在大多數工作階段中,它會以方括號標示相符的規則,例如 `[Data Exfiltration]`;其他形式請參閱[檢閱拒絕](/docs/zh-TW/auto-mode-config#review-denials)。對於[無判定的拒絕](#permissiondenied-decision-control),它以 `Auto mode could not evaluate this action and is blocking it for safety` 開頭。對於因分類器模型無法使用而造成的拒絕,它是固定文字 `Classifier unavailable` |2442| `reason` | 拒絕原因。若為分類器判定,在大多數工作階段中會以方括號標示相符的規則,例如 `[Data Exfiltration]`;其他形式請參閱[檢視拒絕](/docs/zh-TW/auto-mode-config#review-denials)。若為[無判定的拒絕](#permissiondenied-decision-control),則以 `Auto mode could not evaluate this action and is blocking it for safety` 開頭。若因分類器模型無法使用而拒絕,則為固定文字 `Classifier unavailable` |
2444 2443
2445<h4 id="permissiondenied-decision-control">2444<h4 id="permissiondenied-decision-control">
2446 PermissionDenied 決策控制2445 PermissionDenied 決策控制
2447</h4>2446</h4>
2448 2447
2449PermissionDenied hook 可以告知模型它可以重試遭拒的工具呼叫。傳回將 `hookSpecificOutput.retry` 設為 `true` 的 JSON 物件:2448PermissionDenied hook 可以告知模型它可以重試遭拒的工具呼叫。回傳一個將 `hookSpecificOutput.retry` 設為 `true` 的 JSON 物件:
2450 2449
2451```json theme={null}2450```json theme={null}
2452{2451{
2457}2456}
2458```2457```
2459 2458
2460當 `retry` 為 `true` 時,Claude Code 會在對話中加入一則訊息,告知模型可以重試該工具呼叫。Claude Code 本身不會撤銷拒絕。如果您的 hook 未傳回 JSON,或傳回 `retry: false`,拒絕將維持不變,模型會收到原始的拒絕訊息。2459當 `retry` 為 `true` 時,Claude Code 會在對話中加入一則訊息,告知模型它可以重試該工具呼叫。Claude Code 本身不會撤銷該拒絕。如果您的 hook 沒有回傳 JSON,或回傳 `retry: false`,拒絕就會維持,模型會收到原始的拒絕訊息。
2461 2460
2462當分類器[未對該動作做出判定](/docs/zh-TW/errors#auto-mode-cannot-determine-the-safety-of-an-action)時,Claude Code 會忽略 `retry: true`:即其回應無法解析,或與自動模式分開的安全檢查拒絕了分類器本身的請求。對於這些拒絕,Claude Code 已會在拒絕訊息中告知模型應稍後重試或繼續進行其他工作。2461當分類器[對該動作沒有做出判定](/docs/zh-TW/errors#auto-mode-cannot-determine-the-safety-of-an-action)時,Claude Code 會忽略 `retry: true`:分類器的回應無法解析,或與自動模式分開的安全檢查拒絕了分類器本身的請求。對於這些拒絕,Claude Code 已在拒絕訊息中告知模型應稍後重試還是繼續進行。
2463 2462
2464<h3 id="notification">2463<h3 id="notification">
2465 Notification2464 Notification
2467 2466
2468在 Claude Code 傳送通知時執行。依通知類型比對。省略 matcher 即可針對所有通知類型執行 hook。2467在 Claude Code 傳送通知時執行。依通知類型比對。省略 matcher 即可針對所有通知類型執行 hook。
2469 2468
2470即使關閉桌面通知,您仍會收到這些 hook 事件:`preferredNotifChannel` 設定(包括 `notifications_disabled`)只會改變提醒您的方式,不會影響您的 hook 是否執行。2469即使關閉桌面通知,您仍會收到這些 hook 事件:`preferredNotifChannel` 設定(包括 `notifications_disabled`)只會改變您收到提醒的方式,而不會影響您的 hook 是否執行。
2471 2470
2472| Matcher | 觸發時機 |2471| Matcher | 觸發時機 |
2473| :- | :- |2472| :- | :- |
2474| `permission_prompt` | Claude 需要您核准工具使用或沙箱命令的[網路請求](/docs/zh-TW/sandboxing#network-isolation),且提示已等待約六秒 |2473| `permission_prompt` | Claude 需要您核准工具使用或沙箱化命令的[網路請求](/docs/zh-TW/sandboxing#network-isolation),且提示已等待約六秒 |
2475| `idle_prompt` | Claude 約在 60 秒前完成回應,且您此後未曾輸入 |2474| `idle_prompt` | Claude 約 60 秒前已完成回應,且您之後未曾輸入 |
2476| `auth_success` | 身分驗證完成 |2475| `auth_success` | 身分驗證完成 |
2477| `elicitation_dialog` | MCP 伺服器開啟 elicitation 表單,且您約六秒未輸入 |2476| `elicitation_dialog` | MCP 伺服器開啟了 elicitation 表單,且您約六秒未輸入 |
2478| `elicitation_url_dialog` | MCP 伺服器要求您開啟瀏覽器 URL,且您約六秒未輸入 |2477| `elicitation_url_dialog` | MCP 伺服器要求您開啟瀏覽器 URL,且您約六秒未輸入 |
2479| `elicitation_complete` | MCP 伺服器回報 [URL 模式 elicitation](#elicitation-input) 已完成 |2478| `elicitation_complete` | MCP 伺服器回報 [URL 模式 elicitation](#elicitation-input) 已完成 |
2480| `elicitation_response` | MCP elicitation 回應已傳回伺服器 |2479| `elicitation_response` | MCP elicitation 回應已傳回伺服器 |
2481| `agent_needs_input` | 當 [agent view](/docs/zh-TW/agent-view) 在終端機中開啟時,背景工作階段開始等待您的輸入。當終端機工作階段向您顯示 [agent team 隊員的終端機設定問題](/docs/zh-TW/agent-teams#choose-a-display-mode)或自動模式關於[分類器請求費用](/docs/zh-TW/auto-mode-classifier-billing)的通知,且您約六秒未輸入時,也會觸發 |2480| `agent_needs_input` | 在終端機中開啟 [agent view](/docs/zh-TW/agent-view) 時,背景工作階段開始等待您的輸入。當終端機工作階段向您顯示 [agent team 隊員的終端機設定問題](/docs/zh-TW/agent-teams#choose-a-display-mode),或自動模式關於[分類器請求費用](/docs/zh-TW/auto-mode-classifier-billing)的通知,且您約六秒未輸入時,也會觸發 |
2482| `agent_completed` | 背景工作階段完成或失敗。僅在 [agent view](/docs/zh-TW/agent-view) 於終端機中開啟時觸發 |2481| `agent_completed` | 背景工作階段完成或失敗。僅在終端機中開啟 [agent view](/docs/zh-TW/agent-view) 時觸發 |
2483| `quota_auto_resume_fired` | Claude Code 在 claude.ai 用量上限暫停您的任務後繼續執行:於重設時,或當您在等待期間於 Claude Code 中執行的某些操作(例如新增用量點數、升級方案或切換模型)使用量再次可用時提前繼續,但有[模型設定例外](/docs/zh-TW/interactive-mode#wait-for-a-usage-limit-to-reset) |2482| `quota_auto_resume_fired` | 在 claude.ai 用量上限暫停您的任務後,Claude Code 繼續執行該任務:於重設時,或當您在等待期間於 Claude Code 中所做的某些事情(例如新增用量點數、升級方案或切換模型)使用量再次可用時提前繼續,但有[模型設定例外](/docs/zh-TW/interactive-mode#wait-for-a-usage-limit-to-reset) |
2484| `quota_auto_resume_stale` | claude.ai 用量上限在您的電腦休眠超過約 30 分鐘期間重設。Claude Code 會等待您按下 `Enter`,而不是自動繼續。若休眠時間較短,則會繼續並改為觸發 `quota_auto_resume_fired` |2483| `quota_auto_resume_stale` | claude.ai 用量上限在您的電腦休眠超過約 30 分鐘期間重設。Claude Code 會等待您按下 `Enter`,而不是直接繼續。若休眠時間較短,它會繼續並改為觸發 `quota_auto_resume_fired` |
2485| `quota_auto_resume_disabled` | Claude Code 結束對 claude.ai 用量上限的等待,但未繼續您的任務:[`autoContinueAtUsageLimit`](/docs/zh-TW/settings-reference#autocontinueatusagelimit) 已關閉,或在 Claude Code 自行開始的等待期間重設時間延後超過 24 小時、繼續的任務持續觸及上限,或繼續操作在抵達模型前遭到封鎖。當您按下 `Esc` 或 `Ctrl+C`,或選擇 **Don't continue automatically** 時不會觸發 |2484| `quota_auto_resume_disabled` | Claude Code 結束對 claude.ai 用量上限的等待,但未繼續您的任務:[`autoContinueAtUsageLimit`](/docs/zh-TW/settings-reference#autocontinueatusagelimit) 已關閉,或在 Claude Code 自行開始的等待期間重設時間延後超過 24 小時、繼續的任務持續觸及上限,或繼續動作在抵達模型前遭到封鎖。當您按下 `Esc` 或 `Ctrl+C`,或選擇 **Don't continue automatically** 時不會觸發 |
2486 2485
2487`quota_auto_resume_fired`、`quota_auto_resume_stale` 與 `quota_auto_resume_disabled` 類型需要 Claude Code v2.1.234 或更新版本。2486`quota_auto_resume_fired`、`quota_auto_resume_stale` 與 `quota_auto_resume_disabled` 類型需要 Claude Code v2.1.234 或更新版本。
2488 2487
2489在終端機工作階段中,針對沙箱命令網路請求的 `permission_prompt` 需要 Claude Code v2.1.246 或更新版本。2488在終端機工作階段中,針對沙箱化命令網路請求的 `permission_prompt` 需要 Claude Code v2.1.246 或更新版本。
2490 2489
2491針對隊員終端機設定問題的 `agent_needs_input` 需要 Claude Code v2.1.248 或更新版本。2490針對隊員終端機設定問題的 `agent_needs_input` 需要 Claude Code v2.1.248 或更新版本。
2492 2491
2493<Note>2492<Note>
2494 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 與 `elicitation_url_dialog` 類型與桌面通知共用相同的計時方式,因此在終端機工作階段中,只有當您看起來已離開終端機時才會看到它們:2493 `permission_prompt`、`idle_prompt`、`elicitation_dialog` 與 `elicitation_url_dialog` 類型與桌面通知共用相同的時機,因此在終端機工作階段中,只有當您看起來已離開終端機時才會看到它們:
2495 2494
2496 * 當您約六秒未輸入時,預期會出現 `permission_prompt`。計時器在權限提示出現時開始,每次按鍵都會使其延後。若要在 Claude 要求使用工具的權限時立即執行 hook,請改用 [PermissionRequest](#permissionrequest)。2495 * 預期在您約六秒未輸入後出現 `permission_prompt`。計時器在權限提示出現時開始,每次按鍵都會延後它。若要在 Claude 要求使用工具的權限時立即執行 hook,請改用 [PermissionRequest](#permissionrequest)。
2497 * 預期 `idle_prompt` 會在 Claude 完成回應約 60 秒後出現,且僅在您此後未曾輸入,並且沒有背景 agent(例如背景 [subagent](/docs/zh-TW/sub-agents))仍在執行時才會出現。Claude Code 在等待 claude.ai 用量上限重設期間不會傳送 `idle_prompt`。當等待自行結束時,會改為觸發其中一種 `quota_auto_resume_*` 類型。2496 * 預期在 Claude 完成回應約 60 秒後出現 `idle_prompt`,且僅限於您之後未曾輸入,並且沒有背景 agent(例如背景 [subagent](/docs/zh-TW/sub-agents))仍在執行時。Claude Code 在等待 claude.ai 用量上限重設期間不會傳送 `idle_prompt`。當等待自行結束時,會改為觸發其中一個 `quota_auto_resume_*` 類型。
2498 * 當您約六秒未輸入時,預期會出現 `elicitation_dialog`(針對 elicitation 表單)或 `elicitation_url_dialog`(針對瀏覽器 URL 請求)。兩者與 `permission_prompt` 共用相同的六秒門檻:計時器在對話框出現時開始,每次按鍵都會使其延後。2497 * 預期在您約六秒未輸入後,針對 elicitation 表單出現 `elicitation_dialog`,或針對瀏覽器 URL 請求出現 `elicitation_url_dialog`。兩者與 `permission_prompt` 共用相同的六秒門檻:計時器在對話方塊出現時開始,每次按鍵都會延後它。
2499 2498
2500 在另一個對話框顯示於畫面上時抵達的權限請求或 elicitation,會維持相同的六秒門檻,並從請求抵達時開始計時。即使該請求仍在已開啟的對話框後方等待,其通知也可能送達您。2499 在另一個對話方塊仍顯示於畫面上時抵達的權限請求或 elicitation,會維持相同的六秒門檻,並從請求抵達時開始計時。其通知可能會在該請求仍在已開啟的對話方塊後方等待時送達給您。
2501</Note>2500</Note>
2502 2501
2503在 Claude Code 將權限請求傳送給 Agent SDK 的 [`canUseTool` 回呼](/docs/zh-TW/agent-sdk/user-input)的工作階段中(Claude Desktop 與 VS Code 擴充功能即以此方式託管 Claude Code),Claude Code 對 `permission_prompt` 的計時方式有所不同:2502在 Claude Code 將權限請求傳送到 Agent SDK 的 [`canUseTool` 回呼](/docs/zh-TW/agent-sdk/user-input)的工作階段中(Claude Desktop 與 VS Code 擴充功能即以此方式託管 Claude Code),Claude Code 對 `permission_prompt` 的計時方式不同:
2504 2503
2505* 預期 `permission_prompt` 會在 Claude 要求權限約六秒後出現。Claude Code 不會因您輸入而延後它。2504* 預期在 Claude 要求權限約六秒後出現 `permission_prompt`。Claude Code 不會因為您正在輸入而延後它。
2506* 如果您或 [PermissionRequest](#permissionrequest) hook 較早回應,Claude Code 不會執行 `permission_prompt`。2505* 如果您或 [PermissionRequest](#permissionrequest) hook 較早回應,Claude Code 就不會執行 `permission_prompt`。
2507* 將 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-TW/env-vars) 設為 `1`,即可在這些工作階段中關閉 `permission_prompt`。2506* 將 [`CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKS`](/docs/zh-TW/env-vars) 設為 `1`,即可在這些工作階段中關閉 `permission_prompt`。
2508 2507
2509在 v2.1.233 之前,`permission_prompt` 不會在這些工作階段中觸發。2508在 v2.1.233 之前,`permission_prompt` 不會在這些工作階段中觸發。
2510 2509
2511使用不同的 matcher,即可依通知類型執行不同的處理常式。此設定會在 Claude 需要權限核准時觸發權限專用的警示指令碼,並在 Claude 閒置時觸發另一個通知:2510使用不同的 matcher,可依通知類型執行不同的處理程式。以下設定會在 Claude 需要權限核准時觸發權限專用的警示指令碼,並在 Claude 閒置時觸發另一個通知:
2512 2511
2513```json theme={null}2512```json theme={null}
2514{2513{
2541 Notification 輸入2540 Notification 輸入
2542</h4>2541</h4>
2543 2542
2544除了[通用輸入欄位](#common-input-fields)之外,Notification hook 還會收到含有通知文字的 `message`、選用的 `title`,以及指出觸發類型的 `notification_type`。2543除了[共通輸入欄位](#common-input-fields)外,Notification hook 還會收到帶有通知文字的 `message`、選用的 `title`,以及指出觸發類型的 `notification_type`。
2545 2544
2546```json theme={null}2545```json theme={null}
2547{2546{
2555}2554}
2556```2555```
2557 2556
2558Notification hook 無法封鎖或修改通知。Claude Code 會捨棄其 `systemMessage` 與 `continue` 欄位,但仍會輸出 [`terminalSequence`](#emit-terminal-notifications),桌面通知範例即仰賴此欄位。Notification hook 的用途是執行副作用,例如將通知轉送至外部服務。2557Notification hook 無法封鎖或修改通知。Claude Code 會捨棄其 `systemMessage` 與 `continue` 欄位,但仍會輸出 [`terminalSequence`](#emit-terminal-notifications),這正是桌面通知範例所依賴的。Notification hook 的用途是產生副作用,例如將通知轉送到外部服務。
2559 2558
2560<h3 id="subagentstart">2559<h3 id="subagentstart">
2561 SubagentStart2560 SubagentStart
2562</h3>2561</h3>
2563 2562
2564當 Claude 使用 Agent 工具產生 subagent、當 Claude [恢復 subagent](/docs/zh-TW/sub-agents#resume-subagents),以及每當行程內 [agent team](/docs/zh-TW/agent-teams) 隊員處理新訊息時執行。支援以 matcher 依 agent 類型名稱篩選。對於內建 agent,這是 agent 名稱,例如 `general-purpose`、`Explore` 或 `Plan`。對於[自訂 subagent](/docs/zh-TW/sub-agents),這是 agent frontmatter 中的 `name` 欄位,而非檔案名稱。2563在 Claude 以 Agent 工具產生 subagent 時、在 Claude [恢復 subagent](/docs/zh-TW/sub-agents#resume-subagents) 時,以及每次程序內 [agent team](/docs/zh-TW/agent-teams) 隊員處理新訊息時執行。支援以 matcher 依 agent 類型名稱篩選。對於內建 agent,這是 agent 名稱,例如 `general-purpose`、`Explore` 或 `Plan`。對於[自訂 subagent](/docs/zh-TW/sub-agents),這是 agent frontmatter 中的 `name` 欄位,而非檔案名稱。
2565 2564
2566對於由[外掛](/docs/zh-TW/plugins/overview)提供的 subagent,agent 類型是外掛範圍的識別碼,例如 `my-plugin:reviewer`,而非單純的 frontmatter 名稱。冒號會使外掛範圍的名稱走正規表示式路徑,因此請以 `^` 與 `$` 錨定 matcher 以進行完全比對:`^my-plugin:reviewer$`。2565對於由[外掛](/docs/zh-TW/plugins/overview)提供的 subagent,agent 類型是外掛範圍的識別碼,例如 `my-plugin:reviewer`,而非單純的 frontmatter 名稱。冒號會使外掛範圍的名稱走正規表示式路徑,因此請以 `^` 與 `$` 錨定 matcher 以進行精確比對:`^my-plugin:reviewer$`。
2567 2566
2568<h4 id="subagentstart-input">2567<h4 id="subagentstart-input">
2569 SubagentStart 輸入2568 SubagentStart 輸入
2570</h4>2569</h4>
2571 2570
2572除了[通用輸入欄位](#common-input-fields)之外,SubagentStart hook 還會收到含有 subagent 唯一識別碼的 `agent_id`,以及含有 matcher 篩選所依據之 agent 名稱的 `agent_type`。2571除了[共通輸入欄位](#common-input-fields)外,SubagentStart hook 還會收到帶有 subagent 唯一識別碼的 `agent_id`,以及帶有 matcher 篩選依據之 agent 名稱的 `agent_type`。
2573 2572
2574```json theme={null}2573```json theme={null}
2575{2574{
2582}2581}
2583```2582```
2584 2583
2585SubagentStart hook 無法封鎖 subagent 的建立,但可以將上下文注入 subagent。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)之外,您還可以傳回:2584SubagentStart hook 無法封鎖 subagent 的建立,但可以將上下文注入 subagent。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)外,您還可以回傳:
2586 2585
2587| 欄位 | 說明 |2586| 欄位 | 說明 |
2588| :- | :- |2587| :- | :- |
2597}2596}
2598```2597```
2599 2598
2600當 hook 針對同一個 subagent 再次執行時,Claude Code 只會在 subagent 的上下文中尚未保有先前執行所注入的副本時,才注入傳回的上下文。啟動時注入的副本會保留在原處,使 subagent 的[提示快取](/docs/zh-TW/prompt-caching#subagents-and-the-cache)維持完整。在[自動壓縮](/docs/zh-TW/sub-agents#auto-compaction)捨棄該副本後,Claude Code 會再次注入下一次執行的上下文。2599當 hook 針對同一個 subagent 再次執行時,只有在 subagent 的上下文中尚未保有先前執行的副本時,Claude Code 才會注入回傳的上下文。啟動時注入的副本會保留在原處,使 subagent 的[提示快取](/docs/zh-TW/prompt-caching#subagents-and-the-cache)保持完整。在[自動壓縮](/docs/zh-TW/sub-agents#auto-compaction)捨棄該副本後,Claude Code 會再次注入下一次執行的上下文。
2601 2600
2602<h3 id="subagentstop">2601<h3 id="subagentstop">
2603 SubagentStop2602 SubagentStop
2609 SubagentStop 輸入2608 SubagentStop 輸入
2610</h4>2609</h4>
2611 2610
2612除了[通用輸入欄位](#common-input-fields)之外,SubagentStop hook 還會收到 `stop_hook_active`、`agent_id`、`agent_type`、`agent_transcript_path` 與 `last_assistant_message`。`agent_type` 欄位是用於 matcher 篩選的值。`transcript_path` 是主工作階段的逐字稿,而 `agent_transcript_path` 則是 subagent 自己的逐字稿,儲存在巢狀的 `subagents/` 資料夾中。`last_assistant_message` 欄位包含 subagent 最終回應的文字內容,因此 hook 無需解析逐字稿檔案即可存取它。2611除了[共通輸入欄位](#common-input-fields)外,SubagentStop hook 還會收到 `stop_hook_active`、`agent_id`、`agent_type`、`agent_transcript_path` 與 `last_assistant_message`。`agent_type` 欄位是用於 matcher 篩選的值。`transcript_path` 是主工作階段的逐字稿,而 `agent_transcript_path` 則是 subagent 自己的逐字稿,儲存在巢狀的 `subagents/` 資料夾中。`last_assistant_message` 欄位包含 subagent 最終回應的文字內容,因此 hook 不需解析逐字稿檔案即可存取。
2613 2612
2614並非每個 SubagentStop 事件都來自 Claude 產生的 subagent。Claude Code 也會為其部分功能執行內部 agent,例如[提示詞建議](/docs/zh-TW/interactive-mode#prompt-suggestions)與 [`/btw` 旁支問題](/docs/zh-TW/interactive-mode#side-questions-with-%2Fbtw),這些 agent 完成時同樣會觸發 SubagentStop。對於這些事件,`agent_type` 是工作階段本身所執行的 agent 名稱,例如以 [`--agent`](/docs/zh-TW/cli-reference#cli-flags) 或 [`agent` 設定](/docs/zh-TW/settings-reference#agent)指定的名稱;若工作階段未指定任何 agent,則為空字串。2613並非每個 SubagentStop 事件都來自 Claude 產生的 subagent。Claude Code 也會為其部分功能執行內部 agent,例如[提示詞建議](/docs/zh-TW/interactive-mode#prompt-suggestions)與 [`/btw` 旁支問題](/docs/zh-TW/interactive-mode#side-questions-with-%2Fbtw),當其中之一完成時也會觸發 SubagentStop。對於這些事件,`agent_type` 是工作階段本身執行時所用的 agent 名稱,例如透過 [`--agent`](/docs/zh-TW/cli-reference#cli-flags) 或 [`agent` 設定](/docs/zh-TW/settings-reference#agent)設定的名稱;若工作階段未使用 agent,則為空字串。
2615 2614
2616指定 agent 類型的 `matcher` 不會比對到空的 `agent_type`。matcher 省略、為 `""` 或 `"*"`,或為可比對空字串之正規表示式的 hook,也會針對 `agent_type` 為空的事件執行。2615指名 agent 類型的 `matcher` 不會比對到空的 `agent_type`。matcher 省略、為 `""` 或 `"*"`,或是可比對空字串之正規表示式的 hook,也會針對 `agent_type` 為空的事件執行。
2617 2616
2618在 Claude Code v2.1.271 或更新版本中,搭配 [`SubagentHandback`](/docs/zh-TW/tools-reference) 工具執行的 subagent 會在停止前透過該工具傳遞其報告。此時 `last_assistant_message` 欄位保存的是 subagent 的結尾文字(若有),而非所傳遞的報告。報告是該次呼叫的 `message` 輸入,比對 `SubagentHandback` 的 `PreToolUse` 或 `PostToolUse` hook 會以 `tool_input.message` 收到它。2617在 Claude Code v2.1.271 或更新版本中,使用 [`SubagentHandback`](/docs/zh-TW/tools-reference) 工具執行的 subagent 會在停止前透過該工具傳遞其報告。此時 `last_assistant_message` 欄位保存的是 subagent 的結尾文字(若有),而非傳遞的報告。報告是該呼叫的 `message` 輸入,比對 `SubagentHandback` 的 `PreToolUse` 或 `PostToolUse` hook 會以 `tool_input.message` 收到它。
2619 2618
2620SubagentStop hook 也會收到 [Stop 輸入](#stop-input)中所述的 `background_tasks` 與 `session_crons` 陣列。這兩個陣列的範圍都是父工作階段,而非 subagent。2619SubagentStop hook 也會收到 [Stop 輸入](#stop-input)中所述的 `background_tasks` 與 `session_crons` 陣列。這兩個陣列的範圍都是父工作階段,而非 subagent。
2621 2620
2636}2635}
2637```2636```
2638 2637
2639SubagentStop hook 使用與 [Stop hook](#stop-decision-control) 相同的決策控制格式,包括將 `hookEventName` 設為 `"SubagentStop"` 的 `hookSpecificOutput.additionalContext`,用於提供讓 subagent 繼續執行的非錯誤回饋。傳回附有 `reason` 的 `decision: "block"` 會讓 subagent 繼續執行,並將 `reason` 作為其下一個指令傳遞給 subagent。以退出碼 2 封鎖的 hook 也會以相同方式傳遞其 stderr 訊息。若要在 subagent 返回後將上下文注入父工作階段,請改用針對 `Agent` 工具的 [`PostToolUse`](#posttooluse) hook。2638SubagentStop hook 使用與 [Stop hook](#stop-decision-control) 相同的決策控制格式,包括將 `hookEventName` 設為 `"SubagentStop"` 的 `hookSpecificOutput.additionalContext`,用於讓 subagent 繼續執行的非錯誤回饋。回傳帶有 `reason` 的 `decision: "block"` 會讓 subagent 繼續執行,並將 `reason` 作為其下一個指令傳遞給 subagent。以退出碼 2 封鎖的 hook 也會以相同方式傳遞其 stderr 訊息。若要在 subagent 返回後將上下文注入父工作階段,請改在 `Agent` 工具上使用 [`PostToolUse`](#posttooluse) hook。
2640 2639
2641<h3 id="taskcreated">2640<h3 id="taskcreated">
2642 TaskCreated2641 TaskCreated
2643</h3>2642</h3>
2644 2643
2645在透過 `TaskCreate` 工具建立任務時執行。可用來強制執行命名慣例、要求任務描述,或阻止特定任務被建立。在[不含 Task 工具的工作階段](/docs/zh-TW/tools-reference#task-tool-availability)中,此事件不會觸發。2644在透過 `TaskCreate` 工具建立任務時執行。可用來強制執行命名慣例、要求任務說明,或阻止建立特定任務。在[沒有 Task 工具的工作階段](/docs/zh-TW/tools-reference#task-tool-availability)中,此事件不會觸發。
2646 2645
2647TaskCreated hook 不支援 matcher,每次發生時都會觸發。2646TaskCreated hook 不支援 matcher,每次發生時都會觸發。
2648 2647
2650 TaskCreated 輸入2649 TaskCreated 輸入
2651</h4>2650</h4>
2652 2651
2653除了[通用輸入欄位](#common-input-fields)之外,TaskCreated hook 還會收到 `task_id`、`task_subject`,以及選用的 `task_description`、`teammate_name` 與 `team_name`。2652除了[共通輸入欄位](#common-input-fields)外,TaskCreated hook 還會收到 `task_id`、`task_subject`,以及選用的 `task_description`、`teammate_name` 與 `team_name`。
2654 2653
2655```json theme={null}2654```json theme={null}
2656{2655{
2669| 欄位 | 說明 |2668| 欄位 | 說明 |
2670| :- | :- |2669| :- | :- |
2671| `task_id` | 正在建立之任務的識別碼 |2670| `task_id` | 正在建立之任務的識別碼 |
2672| `task_subject` | 任務標題 |2671| `task_subject` | 任務的標題 |
2673| `task_description` | 任務的詳細描述。可能不存在 |2672| `task_description` | 任務的詳細說明。可能不存在 |
2674| `teammate_name` | 建立任務之隊員的名稱。可能不存在 |2673| `teammate_name` | 建立任務之隊員的名稱。可能不存在 |
2675| `team_name` | 已棄用。由工作階段衍生的團隊名稱;將在未來版本中移除 |2674| `team_name` | 已棄用。衍生自工作階段的團隊名稱;將在未來的版本中移除 |
2675| `agent_id` | 在此事件中,此[共通輸入欄位](#common-input-fields)識別建立任務的 subagent 或[程序內隊員](/docs/zh-TW/agent-teams#choose-a-display-mode)。可能不存在。需要 Claude Code v2.1.290 或更新版本 |
2676 2676
2677<h4 id="taskcreated-decision-control">2677<h4 id="taskcreated-decision-control">
2678 TaskCreated 決策控制2678 TaskCreated 決策控制
2679</h4>2679</h4>
2680 2680
2681TaskCreated hook 可以透過兩種方式封鎖建立。無論哪種方式,Claude Code 都會刪除該任務,並將您的訊息作為工具錯誤傳回給 Claude。Claude Code 會忽略此事件的 `continue: false`,Claude 會繼續工作。2681TaskCreated hook 可以透過兩種方式封鎖建立。無論哪種方式,Claude Code 都會刪除該任務,並將您的訊息作為工具錯誤回傳給 Claude。Claude Code 會忽略此事件的 `continue: false`,Claude 會繼續工作。
2682 2682
2683* **退出碼 2**:Claude Code 將 stderr 文字作為訊息傳回。2683* **退出碼 2**:Claude Code 會將 stderr 文字作為訊息回傳。
2684* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 將 `reason` 作為訊息傳回。2684* **JSON `{"decision": "block", "reason": "..."}`**:Claude Code 會將 `reason` 作為訊息回傳。
2685 2685
2686此範例會封鎖主旨不符合所需格式的任務:2686以下範例會封鎖主旨不符合規定格式的任務:
2687 2687
2688```bash theme={null}2688```bash theme={null}
2689#!/bin/bash2689#!/bin/bash
2702 TaskCompleted2702 TaskCompleted
2703</h3>2703</h3>
2704 2704
2705在任務即將被標記為已完成時執行。這會在兩種情況下觸發:任何 agent 透過 TaskUpdate 工具明確將任務標記為已完成時,或 [agent team](/docs/zh-TW/agent-teams) 隊員在仍有進行中任務的情況下結束其回合時。可用來在任務關閉前強制執行完成條件,例如通過測試或 lint 檢查。2705在任務被標記為已完成時執行。這會在兩種情況下觸發:任何 agent 透過 TaskUpdate 工具明確將任務標記為已完成時,或 [agent team](/docs/zh-TW/agent-teams) 隊員在仍有進行中任務的情況下結束其回合時。可用來在任務關閉前強制執行完成條件,例如通過測試或 lint 檢查。
2706 2706
2707TaskCompleted hook 不支援 matcher,每次發生時都會觸發。2707TaskCompleted hook 不支援 matcher,每次發生時都會觸發。
2708 2708
2710 TaskCompleted 輸入2710 TaskCompleted 輸入
2711</h4>2711</h4>
2712 2712
2713除了[通用輸入欄位](#common-input-fields)之外,TaskCompleted hook 還會收到 `task_id`、`task_subject`,以及選用的 `task_description`、`teammate_name` 與 `team_name`。2713除了[共通輸入欄位](#common-input-fields)外,TaskCompleted hook 還會收到 `task_id`、`task_subject`,以及選用的 `task_description`、`teammate_name` 與 `team_name`。
2714 2714
2715```json theme={null}2715```json theme={null}
2716{2716{
2730| 欄位 | 說明 |2730| 欄位 | 說明 |
2731| :- | :- |2731| :- | :- |
2732| `task_id` | 正在完成之任務的識別碼 |2732| `task_id` | 正在完成之任務的識別碼 |
2733| `task_subject` | 任務標題 |2733| `task_subject` | 任務的標題 |
2734| `task_description` | 任務的詳細描述。可能不存在 |2734| `task_description` | 任務的詳細說明。可能不存在 |
2735| `teammate_name` | 完成任務之隊員的名稱。可能不存在 |2735| `teammate_name` | 完成任務之隊員的名稱。可能不存在 |
2736| `team_name` | 已棄用。由工作階段衍生的團隊名稱;將在未來版本中移除 |2736| `team_name` | 已棄用。衍生自工作階段的團隊名稱;將在未來的版本中移除 |
2737| `agent_id` | 在此事件中,此[共通輸入欄位](#common-input-fields)識別完成任務的 subagent 或[程序內隊員](/docs/zh-TW/agent-teams#choose-a-display-mode)。可能不存在。需要 Claude Code v2.1.290 或更新版本 |
2737 2738
2738<h4 id="taskcompleted-decision-control">2739<h4 id="taskcompleted-decision-control">
2739 TaskCompleted 決策控制2740 TaskCompleted 決策控制
2742TaskCompleted hook 支援兩種控制任務完成的方式:2743TaskCompleted hook 支援兩種控制任務完成的方式:
2743 2744
2744* **退出碼 2**:任務不會被標記為已完成,stderr 訊息會作為回饋傳回給模型。2745* **退出碼 2**:任務不會被標記為已完成,stderr 訊息會作為回饋傳回給模型。
2745* **JSON `{"continue": false, "stopReason": "..."}`**:當事件是由隊員結束其回合所觸發時,會完全停止該隊員,與 `Stop` hook 的行為一致。`stopReason` 會顯示給使用者。當事件是由 `TaskUpdate` 工具觸發時,Claude Code 會忽略 `continue: false`;退出碼 2 仍會封鎖完成。2746* **JSON `{"continue": false, "stopReason": "..."}`**:當事件是由隊員結束其回合所觸發時,會完全停止該隊員,行為與 `Stop` hook 相同。`stopReason` 會顯示給使用者。當事件是由 `TaskUpdate` 工具觸發時,Claude Code 會忽略 `continue: false`;退出碼 2 仍會封鎖完成。
2746 2747
2747此範例會執行測試,並在測試失敗時封鎖任務完成:2748以下範例會執行測試,並在測試失敗時封鎖任務完成:
2748 2749
2749```bash theme={null}2750```bash theme={null}
2750#!/bin/bash2751#!/bin/bash
2764 Stop2765 Stop
2765</h3>2766</h3>
2766 2767
2767在主要 Claude Code agent 完成回應時執行。若停止是由使用者中斷所造成,則不會執行。API 錯誤會改為觸發2768在主要的 Claude Code agent 完成回應時執行。如果停止是因使用者中斷所致,則不會執行。API 錯誤會改為觸發
2768[StopFailure](#stopfailure)。2769[StopFailure](#stopfailure)。
2769 2770
2770<Tip>2771<Tip>
2771 [`/goal`](/docs/zh-TW/goal) 命令是工作階段範圍、以提示詞為基礎之 Stop hook 的內建捷徑。當您希望 Claude 持續朝某個條件努力,而不想撰寫 hook 設定時,可以使用它。2772 [`/goal`](/docs/zh-TW/goal) 命令是以工作階段為範圍、基於提示詞之 Stop hook 的內建捷徑。當您希望 Claude 持續朝某個條件努力,而不想撰寫 hook 設定時,請使用它。
2772</Tip>2773</Tip>
2773 2774
2774<h4 id="stop-input">2775<h4 id="stop-input">
2775 Stop 輸入2776 Stop 輸入
2776</h4>2777</h4>
2777 2778
2778除了[通用輸入欄位](#common-input-fields)之外,Stop hook 還會收到 `stop_hook_active`、`last_assistant_message`、`background_tasks` 與 `session_crons`。當 Claude Code 已因 stop hook 而繼續執行時,`stop_hook_active` 欄位為 `true`。請檢查此值或處理逐字稿,以避免在永遠無法解決的條件上持續封鎖。2779除了[共通輸入欄位](#common-input-fields)外,Stop hook 還會收到 `stop_hook_active`、`last_assistant_message`、`background_tasks` 與 `session_crons`。當 Claude Code 已因 stop hook 而繼續執行時,`stop_hook_active` 欄位為 `true`。請檢查此值或處理逐字稿,以避免在永遠不會解決的條件上持續封鎖。
2779 2780
2780Claude Code 套用 8 次連續繼續的上限:在 stop hook 連續八次讓回合繼續之後,Claude Code 會覆寫下一次封鎖並結束回合。每當 Claude 呼叫工具時,連續繼續的計數就會重設。若要提高上限,請設定 [`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`](/docs/zh-TW/env-vars)。2781Claude Code 套用了 8 次連續繼續的上限:在 stop hook 連續讓回合繼續八次後,Claude Code 會覆寫下一次封鎖並結束該回合。每當 Claude 呼叫工具時,連續繼續的次數就會重設。若要提高上限,請設定 [`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`](/docs/zh-TW/env-vars)。
2781 2782
2782`last_assistant_message` 欄位包含 Claude 最終回應的文字內容,因此 hook 無需解析逐字稿檔案即可存取它。對於針對剛完成之回合採取動作的 hook(例如朗讀或通知 hook),請使用此欄位,而非讀取 `transcript_path`:並非所有版本都保證逐字稿檔案在 Stop 時已包含最終訊息。2783`last_assistant_message` 欄位包含 Claude 最終回應的文字內容,因此 hook 不需解析逐字稿檔案即可存取。對於針對剛完成之回合採取動作的 hook(例如朗讀或通知 hook),請使用此欄位而非讀取 `transcript_path`:並非所有版本都保證逐字稿檔案在 Stop 時已包含最終訊息。
2783 2784
2784`background_tasks` 與 `session_crons` 陣列讓 hook 能夠區分「工作階段已完成」與「工作階段已暫停,等待背景工作將其喚醒」。當任務登錄可存取時,兩個陣列都會存在;若沒有正在進行或已排程的項目,則為空陣列。2785`background_tasks` 與 `session_crons` 陣列讓 hook 能夠區分「工作階段已結束」與「工作階段已暫停,正等待背景工作將其喚醒」。當任務登錄可存取時,兩個陣列都會存在;若沒有進行中或已排程的項目,則為空陣列。
2785 2786
2786`background_tasks` 中的每個項目描述一個正在進行的任務,並使用以下欄位:2787`background_tasks` 中的每個項目描述一個進行中的任務,並使用下列欄位:
2787 2788
2788| 欄位 | 說明 |2789| 欄位 | 說明 |
2789| :- | :- |2790| :- | :- |
2790| `id` | 任務識別碼 |2791| `id` | 任務識別碼 |
2791| `type` | 易讀的任務類型標籤,例如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每個標籤識別建立該任務的 Claude Code 功能。對於無法辨識的類型,會退回使用原始判別值 |2792| `type` | 易讀的任務類型標籤,例如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每個標籤識別建立該任務的 Claude Code 功能。對於無法辨識的類型,會退回使用原始的判別值 |
2792| `status` | 目前的任務狀態 |2793| `status` | 目前的任務狀態 |
2793| `description` | 自由文字描述,上限為 1000 個字元,截斷時字串中會帶有 `… [+N chars]` 標記 |2794| `description` | 自由文字說明,上限為 1000 個字元,遭截斷時字串內會帶有 `… [+N chars]` 標記 |
2794| `command` | shell 命令列,上限為 1000 個字元。僅存在於 `shell` 任務 |2795| `command` | shell 命令列,上限為 1000 個字元。僅存在於 `shell` 任務 |
2795| `agent_type` | subagent 類型名稱。僅存在於 `subagent` 任務 |2796| `agent_type` | subagent 類型名稱。僅存在於 `subagent` 任務 |
2796| `server` | MCP 伺服器名稱。僅存在於 `monitor` 與 `MCP task` 任務 |2797| `server` | MCP 伺服器名稱。僅存在於 `monitor` 與 `MCP task` 任務 |
2797| `tool` | MCP 工具名稱。僅存在於 `monitor` 與 `MCP task` 任務 |2798| `tool` | MCP 工具名稱。僅存在於 `monitor` 與 `MCP task` 任務 |
2798| `name` | 工作流程名稱。僅存在於 `workflow` 任務 |2799| `name` | 工作流程名稱。僅存在於 `workflow` 任務 |
2799 2800
2800`session_crons` 中的每個項目描述一個工作階段範圍的排程喚醒,來源為 `CronCreate`、`ScheduleWakeup` 與 `/loop`:2801`session_crons` 中的每個項目描述一個以工作階段為範圍的排程喚醒,來源為 `CronCreate`、`ScheduleWakeup` 與 `/loop`:
2801 2802
2802| 欄位 | 說明 |2803| 欄位 | 說明 |
2803| :- | :- |2804| :- | :- |
2804| `id` | Cron 任務識別碼 |2805| `id` | Cron 任務識別碼 |
2805| `schedule` | Cron 運算式,例如 `0 9 * * 1-5` |2806| `schedule` | Cron 運算式,例如 `0 9 * * 1-5` |
2806| `recurring` | 對於排程只編碼單一觸發時間的一次性喚醒為 `false`,對於每次相符時都會再次觸發的任務為 `true` |2807| `recurring` | 對於排程只編碼單一觸發時間的一次性喚醒為 `false`,對於每次比對都會再次觸發的任務為 `true` |
2807| `prompt` | cron 觸發時送出的提示詞,上限為 1000 個字元,並帶有相同的 `… [+N chars]` 標記 |2808| `prompt` | cron 觸發時提交的提示詞,上限為 1000 個字元,並使用相同的 `… [+N chars]` 標記 |
2808 2809
2809此範例顯示含有一個正在進行之 shell 任務與一個週期性 cron 的 Stop 輸入:2810以下範例顯示一個帶有一個進行中 shell 任務與一個週期性 cron 的 Stop 輸入:
2810 2811
2811```json theme={null}2812```json theme={null}
2812{2813{
2841 Stop 決策控制2842 Stop 決策控制
2842</h4>2843</h4>
2843 2844
2844`Stop` 與 `SubagentStop` hook 可以控制 Claude 是否繼續。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)之外,您的 hook 指令碼還可以傳回以下事件專屬欄位:2845`Stop` 與 `SubagentStop` hook 可以控制 Claude 是否繼續。除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)外,您的 hook 指令碼還可以回傳下列事件專屬欄位:
2845 2846
2846| 欄位 | 說明 |2847| 欄位 | 說明 |
2847| :- | :- |2848| :- | :- |
2848| `decision` | `"block"` 會阻止 Claude 停止。省略即允許 Claude 停止 |2849| `decision` | `"block"` 會阻止 Claude 停止。省略則允許 Claude 停止 |
2849| `reason` | 當 `decision` 為 `"block"` 時為必填。告訴 Claude 為何應繼續 |2850| `reason` | 當 `decision` 為 `"block"` 時為必填。告訴 Claude 為何應該繼續 |
2850| `hookSpecificOutput.additionalContext` | 提供給 Claude 的非錯誤回饋。對話會繼續,讓 Claude 能據以行動,但與 `decision: "block"` 不同,它在逐字稿中會顯示為 hook 回饋,而非 hook 錯誤 |2851| `hookSpecificOutput.additionalContext` | 給 Claude 的非錯誤回饋。對話會繼續,讓 Claude 可以據此採取動作,但與 `decision: "block"` 不同,它在逐字稿中會顯示為 hook 回饋,而非 hook 錯誤 |
2851 2852
2852以退出碼 2 封鎖的 hook,其處理方式與 `reason` 相同:Claude 會收到 stderr 訊息,作為它應繼續的原因說明。2853以退出碼 2 封鎖的 hook 會以與 `reason` 相同的方式傳遞:Claude 會收到 stderr 訊息,作為它應該繼續的原因說明。
2853 2854
2854```json theme={null}2855```json theme={null}
2855{2856{
2858}2859}
2859```2860```
2860 2861
2861當 hook 依設計運作並為 Claude 提供指引時(例如「完成前請執行測試套件」),請使用 `additionalContext`。它會透過與 `decision: "block"` 相同的迴圈保護機制讓對話繼續,即 `stop_hook_active` 輸入與連續 8 次繼續的上限,但逐字稿會將其標示為 `Stop hook feedback`,且不會顯示 hook 錯誤通知:2862當 hook 依設計運作並為 Claude 提供指引時,例如「在結束前執行測試套件」,請使用 `additionalContext`。它會透過與 `decision: "block"` 相同的迴圈保護機制(即 `stop_hook_active` 輸入與 8 次連續繼續上限)讓對話繼續,但逐字稿會將其標示為 `Stop hook feedback`,且不會顯示 hook 錯誤通知:
2862 2863
2863```json theme={null}2864```json theme={null}
2864{2865{
2879 StopFailure 輸入2880 StopFailure 輸入
2880</h4>2881</h4>
2881 2882
2882除了[通用輸入欄位](#common-input-fields)之外,StopFailure hook 還會收到 `error`、選用的 `error_details` 與選用的 `last_assistant_message`。`error` 欄位識別錯誤類型,並用於 matcher 篩選。2883除了[共通輸入欄位](#common-input-fields)外,StopFailure hook 還會收到 `error`、選用的 `error_details`,以及選用的 `last_assistant_message`。`error` 欄位識別錯誤類型,並用於 matcher 篩選。
2883 2884
2884| 欄位 | 說明 |2885| 欄位 | 說明 |
2885| :- | :- |2886| :- | :- |
2886| `error` | 錯誤類型:`rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`account_on_hold`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens`、`cloud_credential_error` 或 `unknown` |2887| `error` | 錯誤類型:`rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`account_on_hold`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens`、`cloud_credential_error` 或 `unknown` |
2887| `error_details` | 關於錯誤的其他細節(若有) |2888| `error_details` | 關於錯誤的其他詳細資訊(若有) |
2888| `last_assistant_message` | 對話中顯示的錯誤文字。與 `Stop` 和 `SubagentStop` 中此欄位保存 Claude 對話輸出的情況不同,對於 `StopFailure`,它包含 API 錯誤字串本身,例如 `"API Error: Rate limit reached"` |2889| `last_assistant_message` | 對話中顯示的已呈現錯誤文字。與 `Stop` 及 `SubagentStop` 中此欄位保存 Claude 的對話輸出不同,對於 `StopFailure`,它包含 API 錯誤字串本身,例如 `"API Error: Rate limit reached"` |
2889 2890
2890```json theme={null}2891```json theme={null}
2891{2892{
2905 TeammateIdle2906 TeammateIdle
2906</h3>2907</h3>
2907 2908
2908當 [agent team](/docs/zh-TW/agent-teams) 隊員在結束其回合後即將進入閒置狀態時執行。可用來在隊員停止工作前強制執行品質關卡,例如要求通過 lint 檢查或確認輸出檔案存在。2909在 [agent team](/docs/zh-TW/agent-teams) 隊員結束其回合、即將進入閒置時執行。可用來在隊員停止工作前強制執行品質關卡,例如要求通過 lint 檢查或驗證輸出檔案存在。
2909 2910
2910TeammateIdle hook 不支援 matcher,每次發生時都會觸發。2911TeammateIdle hook 不支援 matcher,每次發生時都會觸發。
2911 2912
2913 TeammateIdle 輸入2914 TeammateIdle 輸入
2914</h4>2915</h4>
2915 2916
2916除了[通用輸入欄位](#common-input-fields)之外,TeammateIdle hook 還會收到 `teammate_name` 與 `team_name`。2917除了[共通輸入欄位](#common-input-fields)外,TeammateIdle hook 還會收到 `teammate_name` 與 `team_name`。
2917 2918
2918```json theme={null}2919```json theme={null}
2919{2920{
2929 2930
2930| 欄位 | 說明 |2931| 欄位 | 說明 |
2931| :- | :- |2932| :- | :- |
2932| `teammate_name` | 即將進入閒置狀態之隊員的名稱 |2933| `teammate_name` | 即將進入閒置之隊員的名稱 |
2933| `team_name` | 已棄用。由工作階段衍生的團隊名稱;將在未來版本中移除 |2934| `team_name` | 已棄用。衍生自工作階段的團隊名稱;將在未來的版本中移除 |
2935| `agent_id` | 在此事件中,此[共通輸入欄位](#common-input-fields)識別即將進入閒置的[程序內隊員](/docs/zh-TW/agent-teams#choose-a-display-mode)。可能不存在。需要 Claude Code v2.1.290 或更新版本 |
2934 2936
2935<h4 id="teammateidle-decision-control">2937<h4 id="teammateidle-decision-control">
2936 TeammateIdle 決策控制2938 TeammateIdle 決策控制
2938 2940
2939TeammateIdle hook 支援兩種控制隊員行為的方式:2941TeammateIdle hook 支援兩種控制隊員行為的方式:
2940 2942
2941* **退出碼 2**:隊員會收到 stderr 訊息作為回饋,並繼續工作而不進入閒置狀態。2943* **退出碼 2**:隊員會收到 stderr 訊息作為回饋,並繼續工作而不進入閒置。
2942* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止該隊員,與 `Stop` hook 的行為一致。`stopReason` 會顯示給使用者。2944* **JSON `{"continue": false, "stopReason": "..."}`**:完全停止該隊員,行為與 `Stop` hook 相同。`stopReason` 會顯示給使用者。
2943 2945
2944此範例會在允許隊員進入閒置狀態前,檢查建置產物是否存在:2946以下範例會在允許隊員進入閒置前,檢查建置產物是否存在:
2945 2947
2946```bash theme={null}2948```bash theme={null}
2947#!/bin/bash2949#!/bin/bash
2960 2962
2961在工作階段期間設定檔變更時執行。可用來稽核設定變更、強制執行安全政策,或封鎖對設定檔未經授權的修改。2963在工作階段期間設定檔變更時執行。可用來稽核設定變更、強制執行安全政策,或封鎖對設定檔未經授權的修改。
2962 2964
2963當設定檔、受管政策檔案或 skill 檔案變更時,Claude Code 會執行 ConfigChange hook。對於受管政策,只有在 `managed-settings.json` 或 `managed-settings.d/` 中的檔案變更時才會執行。套用[伺服器管理設定](/docs/zh-TW/server-managed-settings)以及 macOS 受管偏好設定或 Windows 登錄政策的變更時,不會執行這些 hook。在啟用 [`wslInheritsWindowsSettings`](/docs/zh-TW/settings-reference#wslinheritswindowssettings) 的 WSL 上,它在政策輪詢時套用已變更的 Windows 端受管設定檔,同樣不會執行這些 hook。2965當設定檔、受管政策檔或 skill 檔案變更時,Claude Code 會執行 ConfigChange hook。對於受管政策,只有在 `managed-settings.json` 或 `managed-settings.d/` 中的檔案變更時才會執行。對於[伺服器受管設定](/docs/zh-TW/server-managed-settings),以及對 macOS 受管偏好設定或 Windows 登錄政策的變更,它會直接套用而不執行這些 hook。在啟用 [`wslInheritsWindowsSettings`](/docs/zh-TW/settings-reference#wslinheritswindowssettings) 的 WSL 上,它也會在其政策輪詢時套用變更後的 Windows 端受管設定檔,而不執行這些 hook。
2964 2966
2965matcher 依設定來源篩選:2967matcher 會依設定來源進行篩選:
2966 2968
2967| Matcher | 觸發時機 |2969| Matcher | 觸發時機 |
2968| :- | :- |2970| :- | :- |
2972| `policy_settings` | `managed-settings.json` 或 `managed-settings.d/` 中的檔案變更 |2974| `policy_settings` | `managed-settings.json` 或 `managed-settings.d/` 中的檔案變更 |
2973| `skills` | `.claude/skills/` 中的 skill 檔案變更 |2975| `skills` | `.claude/skills/` 中的 skill 檔案變更 |
2974 2976
2975此範例會記錄所有設定變更以供安全稽核:2977以下範例會記錄所有設定變更以進行安全稽核:
2976 2978
2977```json theme={null}2979```json theme={null}
2978{2980{
2996 ConfigChange 輸入2998 ConfigChange 輸入
2997</h4>2999</h4>
2998 3000
2999除了[通用輸入欄位](#common-input-fields)之外,ConfigChange hook 還會收到 `source` 與選用的 `file_path`。`source` 欄位指出哪種設定類型發生變更,`file_path` 則提供被修改之特定檔案的路徑。3001除了[共通輸入欄位](#common-input-fields)外,ConfigChange hook 還會收到 `source`,以及選用的 `file_path`。`source` 欄位指出變更的是哪種設定類型,`file_path` 則提供被修改之特定檔案的路徑。
3000 3002
3001```json theme={null}3003```json theme={null}
3002{3004{
3013 ConfigChange 決策控制3015 ConfigChange 決策控制
3014</h4>3016</h4>
3015 3017
3016ConfigChange hook 可以封鎖設定變更使其不生效。使用退出碼 2 或 JSON `decision` 即可阻止變更。遭封鎖時,新設定不會套用至正在執行的工作階段。3018ConfigChange hook 可以阻止設定變更生效。使用退出碼 2 或 JSON `decision` 即可阻止變更。遭封鎖時,新的設定不會套用到執行中的工作階段。
3017 3019
3018| 欄位 | 說明 |3020| 欄位 | 說明 |
3019| :- | :- |3021| :- | :- |
3020| `decision` | `"block"` 會阻止套用設定變更。省略即允許變更 |3022| `decision` | `"block"` 會阻止套用設定變更。省略則允許變更 |
3021| `reason` | 會被接受,但永遠不會顯示 |3023| `reason` | 會被接受,但永遠不會顯示 |
3022 3024
3023```json theme={null}3025```json theme={null}
3027}3029}
3028```3030```
3029 3031
3030`policy_settings` 變更無法被封鎖。當機器上的受管設定檔變更時,hook 仍會針對 `policy_settings` 來源觸發,因此您可以用它們記錄這些編輯,但任何封鎖決策都會被忽略。這可確保企業受管設定一律生效。當[伺服器管理設定](/docs/zh-TW/server-managed-settings)抵達或重新整理時,Claude Code 不會執行 `ConfigChange` hook。3032`policy_settings` 的變更無法被封鎖。當電腦上的受管設定檔變更時,hook 仍會針對 `policy_settings` 來源觸發,因此您可以用它們記錄這些編輯,但任何封鎖決策都會被忽略。這可確保企業受管設定一律生效。當[伺服器受管設定](/docs/zh-TW/server-managed-settings)抵達或重新整理時,Claude Code 不會執行 `ConfigChange` hook。
3031 3033
3032Claude Code 會依據 ConfigChange hook JSON 輸出中的封鎖決策採取行動,並捨棄 `systemMessage` 與 `continue`。無論您是以 `reason` 還是以退出碼 2 的 stderr 封鎖,遭封鎖的變更都不會向您或 Claude 顯示任何訊息。Claude Code 只會在偵錯日誌中寫入一行。3034Claude Code 會依據 ConfigChange hook JSON 輸出中的封鎖決策採取動作,並捨棄 `systemMessage` 與 `continue`。無論您是以 `reason` 還是以退出碼 2 時的 stderr 封鎖,遭封鎖的變更都不會向您或 Claude 顯示任何訊息。Claude Code 只會在偵錯日誌中寫入一行。
3033 3035
3034<h3 id="cwdchanged">3036<h3 id="cwdchanged">
3035 CwdChanged3037 CwdChanged
3036</h3>3038</h3>
3037 3039
3038當主要對話中的 shell 命令變更工作目錄時執行,例如 Claude 執行 `cd` 命令時。可用來回應目錄變更:重新載入環境變數、啟用專案專屬的工具鏈,或自動執行設定指令碼。可與 [FileChanged](#filechanged) 搭配,用於像 [direnv](https://direnv.net/) 這類管理各目錄環境的工具。3040在主對話中的 shell 命令變更工作目錄時執行,例如 Claude 執行 `cd` 命令時。可用來回應目錄變更:重新載入環境變數、啟用專案專屬的工具鏈,或自動執行設定指令碼。可與 [FileChanged](#filechanged) 搭配,用於像 [direnv](https://direnv.net/) 這類管理各目錄環境的工具。
3039 3041
3040CwdChanged hook 可以存取 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。寫入該檔案的變數會保留到後續的 Bash 命令中,直到下一個 CwdChanged 事件時由 Claude Code 清除。3042CwdChanged hook 可以存取 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。寫入該檔案的變數會延續到後續的 Bash 命令中,直到下一次 CwdChanged 事件時由 Claude Code 清除。
3041 3043
3042CwdChanged 不支援 matcher,每次發生時都會觸發。3044CwdChanged 不支援 matcher,每次發生時都會觸發。
3043 3045
3045 CwdChanged 輸入3047 CwdChanged 輸入
3046</h4>3048</h4>
3047 3049
3048除了[通用輸入欄位](#common-input-fields)之外,CwdChanged hook 還會收到 `old_cwd` 與 `new_cwd`。3050除了[共通輸入欄位](#common-input-fields)外,CwdChanged hook 還會收到 `old_cwd` 與 `new_cwd`。
3049 3051
3050```json theme={null}3052```json theme={null}
3051{3053{
3062 CwdChanged 輸出3064 CwdChanged 輸出
3063</h4>3065</h4>
3064 3066
3065除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)之外,CwdChanged hook 還可以傳回 `watchPaths`,以動態設定 [FileChanged](#filechanged) 監看的檔案路徑:3067除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)外,CwdChanged hook 還可以回傳 `watchPaths`,以動態設定 [FileChanged](#filechanged) 要監看哪些檔案路徑:
3066 3068
3067| 欄位 | 說明 |3069| 欄位 | 說明 |
3068| :- | :- |3070| :- | :- |
3069| `watchPaths` | 絕對路徑陣列。取代目前的動態監看清單。來自您 `matcher` 設定的路徑一律會被監看。傳回空陣列會清除動態清單,這在進入新目錄時很常見 |3071| `watchPaths` | 絕對路徑的陣列。會取代目前的動態監看清單。來自您 `matcher` 設定的路徑一律會被監看。回傳空陣列會清除動態清單,這在進入新目錄時很常見 |
3070 3072
3071CwdChanged hook 沒有決策控制。它們無法封鎖目錄變更。3073CwdChanged hook 沒有決策控制。它們無法封鎖目錄變更。
3072 3074
3073Claude Code 會從其 JSON 輸出讀取 `watchPaths` 與 `systemMessage`,並捨棄 `continue`。在互動式工作階段中,它會將 `systemMessage` 顯示為簡短的終端機通知。該訊息不會傳到 SDK 訊息串流。3075Claude Code 會從其 JSON 輸出中讀取 `watchPaths` 與 `systemMessage`,並捨棄 `continue`。在互動式工作階段中,它會將 `systemMessage` 顯示為簡短的終端機通知。該訊息不會傳到 SDK 訊息串流。
3074 3076
3075<h3 id="directoryadded">3077<h3 id="directoryadded">
3076 DirectoryAdded3078 DirectoryAdded
3077</h3>3079</h3>
3078 3080
3079在您於工作階段中途使用 `/add-dir` 命令新增工作目錄後,或在 SDK 用戶端以 `register_repo_root` 控制請求新增工作目錄後執行。可用來準備新加入的儲存庫,例如安裝其相依套件。3081在您於工作階段中途以 `/add-dir` 命令新增工作目錄後,或在 SDK 用戶端以 `register_repo_root` 控制請求新增工作目錄後執行。可用來準備新加入的儲存庫,例如安裝其相依套件。
3080 3082
3081在下列情況下,Claude Code 不會觸發此事件:3083在下列情況中,Claude Code 不會觸發此事件:
3082 3084
3083* 您以 `--add-dir` 啟動旗標傳入目錄;這些目錄由 [SessionStart](#sessionstart) 涵蓋3085* 您以 `--add-dir` 啟動旗標傳入目錄;這些目錄由 [SessionStart](#sessionstart) 涵蓋
3084* 您在 `/permissions` 的 Workspace 分頁中新增目錄3086* 您在 `/permissions` 的 Workspace 分頁中新增目錄
3085* 您新增的目錄已是工作目錄或位於某個工作目錄內3087* 您新增的目錄已經是工作目錄,或位於工作目錄內
3086 3088
3087Claude Code 會在重新整理沙箱與權限狀態後觸發 DirectoryAdded,因此當您的 hook 執行時,沙箱化的工具已能看到新目錄。hook 命令本身則在沙箱外執行。3089Claude Code 會在重新整理沙箱與權限狀態後觸發 DirectoryAdded,因此當您的 hook 執行時,沙箱化的工具已經能看到新目錄。hook 命令本身則在沙箱之外執行。
3088 3090
3089Claude Code 不會等待 hook:新增會立即完成,hook 則在背景執行,使用 600 秒的預設逾時。3091Claude Code 不會等待 hook:新增動作會立即完成,而 hook 會以 600 秒的預設逾時在背景執行。
3090 3092
3091matcher 依目錄的新增方式篩選:3093matcher 會依目錄的新增方式進行篩選:
3092 3094
3093| Matcher | 觸發時機 |3095| Matcher | 觸發時機 |
3094| :- | :- |3096| :- | :- |
3099 DirectoryAdded 輸入3101 DirectoryAdded 輸入
3100</h4>3102</h4>
3101 3103
3102除了[通用輸入欄位](#common-input-fields)之外,DirectoryAdded hook 還會收到 `directory` 與 `source`。3104除了[共通輸入欄位](#common-input-fields)外,DirectoryAdded hook 還會收到 `directory` 與 `source`。
3103 3105
3104| 欄位 | 說明 |3106| 欄位 | 說明 |
3105| :- | :- |3107| :- | :- |
3117}3119}
3118```3120```
3119 3121
3120DirectoryAdded hook 沒有決策控制。它們無法封鎖新增,因為 hook 執行時新增已經完成。Claude Code 會捨棄其 JSON 輸出中的 `continue` 欄位,其餘部分則依來源以不同方式呈現:3122DirectoryAdded hook 沒有決策控制。它們無法封鎖新增動作,因為 hook 執行時新增動作已經完成。Claude Code 會捨棄其 JSON 輸出中的 `continue` 欄位,並依來源以不同方式呈現其餘內容:
3121 3123
3122* `slash_command`:Claude Code 會在下一個對話回合將 hook 的 `systemMessage` 作為上下文傳遞給 Claude,而不是顯示給您。失敗 hook 的數量會出現在逐字稿中。完整的失敗輸出會寫入偵錯日誌3124* `slash_command`:Claude Code 會在下一個對話回合中,將 hook 的 `systemMessage` 作為上下文傳遞給 Claude,而不是顯示給您。逐字稿中會顯示失敗 hook 的數量。完整的失敗輸出會寫入偵錯日誌
3123* `register_repo_root`:Claude Code 只會將 `systemMessage` 輸出與失敗輸出寫入偵錯日誌3125* `register_repo_root`:Claude Code 只會將 `systemMessage` 輸出與失敗輸出寫入偵錯日誌
3124 3126
3125<h3 id="filechanged">3127<h3 id="filechanged">
3126 FileChanged3128 FileChanged
3127</h3>3129</h3>
3128 3130
3129當受監看的檔案在磁碟上變更時執行。Claude Code 是以檔案系統監看器偵測變更,而非檢查工具呼叫,因此無論是什麼變更了檔案,它都會執行 hook:`Edit` 或 `Write` 工具呼叫、Claude 以 `Bash` 執行的指令碼,或完全在 Claude Code 之外的程序。常見用途是在專案設定檔變更時重新載入環境變數。3131在受監看的檔案於磁碟上變更時執行。Claude Code 是以檔案系統監看器偵測變更,而不是檢查工具呼叫,因此無論是什麼變更了檔案,它都會執行 hook:`Edit` 或 `Write` 工具呼叫、Claude 以 `Bash` 執行的指令碼,或完全在 Claude Code 之外的程序。常見用途是在專案設定檔變更時重新載入環境變數。
3130 3132
3131此事件的 `matcher` 有兩個作用:3133此事件的 `matcher` 有兩個作用:
3132 3134
3133* **建立監看清單**:其值會以 `|` 分割,每個片段都會被註冊為工作目錄中的字面檔案名稱,因此 `".envrc|.env"` 會精確監看這兩個檔案。正規表示式模式在此沒有用處:像 `^\.env` 這樣的值會監看名稱字面上就是 `^\.env` 的檔案。3135* **建立監看清單**:該值會以 `|` 分割,每個片段都會被註冊為工作目錄中的字面檔案名稱,因此 `".envrc|.env"` 會恰好監看這兩個檔案。正規表示式模式在此沒有用處:像 `^\.env` 這樣的值會監看一個名稱字面上為 `^\.env` 的檔案。
3134* **篩選要執行的 hook**:當受監看的檔案變更時,同一個值會依標準的 [matcher 規則](#matcher-patterns),對變更檔案的基本名稱篩選要執行哪些 hook 群組。3136* **篩選要執行的 hook**:當受監看的檔案變更時,同一個值會依據標準的 [matcher 規則](#matcher-patterns),針對變更檔案的基本名稱篩選要執行哪些 hook 群組。
3135 3137
3136此範例會在任何變更後正規化 `data.csv` 的行尾,包括 `Bash` 命令或外部指令碼改寫該檔案的情況:3138以下範例會在 `data.csv` 發生任何變更後(包括 `Bash` 命令或外部指令碼重寫該檔案)正規化其換行字元:
3137 3139
3138```json theme={null}3140```json theme={null}
3139{3141{
3153}3155}
3154```3156```
3155 3157
3156hook 會從 stdin 上 [JSON 輸入](#filechanged-input)的 `file_path` 欄位讀取變更檔案的絕對路徑。其 `grep` 防護條件檢查的正是 `perl` 要移除的內容,也就是行尾的 CR,因此正規化之後的那次執行會直接結束而不動到檔案。較寬鬆的防護條件會造成無限迴圈,因為即使沒有替換任何內容,`perl -i` 仍會改寫檔案,而 Claude Code 會在每次改寫後再次執行 hook。請將此指令碼儲存於 `/path/to/normalize-line-endings.sh` 並設為可執行:3158hook 會從 stdin 上 [JSON 輸入](#filechanged-input)的 `file_path` 欄位讀取變更檔案的絕對路徑。其 `grep` 防護條件檢查的正是 `perl` 移除的內容,也就是行尾的 CR,因此正規化之後的那次執行會直接結束而不碰觸檔案。較寬鬆的防護條件會造成無限迴圈,因為即使 `perl -i` 沒有替換任何內容,它仍會重寫檔案,而 Claude Code 在每次重寫後都會再次執行 hook。請將此指令碼儲存於 `/path/to/normalize-line-endings.sh` 並設為可執行:
3157 3159
3158```bash theme={null}3160```bash theme={null}
3159#!/bin/bash3161#!/bin/bash
3163fi3165fi
3164```3166```
3165 3167
3166若要確認 hook 正常運作,請要求 Claude 以 `Bash` 命令在 `data.csv` 後附加一行 CRLF。Claude Code 會執行 hook,檔案最終會使用 LF 行尾。3168若要確認 hook 是否運作,請要求 Claude 以 `Bash` 命令在 `data.csv` 末尾附加一行 CRLF。Claude Code 會執行 hook,檔案最後會變成 LF 換行。
3167 3169
3168若要監看無法事先命名的檔案,請從 hook 傳回 [`watchPaths`](#filechanged-output) 以動態更新監看清單。Claude Code 只有在某處指定了要監看的檔案時才會啟動監看器,因此請以 matcher 至少指定一個檔案的 FileChanged 群組,或以傳回 `watchPaths` 的 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 來初始化清單。當受監看的檔案變更時,matcher 仍會篩選要執行哪些 hook 群組,因此請讓處理動態路徑的群組省略 matcher,這樣會比對每個受監看的檔案,且不會在監看清單中新增任何項目。`"*"` matcher 也會比對每個檔案,但 Claude Code 會像處理其他值一樣,將其作為名為 `*` 的字面檔案註冊到監看清單中。3170若要監看無法事先指名的檔案,請從 hook 回傳 [`watchPaths`](#filechanged-output) 以動態更新監看清單。Claude Code 只有在有東西指名要監看的檔案時才會啟動監看器,因此請以 matcher 至少指名一個檔案的 FileChanged 群組,或以回傳 `watchPaths` 的 [SessionStart](#sessionstart-decision-control) 或 [CwdChanged](#cwdchanged) hook 來初始化清單。當受監看的檔案變更時,matcher 仍會篩選要執行哪些 hook 群組,因此請讓處理動態路徑的群組省略 matcher,這樣它會比對每個受監看的檔案,且不會在監看清單中新增任何項目。`"*"` matcher 也會比對每個檔案,但 Claude Code 會像處理其他值一樣將它註冊到監看清單中,作為一個名為 `*` 的字面檔案。
3169 3171
3170FileChanged hook 可以存取 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。寫入該檔案的變數會保留到後續的 Bash 命令中,直到下一個 [CwdChanged](#cwdchanged) 事件時由 Claude Code 清除。3172FileChanged hook 可以存取 [`CLAUDE_ENV_FILE`](#persist-environment-variables)。寫入該檔案的變數會延續到後續的 Bash 命令中,直到下一次 [CwdChanged](#cwdchanged) 事件時由 Claude Code 清除。
3171 3173
3172<h4 id="filechanged-input">3174<h4 id="filechanged-input">
3173 FileChanged 輸入3175 FileChanged 輸入
3174</h4>3176</h4>
3175 3177
3176除了[通用輸入欄位](#common-input-fields)之外,FileChanged hook 還會收到 `file_path` 與 `event`。3178除了[共通輸入欄位](#common-input-fields)外,FileChanged hook 還會收到 `file_path` 與 `event`。
3177 3179
3178| 欄位 | 說明 |3180| 欄位 | 說明 |
3179| :- | :- |3181| :- | :- |
3180| `file_path` | 變更檔案的絕對路徑 |3182| `file_path` | 變更之檔案的絕對路徑 |
3181| `event` | 發生的事件:修改檔案為 `"change"`,建立檔案為 `"add"`,刪除檔案為 `"unlink"` |3183| `event` | 發生的情況:修改檔案為 `"change"`,建立檔案為 `"add"`,刪除檔案為 `"unlink"` |
3182 3184
3183```json theme={null}3185```json theme={null}
3184{3186{
3195 FileChanged 輸出3197 FileChanged 輸出
3196</h4>3198</h4>
3197 3199
3198除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)之外,FileChanged hook 還可以傳回 `watchPaths`,以動態更新要監看的檔案路徑:3200除了所有 hook 皆可使用的 [JSON 輸出欄位](#json-output)外,FileChanged hook 還可以回傳 `watchPaths`,以動態更新要監看哪些檔案路徑:
3199 3201
3200| 欄位 | 說明 |3202| 欄位 | 說明 |
3201| :- | :- |3203| :- | :- |
3202| `watchPaths` | 絕對路徑陣列。取代目前的動態監看清單。來自您 `matcher` 設定的路徑一律會被監看。當您的 hook 指令碼依據變更的檔案發現其他需要監看的檔案時,請使用此欄位 |3204| `watchPaths` | 絕對路徑的陣列。會取代目前的動態監看清單。來自您 `matcher` 設定的路徑一律會被監看。當您的 hook 指令碼根據變更的檔案發現其他要監看的檔案時,請使用此欄位 |
3203 3205
3204FileChanged hook 沒有決策控制。它們無法阻止檔案變更發生。3206FileChanged hook 沒有決策控制。它們無法阻止檔案變更發生。
3205 3207
3206Claude Code 會從其 JSON 輸出讀取 `watchPaths` 與 `systemMessage`,並捨棄 `continue`。在互動式工作階段中,它會將 `systemMessage` 顯示為簡短的終端機通知。該訊息不會傳到 SDK 訊息串流。3208Claude Code 會從其 JSON 輸出中讀取 `watchPaths` 與 `systemMessage`,並捨棄 `continue`。在互動式工作階段中,它會將 `systemMessage` 顯示為簡短的終端機通知。該訊息不會傳到 SDK 訊息串流。
3207 3209
3208<h3 id="worktreecreate">3210<h3 id="worktreecreate">
3209 WorktreeCreate3211 WorktreeCreate
3210</h3>3212</h3>
3211 3213
3212在建立 worktree 時執行,無論是來自 `claude --worktree`、來自[使用 `isolation: "worktree"` 的 subagent](/docs/zh-TW/sub-agents#choose-the-subagent-scope),或是為 Claude Code 隔離在其自身 worktree 中的[背景工作階段](/docs/zh-TW/agent-view#how-file-edits-are-isolated)。依預設,Claude Code 會以 `git worktree` 建立隔離的工作副本。設定 WorktreeCreate hook 會取代該預設的 git 行為,讓您能使用其他版本控制系統,例如 SVN、Perforce 或 Mercurial。3214在建立 worktree 時執行,無論是透過 `claude --worktree`、透過[使用 `isolation: "worktree"` 的 subagent](/docs/zh-TW/sub-agents#choose-the-subagent-scope),或是為 Claude Code 隔離在其自身 worktree 中的[背景工作階段](/docs/zh-TW/agent-view#how-file-edits-are-isolated)而建立。預設情況下,Claude Code 使用 `git worktree` 建立隔離的工作副本。設定 WorktreeCreate hook 會取代此預設的 git 行為,讓您可以使用不同的版本控制系統,例如 SVN、Perforce 或 Mercurial。
3213 3215
3214由於 hook 會完全取代預設行為,因此不會處理 [`.worktreeinclude`](/docs/zh-TW/worktrees#copy-gitignored-files-into-worktrees)。若您需要將 `.env` 之類的本機設定檔複製到新的 worktree,請在您的 hook 指令碼中進行。3216由於 hook 會完全取代預設行為,因此不會處理 [`.worktreeinclude`](/docs/zh-TW/worktrees#copy-gitignored-files-into-worktrees)。如果需要將 `.env` 等本機設定檔複製到新的 worktree 中,請在 hook 腳本內執行此操作。
3215 3217
3216hook 必須傳回所建立之 worktree 目錄的路徑。Claude Code 會將此路徑作為隔離工作階段的工作目錄。關於各 hook 類型如何傳回路徑,請參閱 [WorktreeCreate 輸出](#worktreecreate-output)。3218hook 必須回傳所建立之 worktree 目錄的路徑。Claude Code 會將此路徑用作隔離工作階段的工作目錄。關於每種 hook 類型如何回傳路徑,請參閱 [WorktreeCreate 輸出](#worktreecreate-output)。
3217 3219
3218Claude Code 會依據 hook 是否成功以及傳回的路徑採取行動,並捨棄 `systemMessage` 與 `continue`。3220Claude Code 會依據 hook 是否成功以及回傳的路徑採取行動,並捨棄 `systemMessage` 和 `continue`。
3219 3221
3220此範例會建立 SVN 工作副本,並印出路徑供 Claude Code 使用。請將儲存庫 URL 替換為您自己的:3222此範例會建立 SVN 工作副本,並印出供 Claude Code 使用的路徑。請將儲存庫 URL 替換為您自己的 URL:
3221 3223
3222```json theme={null}3224```json theme={null}
3223{3225{
3236}3238}
3237```3239```
3238 3240
3239hook 會從 stdin 上的 JSON 輸入讀取 worktree 的 `name`,將全新副本簽出到新目錄,並印出目錄路徑。最後一行的 `echo` 就是 Claude Code 讀取為 worktree 路徑的內容。請將其他任何輸出重新導向至 stderr,以免干擾路徑。3241此 hook 會從 stdin 上的 JSON 輸入讀取 worktree 的 `name`,將全新副本 checkout 至新目錄,並印出目錄路徑。最後一行的 `echo` 就是 Claude Code 讀取為 worktree 路徑的內容。請將其他任何輸出重新導向至 stderr,以免干擾路徑。
3240 3242
3241<h4 id="worktreecreate-input">3243<h4 id="worktreecreate-input">
3242 WorktreeCreate 輸入3244 WorktreeCreate 輸入
3243</h4>3245</h4>
3244 3246
3245除了[通用輸入欄位](#common-input-fields)之外,WorktreeCreate hook 還會收到 `name` 欄位。這是新 worktree 的 slug 識別碼,由使用者指定或自動產生,例如 `bold-oak-a3f2`。3247除了[通用輸入欄位](#common-input-fields)之外,WorktreeCreate hook 還會收到 `name` 欄位。這是新 worktree 的 slug 識別碼,可由使用者指定或自動產生,例如 `bold-oak-a3f2`。
3246 3248
3247```json theme={null}3249```json theme={null}
3248{3250{
3258 WorktreeCreate 輸出3260 WorktreeCreate 輸出
3259</h4>3261</h4>
3260 3262
3261WorktreeCreate hook 不使用標準的允許/封鎖決策模型,而是由 hook 的成功或失敗決定結果。hook 必須回傳所建立的 worktree 目錄路徑:3263WorktreeCreate hook 不使用標準的允許/封鎖決策模型,而是由 hook 的成功或失敗決定結果。hook 必須回傳所建立之 worktree 目錄的路徑:
3262 3264
3263* **命令 hook**(`type: "command"`):將路徑印為 stdout 的最後一個非空行。Claude Code 在讀取該行之前會移除 ANSI 跳脫碼,因此在您的 `echo` 之前印出的 shell 啟動橫幅會被忽略。請將任何其他 hook 輸出重新導向至 stderr。3265* **命令 hook**(`type: "command"`):將路徑印為 stdout 的最後一個非空白行。Claude Code 在讀取該行之前會移除 ANSI 跳脫碼,因此在您的 `echo` 之前印出的 shell 啟動橫幅會被忽略。請將其他任何 hook 輸出重新導向至 stderr。
3264* **HTTP hook**(`type: "http"`):在回應主體中回傳 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。3266* **HTTP hook**(`type: "http"`):在回應主體中回傳 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。
3265 3267
3266如果 hook 失敗或未產生路徑,worktree 建立將失敗並顯示錯誤。3268如果 hook 失敗或未產生路徑,worktree 建立會失敗並顯示錯誤。
3267 3269
3268Claude Code 會以 hook 執行時所在的目錄解析相對路徑,並摺疊其中的任何 `.` 或 `..` 區段。如果產生的路徑不是 Claude Code 可以進入的目錄,工作階段會印出指明該路徑的錯誤,並以代碼 1 結束。3270Claude Code 會以 hook 執行時所在的目錄為基準解析相對路徑,並摺疊其中的任何 `.` 或 `..` 片段。如果解析後的路徑不是 Claude Code 可進入的目錄,工作階段會印出指出該路徑的錯誤,並以代碼 1 退出。
3269 3271
3270Claude Code 會拒絕包含 `.` 或 `..` 區段的絕對路徑,以及任何經過儲存庫根目錄下方符號連結的路徑,因為提交至儲存庫的符號連結可能會將 worktree 重新導向至儲存庫之外。錯誤會指明被拒絕的元件。請回傳不經過儲存庫內符號連結的正規化路徑。在 v2.1.216 之前,worktree 建立會直接採用 hook 的路徑,不進行此項檢查。3272Claude Code 會拒絕包含 `.` 或 `..` 片段的絕對路徑,以及任何經過儲存庫根目錄下符號連結的路徑,因為提交至儲存庫的符號連結可能會將 worktree 重新導向至儲存庫之外。錯誤訊息會指出遭拒絕的路徑元件。請回傳未經過儲存庫內符號連結的正規化路徑。在 v2.1.216 之前,worktree 建立會直接依循 hook 的路徑,而不進行此檢查。
3271 3273
3272<h3 id="worktreeremove">3274<h3 id="worktreeremove">
3273 WorktreeRemove3275 WorktreeRemove
3274</h3>3276</h3>
3275 3277
3276當 Claude Code 清理由您的 [`WorktreeCreate`](#worktreecreate) hook 所建立的 worktree 時執行。此事件在以下情況觸發:3278在 Claude Code 清理由您的 [`WorktreeCreate`](#worktreecreate) hook 所建立的 worktree 時執行。此事件會在下列情況觸發:
3277 3279
3278* 您結束互動式 [worktree 工作階段](/docs/zh-TW/worktrees#start-claude-in-a-worktree),並在 Claude Code 提示時選擇移除 worktree3280* 您退出互動式 [worktree 工作階段](/docs/zh-TW/worktrees#start-claude-in-a-worktree),並在 Claude Code 提示時選擇移除 worktree
3279* 您結束一個尚未[命名](/docs/zh-TW/sessions#name-your-sessions)的互動式 worktree 工作階段,Claude Code 未發現任何已變更或未追蹤的檔案,並在未提示的情況下移除 worktree3281* 您退出尚未[命名](/docs/zh-TW/sessions#name-your-sessions)的互動式 worktree 工作階段,Claude Code 未發現任何已變更或未追蹤的檔案,並在不提示您的情況下移除 worktree
3280* 您刪除在該 worktree 中執行的[背景工作階段](/docs/zh-TW/agent-view#what-deleting-a-session-removes)3282* 您刪除在該 worktree 中執行的[背景工作階段](/docs/zh-TW/agent-view#what-deleting-a-session-removes)
3281 3283
3282Claude Code 使用 git 尋找已變更或未追蹤的檔案,因此在不是 git checkout 或不位於 git checkout 內的 worktree 中,即使目錄含有未提交的工作,也找不到任何檔案。請在 WorktreeRemove hook 刪除任何內容之前,先檢查這類工作。3284Claude Code 使用 git 尋找已變更或未追蹤的檔案,因此在不是 git checkout 或不在 git checkout 內的 worktree 中,即使目錄包含未提交的工作,也不會找到任何檔案。請在 WorktreeRemove hook 刪除任何內容之前檢查這類工作。
3283 3285
3284對於基於 git 的 worktree,Claude Code 會透過 `git worktree remove` 自動處理清理。如果您設定了 WorktreeCreate hook,請搭配 WorktreeRemove hook 來控制其所建立 worktree 的清理:3286對於以 git 為基礎的 worktree,Claude Code 會使用 `git worktree remove` 自動處理清理。如果您設定了 WorktreeCreate hook,請搭配 WorktreeRemove hook 來控制其所建立之 worktree 的清理:
3285 3287
3286* **沒有 WorktreeRemove hook**:當 Claude Code 在您結束 worktree 工作階段時移除 worktree,會改用 `git worktree remove --force` 處理您的 WorktreeCreate hook 所回傳的路徑,因此 git 能識別的 worktree 會被移除。git 無法識別的 worktree(例如您的 hook 使用非 git 版本控制系統建立的 worktree)會保留在磁碟上。關於刪除[背景工作階段](/docs/zh-TW/agent-view#what-deleting-a-session-removes)時如何處理由 hook 建立的 worktree,請參閱 agent view 的刪除規則。3288* **沒有 WorktreeRemove hook**:當 Claude Code 在您退出 worktree 工作階段時移除 worktree,會改用對 WorktreeCreate hook 所回傳路徑執行 `git worktree remove --force`,因此 git 能辨識的 worktree 會被移除。git 無法辨識的 worktree(例如您的 hook 以非 git 版本控制系統建立的 worktree)會留在磁碟上。關於刪除[背景工作階段](/docs/zh-TW/agent-view#what-deleting-a-session-removes)時如何處理由 hook 建立的 worktree,請參閱 agent view 的刪除規則。
3287* **Hook 以 0 結束**:該 worktree 視為已移除。Claude Code 不會從 hook 讀取其他任何內容,因此請確保您的 hook 已刪除該目錄。3289* **Hook 以 0 退出**:worktree 視為已移除。Claude Code 不會從 hook 讀取任何其他內容,因此請確保您的 hook 已刪除該目錄。
3288* **Hook 以非零結束**:如果 `worktree_path` 處的目錄在之後仍然存在,移除即失敗,且 worktree 會保留在磁碟上,不會改用 git。在以非零結束之前已刪除目錄的 hook 視為已移除。關於失敗的回報方式,請參閱 [WorktreeRemove 輸入](#worktreeremove-input)。3290* **Hook 以非零值退出**:如果 `worktree_path` 上的目錄在之後仍然存在,移除就會失敗,且 worktree 會留在磁碟上,不會改用 git。在以非零值退出之前已刪除目錄的 hook 視為已移除。關於失敗如何回報,請參閱 [WorktreeRemove 輸入](#worktreeremove-input)。
3289 3291
3290Claude Code 絕不會刪除屬於 hook 建立之 worktree 的分支,因為它只知道您的 WorktreeCreate hook 回傳的路徑。如果您的 WorktreeCreate hook 建立了分支,請在 WorktreeRemove hook 中將其刪除。3292Claude Code 絕不會刪除屬於由 hook 建立之 worktree 的分支,因為它只知道您的 WorktreeCreate hook 所回傳的路徑。如果您的 WorktreeCreate hook 會建立分支,請在 WorktreeRemove hook 中刪除它。
3291 3293
3292Claude Code 會捨棄 WorktreeRemove hook 的 [JSON 輸出欄位](#json-output),例如 `systemMessage` 和 `continue`。3294Claude Code 會捨棄 WorktreeRemove hook 的 [JSON 輸出欄位](#json-output),例如 `systemMessage` 和 `continue`。
3293 3295
3294對於背景工作階段的刪除,Claude Code 會在執行 hook 之前驗證所儲存的 worktree 路徑,並拒絕本身為符號連結或經過儲存庫根目錄下方符號連結的路徑。只有當您在 [agent view](/docs/zh-TW/agent-view#what-deleting-a-session-removes) 中確認刪除時,hook 才會針對仍含有檔案的 worktree 執行;對於這類 worktree,[`claude rm`](/docs/zh-TW/agent-view#manage-sessions-from-the-shell) 則會保留工作階段和 worktree。在 v2.1.216 之前,hook 會在未經這些檢查的情況下針對儲存的路徑執行。3296對於背景工作階段的刪除,Claude Code 會在執行 hook 之前驗證所儲存的 worktree 路徑,並拒絕本身為符號連結或經過儲存庫根目錄下符號連結的路徑。只有當您在 [agent view](/docs/zh-TW/agent-view#what-deleting-a-session-removes) 中確認刪除時,hook 才會針對仍包含檔案的 worktree 執行;對於這類 worktree,[`claude rm`](/docs/zh-TW/agent-view#manage-sessions-from-the-shell) 則會保留工作階段和 worktree。在 v2.1.216 之前,hook 會在未經這些檢查的情況下對所儲存的路徑執行。
3295 3297
3296Claude Code 會將 WorktreeCreate 回傳的路徑作為 hook 輸入中的 `worktree_path` 傳入。以下範例讀取該路徑並移除目錄:3298Claude Code 會將 WorktreeCreate 回傳的路徑作為 `worktree_path` 傳入 hook 輸入。此範例會讀取該路徑並移除目錄:
3297 3299
3298```json theme={null}3300```json theme={null}
3299{3301{
3316 WorktreeRemove 輸入3318 WorktreeRemove 輸入
3317</h4>3319</h4>
3318 3320
3319除了[通用輸入欄位](#common-input-fields)之外,WorktreeRemove hook 還會收到 `worktree_path` 欄位,即要移除之 worktree 的絕對路徑。3321除了[通用輸入欄位](#common-input-fields)之外,WorktreeRemove hook 還會收到 `worktree_path` 欄位,這是要移除之 worktree 的絕對路徑。
3320 3322
3321```json theme={null}3323```json theme={null}
3322{3324{
3328}3330}
3329```3331```
3330 3332
3331WorktreeRemove hook 的退出碼決定結果。當 hook 以非零結束,且 `worktree_path` 處的目錄在之後仍然存在時,移除即失敗:3333WorktreeRemove hook 的退出碼決定結果。當 hook 以非零值退出,且 `worktree_path` 上的目錄在之後仍然存在時,移除就會失敗:
3332 3334
3333* worktree 會保留在磁碟上,hook 的命令和 stderr 會寫入[偵錯日誌](#debug-hooks)。3335* worktree 會留在磁碟上,且 hook 的命令和 stderr 會寫入[偵錯日誌](#debug-hooks)。
3334* 如果您正在刪除背景工作階段,該工作階段也會保留。[agent view](/docs/zh-TW/agent-view#what-deleting-a-session-removes) 中的拒絕訊息會回報 hook 的結束方式(例如 `exited 1`)、引用其 stderr 的開頭,並說明再次刪除該工作階段是否仍會移除該目錄。3336* 如果您當時正在刪除背景工作階段,該工作階段也會保留。[agent view](/docs/zh-TW/agent-view#what-deleting-a-session-removes) 中的拒絕訊息會回報 hook 的結束方式(例如 `exited 1`)、引用其 stderr 的開頭,並說明再次刪除工作階段是否仍會移除該目錄。
3335 3337
3336<h3 id="precompact">3338<h3 id="precompact">
3337 PreCompact3339 PreCompact
3344| Matcher | 觸發時機 |3346| Matcher | 觸發時機 |
3345| :- | :- |3347| :- | :- |
3346| `manual` | `/compact` |3348| `manual` | `/compact` |
3347| `auto` | 當對話達到[自動壓縮視窗](/docs/zh-TW/model-config#set-the-auto-compact-window)時自動壓縮 |3349| `auto` | 對話達到[自動壓縮視窗](/docs/zh-TW/model-config#set-the-auto-compact-window)時自動壓縮 |
3348 3350
3349以代碼 2 結束可封鎖壓縮。對於手動 `/compact`,stderr 訊息會顯示給使用者。您也可以回傳含有 `"decision": "block"` 的 JSON 來封鎖。3351以退出碼 2 退出可封鎖壓縮。對於手動 `/compact`,stderr 訊息會顯示給使用者。您也可以回傳包含 `"decision": "block"` 的 JSON 來封鎖。
3350 3352
3351封鎖自動壓縮的效果取決於其觸發時機。如果壓縮是在達到上下文限制之前主動觸發的,Claude Code 會略過壓縮,對話會在未壓縮的狀態下繼續。如果壓縮是為了從 API 已回傳的上下文限制錯誤中恢復而觸發的,底層錯誤就會浮現,目前的請求會失敗。3353封鎖自動壓縮的效果取決於其觸發時機。如果壓縮是在達到上下文限制之前主動觸發,Claude Code 會略過壓縮,對話會在未壓縮的情況下繼續。如果壓縮是為了從 API 已回傳的上下文限制錯誤中復原而觸發,底層錯誤會浮現,目前的請求會失敗。
3352 3354
3353Claude Code 會捨棄 PreCompact hook 的 `systemMessage` 和 `continue` 欄位。3355Claude Code 會捨棄 PreCompact hook 的 `systemMessage` 和 `continue` 欄位。
3354 3356
3356 PreCompact 輸入3358 PreCompact 輸入
3357</h4>3359</h4>
3358 3360
3359除了[通用輸入欄位](#common-input-fields)之外,PreCompact hook 還會收到 `trigger` 和 `custom_instructions`。對於 `manual`,`custom_instructions` 包含使用者傳入 `/compact` 的內容,未傳入任何內容時為 `null`。對於 `auto`,`custom_instructions` 為 `null`。3361除了[通用輸入欄位](#common-input-fields)之外,PreCompact hook 還會收到 `trigger` 和 `custom_instructions`。對於 `manual`,`custom_instructions` 包含使用者傳入 `/compact` 的內容,若未傳入任何內容則為 `null`。對於 `auto`,`custom_instructions` 為 `null`。
3360 3362
3361```json theme={null}3363```json theme={null}
3362{3364{
3373 PostCompact3375 PostCompact
3374</h3>3376</h3>
3375 3377
3376在 Claude Code 完成壓縮操作之後執行。使用此事件來回應新的壓縮狀態,例如記錄產生的摘要或更新外部狀態。Claude Code 會捨棄 PostCompact hook 的 `systemMessage` 和 `continue` 欄位。3378在 Claude Code 完成壓縮操作之後執行。使用此事件來回應壓縮後的新狀態,例如記錄所產生的摘要或更新外部狀態。Claude Code 會捨棄 PostCompact hook 的 `systemMessage` 和 `continue` 欄位。
3377 3379
3378適用與 `PreCompact` 相同的 matcher 值:3380適用與 `PreCompact` 相同的 matcher 值:
3379 3381
3380| Matcher | 觸發時機 |3382| Matcher | 觸發時機 |
3381| :- | :- |3383| :- | :- |
3382| `manual` | `/compact` 之後 |3384| `manual` | `/compact` 之後 |
3383| `auto` | 當對話達到[自動壓縮視窗](/docs/zh-TW/model-config#set-the-auto-compact-window)而自動壓縮之後 |3385| `auto` | 對話達到[自動壓縮視窗](/docs/zh-TW/model-config#set-the-auto-compact-window)並自動壓縮之後 |
3384 3386
3385<h4 id="postcompact-input">3387<h4 id="postcompact-input">
3386 PostCompact 輸入3388 PostCompact 輸入
3405 PreModelSwitch3407 PreModelSwitch
3406</h3>3408</h3>
3407 3409
3408在 Claude Code 套用您或用戶端所請求的模型切換之前執行。使用它來封鎖切換、要求確認,或在切換發生之前顯示切換的成本。3410在 Claude Code 套用您或用戶端所請求的模型切換之前執行。使用它來封鎖切換、要求確認,或在切換發生前顯示切換的成本。
3409 3411
3410PreModelSwitch 需要 Claude Code v2.1.251 或更新版本。Claude Code 會針對以下請求執行它:3412PreModelSwitch 需要 Claude Code v2.1.251 或更新版本。Claude Code 會針對下列請求執行它:
3411 3413
3412* `/model <name>` 和 `/model` 選擇器3414* `/model <name>` 和 `/model` 選擇器
3413* `Option+P` 或 `Alt+P` 模型選擇器3415* `Option+P` 或 `Alt+P` 模型選擇器
3414* `/config` 中的 Model 設定3416* `/config` 中的 Model 設定
3415* 開啟[快速模式](/docs/zh-TW/fast-mode)而導致工作階段的模型變更時3417* 開啟[快速模式](/docs/zh-TW/fast-mode)且此舉會變更工作階段的模型時
3416* 來自 [Agent SDK](/docs/zh-TW/agent-sdk/typescript#query-object) 主機或 [Remote Control](/docs/zh-TW/remote-control) 的 `set_model` 請求,或 `apply_flag_settings` 請求中的模型變更3418* 來自 [Agent SDK](/docs/zh-TW/agent-sdk/typescript#query-object) 主機或 [Remote Control](/docs/zh-TW/remote-control) 的 `set_model` 請求,或 `apply_flag_settings` 請求中的模型變更
3417 3419
3418對於 Claude Code 自行進行的切換,例如[自動模型備援](/docs/zh-TW/model-config#automatic-model-fallback)或在您恢復工作階段時還原模型,Claude Code 不會執行 PreModelSwitch hook。這些變更只會觸發 [PostModelSwitch](#postmodelswitch)。3420Claude Code 不會針對其自行進行的切換執行 PreModelSwitch hook,例如[自動模型備援](/docs/zh-TW/model-config#automatic-model-fallback)或在您恢復工作階段時還原模型。這些變更只會觸發 [PostModelSwitch](#postmodelswitch)。
3419 3421
3420Claude Code 會將 matcher 與工作階段要切換到的模型的正式名稱進行比對,並忽略任何 `[1m]` 後綴。別名(例如 `opus`)、帶日期的模型 ID,以及供應商專屬 ID(例如 Amazon Bedrock 模型 ID)都會比對到它們解析出的同一個正式名稱,因此 `claude-opus-5` 涵蓋 Opus 5 的所有寫法。3422Claude Code 會將 matcher 與工作階段所要切換之模型的標準名稱進行比對,並忽略任何 `[1m]` 後綴。別名(例如 `opus`)、帶日期的模型 ID,以及供應商專屬 ID(例如 Amazon Bedrock 模型 ID)都會比對到其解析後的同一個標準名稱,因此 `claude-opus-5` 涵蓋 Opus 5 的所有寫法。
3421 3423
3422當 Claude Code 無法判斷目標的正式名稱時,例如只有您的 [LLM 閘道](/docs/zh-TW/llm-gateway)知道的自訂模型 ID,它會不論 matcher 為何都執行每個 PreModelSwitch hook。因此,會進行封鎖的 hook 應檢查其輸入中的 `to_model`,而不是僅依賴 matcher。3424當 Claude Code 無法判斷目標的標準名稱時,例如只有您的 [LLM 閘道](/docs/zh-TW/llm-gateway)才知道的自訂模型 ID,它會執行每一個 PreModelSwitch hook,無論 matcher 為何。因此,會封鎖切換的 hook 應檢查其輸入中的 `to_model`,而非僅依賴 matcher。
3423 3425
3424matcher 可以寫成確切名稱、以 `|` 分隔的清單(例如 `claude-opus-4-6|claude-opus-5`),或正規表示式(例如 `.*opus.*`)。以下範例使用確切名稱 matcher,並同時檢查 hook 輸入中的 `to_model`,因此它會以代碼 2 結束來拒絕切換到 Opus 4.6,並允許任何其他目標通過:3426請將 matcher 寫成確切名稱、以 `|` 分隔的清單(例如 `claude-opus-4-6|claude-opus-5`),或正規表示式(例如 `.*opus.*`)。此範例使用確切名稱 matcher,並同時檢查 hook 輸入中的 `to_model`,因此它會以退出碼 2 退出來拒絕切換至 Opus 4.6,並允許任何其他目標通過:
3425 3427
3426<Tabs>3428<Tabs>
3427 <Tab title="macOS/Linux">3429 <Tab title="macOS/Linux">
3428 該命令使用 `jq` 檢查 `to_model`:3430 此命令使用 `jq` 檢查 `to_model`:
3429 3431
3430 ```json theme={null}3432 ```json theme={null}
3431 {3433 {
3447 </Tab>3449 </Tab>
3448 3450
3449 <Tab title="Windows (PowerShell)">3451 <Tab title="Windows (PowerShell)">
3450 註冊一個透過 PowerShell 執行指令碼的命令 hook:3452 註冊一個透過 PowerShell 執行腳本的命令 hook:
3451 3453
3452 ```json theme={null}3454 ```json theme={null}
3453 {3455 {
3474 }3476 }
3475 ```3477 ```
3476 3478
3477 將此指令碼儲存至專案中的 `.claude/hooks/block-opus-46.ps1`:3479 將此腳本儲存至專案中的 `.claude/hooks/block-opus-46.ps1`:
3478 3480
3479 ```powershell theme={null}3481 ```powershell theme={null}
3480 $hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json3482 $hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
3487 </Tab>3489 </Tab>
3488</Tabs>3490</Tabs>
3489 3491
3490若要確認 hook 正常運作,請在執行其他模型的工作階段中執行 `/model claude-opus-4-6`。Claude Code 會保留目前的模型,並回報 PreModelSwitch hook 封鎖了切換,並以您的訊息作為原因。3492若要確認 hook 是否正常運作,請在執行其他模型的工作階段中執行 `/model claude-opus-4-6`。Claude Code 會保留目前的模型,並回報 PreModelSwitch hook 已封鎖此切換,並以您的訊息作為原因。
3491 3493
3492<h4 id="premodelswitch-input">3494<h4 id="premodelswitch-input">
3493 PreModelSwitch 輸入3495 PreModelSwitch 輸入
3494</h4>3496</h4>
3495 3497
3496除了[通用輸入欄位](#common-input-fields)之外,PreModelSwitch hook 還會收到下表中的欄位。最後五個欄位描述將對話重新傳送至新模型的成本,讓 hook 能在切換發生之前顯示該數字。3498除了[通用輸入欄位](#common-input-fields)之外,PreModelSwitch hook 還會收到此表格中的欄位。最後五個欄位描述將對話重新傳送至新模型的成本,讓 hook 可以在切換發生前顯示該數字。
3497 3499
3498| 欄位 | 類型 | 說明 |3500| 欄位 | 類型 | 說明 |
3499| :- | :- | :- |3501| :- | :- | :- |
3500| `from_model` | string | 切換前的模型 ID |3502| `from_model` | string | 切換前的模型 ID |
3501| `to_model` | string | 切換後的模型 ID。matcher 會與此模型的正式名稱進行比對 |3503| `to_model` | string | 切換後的模型 ID。matcher 會與此模型的標準名稱進行比對 |
3502| `requested_model` | string 或 `null` | 請求中指定的模型:別名(例如 `opus`)、完整模型 ID,或當請求的是預設模型時為 `null` |3504| `requested_model` | string 或 `null` | 請求所指定的模型:別名(例如 `opus`)、完整模型 ID,或在請求預設模型時為 `null` |
3503| `source` | string | 請求的來源:`"command"` 表示 `/model <name>`、`/config` 中的 Model 設定,或開啟快速模式;`"picker"` 表示模型選擇器;`"sdk"` 表示來自 Agent SDK 主機或 Remote Control 的 `set_model` 請求,或 `apply_flag_settings` 請求中的模型變更 |3505| `source` | string | 請求的來源:`"command"` 表示 `/model <name>`、`/config` 中的 Model 設定或開啟快速模式;`"picker"` 表示模型選擇器;`"sdk"` 表示來自 Agent SDK 主機或 Remote Control 的 `set_model` 請求,或 `apply_flag_settings` 請求中的模型變更 |
3504| `context_tokens` | number | 下一個請求作為提示詞重新傳送的 token 數:主對話中最後一個回應的輸入、快取讀取、快取建立和輸出 token 的總和。在第一個回應之前為 `0` |3506| `context_tokens` | number | 下一個請求作為提示詞重新傳送的 token 數:主對話中最後一個回應的輸入、快取讀取、快取建立和輸出 token 的總和。在第一個回應之前為 `0` |
3505| `prompt_cache_warm` | boolean | 目前模型的提示快取是否可能仍處於暖狀態,亦即切換會使其失效 |3507| `prompt_cache_warm` | boolean | 目前模型的提示快取是否可能仍處於熱狀態,亦即切換會放棄該快取 |
3506| `cache_ttl` | string | Claude Code 為此工作階段請求的[提示快取存留期](/docs/zh-TW/prompt-caching#cache-lifetime):`"5m"` 或 `"1h"` |3508| `cache_ttl` | string | Claude Code 為此工作階段請求的[提示快取存留期](/docs/zh-TW/prompt-caching#cache-lifetime):`"5m"` 或 `"1h"` |
3507| `estimated_cache_write_usd` | number | 以 `cache_ttl` 費率將 `context_tokens` 寫入 `to_model` 提示快取的預估成本(美元),不含下一個回應。伺服器可能不需要重新快取整個上下文,因此請將其視為估計值 |3509| `estimated_cache_write_usd` | number | 以 `cache_ttl` 費率將 `context_tokens` 寫入 `to_model` 提示快取的預估成本(美元),不含下一個回應。伺服器可能不需要重新快取整個上下文,因此請將其視為預估值 |
3508| `pricing` | string | Claude Code 計算 `estimated_cache_write_usd` 的方式:`"configured"` 表示在您的組織已設定自有費率時採用該費率,`"catalog"` 表示採用定價表價格,`"default"` 表示 `to_model` 沒有已知價格而 Claude Code 採用預設費率 |3510| `pricing` | string | Claude Code 計算 `estimated_cache_write_usd` 的方式:`"configured"` 表示使用您組織已設定的自有費率,`"catalog"` 表示使用牌價,`"default"` 表示 `to_model` 沒有已知價格而 Claude Code 採用預設費率 |
3509 3511
3510以下範例顯示在執行 Sonnet 5 的工作階段中執行 `/model opus` 時的輸入:3512此範例顯示在執行 Sonnet 5 的工作階段中執行 `/model opus` 的輸入:
3511 3513
3512```json theme={null}3514```json theme={null}
3513{3515{
3531 PreModelSwitch 決策控制3533 PreModelSwitch 決策控制
3532</h4>3534</h4>
3533 3535
3534`PreModelSwitch` hook 可以取消切換、要求使用者確認,或讓切換繼續進行。退出碼 2 或頂層 `decision: "block"` 會取消切換。3536`PreModelSwitch` hook 可以取消切換、要求使用者確認,或讓切換繼續進行。退出碼 2 或頂層的 `decision: "block"` 會取消切換。
3535 3537
3536若需要更精細的控制,請在 `hookSpecificOutput` 物件中回傳 `permissionDecision` 和 `permissionDecisionReason`,與 [PreToolUse](#pretooluse-decision-control) 相同。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表說明這兩個欄位:3538若要進行更精細的控制,請在 `hookSpecificOutput` 物件中回傳 `permissionDecision` 和 `permissionDecisionReason`,與 [PreToolUse](#pretooluse-decision-control) 相同。`PreModelSwitch` 接受 `"allow"`、`"deny"` 和 `"ask"`。它不接受 `"defer"`、`updatedInput` 或 `additionalContext`。下表說明這兩個欄位:
3537 3539
3538| 欄位 | 說明 |3540| 欄位 | 說明 |
3539| :- | :- |3541| :- | :- |
3540| `permissionDecision` | `"allow"` 會繼續進行並略過[提示快取處於暖狀態時 Claude Code 顯示的確認](/docs/zh-TW/prompt-caching#switching-models)。`"deny"` 會取消切換。`"ask"` 會提示使用者確認 |3542| `permissionDecision` | `"allow"` 會繼續進行,並略過[提示快取處於熱狀態時 Claude Code 顯示的確認](/docs/zh-TW/prompt-caching#switching-models)。`"deny"` 會取消切換。`"ask"` 會提示使用者確認 |
3541| `permissionDecisionReason` | 對於 `"deny"`,會作為切換被封鎖的原因顯示給使用者,或作為 `set_model` 請求的錯誤回傳。對於 `"ask"`,會顯示在確認提示中。對於 `"allow"` 則會被忽略 |3543| `permissionDecisionReason` | 對於 `"deny"`,會作為切換遭封鎖的原因顯示給使用者,或作為 `set_model` 請求的錯誤回傳。對於 `"ask"`,會顯示在確認提示中。對於 `"allow"` 則會被忽略 |
3542 3544
3543只有互動式工作階段中的 `/model` 能顯示 `"ask"` 提示。在其他所有使用介面上,包括使用 `-p` 旗標的非互動模式、`/config` 和 `set_model` 請求,Claude Code 都會將 `"ask"` 視為拒絕。3545只有互動式工作階段中的 `/model` 可以顯示 `"ask"` 提示。在其他所有使用介面上,包括使用 `-p` 旗標的非互動模式、`/config` 和 `set_model` 請求,Claude Code 都會將 `"ask"` 視為拒絕。
3544 3546
3545以下範例要求使用者確認,並引用 `context_tokens` 中的 token 數:3547此範例會要求使用者確認,並引用 `context_tokens` 中的 token 數:
3546 3548
3547```json theme={null}3549```json theme={null}
3548{3550{
3554}3556}
3555```3557```
3556 3558
3557當多個 PreModelSwitch hook 回傳不同的決策時,優先順序為 `deny` > `ask` > `allow`。3559當多個 PreModelSwitch hook 回傳不同決策時,優先順序為 `deny` > `ask` > `allow`。
3558 3560
3559無論決策為何,Claude Code 都會向使用者顯示您的 hook 回傳的任何 `systemMessage`,因此成本回報 hook 可以回傳 `{"systemMessage": "..."}` 並以 0 結束。3561無論決策為何,Claude Code 都會向使用者顯示 hook 回傳的任何 `systemMessage`,因此回報成本的 hook 可以回傳 `{"systemMessage": "..."}` 並以 0 退出。
3560 3562
3561在逾時前未回應的 PreModelSwitch hook 會封鎖切換。相較之下,在 [PreToolUse](#timeouts) 上,逾時的命令 hook 會讓工具呼叫繼續進行。此事件的預設逾時為 30 秒。`PreModelSwitch` 只執行 `command`、`http` 和 `mcp_tool` hook,因此 `prompt` 和 `agent` 的預設值不適用。3563在逾時前未回應的 PreModelSwitch hook 會封鎖切換。相較之下,在 [PreToolUse](#timeouts) 上,逾時的命令 hook 會讓工具呼叫繼續進行。此事件的預設逾時為 30 秒。`PreModelSwitch` 只會執行 `command`、`http` 和 `mcp_tool` hook,因此 `prompt` 和 `agent` 的預設值不適用。
3562 3564
3563以 0 或 2 以外的代碼結束且未印出 JSON 決策的 hook 不會封鎖:Claude Code 會顯示其 stderr 並套用切換,如[其他退出碼](#other-exit-codes)中所述。3565以 0 或 2 以外的代碼退出且未印出 JSON 決策的 hook 不會封鎖:Claude Code 會顯示其 stderr 並套用切換,如[其他退出碼](#other-exit-codes)中所述。
3564 3566
3565<h3 id="postmodelswitch">3567<h3 id="postmodelswitch">
3566 PostModelSwitch3568 PostModelSwitch
3567</h3>3569</h3>
3568 3570
3569在工作階段的模型變更之後執行。使用它來為 Claude 提供特定於模型的指引,而無需編輯每個 CLAUDE.md,例如適用於特定模型的全組織指令。3571在工作階段的模型變更之後執行。使用它為 Claude 提供特定模型的指引,而無需編輯每個 CLAUDE.md,例如適用於特定模型的全組織指令。
3570 3572
3571PostModelSwitch 需要 Claude Code v2.1.251 或更新版本。它無法封鎖,因為模型已經變更。Claude Code 會在以下任何變更之後執行 PostModelSwitch hook:3573PostModelSwitch 需要 Claude Code v2.1.251 或更新版本。它無法封鎖,因為模型已經變更。Claude Code 會在下列任何變更之後執行 PostModelSwitch hook:
3572 3574
3573* 您或用戶端所請求的切換3575* 您或用戶端所請求的切換
3574* [自動模型備援](/docs/zh-TW/model-config#automatic-model-fallback),會變更工作階段的模型3576* [自動模型備援](/docs/zh-TW/model-config#automatic-model-fallback),這會變更工作階段的模型
3575* 諸如 [`opusplan`](/docs/zh-TW/model-config#opusplan-model-setting) 之類的設定進入或離開 plan mode3577* [`opusplan`](/docs/zh-TW/model-config#opusplan-model-setting) 等設定進入或離開 plan mode
3576* Claude Code 在您恢復工作階段時還原模型3578* Claude Code 在您恢復工作階段時還原模型
3577 3579
3578當[備援模型鏈](/docs/zh-TW/model-config#fallback-model-chains)中的模型服務某個回合時,Claude Code 不會執行 PostModelSwitch hook,因為該替換只持續一個回合,且不會變更工作階段的模型。3580當[備援模型鏈](/docs/zh-TW/model-config#fallback-model-chains)中的模型為某個回合提供服務時,Claude Code 不會執行 PostModelSwitch hook,因為該替換僅持續一個回合,且不會變更工作階段的模型。
3579 3581
3580matcher 遵循與 [PreModelSwitch](#premodelswitch) 相同的規則:Claude Code 會將其與工作階段所切換到的模型的正式名稱進行比對。3582matcher 遵循與 [PreModelSwitch](#premodelswitch) 相同的規則:Claude Code 會將其與工作階段所切換至之模型的標準名稱進行比對。
3581 3583
3582以下範例會在工作階段的模型變更為任何 Opus 模型時新增指引:3584此範例會在工作階段的模型變更為任何 Opus 模型時新增指引:
3583 3585
3584```json theme={null}3586```json theme={null}
3585{3587{
3599}3601}
3600```3602```
3601 3603
3602若要確認 hook 正常運作,請從執行其他模型的工作階段切換到 Opus 模型,例如在 Sonnet 工作階段中執行 `/model opus`,然後詢問 Claude 它對目前模型有哪些指引。3604若要確認 hook 是否正常運作,請在執行其他模型的工作階段中切換至 Opus 模型,例如在 Sonnet 工作階段中執行 `/model opus`,然後詢問 Claude 關於目前模型有哪些指引。
3603 3605
3604<h4 id="postmodelswitch-input">3606<h4 id="postmodelswitch-input">
3605 PostModelSwitch 輸入3607 PostModelSwitch 輸入
3606</h4>3608</h4>
3607 3609
3608PostModelSwitch hook 會收到與 [PreModelSwitch](#premodelswitch-input) 相同的欄位,其中 `hook_event_name` 設定為 `"PostModelSwitch"`,且多了兩個 `source` 值:`"auto"` 表示自動備援或 Claude Code 自行進行的其他變更,`"resume"` 表示在您恢復工作階段時還原的模型。3610PostModelSwitch hook 會收到與 [PreModelSwitch](#premodelswitch-input) 相同的欄位,其中 `hook_event_name` 設為 `"PostModelSwitch"`,並多了兩個 `source` 值:`"auto"` 表示自動備援或 Claude Code 自行進行的其他變更,`"resume"` 表示在您恢復工作階段時所還原的模型。
3609 3611
3610當 `source` 為 `"auto"` 時,`requested_model` 為 `null`。當 `source` 為 `"resume"` 時,它是 Claude Code 所還原的已儲存模型設定。3612當 `source` 為 `"auto"` 時,`requested_model` 為 `null`。當 `source` 為 `"resume"` 時,它是 Claude Code 所還原的已儲存模型設定。
3611 3613
3613 PostModelSwitch 決策控制3615 PostModelSwitch 決策控制
3614</h4>3616</h4>
3615 3617
3616Claude Code 會在結束代碼為 0 時取用您的 hook 的[純文字 stdout](#exit-code-0),或取用 JSON 輸出中的 `additionalContext`,並隨切換後的下一個請求傳遞給 Claude。除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,您還可以回傳:3618Claude Code 會在退出碼為 0 時擷取 hook 的[純文字 stdout](#exit-code-0),或擷取 JSON 輸出中的 `additionalContext`,並在切換後隨下一個請求傳遞給 Claude。除了所有 hook 都可使用的 [JSON 輸出欄位](#json-output)之外,您還可以回傳:
3617 3619
3618| 欄位 | 說明 |3620| 欄位 | 說明 |
3619| :- | :- |3621| :- | :- |
3620| `additionalContext` | 隨下一個請求加入 Claude 上下文的字串。請參閱[為 Claude 新增上下文](#add-context-for-claude) |3622| `additionalContext` | 隨下一個請求加入 Claude 上下文的字串。請參閱[為 Claude 新增上下文](#add-context-for-claude) |
3621 3623
3622如果在您傳送下一個提示詞後五秒內 hook 尚未完成,Claude Code 會在不含該輸出的情況下傳送該請求,並改為將輸出附加到之後的請求。如果模型在下一個請求之前變更多次,Claude Code 只會傳遞最後一次切換之目標模型的輸出。3624如果 hook 在您傳送下一個提示詞後五秒內尚未完成,Claude Code 會在不含該輸出的情況下傳送該請求,並改為將輸出附加至之後的請求。如果模型在下一個請求之前變更多次,Claude Code 只會傳遞最後一次切換之目標模型的輸出。
3623 3625
3624<h3 id="sessionend">3626<h3 id="sessionend">
3625 SessionEnd3627 SessionEnd
3626</h3>3628</h3>
3627 3629
3628在 Claude Code 工作階段結束時執行。適用於清理工作、記錄工作階段3630在 Claude Code 工作階段結束時執行。適用於清理工作、記錄工作階段
3629統計資料或儲存工作階段狀態。支援使用 matcher 依結束原因進行篩選。3631統計資料或儲存工作階段狀態。支援使用 matcher 依退出原因篩選。
3630 3632
3631hook 輸入中的 `reason` 欄位表示工作階段結束的原因:3633hook 輸入中的 `reason` 欄位表示工作階段結束的原因:
3632 3634
3634| :- | :- |3636| :- | :- |
3635| `clear` | 使用 `/clear` 命令清除工作階段 |3637| `clear` | 使用 `/clear` 命令清除工作階段 |
3636| `resume` | 透過互動式 `/resume` 切換工作階段 |3638| `resume` | 透過互動式 `/resume` 切換工作階段 |
3637| `logout` | 使用者登出 |3639| `logout` | 使用者已登出 |
3638| `prompt_input_exit` | 使用者在提示詞輸入可見時結束 |3640| `prompt_input_exit` | 使用者在提示詞輸入可見時退出 |
3639| `other` | 其他結束原因 |3641| `other` | 其他退出原因 |
3640| `bypass_permissions_disabled` | 已在 v2.1.234 中移除;Claude Code 不會傳送此值。請從您的 `SessionEnd` matcher 中移除它 |3642| `bypass_permissions_disabled` | 已於 v2.1.234 移除;Claude Code 不會傳送此值。請將其從您的 `SessionEnd` matcher 中移除 |
3641 3643
3642<h4 id="sessionend-input">3644<h4 id="sessionend-input">
3643 SessionEnd 輸入3645 SessionEnd 輸入
3655}3657}
3656```3658```
3657 3659
3658SessionEnd hook 沒有決策控制。它們無法封鎖工作階段終止,但可以執行清理工作。Claude Code 會捨棄它們的 [JSON 輸出欄位](#json-output),例如 `systemMessage`。3660SessionEnd hook 沒有決策控制。它們無法封鎖工作階段終止,但可以執行清理工作。Claude Code 會捨棄其 [JSON 輸出欄位](#json-output),例如 `systemMessage`。
3659 3661
3660SessionEnd hook 的預設逾時為 1.5 秒。此逾時適用於您結束、執行 `/clear` 或透過互動式 `/resume` 切換工作階段時。您可以透過兩種方式給予 hook 更多時間:3662SessionEnd hook 的預設逾時為 1.5 秒。此逾時適用於您退出、執行 `/clear` 或透過互動式 `/resume` 切換工作階段時。您可以透過兩種方式給予 hook 更多時間:
3661 3663
3662* **個別 hook 的 `timeout`**:在該 hook 的設定中設定 `timeout`。整體預算會自動提高,以符合您設定檔中最高的個別 hook `timeout`,上限為 60 秒。如果您以這種方式提高預算,沒有自己 `timeout` 的 hook 仍會保留預設值。在外掛程式提供的 hook 上設定的逾時不會提高預算。3664* **個別 hook 的 `timeout`**:在該 hook 的設定中設定 `timeout`。整體預算會自動提高,以符合設定檔中最高的個別 hook `timeout`,上限為 60 秒。如果您以此方式提高預算,沒有自己 `timeout` 的 hook 仍會保留預設值。在外掛程式提供的 hook 上設定的逾時不會提高預算。
3663* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:以毫秒為單位設定此環境變數,以明確覆寫預算。您設定的值也會成為每個沒有自己 `timeout` 之 hook 的逾時。3665* **`CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS`**:以毫秒為單位設定此環境變數,以明確覆寫預算。您設定的值也會成為每個沒有自己 `timeout` 之 hook 的逾時。
3664 3666
3665以下範例將預算設定為 5 秒:3667此範例將預算設為 5 秒:
3666 3668
3667```bash theme={null}3669```bash theme={null}
3668CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude3670CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
3674 Elicitation3676 Elicitation
3675</h3>3677</h3>
3676 3678
3677在 MCP 伺服器於工作進行中請求使用者輸入時執行。根據預設,Claude Code 會顯示互動式對話方塊供使用者回應。hook 可以攔截此請求並以程式化方式回應,完全略過對話方塊。3679在 MCP 伺服器於任務進行中請求使用者輸入時執行。預設情況下,Claude Code 會顯示互動式對話方塊供使用者回應。hook 可以攔截此請求並以程式方式回應,完全略過對話方塊。
3680
3681關於包含設定項目和腳本的完整 hook,請參閱[從腳本回答表單請求](#answer-a-form-request-from-a-script)。
3678 3682
3679matcher 欄位會與 MCP 伺服器名稱進行比對。3683matcher 欄位會與 MCP 伺服器名稱進行比對。
3680 3684
3704}3708}
3705```3709```
3706 3710
3707對於 URL 模式的 elicitation,用於基於瀏覽器的身分驗證:3711對於用於瀏覽器型身分驗證的 URL 模式 elicitation:
3708 3712
3709```json theme={null}3713```json theme={null}
3710{3714{
3723 Elicitation 輸出3727 Elicitation 輸出
3724</h4>3728</h4>
3725 3729
3726若要在不顯示對話方塊的情況下以程式化方式回應,請回傳含有 `hookSpecificOutput` 的 JSON 物件:3730Elicitation hook 可以代替使用者回答請求、拒絕或取消請求,或將其交由對話方塊處理。若要回答、拒絕或取消,請以 0 退出並印出包含 `action` 的 `hookSpecificOutput` 物件。伺服器會收到您的回答,且不會出現對話方塊。此表格的每一列顯示針對某一結果應回傳的內容,以及 MCP 伺服器所收到的內容:
3731
3732| 目的 | 回傳 | 伺服器收到 |
3733| :- | :- | :- |
3734| 代替使用者回答 | `"action": "accept"`,並在 `content` 中提供表單欄位值 | `accept` 以及您的 `content` |
3735| 拒絕請求 | `"action": "decline"` | `decline` |
3736| 取消請求 | `"action": "cancel"` | `cancel` |
3737| 將請求交由使用者處理 | 不輸出任何內容,並以退出碼 0 退出 | 使用者從[對話方塊](/docs/zh-TW/mcp#respond-to-mcp-elicitation-requests)提供的回答 |
3738
3739此輸出會回答 [Elicitation 輸入](#elicitation-input)中所示的表單模式請求。`content` 中的鍵是該請求 `requested_schema` 中的屬性名稱:
3727 3740
3728```json theme={null}3741```json theme={null}
3729{3742{
3737}3750}
3738```3751```
3739 3752
3740| 欄位 | 值 | 說明 |3753此輸出會拒絕請求:
3741| :- | :- | :- |3754
3742| `action` | `accept`、`decline`、`cancel` | 是否接受、拒絕或取消請求 |3755```json theme={null}
3743| `content` | object | 要提交的表單欄位值。僅在 `action` 為 `accept` 時使用 |3756{
3757 "hookSpecificOutput": {
3758 "hookEventName": "Elicitation",
3759 "action": "decline"
3760 }
3761}
3762```
3763
3764在對話方塊中,選取 **Decline** 會傳送 `decline`,按下 `Esc` 則會傳送 `cancel`,因此請回傳您希望伺服器看到的那一個。
3765
3766對於 URL 模式的請求,回傳 `accept` 的 hook 會略過對話方塊,因此 URL 永遠不會開啟。
3767
3768無論您回傳哪一個 `action`,Claude Code 都會捨棄 Elicitation hook JSON 輸出中的 `reason`、`systemMessage` 和 `continue`。
3744 3769
3745退出碼 2 會拒絕 elicitation。Claude Code 不會在任何地方顯示您的 stderr 訊息。3770<h4 id="other-ways-to-decline-an-elicitation">
3771 拒絕 elicitation 的其他方式
3772</h4>
3773
3774您的 hook 也可以透過下列方式拒絕。伺服器收到的 `decline` 與 `"action": "decline"` 相同:
3775
3776* **以代碼 2 退出**:Claude Code 會忽略同一個 hook 所印出的 `hookSpecificOutput`
3777* **印出頂層的 `"decision": "block"`**:此封鎖會覆寫同一輸出中的 `action`
3778
3779當多個 hook 比對到同一個請求時,其中一個 hook 的拒絕會覆寫另一個 hook 的 `accept` 或 `cancel`。
3780
3781此腳本會拒絕 URL 模式的請求,並將表單請求交由對話方塊處理:
3782
3783```bash theme={null}
3784#!/bin/bash
3785if [ "$(jq -r '.mode')" = "url" ]; then
3786 exit 2
3787fi
3788```
3789
3790使用者和伺服器都不會看到您的 hook 拒絕的原因,因為 Claude Code 不會顯示您的 stderr 或 `reason`。
3791
3792從 v2.1.105 起直到 v2.1.284 修正之前,Claude Code 會忽略 `Elicitation` 和 `ElicitationResult` hook 的頂層 `decision`。
3793
3794<h4 id="answer-a-form-request-from-a-script">
3795 從腳本回答表單請求
3796</h4>
3746 3797
3747Claude Code 會依據 Elicitation hook JSON 輸出中的 `hookSpecificOutput` 採取行動,並捨棄 `systemMessage` 和 `continue`。3798此範例會代替使用者回答一個重複出現的問題。名為 `issue-tracker` 的 MCP 伺服器在表單中詢問專案代碼,而 hook 會填入 `DOCS`。當 `project_key` 是表單唯一的欄位時,腳本會接受請求。對於任何其他請求,它不會印出任何內容,因此會出現對話方塊。
3799
3800<Tabs>
3801 <Tab title="macOS/Linux">
3802 在設定檔中為此事件註冊命令 hook,並以伺服器名稱作為 matcher:
3803
3804 ```json theme={null}
3805 {
3806 "hooks": {
3807 "Elicitation": [
3808 {
3809 "matcher": "issue-tracker",
3810 "hooks": [
3811 {
3812 "type": "command",
3813 "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/answer-project-key.sh",
3814 "args": []
3815 }
3816 ]
3817 }
3818 ]
3819 }
3820 }
3821 ```
3822
3823 將此腳本儲存至專案中的 `.claude/hooks/answer-project-key.sh`,並使用 `chmod +x` 使其可執行:
3824
3825 ```bash theme={null}
3826 #!/bin/bash
3827 input=$(cat)
3828 fields=$(jq -c '.requested_schema.properties // {} | keys' <<<"$input")
3829
3830 if [ "$fields" = '["project_key"]' ]; then
3831 jq -n '{hookSpecificOutput: {hookEventName: "Elicitation", action: "accept", content: {project_key: "DOCS"}}}'
3832 fi
3833 ```
3834 </Tab>
3835
3836 <Tab title="Windows (PowerShell)">
3837 註冊一個透過 PowerShell 執行腳本的命令 hook,並以伺服器名稱作為 matcher:
3838
3839 ```json theme={null}
3840 {
3841 "hooks": {
3842 "Elicitation": [
3843 {
3844 "matcher": "issue-tracker",
3845 "hooks": [
3846 {
3847 "type": "command",
3848 "command": "powershell.exe",
3849 "args": [
3850 "-NoProfile",
3851 "-ExecutionPolicy",
3852 "Bypass",
3853 "-File",
3854 "${CLAUDE_PROJECT_DIR}/.claude/hooks/answer-project-key.ps1"
3855 ]
3856 }
3857 ]
3858 }
3859 ]
3860 }
3861 }
3862 ```
3863
3864 將此腳本儲存至專案中的 `.claude/hooks/answer-project-key.ps1`:
3865
3866 ```powershell theme={null}
3867 $request = [Console]::In.ReadToEnd() | ConvertFrom-Json
3868 $fields = @($request.requested_schema.properties.PSObject.Properties.Name)
3869
3870 if ($fields.Count -eq 1 -and $fields[0] -eq 'project_key') {
3871 @{
3872 hookSpecificOutput = @{
3873 hookEventName = "Elicitation"
3874 action = "accept"
3875 content = @{ project_key = "DOCS" }
3876 }
3877 } | ConvertTo-Json -Depth 3
3878 }
3879 ```
3880 </Tab>
3881</Tabs>
3882
3883若要確認 hook 是否正常運作,請使用 `claude --debug` 啟動 Claude Code,並給 Claude 一個會讓伺服器詢問專案代碼的任務。不會出現對話方塊,且[偵錯日誌](#debug-hooks)中會有一行以 `Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}` 結尾。
3748 3884
3749<h3 id="elicitationresult">3885<h3 id="elicitationresult">
3750 ElicitationResult3886 ElicitationResult
3752 3888
3753在使用者回應 MCP elicitation 之後執行。hook 可以在回應傳回 MCP 伺服器之前觀察、修改或封鎖該回應。3889在使用者回應 MCP elicitation 之後執行。hook 可以在回應傳回 MCP 伺服器之前觀察、修改或封鎖該回應。
3754 3890
3891當 [Elicitation](#elicitation) hook 回答了請求時,Claude Code 會將該回答傳送至伺服器,而不執行 ElicitationResult hook。
3892
3755matcher 欄位會與 MCP 伺服器名稱進行比對。3893matcher 欄位會與 MCP 伺服器名稱進行比對。
3756 3894
3757<h4 id="elicitationresult-input">3895<h4 id="elicitationresult-input">
3769 "mcp_server_name": "my-mcp-server",3907 "mcp_server_name": "my-mcp-server",
3770 "action": "accept",3908 "action": "accept",
3771 "content": { "username": "alice" },3909 "content": { "username": "alice" },
3772 "mode": "form",3910 "mode": "form"
3773 "elicitation_id": "elicit-123"
3774}3911}
3775```3912```
3776 3913
3778 ElicitationResult 輸出3915 ElicitationResult 輸出
3779</h4>3916</h4>
3780 3917
3781若要覆寫使用者的回應,請回傳含有 `hookSpecificOutput` 的 JSON 物件:3918ElicitationResult hook 可以讓使用者的回應通過、變更其值,或封鎖它。若要變更或封鎖回應,請以 0 退出並印出包含 `action` 的 `hookSpecificOutput` 物件。此表格的每一列顯示針對某一結果應回傳的內容,以及 MCP 伺服器所收到的內容:
3919
3920| 目的 | 回傳 | 伺服器收到 |
3921| :- | :- | :- |
3922| 讓回應通過 | 不輸出任何內容,並以退出碼 0 退出 | 使用者的回應,未經變更 |
3923| 變更提交的值 | `"action": "accept"`,並在 `content` 中提供新值 | `accept` 以及您的 `content`,取代使用者的值 |
3924| 封鎖回應 | `"action": "decline"` | `decline`,不含使用者的值 |
3925| 取消請求 | `"action": "cancel"` | `cancel`,以及使用者提交的值。若要保留這些值不傳送,請回傳 `"decline"` |
3926
3927此輸出會變更 [ElicitationResult 輸入](#elicitationresult-input)中所示的回應,因此在使用者提交 `alice` 之處,伺服器會收到 `alice@example.com`:
3782 3928
3783```json theme={null}3929```json theme={null}
3784{3930{
3785 "hookSpecificOutput": {3931 "hookSpecificOutput": {
3786 "hookEventName": "ElicitationResult",3932 "hookEventName": "ElicitationResult",
3787 "action": "decline",3933 "action": "accept",
3788 "content": {}3934 "content": {
3935 "username": "alice@example.com"
3936 }
3789 }3937 }
3790}3938}
3791```3939```
3792 3940
3793| 欄位 | 值 | 說明 |3941您的 `content` 會取代使用者的整個 `content` 物件,因此請包含您未變更的欄位。請同時回傳 `action`,因為 Claude Code 會忽略沒有 `action` 的 `hookSpecificOutput`。
3794| :- | :- | :- |3942
3795| `action` | `accept`、`decline`、`cancel` | 覆寫使用者的動作 |3943ElicitationResult hook 也會在使用者拒絕或取消時執行,且您的 `action` 會取代使用者的 `action`。請在回傳 `accept` 之前檢查輸入的 `action` 是否為 `accept`,否則您的 hook 會將已拒絕的請求變成已接受的請求。此腳本會在使用者接受時進行相同的變更,保留其他欄位,否則不印出任何內容:
3796| `content` | object | 覆寫表單欄位值。僅在 `action` 為 `accept` 時有意義 |3944
3945```bash theme={null}
3946#!/bin/bash
3947input=$(cat)
3797 3948
3798退出碼 2 會封鎖回應,將實際動作變更為 `decline`。Claude Code 不會在任何地方顯示您的 stderr 訊息。3949if [ "$(jq -r '.action' <<<"$input")" = "accept" ]; then
3950 jq '{hookSpecificOutput: {hookEventName: "ElicitationResult", action: "accept", content: (.content + {username: (.content.username + "@example.com")})}}' <<<"$input"
3951fi
3952```
3799 3953
3800Claude Code 會依據 ElicitationResult hook JSON 輸出中的 `hookSpecificOutput` 採取行動,並捨棄 `systemMessage` 和 `continue`。3954此輸出會封鎖回應:
3955
3956```json theme={null}
3957{
3958 "hookSpecificOutput": {
3959 "hookEventName": "ElicitationResult",
3960 "action": "decline"
3961 }
3962}
3963```
3964
3965退出碼 2 和頂層的 `"decision": "block"` 也會封鎖回應。[拒絕 elicitation 的其他方式](#other-ways-to-decline-an-elicitation)說明了當 hook 組合使用這些方式時哪一個會生效、使用者會看到什麼,以及哪些版本會忽略 `decision`。
3966
3967無論您回傳哪一個 `action`,Claude Code 都會捨棄 ElicitationResult hook JSON 輸出中的 `reason`、`systemMessage` 和 `continue`。
3801 3968
3802<h2 id="prompt-based-hooks">3969<h2 id="prompt-based-hooks">
3803 基於提示的 hooks3970 基於提示的 hooks
3861 4028
3862將 `type` 設定為 `"prompt"` 並提供 `prompt` 字串而不是 `command`。使用 `$ARGUMENTS` 佔位符將 hook 的 JSON 輸入資料注入到您的提示文字中。4029將 `type` 設定為 `"prompt"` 並提供 `prompt` 字串而不是 `command`。使用 `$ARGUMENTS` 佔位符將 hook 的 JSON 輸入資料注入到您的提示文字中。
3863 4030
4031在提示詞 hook 或 [agent hook](#agent-based-hooks) 中,您可以將 `prompt` 寫成關於要阻止或允許什麼的規則,例如「Block any Bash command that reads `.env` files」,或寫成必須成立的條件,例如「All unit tests pass」。
4032
3864此 `Stop` hook 詢問 LLM 在允許 Claude 完成之前是否應該評估所有任務是否完成:4033此 `Stop` hook 詢問 LLM 在允許 Claude 完成之前是否應該評估所有任務是否完成:
3865 4034
3866```json theme={null}4035```json theme={null}