> ## Documentation Index
> Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks 參考

> Claude Code hook 事件、配置架構、JSON 輸入/輸出格式、退出代碼、非同步 hooks、HTTP hooks、提示 hooks 和 MCP 工具 hooks 的參考。

<Tip>
  如需快速入門指南和範例，請參閱 [使用 hooks 自動化工作流程](/zh-TW/hooks-guide)。
</Tip>

Hooks 是使用者定義的 shell 命令、HTTP 端點或 LLM 提示，在 Claude Code 生命週期的特定時間點自動執行。使用此參考來查詢事件架構、配置選項、JSON 輸入/輸出格式，以及非同步 hooks、HTTP hooks 和 MCP 工具 hooks 等進階功能。如果您是第一次設定 hooks，請改為從 [指南](/zh-TW/hooks-guide) 開始。

<h2 id="hook-lifecycle">
  Hook 生命週期
</h2>

Hooks 在 Claude Code 工作階段期間的特定時間點觸發。當事件觸發且匹配器匹配時，Claude Code 會將有關該事件的 JSON 上下文傳遞給您的 hook 處理程式。對於命令 hooks，輸入會到達 stdin。對於 HTTP hooks，它會作為 POST 請求正文到達。您的處理程式可以檢查輸入、採取行動，並可選擇性地返回決定。

事件分為三種節奏：

* 每個工作階段一次：`SessionStart` 和 `SessionEnd`
* 每個轉向一次：`UserPromptSubmit`、`Stop` 和 `StopFailure`
* 代理迴圈內每個工具呼叫：`PreToolUse` 和 `PostToolUse`

<div style={{maxWidth: "500px", margin: "0 auto"}}>
  <Frame>
    <img src="https://mintcdn.com/claude-code/uLsR38F1U_5zPppm/images/hooks-lifecycle.svg?fit=max&auto=format&n=uLsR38F1U_5zPppm&q=85&s=fbdbd78ad9f474da7d344879341341f0" alt="Hook 生命週期圖表，顯示可選的 Setup 進入 SessionStart，然後是每個轉向的迴圈，包含 UserPromptSubmit、用於 slash commands 的 UserPromptExpansion、嵌套的代理迴圈（PreToolUse、PermissionRequest、PostToolUse、PostToolUseFailure、PostToolBatch、SubagentStart/Stop、TaskCreated、TaskCompleted）和 Stop 或 StopFailure，接著是 TeammateIdle、PreCompact、PostCompact 和 SessionEnd，Elicitation 和 ElicitationResult 嵌套在 MCP 工具執行內，PermissionDenied 作為 PermissionRequest 的側分支用於自動模式拒絕，WorktreeCreate、WorktreeRemove、Notification、ConfigChange、InstructionsLoaded、CwdChanged 和 FileChanged 作為獨立非同步事件，以及 MessageDisplay 作為顯示專用事件，在助手訊息文字串流時執行" width="520" height="1228" data-path="images/hooks-lifecycle.svg" />
  </Frame>
</div>

下表總結了每個事件何時觸發。[Hook 事件](#hook-events)部分記錄了每個事件的完整輸入架構和決定控制選項。

| Event                 | When it fires                                                                                                                                          |
| :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SessionStart`        | When a session begins or resumes                                                                                                                       |
| `Setup`               | When you start Claude Code with `--init-only`, or with `--init` or `--maintenance` in `-p` mode. For one-time preparation in CI or scripts             |
| `UserPromptSubmit`    | When you submit a prompt, before Claude processes it                                                                                                   |
| `UserPromptExpansion` | When a user-typed command expands into a prompt, before it reaches Claude. Can block the expansion                                                     |
| `PreToolUse`          | Before a tool call executes. Can block it                                                                                                              |
| `PermissionRequest`   | When a permission dialog appears                                                                                                                       |
| `PermissionDenied`    | When a tool call is denied by the auto mode classifier. Return `{retry: true}` to tell the model it may retry the denied tool call                     |
| `PostToolUse`         | After a tool call succeeds                                                                                                                             |
| `PostToolUseFailure`  | After a tool call fails                                                                                                                                |
| `PostToolBatch`       | After a full batch of parallel tool calls resolves, before the next model call                                                                         |
| `Notification`        | When Claude Code sends a notification                                                                                                                  |
| `MessageDisplay`      | While assistant message text is displayed                                                                                                              |
| `SubagentStart`       | When a subagent is spawned                                                                                                                             |
| `SubagentStop`        | When a subagent finishes                                                                                                                               |
| `TaskCreated`         | When a task is being created via `TaskCreate`                                                                                                          |
| `TaskCompleted`       | When a task is being marked as completed                                                                                                               |
| `Stop`                | When Claude finishes responding                                                                                                                        |
| `StopFailure`         | When the turn ends due to an API error. Output and exit code are ignored                                                                               |
| `TeammateIdle`        | When an [agent team](/en/agent-teams) teammate is about to go idle                                                                                     |
| `InstructionsLoaded`  | When a CLAUDE.md or `.claude/rules/*.md` file is loaded into context. Fires at session start and when files are lazily loaded during a session         |
| `ConfigChange`        | When a configuration file changes during a session                                                                                                     |
| `CwdChanged`          | When the working directory changes, for example when Claude executes a `cd` command. Useful for reactive environment management with tools like direnv |
| `FileChanged`         | When a watched file changes on disk. The `matcher` field specifies which filenames to watch                                                            |
| `WorktreeCreate`      | When a worktree is being created via `--worktree` or `isolation: "worktree"`. Replaces default git behavior                                            |
| `WorktreeRemove`      | When a worktree is being removed, either at session exit or when a subagent finishes                                                                   |
| `PreCompact`          | Before context compaction                                                                                                                              |
| `PostCompact`         | After context compaction completes                                                                                                                     |
| `Elicitation`         | When an MCP server requests user input during a tool call                                                                                              |
| `ElicitationResult`   | After a user responds to an MCP elicitation, before the response is sent back to the server                                                            |
| `SessionEnd`          | When a session terminates                                                                                                                              |

<h3 id="how-a-hook-resolves">
  Hook 如何解析
</h3>

為了了解這些部分如何組合在一起，請考慮此 `PreToolUse` hook，它會阻止破壞性 shell 命令。`matcher` 縮小到 Bash 工具呼叫，`if` 條件進一步縮小到符合 `rm *` 的 Bash 子命令，因此 `block-rm.sh` 僅在兩個篩選器都匹配時才生成：

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(rm *)",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh",
            "args": []
          }
        ]
      }
    ]
  }
}
```

該指令碼從 stdin 讀取 JSON 輸入，提取命令，如果包含 `rm -rf`，則返回 `permissionDecision` 為 `"deny"`：

```bash theme={null}
#!/bin/bash
# .claude/hooks/block-rm.sh
COMMAND=$(jq -r '.tool_input.command')

if echo "$COMMAND" | grep -q 'rm -rf'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "Destructive command blocked by hook"
    }
  }'
else
  exit 0  # no decision; normal permission flow applies
fi
```

現在假設 Claude Code 決定執行 `Bash "rm -rf /tmp/build"`。以下是發生的情況：

<Frame>
  <img src="https://mintcdn.com/claude-code/ikqp3_70mqIahteV/images/hook-resolution.svg?fit=max&auto=format&n=ikqp3_70mqIahteV&q=85&s=be0bf3053550c26de5f54cd64674c197" alt="Hook 解析流程：PreToolUse 事件觸發，匹配器檢查 Bash 匹配，if 條件檢查 Bash(rm *) 匹配。如果兩者都匹配，hook 命令執行並返回 permissionDecision deny，因此工具呼叫被阻止，Claude Code 繼續。如果任一檢查未能匹配，hook 被跳過，工具呼叫允許繼續進行。" width="930" height="270" data-path="images/hook-resolution.svg" />
</Frame>

<Steps>
  <Step title="事件觸發">
    `PreToolUse` 事件觸發。Claude Code 將工具輸入作為 JSON 在 stdin 上發送到 hook：

    ```json theme={null}
    { "tool_name": "Bash", "tool_input": { "command": "rm -rf /tmp/build" }, ... }
    ```
  </Step>

  <Step title="匹配器檢查">
    匹配器 `"Bash"` 與工具名稱匹配，因此此 hook 群組啟動。如果您省略匹配器或使用 `"*"`，群組在事件的每次出現時啟動。
  </Step>

  <Step title="If 條件檢查">
    `if` 條件 `"Bash(rm *)"` 匹配，因為 `rm -rf /tmp/build` 是符合 `rm *` 的子命令，因此此處理程式生成。如果命令是 `npm test`，`if` 檢查會失敗，`block-rm.sh` 永遠不會執行，避免程序生成開銷。`if` 欄位是可選的；沒有它，匹配群組中的每個處理程式都執行。
  </Step>

  <Step title="Hook 處理程式執行">
    該指令碼檢查完整命令並找到 `rm -rf`，因此它將決定列印到 stdout：

    ```json theme={null}
    {
      "hookSpecificOutput": {
        "hookEventName": "PreToolUse",
        "permissionDecision": "deny",
        "permissionDecisionReason": "Destructive command blocked by hook"
      }
    }
    ```

    如果命令是更安全的 `rm` 變體，如 `rm file.txt`，指令碼會改為執行 `exit 0`。Exit code 0 且沒有輸出表示 hook 沒有決定要報告，因此工具呼叫會繼續通過正常的[權限流程](/zh-TW/permissions)。Hook 可以拒絕呼叫，但保持沉默不會批准它。
  </Step>

  <Step title="Claude Code 根據結果採取行動">
    Claude Code 讀取 JSON 決定，阻止工具呼叫，並向 Claude 顯示原因。
  </Step>
</Steps>

下面的[配置](#configuration)部分記錄了完整架構，每個 [hook 事件](#hook-events)部分記錄了您的命令接收的輸入以及它可以返回的輸出。

<h2 id="configuration">
  配置
</h2>

Hooks 在 JSON 設定檔中定義。配置有三個嵌套層級：

1. 選擇要回應的 [hook 事件](#hook-events)，例如 `PreToolUse` 或 `Stop`
2. 新增 [匹配器群組](#matcher-patterns) 以篩選何時觸發，例如「僅針對 Bash 工具」
3. 定義一個或多個 [hook 處理程式](#hook-handler-fields) 以在匹配時執行

有關完整的逐步說明和註解範例，請參閱上面的 [Hook 如何解析](#how-a-hook-resolves)。

<Note>
  此頁面為每個層級使用特定術語：**hook 事件**表示生命週期點，**匹配器群組**表示篩選器，**hook 處理程式**表示執行的 shell 命令、HTTP 端點、MCP 工具、提示或代理。'Hook' 本身指的是一般功能。
</Note>

<h3 id="hook-locations">
  Hook 位置
</h3>

您定義 hook 的位置決定了其範圍：

| 位置                                                              | 範圍        | 可共享          |
| :-------------------------------------------------------------- | :-------- | :----------- |
| `~/.claude/settings.json`                                       | 您的所有專案    | 否，本機限定       |
| `.claude/settings.json`                                         | 單一專案      | 是，可提交到儲存庫    |
| `.claude/settings.local.json`                                   | 單一專案      | 否，gitignored |
| 受管理的原則設定                                                        | 組織範圍      | 是，由管理員控制     |
| [Plugin](/zh-TW/plugins) `hooks/hooks.json`                     | 啟用外掛程式時   | 是，與外掛程式一起打包  |
| [Skill](/zh-TW/skills) 或 [agent](/zh-TW/sub-agents) frontmatter | 元件處於活動狀態時 | 是，在元件檔案中定義   |

有關設定檔解析的詳細資訊，請參閱 [settings](/zh-TW/settings)。企業管理員可以使用 `allowManagedHooksOnly` 來阻止使用者、專案和外掛程式 hooks。在受管理的設定 `enabledPlugins` 中強制啟用的外掛程式的 Hooks 是例外，因此管理員可以通過組織市場分發經過驗證的 hooks。請參閱 [Hook 配置](/zh-TW/settings#hook-configuration)。

<h3 id="matcher-patterns">
  匹配器模式
</h3>

`matcher` 欄位篩選 hooks 何時觸發。匹配器的評估方式取決於它包含的字元：

| 匹配器值                         | 評估為                                | 範例                                                                                   |
| :--------------------------- | :--------------------------------- | :----------------------------------------------------------------------------------- |
| `"*"`、`""` 或省略               | 匹配所有                               | 在事件的每次出現時觸發                                                                          |
| 僅字母、數字、`_`、`-`、空格、`,` 和 `\|` | 精確字串或由 `\|` 或 `,` 分隔的精確字串清單，可選周圍空格 | `Bash` 僅匹配 Bash 工具；`Edit\|Write` 和 `Edit, Write` 各自精確匹配任一工具；`code-reviewer` 僅匹配該代理類型 |
| 包含任何其他字元                     | JavaScript 正規表達式，未錨定               | `^Notebook` 匹配任何以 Notebook 開頭的工具；`mcp__memory__.*` 匹配來自 `memory` 伺服器的每個工具            |

在正規表達式路徑上的匹配器使用 JavaScript 的 `RegExp.prototype.test` 進行測試，該測試在值中任何位置的匹配時成功。`Edit.*` 匹配 `Edit` 和 `NotebookEdit`；當您需要整個字串匹配時，用 `^` 和 `$` 包裝模式，如 `^Edit$`。

逗號分隔符和周圍空格容差需要 Claude Code v2.1.191 或更新版本。

精確匹配集中的連字號需要 Claude Code v2.1.195 或更新版本。在較早的版本上，像 `code-reviewer` 這樣的連字號名稱被評估為未錨定的正規表達式，因此它也會針對 `senior-code-reviewer` 觸發；在這些版本上將其錨定為 `^code-reviewer$` 以僅匹配該名稱。

`FileChanged` 和 `StopFailure` 使用更窄的精確匹配集，僅包含字母、數字、`_` 和 `|`。匹配器中的連字號、空格或逗號會將其保留在正規表達式路徑上，只有 `|` 分隔替代項。表格中列出的支援匹配器的所有其他事件接受 `|` 或 `,`。

`FileChanged` 事件在建立其監視清單時不遵循這些規則。請參閱 [FileChanged](#filechanged)。

每個事件類型在不同的欄位上匹配：

| 事件                                                                                                                                        | 匹配器篩選的內容                                  | 範例匹配器值                                                                                                                                                                     |
| :---------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`PermissionRequest`、`PermissionDenied`                                                    | 工具名稱                                      | `Bash`、`Edit\|Write`、`mcp__.*`                                                                                                                                             |
| `SessionStart`                                                                                                                            | 工作階段如何開始                                  | `startup`、`resume`、`clear`、`compact`                                                                                                                                       |
| `Setup`                                                                                                                                   | 哪個 CLI 旗標觸發設定                             | `init`、`maintenance`                                                                                                                                                       |
| `SessionEnd`                                                                                                                              | 工作階段為何結束                                  | `clear`、`resume`、`logout`、`prompt_input_exit`、`bypass_permissions_disabled`、`other`                                                                                        |
| `Notification`                                                                                                                            | 通知類型                                      | `permission_prompt`、`idle_prompt`、`auth_success`、`elicitation_dialog`、`elicitation_complete`、`elicitation_response`、`agent_needs_input`、`agent_completed`                  |
| `SubagentStart`                                                                                                                           | 代理類型                                      | `general-purpose`、`Explore`、`Plan`、自訂代理名稱或外掛程式範圍名稱，如 `^my-plugin:reviewer$`                                                                                                |
| `PreCompact`、`PostCompact`                                                                                                                | 觸發壓縮的原因                                   | `manual`、`auto`                                                                                                                                                            |
| `SubagentStop`                                                                                                                            | 代理類型                                      | 與 `SubagentStart` 相同的值                                                                                                                                                     |
| `ConfigChange`                                                                                                                            | 配置來源                                      | `user_settings`、`project_settings`、`local_settings`、`policy_settings`、`skills`                                                                                             |
| `CwdChanged`                                                                                                                              | 不支援匹配器                                    | 總是在每次目錄變更時觸發                                                                                                                                                               |
| `FileChanged`                                                                                                                             | 要監視的檔案名稱（請參閱 [FileChanged](#filechanged)） | `.envrc\|.env`                                                                                                                                                             |
| `StopFailure`                                                                                                                             | 錯誤類型                                      | `rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens`、`unknown` |
| `InstructionsLoaded`                                                                                                                      | 載入原因                                      | `session_start`、`nested_traversal`、`path_glob_match`、`include`、`compact`                                                                                                   |
| `UserPromptExpansion`                                                                                                                     | 命令名稱                                      | 您的 skill 或命令名稱                                                                                                                                                             |
| `Elicitation`                                                                                                                             | MCP 伺服器名稱                                 | 您配置的 MCP 伺服器名稱                                                                                                                                                             |
| `ElicitationResult`                                                                                                                       | MCP 伺服器名稱                                 | 與 `Elicitation` 相同的值                                                                                                                                                       |
| `UserPromptSubmit`、`PostToolBatch`、`Stop`、`TeammateIdle`、`TaskCreated`、`TaskCompleted`、`WorktreeCreate`、`WorktreeRemove`、`MessageDisplay` | 不支援匹配器                                    | 總是在每次出現時觸發                                                                                                                                                                 |

匹配器針對 Claude Code 在 stdin 上發送給您的 hook 的 [JSON 輸入](#hook-input-and-output) 中的欄位執行。對於工具事件，該欄位是 `tool_name`。每個 [hook 事件](#hook-events) 部分列出了該事件的完整匹配器值集和輸入架構。

此範例僅在 Claude 寫入或編輯檔案時執行 linting 指令碼：

```json theme={null}
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/lint-check.sh"
          }
        ]
      }
    ]
  }
}
```

`UserPromptSubmit`、`PostToolBatch`、`Stop`、`TeammateIdle`、`TaskCreated`、`TaskCompleted`、`WorktreeCreate`、`WorktreeRemove`、`MessageDisplay` 和 `CwdChanged` 不支援匹配器，總是在每次出現時觸發。如果您將 `matcher` 欄位新增到這些事件，它會被無聲地忽略。

對於工具事件，您可以通過在個別 hook 處理程式上設定 [`if` 欄位](#common-fields) 來更狹隘地篩選。`if` 使用 [權限規則語法](/zh-TW/permissions) 來匹配工具名稱和參數，因此 `"Bash(git *)"` 僅在任何 Bash 輸入的子命令匹配 `git *` 時執行，`"Edit(*.ts)"` 僅針對 TypeScript 檔案執行。

<h4 id="match-mcp-tools">
  匹配 MCP 工具
</h4>

[MCP](/zh-TW/mcp) 伺服器工具在工具事件中顯示為常規工具（`PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`PermissionRequest`、`PermissionDenied`），因此您可以像匹配任何其他工具名稱一樣匹配它們。

MCP 工具遵循命名模式 `mcp__<server>__<tool>`，例如：

* `mcp__memory__create_entities`：Memory 伺服器的建立實體工具
* `mcp__filesystem__read_file`：Filesystem 伺服器的讀取檔案工具
* `mcp__github__search_repositories`：GitHub 伺服器的搜尋工具

要匹配來自伺服器的每個工具，請在伺服器前綴後附加 `.*`。`.*` 是必需的：像 `mcp__memory` 或 `mcp__brave-search` 這樣的匹配器僅包含精確匹配字元，因此它被比較為精確字串，不匹配任何工具。

* `mcp__memory__.*` 匹配來自 `memory` 伺服器的所有工具
* `mcp__brave-search__.*` 匹配來自名稱包含連字號的伺服器的所有工具
* `mcp__.*__write.*` 匹配來自任何伺服器的任何名稱以 `write` 開頭的工具

精確匹配集中的連字號需要 Claude Code v2.1.195 或更新版本。在較早的版本上，像 `mcp__brave-search` 這樣的裸連字號前綴被評估為未錨定的正規表達式，並匹配來自該伺服器的每個工具。`mcp__brave-search__.*` 形式在每個版本上都有效。

來自 [plugin-bundled MCP server](/zh-TW/mcp#plugin-provided-mcp-servers) 的工具使用包含外掛程式名稱的範圍伺服器段：`mcp__plugin_<plugin-name>_<server-name>__<tool>`。針對裸伺服器金鑰編寫的匹配器永遠不會針對這些工具觸發。對於名為 `my-plugin` 的外掛程式，在金鑰 `db` 下打包伺服器，`query` 工具顯示為 `mcp__plugin_my-plugin_db__query`，因此來自該伺服器的每個工具的匹配器是 `mcp__plugin_my-plugin_db__.*`。在處理程式的 [`if` 欄位](#common-fields) 中使用相同的範圍工具名稱。請參閱 [Plugin-provided MCP servers](/zh-TW/mcp#plugin-provided-mcp-servers) 以了解如何建立範圍名稱。

此範例記錄所有 memory 伺服器操作並驗證來自任何 MCP 伺服器的寫入操作：

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}
```

<h3 id="hook-handler-fields">
  Hook 處理程式欄位
</h3>

內部 `hooks` 陣列中的每個物件都是一個 hook 處理程式：當匹配器匹配時執行的 shell 命令、HTTP 端點、MCP 工具、LLM 提示或代理。有五種類型：

* **[命令 hooks](#command-hook-fields)**（`type: "command"`）：執行 shell 命令。您的指令碼在 stdin 上接收事件的 [JSON 輸入](#hook-input-and-output)，並通過退出代碼和 stdout 傳回結果。
* **[HTTP hooks](#http-hook-fields)**（`type: "http"`）：將事件的 JSON 輸入作為 HTTP POST 請求發送到 URL。端點通過使用與命令 hooks 相同的 [JSON 輸出格式](#json-output) 的回應正文傳回結果。
* **[MCP 工具 hooks](#mcp-tool-hook-fields)**（`type: "mcp_tool"`）：在已連接的 [MCP 伺服器](/zh-TW/mcp) 上呼叫工具。工具的文字輸出被視為類似命令 hook stdout。
* **[提示 hooks](#prompt-and-agent-hook-fields)**（`type: "prompt"`）：將提示發送到 Claude 模型進行單輪評估。模型以 JSON 形式返回是/否決定。請參閱 [基於提示的 hooks](#prompt-based-hooks)。
* **[代理 hooks](#prompt-and-agent-hook-fields)**（`type: "agent"`）：生成一個可以使用 Read、Grep 和 Glob 等工具來驗證條件的 subagent，然後返回決定。代理 hooks 是實驗性的，可能會變更。請參閱 [基於代理的 hooks](#agent-based-hooks)。

所有匹配的 hooks 並行執行，相同的處理程式會自動去重。命令 hooks 按命令字串和 `args` 去重，HTTP hooks 按 URL 去重。

處理程式在目前目錄中執行，使用 Claude Code 的環境。在遠端網路環境中，`$CLAUDE_CODE_REMOTE` 環境變數設定為 `"true"`，在本機 CLI 中未設定。{/* min-version: 2.1.199 */}自 v2.1.199 起，[`$CLAUDE_CODE_BRIDGE_SESSION_ID`](/zh-TW/env-vars) 設定為 [Remote Control](/zh-TW/remote-control) 工作階段 ID，而本機工作階段具有活動的 Remote Control 連接。

<h4 id="common-fields">
  通用欄位
</h4>

這些欄位適用於所有 hook 類型：

| 欄位              | 必需 | 描述                                                                                                                                                                                                                                                                                                                        |
| :-------------- | :- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`          | 是  | `"command"`、`"http"`、`"mcp_tool"`、`"prompt"` 或 `"agent"`                                                                                                                                                                                                                                                                  |
| `if`            | 否  | 權限規則語法以篩選此 hook 何時執行，例如 `"Bash(git *)"` 或 `"Edit(*.ts)"`。Hook 命令僅在工具呼叫匹配模式時執行。請參閱下面的 [Bash 匹配表](#bash-if-matching) 以了解 Bash 模式如何針對子命令、`$()` 和反引號進行評估。僅在工具事件上評估：`PreToolUse`、`PostToolUse`、`PostToolUseFailure`、`PermissionRequest` 和 `PermissionDenied`。在其他事件上，設定 `if` 的 hook 永遠不會執行。使用與 [權限規則](/zh-TW/permissions) 相同的語法 |
| `timeout`       | 否  | 取消前的秒數。預設值：`command`、`http` 和 `mcp_tool` 為 600；`prompt` 為 30；`agent` 為 60。[`UserPromptSubmit`](#userpromptsubmit) 將 `command`、`http` 和 `mcp_tool` 的預設值降低到 30，[`MessageDisplay`](#messagedisplay) 將其降低到 10                                                                                                                 |
| `statusMessage` | 否  | hook 執行時顯示的自訂微調訊息                                                                                                                                                                                                                                                                                                         |
| `once`          | 否  | 如果為 `true`，每個工作階段只執行一次，然後被移除。僅在 [skill frontmatter](#hooks-in-skills-and-agents) 中受尊重；在設定檔和代理 frontmatter 中被忽略                                                                                                                                                                                                            |

`if` 欄位恰好包含一個權限規則。沒有 `&&`、`||` 或清單語法來組合規則；要應用多個條件，請為每個條件定義一個單獨的 hook 處理程式。

<span id="bash-if-matching" />對於 Bash 模式，您的 hook 命令是否執行取決於模式的形狀和 Claude 正在呼叫的 Bash 命令。前導 `VAR=value` 指派在匹配前被移除。

| `if` 模式            | Bash 命令                | Hook 執行？ | 原因                                      |
| :----------------- | :--------------------- | :------- | :-------------------------------------- |
| `Bash(git *)`      | `FOO=bar git push`     | 是        | 前導指派被移除；`git push` 匹配                   |
| `Bash(git *)`      | `npm test && git push` | 是        | 每個子命令都被檢查；`git push` 匹配                 |
| `Bash(rm *)`       | `echo $(rm -rf /)`     | 是        | `$()` 和反引號內的命令被檢查；`rm -rf /` 匹配         |
| `Bash(rm *)`       | `echo $(date)`         | 否        | 沒有子命令匹配 `rm *`                          |
| `Bash(git push *)` | `echo $(date)`         | 是        | 指定超過命令名稱的模式在 `$()`、反引號或 `$VAR` 上執行 hook |

當 Bash 命令無法解析時，篩選器也會失敗開放，無論如何執行您的 hook。因為 `if` 篩選器是盡力而為的，請使用 [權限系統](/zh-TW/permissions) 而不是 hook 來強制執行硬允許或拒絕。

<h4 id="command-hook-fields">
  命令 hook 欄位
</h4>

除了 [通用欄位](#common-fields) 外，命令 hooks 還接受這些欄位：

| 欄位            | 必需 | 描述                                                                                                                                                                                                                                     |
| :------------ | :- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `command`     | 是  | 要執行的 shell 命令。使用 `args` 時，要直接生成的可執行檔。請參閱 [Exec 形式和 shell 形式](#exec-form-and-shell-form)                                                                                                                                                |
| `args`        | 否  | 參數清單。存在時，`command` 被解析為可執行檔並直接使用 `args` 作為參數向量生成，不涉及 shell。請參閱 [Exec 形式和 shell 形式](#exec-form-and-shell-form)                                                                                                                          |
| `async`       | 否  | 如果為 `true`，在背景執行而不阻止。請參閱 [在背景執行 hooks](#run-hooks-in-the-background)                                                                                                                                                                   |
| `asyncRewake` | 否  | 如果為 `true`，在背景執行並在退出代碼 2 時喚醒 Claude。暗示 `async`。Hook 的 stderr，或如果 stderr 為空則為 stdout，作為系統提醒顯示給 Claude，以便它可以對長時間執行的背景失敗做出反應                                                                                                              |
| `shell`       | 否  | 用於此 hook 的 shell。接受 `"bash"` 或 `"powershell"`。預設為 `"bash"`，或在未安裝 Git Bash 時在 Windows 上預設為 `"powershell"`。設定 `"powershell"` 在 Windows 上通過 PowerShell 執行命令。不需要 `CLAUDE_CODE_USE_POWERSHELL_TOOL`，因為 hooks 直接生成 PowerShell。設定 `args` 時被忽略 |

<a id="exec-form-and-shell-form" />

<h5 id="exec-form-and-shell-form">
  Exec 形式和 shell 形式
</h5>

當設定 `args` 時，命令 hook 以 exec 形式執行，當省略 `args` 時以 shell 形式執行。每當 hook 參考 [路徑佔位符](#reference-scripts-by-path) 時設定 `args`，因為每個元素作為一個參數傳遞，不進行引用。當您需要 shell 功能（如管道或 `&&`）時，或當兩個問題都不適用時，省略 `args`。

**Exec 形式**在設定 `args` 時執行。Claude Code 在 `PATH` 上解析 `command` 作為可執行檔並直接使用 `args` 作為參數向量生成它。沒有 shell，因此每個 `args` 元素恰好是一個參數，完全按照編寫的方式，路徑佔位符如 `${CLAUDE_PLUGIN_ROOT}` 被替換為 `command` 和每個 `args` 元素中的純字串。特殊字元如撇號、`$` 和反引號逐字傳遞，因為沒有 shell 來解釋它們。任何平台上都不會發生 shell 標記化。

**Shell 形式**在省略 `args` 時執行。`command` 字串被傳遞到 shell：macOS 和 Linux 上的 `sh -c`、Windows 上的 Git Bash，或未安裝 Git Bash 時的 PowerShell。設定 `shell` 欄位以明確選擇。Shell 標記化字串、展開變數並解釋管道、`&&`、重定向和 glob。

<Note>
  在 Windows 上，exec 形式需要 `command` 解析為真實可執行檔，如 `.exe`。npm、npx、eslint 和其他工具在 `node_modules/.bin` 中安裝的 `.cmd` 和 `.bat` 填充程式不是可執行檔，無法在沒有 shell 的情況下生成。要在 exec 形式中執行它們，直接使用 `node` 呼叫底層指令碼，例如 `"command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/node_modules/eslint/bin/eslint.js"]`。`node` 加上指令碼路徑模式在每個平台上都有效，因為 `node.exe` 是真實二進位檔。要按名稱執行 `.cmd` 或 `.bat` 填充程式，請使用 shell 形式。
</Note>

此範例執行與外掛程式一起打包的 Node 指令碼。Exec 形式將解析的指令碼路徑作為一個參數傳遞，不進行引用：

```json theme={null}
{
  "type": "command",
  "command": "node",
  "args": ["${CLAUDE_PLUGIN_ROOT}/scripts/format.js", "--fix"]
}
```

等效的 shell 形式需要引用以處理包含空格或特殊字元的路徑：

```json theme={null}
{
  "type": "command",
  "command": "node \"${CLAUDE_PLUGIN_ROOT}\"/scripts/format.js --fix"
}
```

兩種形式都支援相同的 [路徑佔位符](#reference-scripts-by-path)，並且都將它們作為環境變數 `CLAUDE_PROJECT_DIR`、`CLAUDE_PLUGIN_ROOT` 和 `CLAUDE_PLUGIN_DATA` 匯出到生成的程序，因此指令碼可以讀取 `process.env.CLAUDE_PLUGIN_ROOT`，無論它是如何啟動的。外掛程式 hooks 另外替換 `${user_config.*}` 值；請參閱 [使用者配置](/zh-TW/plugins-reference#user-configuration)。

<Note>
  在 exec 形式中，`command` 僅是可執行檔名稱或路徑。如果 `command` 是沒有路徑分隔符的裸名稱，並且與 `args` 一起包含空格，Claude Code 會記錄警告，因為生成將失敗：沒有名為 `node script.js` 的可執行檔。將額外的令牌移到 `args` 中。包含空格的絕對路徑，如 `C:\Program Files\nodejs\node.exe`，是單個有效的可執行檔，不會觸發警告。
</Note>

<h4 id="http-hook-fields">
  HTTP hook 欄位
</h4>

除了 [通用欄位](#common-fields) 外，HTTP hooks 還接受這些欄位：

| 欄位               | 必需 | 描述                                                                                          |
| :--------------- | :- | :------------------------------------------------------------------------------------------ |
| `url`            | 是  | 要發送 POST 請求的 URL                                                                            |
| `headers`        | 否  | 其他 HTTP 標頭作為鍵值對。值支援使用 `$VAR_NAME` 或 `${VAR_NAME}` 語法的環境變數插值。只有列在 `allowedEnvVars` 中的變數才會被解析 |
| `allowedEnvVars` | 否  | 可能被插值到標頭值中的環境變數名稱清單。對未列出的變數的參考會被替換為空字串。任何環境變數插值都需要此項                                        |

Claude Code 將 hook 的 [JSON 輸入](#hook-input-and-output) 作為 POST 請求正文發送，`Content-Type: application/json`。回應正文使用與命令 hooks 相同的 [JSON 輸出格式](#json-output)。

錯誤處理與命令 hooks 不同：非 2xx 回應、連線失敗和逾時都會產生非阻止性錯誤，允許執行繼續。要阻止工具呼叫或拒絕權限，請返回 2xx 回應，其 JSON 正文包含 `decision: "block"` 或 `hookSpecificOutput` 與 `permissionDecision: "deny"`。

此範例將 `PreToolUse` 事件發送到本機驗證服務，使用來自 `MY_TOKEN` 環境變數的令牌進行驗證：

```json theme={null}
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "http",
            "url": "http://localhost:8080/hooks/pre-tool-use",
            "timeout": 30,
            "headers": {
              "Authorization": "Bearer $MY_TOKEN"
            },
            "allowedEnvVars": ["MY_TOKEN"]
          }
        ]
      }
    ]
  }
}
```

<h4 id="mcp-tool-hook-fields">
  MCP 工具 hook 欄位
</h4>

除了 [通用欄位](#common-fields) 外，MCP 工具 hooks 還接受這些欄位：

| 欄位       | 必需 | 描述                                                                                                                                                                                                 |
| :------- | :- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `server` | 是  | 已配置的 MCP 伺服器的名稱。對於 [plugin-bundled server](/zh-TW/mcp#plugin-provided-mcp-servers)，這是範圍名稱 `plugin:<plugin-name>:<server-name>`，例如 `plugin:my-plugin:db`，而不是裸伺服器金鑰。伺服器必須已連接；hook 永遠不會觸發 OAuth 或連接流程 |
| `tool`   | 是  | 該伺服器上要呼叫的工具名稱                                                                                                                                                                                      |
| `input`  | 否  | 傳遞給工具的參數。字串值支援來自 hook 的 [JSON 輸入](#hook-input-and-output) 的 `${path}` 替換，例如 `"${tool_input.file_path}"`                                                                                            |

工具的文字內容被視為類似命令 hook stdout：如果它解析為有效的 [JSON 輸出](#json-output)，它會被處理為決定，否則它會顯示為純文字。如果命名的伺服器未連接，或工具返回 `isError: true`，hook 會產生非阻止性錯誤，執行繼續。

MCP 工具 hooks 在 Claude Code 連接到您的 MCP 伺服器後在每個 hook 事件上都可用。`SessionStart` 和 `Setup` 通常在伺服器完成連接之前觸發，因此這些事件上的 hooks 應該預期首次執行時出現「未連接」錯誤。

此範例在每個 `Write` 或 `Edit` 後在 `my_server` MCP 伺服器上呼叫 `security_scan` 工具，傳遞編輯檔案的路徑：

```json theme={null}
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "mcp_tool",
            "server": "my_server",
            "tool": "security_scan",
            "input": { "file_path": "${tool_input.file_path}" }
          }
        ]
      }
    ]
  }
}
```

<h4 id="prompt-and-agent-hook-fields">
  提示和代理 hook 欄位
</h4>

除了 [通用欄位](#common-fields) 外，提示和代理 hooks 還接受這些欄位：

| 欄位       | 必需 | 描述                                                                                   |
| :------- | :- | :----------------------------------------------------------------------------------- |
| `prompt` | 是  | 要發送到模型的提示文字。使用 `$ARGUMENTS` 作為 hook 輸入 JSON 的佔位符。使用反斜線逸出以包含字面文字：`\$1.00` 呈現為 `$1.00` |
| `model`  | 否  | 用於評估的模型。預設為快速模型                                                                      |

<h3 id="reference-scripts-by-path">
  按路徑參考指令碼
</h3>

使用這些佔位符按相對於專案或外掛程式根目錄的路徑參考 hook 指令碼，無論 hook 執行時的工作目錄如何：

* `${CLAUDE_PROJECT_DIR}`：專案根目錄。Claude Code 也在 [stdio MCP 伺服器](/zh-TW/mcp#option-3-add-a-local-stdio-server) 和外掛程式 LSP 伺服器的環境中設定此變數。
* `${CLAUDE_PLUGIN_ROOT}`：外掛程式的安裝目錄，用於與 [plugin](/zh-TW/plugins) 一起打包的指令碼。在每次外掛程式更新時變更。
* `${CLAUDE_PLUGIN_DATA}`：外掛程式的 [持久資料目錄](/zh-TW/plugins-reference#persistent-data-directory)，用於應該在外掛程式更新後保留的依賴項和狀態。

對於任何參考路徑佔位符的 hook，優先使用 [exec 形式](#exec-form-and-shell-form)。Exec 形式將每個 `args` 元素作為一個參數傳遞，不進行 shell 標記化，因此包含空格或特殊字元的路徑不需要引用。在 shell 形式中，用雙引號括起每個佔位符。

<Tabs>
  <Tab title="專案指令碼">
    此範例使用 `${CLAUDE_PROJECT_DIR}` 在任何 `Write` 或 `Edit` 工具呼叫後從專案的 `.claude/hooks/` 目錄執行樣式檢查器：

    ```json theme={null}
    {
      "hooks": {
        "PostToolUse": [
          {
            "matcher": "Write|Edit",
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/check-style.sh",
                "args": []
              }
            ]
          }
        ]
      }
    }
    ```
  </Tab>

  <Tab title="外掛程式指令碼">
    在 `hooks/hooks.json` 中定義外掛程式 hooks，使用可選的頂層 `description` 欄位。啟用外掛程式時，其 hooks 會與您的使用者和專案 hooks 合併。

    此範例執行與外掛程式一起打包的格式化指令碼：

    ```json theme={null}
    {
      "description": "Automatic code formatting",
      "hooks": {
        "PostToolUse": [
          {
            "matcher": "Write|Edit",
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
                "args": [],
                "timeout": 30
              }
            ]
          }
        ]
      }
    }
    ```

    有關建立外掛程式 hooks 的詳細資訊，請參閱 [外掛程式元件參考](/zh-TW/plugins-reference#hooks)。
  </Tab>
</Tabs>

<h3 id="hooks-in-skills-and-agents">
  Skills 和代理中的 Hooks
</h3>

除了設定檔和外掛程式外，hooks 還可以使用 frontmatter 直接在 [skills](/zh-TW/skills) 和 [subagents](/zh-TW/sub-agents) 中定義。這些 hooks 的範圍限於元件的生命週期，只有在該元件處於活動狀態時才執行。

支援所有 hook 事件。對於 subagents，`Stop` hooks 會自動轉換為 `SubagentStop`，因為這是 subagent 完成時觸發的事件。

Hooks 使用與基於設定的 hooks 相同的配置格式，但範圍限於元件的生命週期，並在完成時清理。

此 skill 定義了一個 `PreToolUse` hook，在每個 `Bash` 命令之前執行安全驗證指令碼：

```yaml theme={null}
---
name: secure-operations
description: Perform operations with security checks
hooks:
  PreToolUse:
    - matcher: "Bash"
      hooks:
        - type: command
          command: "./scripts/security-check.sh"
---
```

代理在其 YAML frontmatter 中使用相同的格式。

<h3 id="the-/hooks-menu">
  `/hooks` 選單
</h3>

在 Claude Code 中輸入 `/hooks` 以開啟唯讀瀏覽器來查看您配置的 hooks。選單顯示每個 hook 事件及其配置的 hooks 計數，讓您深入查看匹配器，並顯示每個 hook 處理程式的完整詳細資訊。使用它來驗證配置、檢查 hook 來自哪個設定檔，或檢查 hook 的命令、提示或 URL。

選單顯示所有五種 hook 類型：`command`、`prompt`、`agent`、`http` 和 `mcp_tool`。每個 hook 都標有 `[type]` 前綴和指示其定義位置的來源：

* `User`：來自 `~/.claude/settings.json`
* `Project`：來自 `.claude/settings.json`
* `Local`：來自 `.claude/settings.local.json`
* `Plugin`：來自外掛程式的 `hooks/hooks.json`
* `Session`：在目前工作階段中記錄在記憶體中
* `Built-in`：由 Claude Code 內部註冊

選擇 hook 會開啟詳細檢視，顯示其事件、匹配器、類型、來源檔案和完整命令、提示或 URL。選單是唯讀的：要新增、修改或移除 hooks，請直接編輯設定 JSON 或要求 Claude 進行變更。

<h3 id="disable-or-remove-hooks">
  停用或移除 hooks
</h3>

要移除 hook，請從設定 JSON 檔案中刪除其項目。

要暫時停用所有 hooks 而不移除它們，請在設定檔中設定 `"disableAllHooks": true`。沒有辦法在保留 hook 在配置中的同時停用單個 hook。

`disableAllHooks` 設定遵循受管理的設定階層。如果管理員已通過受管理的原則設定配置了 hooks，則在使用者、專案或本機設定中設定的 `disableAllHooks` 無法停用這些受管理的 hooks。只有在受管理的設定層級設定的 `disableAllHooks` 才能停用受管理的 hooks。

對設定檔中 hooks 的直接編輯通常由檔案監視程式自動拾取。

<h2 id="hook-input-and-output">
  Hook 輸入和輸出
</h2>

命令 hooks 通過 stdin 接收 JSON 資料，並通過退出代碼、stdout 和 stderr 傳回結果。HTTP hooks 接收相同的 JSON 作為 POST 請求正文，並通過 HTTP 回應正文傳回結果。本部分涵蓋所有事件通用的欄位和行為。每個事件在 [Hook 事件](#hook-events) 下的部分包括其特定的輸入架構和決定控制選項。

在 macOS 和 Linux 上，自 v2.1.139 起，命令 hooks 在沒有控制終端的自己的工作階段中執行。Hook 程序和任何子程序無法開啟 `/dev/tty` 或直接向 Claude Code 介面發送逃逸序列。Windows 沒有 `/dev/tty`。要在任何平台上向使用者顯示訊息，請在 JSON 輸出中返回 [`systemMessage`](#json-output)。要觸發桌面通知、設定視窗標題或響鈴，請改為返回 [`terminalSequence`](#emit-terminal-notifications)。

<h3 id="common-input-fields">
  通用輸入欄位
</h3>

Hook 事件接收這些欄位作為 JSON，除了每個 [hook 事件](#hook-events) 部分中記錄的事件特定欄位。對於命令 hooks，此 JSON 通過 stdin 到達。對於 HTTP hooks，它作為 POST 請求正文到達。

| 欄位                | 描述                                                                                                                                                                                                                                                                                                                                                                                                |
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `session_id`      | 目前工作階段識別碼                                                                                                                                                                                                                                                                                                                                                                                         |
| `prompt_id`       | UUID 識別目前正在處理的使用者提示。與 [OpenTelemetry 事件上的 `prompt.id` 屬性](/zh-TW/monitoring-usage#event-correlation-attributes) 相符，因此您可以將 hook 輸出與單一提示的遙測相關聯。在第一個使用者輸入之前不存在。{/* min-version: 2.1.196 */}需要 Claude Code v2.1.196 或更新版本                                                                                                                                                                             |
| `transcript_path` | 對話 JSON 的路徑。成績單檔案以非同步方式寫入，可能滯後於記憶體中的對話，因此當 hook 觸發時，它可能尚未包含目前回合的最新訊息。需要目前回合最後助手文字的 Hooks 應在 [Stop](#stop) 和 [SubagentStop](#subagentstop) 上使用 `last_assistant_message`，而不是讀取成績單                                                                                                                                                                                                                   |
| `cwd`             | 叫用 hook 時的目前工作目錄                                                                                                                                                                                                                                                                                                                                                                                  |
| `permission_mode` | 目前 [權限模式](/zh-TW/permissions#permission-modes)：`"default"`、`"plan"`、`"acceptEdits"`、`"auto"`、`"dontAsk"` 或 `"bypassPermissions"`。標記為**手動**的模式以 `"default"` 到達，永遠不會以 `"manual"` 到達，因此匹配 `"default"` 的指令碼繼續工作。並非所有事件都接收此欄位。檢查每個 [hook 事件](#hook-events) 部分中的 JSON 範例                                                                                                                                |
| `effort`          | 物件，其 `level` 欄位保存該回合的活躍 [努力等級](/zh-TW/model-config#adjust-effort-level)：`"low"`、`"medium"`、`"high"`、`"xhigh"` 或 `"max"`。如果請求的模型努力等級超過目前模型支援的等級，這是模型實際使用的降級等級。Ultracode 不是一個不同的等級，報告為 `"xhigh"`。該物件與 [狀態行](/zh-TW/statusline#available-data) `effort` 欄位相符。存在於在工具使用上下文中觸發的事件，例如 `PreToolUse`、`PostToolUse`、`Stop` 和 `SubagentStop`，當目前模型支援努力參數時。該等級也可作為 `$CLAUDE_EFFORT` 環境變數提供給 hook 命令和 Bash 工具。 |
| `hook_event_name` | 觸發的事件名稱                                                                                                                                                                                                                                                                                                                                                                                           |

使用 `--agent` 執行或在 subagent 內執行時，包括兩個額外欄位：

| 欄位           | 描述                                                                                                                                                                                                                                                                                                                                                                        |
| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `agent_id`   | Subagent 的唯一識別碼。僅當 hook 在 subagent 呼叫內觸發時出現。使用此項來區分 subagent hook 呼叫與主執行緒呼叫。                                                                                                                                                                                                                                                                                              |
| `agent_type` | 代理名稱（例如 `"Explore"` 或 `"security-reviewer"`）。當工作階段使用 `--agent` 或 hook 在 subagent 內觸發時出現。對於 subagents，subagent 的類型優先於工作階段的 `--agent` 值。對於 [自訂 subagents](/zh-TW/sub-agents)，這是代理 frontmatter 中的 `name` 欄位，而不是檔案名稱。對於由 [plugin](/zh-TW/plugins) 提供的 subagents，這是外掛範圍識別碼，例如 `my-plugin:reviewer`，而不是裸 frontmatter 名稱。請參閱 [SubagentStart](#subagentstart) 以了解如何針對外掛範圍名稱編寫匹配器。 |

只有 [`SessionStart`](#sessionstart) hooks 可以接收 `model` 欄位，且不保證存在。沒有 `$CLAUDE_MODEL` 環境變數。Hook 程序繼承父環境，因此如果您在 shell 中設定它，它可以讀取 `$ANTHROPIC_MODEL`，但當您在工作階段期間使用 `/model` 切換模型時，該值不會改變。

例如，Bash 命令的 `PreToolUse` hook 在 stdin 上接收此內容：

```json theme={null}
{
  "session_id": "abc123",
  "prompt_id": "550e8400-e29b-41d4-a716-446655440000",
  "transcript_path": "/home/user/.claude/projects/.../transcript.jsonl",
  "cwd": "/home/user/my-project",
  "permission_mode": "default",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}
```

`tool_name` 和 `tool_input` 欄位是事件特定的。每個 [hook 事件](#hook-events) 部分記錄了該事件的額外欄位。

<h3 id="exit-code-output">
  退出代碼輸出
</h3>

來自您的 hook 命令的退出代碼告訴 Claude Code 該操作是應該進行、被阻止還是被忽略。

**退出 0** 表示成功。Claude Code 解析 stdout 以查找 [JSON 輸出欄位](#json-output)。JSON 輸出僅在退出 0 時處理。對於大多數事件，stdout 被寫入詳細日誌，但不在成績單中顯示。例外是 `UserPromptSubmit`、`UserPromptExpansion` 和 `SessionStart`，其中 stdout 被新增為 Claude 可以看到和作用的上下文。

**退出 2** 表示阻止性錯誤。Claude Code 忽略 stdout 和其中的任何 JSON。相反，stderr 文字被反饋給 Claude 作為錯誤訊息。效果取決於事件：`PreToolUse` 阻止工具呼叫，`UserPromptSubmit` 拒絕提示，等等。有關完整清單，請參閱 [退出代碼 2 行為](#exit-code-2-behavior-per-event)。

**任何其他退出代碼** 是大多數 hook 事件的非阻止性錯誤。成績單顯示 `<hook name> hook error` 通知，後跟 stderr 的第一行，因此您可以識別原因而無需 `--debug`。執行繼續，完整的 stderr 被寫入詳細日誌。

例如，一個 hook 命令指令碼，阻止危險的 Bash 命令：

```bash theme={null}
#!/bin/bash
# 從 stdin 讀取 JSON 輸入，檢查命令
command=$(jq -r '.tool_input.command' < /dev/stdin)

if [[ "$command" == rm* ]]; then
  echo "Blocked: rm commands are not allowed" >&2
  exit 2  # 阻止性錯誤：工具呼叫被阻止
fi

exit 0  # 無決定：正常權限流程適用
```

<Warning>
  對於大多數 hook 事件，只有退出代碼 2 會阻止操作。Claude Code 將退出代碼 1 視為非阻止性錯誤並繼續操作，儘管 1 是傳統的 Unix 失敗代碼。如果您的 hook 旨在強制執行原則，請使用 `exit 2`。例外是 `WorktreeCreate`，其中任何非零退出代碼都會中止 worktree 建立。
</Warning>

<h4 id="exit-code-2-behavior-per-event">
  每個事件的退出代碼 2 行為
</h4>

退出代碼 2 是 hook 發出「停止，不要這樣做」的方式。效果取決於事件，因為某些事件代表可以被阻止的操作（例如尚未發生的工具呼叫），而其他事件代表已經發生或無法防止的事情。

| Hook 事件               | 可以阻止？ | 退出 2 時發生的情況                                                                 |
| :-------------------- | :---- | :-------------------------------------------------------------------------- |
| `PreToolUse`          | 是     | 阻止工具呼叫                                                                      |
| `PermissionRequest`   | 是     | 拒絕權限                                                                        |
| `UserPromptSubmit`    | 是     | 阻止提示處理並清除提示                                                                 |
| `UserPromptExpansion` | 是     | 阻止擴展                                                                        |
| `Stop`                | 是     | 防止 Claude 停止，繼續對話                                                           |
| `SubagentStop`        | 是     | 防止 subagent 停止                                                              |
| `TeammateIdle`        | 是     | 防止隊友閒置，所以它繼續工作                                                              |
| `TaskCreated`         | 是     | 回滾任務建立                                                                      |
| `TaskCompleted`       | 是     | 防止任務被標記為已完成                                                                 |
| `ConfigChange`        | 是     | 阻止配置變更生效（除了 `policy_settings`）                                              |
| `StopFailure`         | 否     | 輸出和退出代碼被忽略                                                                  |
| `PostToolUse`         | 否     | 向 Claude 顯示 stderr；工具已執行                                                    |
| `PostToolUseFailure`  | 否     | 向 Claude 顯示 stderr；工具已失敗                                                    |
| `PostToolBatch`       | 是     | 在下一個模型呼叫之前停止代理迴圈                                                            |
| `PermissionDenied`    | 否     | 退出代碼和 stderr 被忽略，因為拒絕已發生。使用 JSON `hookSpecificOutput.retry: true` 告訴模型它可能重試 |
| `Notification`        | 否     | 僅向使用者顯示 stderr                                                              |
| `SubagentStart`       | 否     | 僅向使用者顯示 stderr                                                              |
| `SessionStart`        | 否     | 僅向使用者顯示 stderr                                                              |
| `Setup`               | 否     | 僅向使用者顯示 stderr                                                              |
| `SessionEnd`          | 否     | 僅向使用者顯示 stderr                                                              |
| `CwdChanged`          | 否     | 僅向使用者顯示 stderr                                                              |
| `FileChanged`         | 否     | 僅向使用者顯示 stderr                                                              |
| `PreCompact`          | 是     | 阻止壓縮                                                                        |
| `PostCompact`         | 否     | 僅向使用者顯示 stderr                                                              |
| `Elicitation`         | 是     | 拒絕徵詢                                                                        |
| `ElicitationResult`   | 是     | 阻止回應（操作變為拒絕）                                                                |
| `WorktreeCreate`      | 是     | 任何非零退出代碼都會導致 worktree 建立失敗                                                  |
| `WorktreeRemove`      | 否     | 失敗僅在偵錯模式中記錄                                                                 |
| `InstructionsLoaded`  | 否     | 退出代碼被忽略                                                                     |
| `MessageDisplay`      | 否     | 原始文字被顯示                                                                     |

對於 `SessionStart`、`Setup` 和 `SubagentStart`，退出代碼 2 stderr 在成績單中呈現為 `<hook name> hook error` 通知，與 [非阻止性錯誤](#exit-code-output) 相同的方式。Claude 看不到它，工作階段或 subagent 繼續進行。對於 `SubagentStart`，通知出現在 subagent 自己的成績單中，而不是在父對話中。

自 Claude Code v2.1.199 起，`SessionStart`、`Setup` 和 `SubagentStart` 在成績單中顯示退出代碼 2 stderr。較早的版本僅將其寫入詳細日誌。

<h3 id="http-response-handling">
  HTTP 回應處理
</h3>

HTTP hooks 使用 HTTP 狀態代碼和回應正文，而不是退出代碼和 stdout：

* **2xx 且正文為空**：成功，等同於退出代碼 0 且無輸出
* **2xx 且正文為純文字**：成功，文字被新增為上下文
* **2xx 且正文為 JSON**：成功，使用與命令 hooks 相同的 [JSON 輸出](#json-output) 架構進行解析
* **非 2xx 狀態**：非阻止性錯誤，執行繼續
* **連線失敗或逾時**：非阻止性錯誤，執行繼續

與命令 hooks 不同，HTTP hooks 無法僅通過狀態代碼發出阻止性錯誤信號。要阻止工具呼叫或拒絕權限，請返回 2xx 回應，其 JSON 正文包含適當的決定欄位。

<h3 id="json-output">
  JSON 輸出
</h3>

退出代碼讓您允許或阻止，但 JSON 輸出提供更細粒度的控制。與其以代碼 2 退出來阻止，不如以 0 退出並將 JSON 物件列印到 stdout。Claude Code 從該 JSON 讀取特定欄位以控制行為，包括 [決定控制](#decision-control) 以阻止、允許或升級給使用者。

<Note>
  您必須為每個 hook 選擇一種方法，而不是兩種：要麼單獨使用退出代碼進行信號傳遞，要麼以 0 退出並列印 JSON 以進行結構化控制。Claude Code 僅在退出 0 時處理 JSON。如果您退出 2，任何 JSON 都會被忽略。
</Note>

您的 hook 的 stdout 必須僅包含 JSON 物件。如果您的 shell 設定檔在啟動時列印文字，它可能會干擾 JSON 解析。請參閱故障排除指南中的 [JSON 驗證失敗](/zh-TW/hooks-guide#json-validation-failed)。

Hook 輸出字串，包括 `additionalContext`、`systemMessage` 和純 stdout，上限為 10,000 個字元。超過此限制的輸出會儲存到檔案並替換為預覽和檔案路徑，與大型工具結果的處理方式相同。

JSON 物件支援三種欄位：

* **通用欄位**，如 `continue`，在所有事件中工作。這些列在下表中。
* **頂層 `decision` 和 `reason`** 由某些事件用來阻止或提供反饋。
* **`hookSpecificOutput`** 是一個嵌套物件，用於需要更豐富控制的事件。它需要一個設定為事件名稱的 `hookEventName` 欄位。

| 欄位                 | 預設      | 描述                                                                                                                                          |
| :----------------- | :------ | :------------------------------------------------------------------------------------------------------------------------------------------ |
| `continue`         | `true`  | 如果為 `false`，Claude 在 hook 執行後完全停止處理。優先於任何事件特定的決定欄位                                                                                          |
| `stopReason`       | 無       | 當 `continue` 為 `false` 時向使用者顯示的訊息。不向 Claude 顯示                                                                                              |
| `suppressOutput`   | `false` | 如果為 `true`，隱藏詳細日誌中的 hook stdout                                                                                                             |
| `systemMessage`    | 無       | 向使用者顯示的警告訊息                                                                                                                                 |
| `terminalSequence` | 無       | Claude Code 代表您發出的終端逃逸序列，例如桌面通知、視窗標題或響鈴。限制為 OSC `0`/`1`/`2`/`9`/`99`/`777` 和 BEL。如果值包含允許清單外的任何內容，該欄位將被忽略。使用此項而不是寫入 `/dev/tty`，後者對 hooks 不可用 |

要無論事件類型如何都完全停止 Claude：

```json theme={null}
{ "continue": false, "stopReason": "Build failed, fix errors before continuing" }
```

<h4 id="emit-terminal-notifications">
  發出終端通知
</h4>

`terminalSequence` 欄位需要 Claude Code v2.1.141 或更新版本。

Hooks 在沒有控制終端的情況下執行，因此直接寫入逃逸序列到 `/dev/tty` 會失敗。相反，在 `terminalSequence` 欄位中返回逃逸序列，Claude Code 通過其自己的終端寫入路徑為您發出它。這是無競爭的，在 tmux 和 GNU screen 內工作，並在沒有 `/dev/tty` 的 Windows 上工作。

該欄位接受一個或多個允許清單逃逸序列的字串：

* OSC `0`、`1`、`2`：視窗和圖示標題
* OSC `9`：iTerm2、ConEmu、Windows Terminal 和 WezTerm 通知，包括 `9;4` 工作列進度
* OSC `99`：Kitty 通知
* OSC `777`：urxvt、Ghostty 和 Warp 通知
* 裸 BEL

序列可以用 BEL 或 ST 終止。允許清單外的任何內容，包括 CSI 游標和顏色序列、OSC 調色板序列、OSC 8 超連結、OSC 52 剪貼簿寫入和 OSC 1337，都會被拒絕，該欄位將被忽略。

下面的範例從 `Notification` hook 觸發桌面通知。逃逸序列使用 `printf` 八進位逃逸構建，因此控制位元組永遠不會出現在 shell 命令行上，`jq -n --arg` 構建 JSON 輸出，因此通知訊息中的引號、反斜線和換行符被正確逃逸：

```bash theme={null}
#!/bin/bash
# Notification hook：當 Claude Code 需要注意時 ping 桌面。
input=$(cat)
title="Claude Code'
body=$(jq -r '.message // 'Needs your attention"' <<<"$input")
seq=$(printf '\033]777;notify;%s;%s\007' "$title" "$body")
jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
```

`{ "terminalSequence": "..." }` 形狀在任何 shell 或語言中都相同。在 Windows 上，在 PowerShell 或指令碼中構建逃逸字串並發出相同的 JSON 物件。

<Note>
  `terminalSequence` 是之前直接寫入逃逸序列到 `/dev/tty` 的 hooks 的支援替代品。允許清單限制為無法移動游標或改變顏色的序列，因此 hook 永遠無法損壞螢幕上的提示。
</Note>

<h4 id="add-context-for-claude">
  為 Claude 新增上下文
</h4>

`additionalContext` 欄位將字串從您的 hook 傳遞到 Claude 的上下文視窗。Claude Code 將字串包裝在系統提醒中，並將其插入到 hook 觸發的對話點。Claude 在下一個模型請求時讀取提醒，但它不會在介面中顯示為聊天訊息。

在 `hookSpecificOutput` 中返回 `additionalContext` 以及事件名稱：

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "This file is generated. Edit src/schema.ts and run `bun generate` instead."
  }
}
```

提醒出現的位置取決於事件：

* [SessionStart](#sessionstart)、[Setup](#setup) 和 [SubagentStart](#subagentstart)：在對話開始，在第一個提示之前
* [UserPromptSubmit](#userpromptsubmit) 和 [UserPromptExpansion](#userpromptexpansion)：與提交的提示一起
* [PreToolUse](#pretooluse)、[PostToolUse](#posttooluse)、[PostToolUseFailure](#posttoolusefailure) 和 [PostToolBatch](#posttoolbatch)：在工具結果旁邊
* [Stop](#stop) 和 [SubagentStop](#subagentstop)：在回合結束。對話繼續，以便 Claude 可以對反饋採取行動。請參閱 [Stop 決定控制](#stop-decision-control)

當多個 hooks 為同一事件返回 `additionalContext` 時，Claude 接收所有值。如果值超過 10,000 個字元，Claude Code 會將完整文字寫入工作階段目錄中的檔案，並將檔案路徑與簡短預覽傳遞給 Claude。

使用 `additionalContext` 來提供 Claude 應該知道的有關您環境目前狀態或剛剛執行的操作的資訊：

* **環境狀態**：目前分支、部署目標或活躍的功能旗標
* **條件專案規則**：哪個測試命令適用於剛編輯的檔案，此 worktree 中哪些目錄是唯讀的
* **外部資料**：分配給您的開放問題、最近的 CI 結果、從內部服務擷取的內容

對於永遠不會改變的指示，優先使用 [CLAUDE.md](/zh-TW/memory)。它無需執行指令碼即可載入，是靜態專案約定的標準位置。

將文字寫成事實陳述，而不是命令式系統指示。「部署目標是生產」或「此儲存庫使用 `bun test`」之類的措辭讀起來像專案資訊。框架為帶外系統命令的文字可能會觸發 Claude 的提示注入防禦，這會導致 Claude 將文字呈現給您，而不是將其視為上下文。

注入後，文字會儲存在工作階段成績單中。對於 `PostToolUse` 或 `UserPromptSubmit` 等中期事件，使用 `--continue` 或 `--resume` 繼續會重播儲存的文字，而不是為過去的回合重新執行 hook，因此時間戳或提交 SHA 等值在繼續時變得陳舊。`SessionStart` hooks 在使用 `source` 設定為 `"resume"` 的 `--resume` 時再次執行，因此它們可以刷新其上下文。

<h4 id="decision-control">
  決定控制
</h4>

並非每個事件都支援阻止或通過 JSON 控制行為。支援的事件各自使用不同的欄位集來表達該決定。在編寫 hook 之前，使用此表作為快速參考：

| 事件                                                                                                                          | 決定模式                    | 關鍵欄位                                                                                                                                                                                |
| :-------------------------------------------------------------------------------------------------------------------------- | :---------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| UserPromptSubmit、UserPromptExpansion、PostToolUse、PostToolUseFailure、PostToolBatch、Stop、SubagentStop、ConfigChange、PreCompact | 頂層 `decision`           | `decision: "block"`、`reason`。Stop 和 SubagentStop 也接受 `hookSpecificOutput.additionalContext` 用於 [繼續對話的非錯誤反饋](#stop-decision-control)                                                 |
| TeammateIdle、TaskCreated、TaskCompleted                                                                                      | 退出代碼或 `continue: false` | 退出代碼 2 使用 stderr 反饋阻止操作。JSON `{"continue": false, "stopReason": "..."}` 也會完全停止隊友，匹配 `Stop` hook 行為                                                                                  |
| PreToolUse                                                                                                                  | `hookSpecificOutput`    | `permissionDecision`（allow/deny/ask/defer）、`permissionDecisionReason`                                                                                                               |
| PermissionRequest                                                                                                           | `hookSpecificOutput`    | `decision.behavior`（allow/deny）                                                                                                                                                     |
| PermissionDenied                                                                                                            | `hookSpecificOutput`    | `retry: true` 告訴模型它可能重試被拒絕的工具呼叫                                                                                                                                                     |
| WorktreeCreate                                                                                                              | 路徑返回                    | 命令 hook 在 stdout 上列印路徑；HTTP hook 通過 `hookSpecificOutput.worktreePath` 返回。Hook 失敗或缺少路徑會導致建立失敗                                                                                        |
| Elicitation                                                                                                                 | `hookSpecificOutput`    | `action`（accept/decline/cancel）、`content`（accept 的表單欄位值）                                                                                                                            |
| ElicitationResult                                                                                                           | `hookSpecificOutput`    | `action`（accept/decline/cancel）、`content`（覆蓋表單欄位值）                                                                                                                                  |
| MessageDisplay                                                                                                              | `hookSpecificOutput`    | `displayContent` 替換螢幕上顯示的文字。僅顯示：成績單和 Claude 看到的內容保持原始                                                                                                                               |
| SessionStart、Setup、SubagentStart                                                                                            | 僅上下文                    | `hookSpecificOutput.additionalContext` 為 Claude 新增上下文。SessionStart 也接受 [`initialUserMessage`、`watchPaths`、`sessionTitle` 和 `reloadSkills`](#sessionstart-decision-control)。無阻止或決定控制 |
| WorktreeRemove、Notification、SessionEnd、PostCompact、InstructionsLoaded、StopFailure、CwdChanged、FileChanged                    | 無                       | 無決定控制。用於副作用，如記錄或清理                                                                                                                                                                  |

一些事件也可以重寫內容，而不僅僅是允許或阻止它：

* `PreToolUse`：`updatedInput` 直接在 `hookSpecificOutput` 下替換工具的引數，然後執行。請參閱 [PreToolUse 決定控制](#pretooluse-decision-control) 以取得完整的選項集。
* `PermissionRequest`：`updatedInput` 在 `decision` 物件內。請參閱 [PermissionRequest 決定控制](#permissionrequest-decision-control) 以取得完整的選項集。
* `PostToolUse`：`updatedToolOutput` 替換工具的結果。請參閱 [PostToolUse 決定控制](#posttooluse-decision-control) 以取得完整的選項集。
* `UserPromptSubmit`：無法替換提示；僅在其旁邊注入 `additionalContext`

對於編輯或轉換使用案例，在 `PreToolUse` 攔截出站工具輸入，在 `PostToolUse` 攔截入站工具結果。

以下是每種模式的實際範例：

<Tabs>
  <Tab title="頂層決定">
    由 `UserPromptSubmit`、`UserPromptExpansion`、`PostToolUse`、`PostToolUseFailure`、`PostToolBatch`、`Stop`、`SubagentStop`、`ConfigChange` 和 `PreCompact` 使用。唯一的值是 `"block"`。要允許操作進行，請從 JSON 中省略 `decision`，或以 0 退出而不帶任何 JSON：

    ```json theme={null}
    {
      "decision": "block",
      "reason": "Test suite must pass before proceeding"
    }
    ```
  </Tab>

  <Tab title="PreToolUse">
    使用 `hookSpecificOutput` 進行更豐富的控制：允許、拒絕或升級給使用者。您還可以在執行前修改工具輸入或為 Claude 注入額外上下文。有關完整的選項集，請參閱 [PreToolUse 決定控制](#pretooluse-decision-control)。

    ```json theme={null}
    {
      "hookSpecificOutput": {
        "hookEventName": "PreToolUse",
        "permissionDecision": "deny",
        "permissionDecisionReason": "Database writes are not allowed"
      }
    }
    ```
  </Tab>

  <Tab title="PermissionRequest">
    使用 `hookSpecificOutput` 代表使用者允許或拒絕權限請求。允許時，您還可以修改工具的輸入或應用權限規則，以便使用者不會再次被提示。有關完整的選項集，請參閱 [PermissionRequest 決定控制](#permissionrequest-decision-control)。

    ```json theme={null}
    {
      "hookSpecificOutput": {
        "hookEventName": "PermissionRequest",
        "decision": {
          "behavior": "allow",
          "updatedInput": {
            "command": "npm run lint"
          }
        }
      }
    }
    ```
  </Tab>
</Tabs>

有關擴展範例，包括 Bash 命令驗證、提示篩選和自動批准指令碼，請參閱指南中的 [您可以自動化的內容](/zh-TW/hooks-guide#what-you-can-automate) 和 [Bash 命令驗證器參考實現](https://github.com/anthropics/claude-code/blob/main/examples/hooks/bash_command_validator_example.py)。

<h2 id="hook-events">
  Hook 事件
</h2>

每個事件對應於 Claude Code 生命週期中 hooks 可以執行的一個點。下面的部分按順序排列以匹配生命週期：從工作階段設定通過代理迴圈到工作階段結束。每個部分描述事件何時觸發、它支援什麼匹配器、它接收的 JSON 輸入，以及如何通過輸出控制行為。

<h3 id="sessionstart">
  SessionStart
</h3>

在 Claude Code 啟動新工作階段或恢復現有工作階段時執行。適用於載入開發上下文，例如現有問題或程式碼庫的最近變更，或設定環境變數。對於不需要指令碼的靜態上下文，請改用 [CLAUDE.md](/zh-TW/memory)。

SessionStart 在每個工作階段執行，因此請保持這些 hooks 快速。僅支援 `type: "command"` 和 `type: "mcp_tool"` hooks。

匹配器值對應於工作階段的啟動方式：

| 匹配器       | 何時觸發                                |
| :-------- | :---------------------------------- |
| `startup` | 新工作階段                               |
| `resume`  | `--resume`、`--continue` 或 `/resume` |
| `clear`   | `/clear`                            |
| `compact` | 自動或手動壓縮                             |

<h4 id="sessionstart-input">
  SessionStart 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，SessionStart hooks 還接收 `source` 和可選的 `model`、`agent_type` 和 `session_title`：

| 欄位              | 描述                                                                                                       |
| :-------------- | :------------------------------------------------------------------------------------------------------- |
| `source`        | 工作階段如何啟動：新工作階段為 `"startup"`，恢復的工作階段為 `"resume"`，`/clear` 後為 `"clear"`，或壓縮後為 `"compact"`                  |
| `model`         | 活動模型識別碼。它可以被省略，例如在 `/clear` 後或當工作階段通過對話恢復被恢復時，因此在讀取它之前檢查欄位                                               |
| `agent_type`    | 代理名稱，當您使用 `claude --agent <name>` 啟動 Claude Code 時出現                                                     |
| `session_title` | 目前工作階段標題（如果已設定），例如通過 `--name` 或 `/rename`。發出 `sessionTitle` 的 hook 可以先檢查 `session_title` 以避免覆寫使用者明確設定的標題 |

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "SessionStart",
  "source": "startup",
  "model": "claude-sonnet-5"
}
```

<h4 id="sessionstart-decision-control">
  SessionStart 決定控制
</h4>

您的 hook 指令碼列印到 stdout 的任何文字都被新增為 Claude 的上下文。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您還可以返回這些事件特定欄位：

| 欄位                   | 描述                                                                                                                                           |
| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------- |
| `additionalContext`  | 新增到 Claude 上下文開始處的字串，在第一個提示之前。請參閱 [為 Claude 新增上下文](#add-context-for-claude) 以了解文字如何傳遞以及要放入其中的內容                                              |
| `initialUserMessage` | 用作工作階段第一個使用者訊息的字串。適用於 [非互動模式](/zh-TW/headless)（`-p`），其中即使未提供提示，它也成為第一個轉向。如果提供了提示，它作為下一個轉向跟隨。與 `additionalContext` 不同，後者附加到現有轉向，這會建立轉向        |
| `sessionTitle`       | 設定工作階段標題，與 `/rename` 的效果相同。使用此項根據啟動資料夾、git 分支或 worktree 名稱自動命名工作階段。僅在 `source` 為 `"startup"` 或 `"resume"` 時適用；在 `"clear"` 和 `"compact"` 上被忽略 |
| `watchPaths`         | 絕對路徑的陣列，用於在此工作階段期間監視 [FileChanged](#filechanged) 事件                                                                                          |
| `reloadSkills`       | 布林值。當為 `true` 時，Claude Code 在 SessionStart hooks 完成後重新掃描 [skill](/zh-TW/skills) 和命令目錄，因此 hook 安裝的 skills 在同一工作階段中可用，從第一個提示開始                 |

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Current branch: feat/auth-refactor\nUncommitted changes: src/auth.ts, src/login.tsx\nActive issue: #4211 Migrate to OAuth2",
    "sessionTitle": "auth-refactor"
  }
}
```

由於純 stdout 已經到達 Claude 用於此事件，只載入上下文的 hook 可以直接列印到 stdout 而無需建立 JSON。當您需要將上下文與其他欄位（例如 `suppressOutput` 或 `sessionTitle`）結合時，請使用 JSON 形式。

當 SessionStart hook 安裝或更新 skills 時，使用 `reloadSkills`。Skill 發現通常在 SessionStart hooks 完成之前執行，因此 hook 寫入 `~/.claude/skills/` 或 `.claude/skills/` 的檔案否則只會在下一個工作階段中出現。此範例同步共享 skills 儲存庫並請求重新掃描：

```bash theme={null}
#!/bin/bash

git -C ~/.claude/skills/team-skills pull --quiet 2>/dev/null || \
  git clone --quiet https://git.example.com/your-org/team-skills.git ~/.claude/skills/team-skills

echo '{"hookSpecificOutput": {"hookEventName": "SessionStart", "reloadSkills": true}}'
```

<h4 id="persist-environment-variables">
  持久化環境變數
</h4>

SessionStart hooks 可以存取 `CLAUDE_ENV_FILE` 環境變數，該變數提供一個檔案路徑，您可以在其中為後續 Bash 命令持久化環境變數。

要設定個別環境變數，請將 `export` 陳述式寫入 `CLAUDE_ENV_FILE`。使用追加（`>>`）來保留由其他 hooks 設定的變數：

```bash theme={null}
#!/bin/bash

if [ -n "$CLAUDE_ENV_FILE" ]; then
  echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
  echo 'export DEBUG_LOG=true' >> "$CLAUDE_ENV_FILE"
  echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi

exit 0
```

要捕獲設定命令中的所有環境變更，請比較之前和之後的匯出變數：

```bash theme={null}
#!/bin/bash

ENV_BEFORE=$(export -p | sort)

# 執行修改環境的設定命令
source ~/.nvm/nvm.sh
nvm use 20

if [ -n "$CLAUDE_ENV_FILE" ]; then
  ENV_AFTER=$(export -p | sort)
  comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi

exit 0
```

寫入此檔案的任何變數都將在工作階段期間 Claude Code 執行的所有後續 Bash 命令中可用。

<Note>
  `CLAUDE_ENV_FILE` 可用於 SessionStart、[Setup](#setup)、[CwdChanged](#cwdchanged) 和 [FileChanged](#filechanged) hooks。其他 hook 類型無法存取此變數。
</Note>

<h3 id="setup">
  Setup
</h3>

僅當您使用 `--init-only` 啟動 Claude Code，或在非互動模式（`-p`）中使用 `--init` 或 `--maintenance` 時觸發。它在正常啟動時不觸發。使用它進行一次性依賴項安裝或您從 CI 或指令碼明確觸發的計劃清理，與正常工作階段啟動分開。對於每個工作階段的初始化，請改用 [SessionStart](#sessionstart)。

匹配器值對應於觸發 hook 的 CLI 標誌：

| 匹配器           | 何時觸發                                      |
| :------------ | :---------------------------------------- |
| `init`        | `claude --init-only` 或 `claude -p --init` |
| `maintenance` | `claude -p --maintenance`                 |

`--init-only` 執行 Setup hooks 和 SessionStart hooks（帶有 `startup` 匹配器），然後退出而不啟動對話。`--init` 和 `--maintenance` 僅在與 `-p` 結合時觸發 Setup hooks；在互動式工作階段中，這兩個標誌目前不觸發 Setup hooks。

因為 Setup 不在每次啟動時觸發，需要安裝依賴項的外掛程式無法僅依賴 Setup。實際的模式是在首次使用時檢查依賴項，如果缺失則安裝，例如測試 `${CLAUDE_PLUGIN_DATA}/node_modules` 的 hook 或 skill，如果不存在則執行 `npm install`。請參閱 [持久資料目錄](/zh-TW/plugins-reference#persistent-data-directory) 以了解在何處儲存已安裝的依賴項。

<h4 id="setup-input">
  Setup 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，Setup hooks 還接收設定為 `"init"` 或 `"maintenance"` 的 `trigger` 欄位：

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "Setup",
  "trigger": "init"
}
```

<h4 id="setup-decision-control">
  Setup 決定控制
</h4>

Setup hooks 無法阻止。任何非零退出代碼（包括 2）都會向使用者顯示 stderr 作為 `<hook name> hook error` 通知，執行繼續。在 [非互動模式](/zh-TW/headless) 中，hook 輸出僅在您使用 `--verbose` 啟動時出現。

要將資訊傳遞到 Claude 的上下文中，請在 JSON 輸出中返回 `additionalContext`；純 stdout 僅寫入偵錯日誌。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您還可以返回這些事件特定欄位：

| 欄位                  | 描述                               |
| :------------------ | :------------------------------- |
| `additionalContext` | 新增到 Claude 上下文的字串。多個 hooks 的值被連接 |

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "Setup",
    "additionalContext": "Dependencies installed: node_modules, .venv"
  }
}
```

Setup hooks 可以存取 `CLAUDE_ENV_FILE`。寫入該檔案的變數會持久化到工作階段的後續 Bash 命令中，就像在 [SessionStart hooks](#persist-environment-variables) 中一樣。僅支援 `type: "command"` 和 `type: "mcp_tool"` hooks。

<h3 id="instructionsloaded">
  InstructionsLoaded
</h3>

當 `CLAUDE.md` 或 `.claude/rules/*.md` 檔案被載入到上下文中時觸發。此事件在工作階段開始時針對急切載入的檔案觸發，稍後當檔案被延遲載入時再次觸發，例如當 Claude 存取包含嵌套 `CLAUDE.md` 的子目錄時，或當具有 `paths:` frontmatter 的條件規則匹配時。該 hook 不支援阻止或決定控制。它以非同步方式執行以用於可觀測性目的。

匹配器針對 `load_reason` 執行。例如，使用 `"matcher": "session_start"` 僅針對在工作階段開始時載入的檔案觸發，或使用 `"matcher": "path_glob_match|nested_traversal"` 僅針對延遲載入觸發。

<h4 id="instructionsloaded-input">
  InstructionsLoaded 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，InstructionsLoaded hooks 還接收這些欄位：

| 欄位                  | 描述                                                                                                                           |
| :------------------ | :--------------------------------------------------------------------------------------------------------------------------- |
| `file_path`         | 被載入的指令檔案的絕對路徑                                                                                                                |
| `memory_type`       | 檔案的範圍：`"User"`、`"Project"`、`"Local"` 或 `"Managed"`                                                                           |
| `load_reason`       | 檔案被載入的原因：`"session_start"`、`"nested_traversal"`、`"path_glob_match"`、`"include"` 或 `"compact"`。`"compact"` 值在壓縮事件後重新載入指令檔案時觸發 |
| `globs`             | 檔案 `paths:` frontmatter 中的路徑 glob 模式（如果有）。僅針對 `path_glob_match` 載入出現                                                         |
| `trigger_file_path` | 觸發此載入的檔案的路徑，用於延遲載入                                                                                                           |
| `parent_file_path`  | 包含此檔案的父指令檔案的路徑，用於 `include` 載入                                                                                               |

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../transcript.jsonl",
  "cwd": "/Users/my-project",
  "hook_event_name": "InstructionsLoaded",
  "file_path": "/Users/my-project/CLAUDE.md",
  "memory_type": "Project",
  "load_reason": "session_start"
}
```

<h4 id="instructionsloaded-decision-control">
  InstructionsLoaded 決定控制
</h4>

InstructionsLoaded hooks 沒有決定控制。它們無法阻止或修改指令載入。使用此事件進行稽核記錄、合規性追蹤或可觀測性。

<h3 id="userpromptsubmit">
  UserPromptSubmit
</h3>

在使用者提交提示時執行，在 Claude 處理之前。這允許您根據提示/對話新增額外上下文、驗證提示或阻止某些類型的提示。

`UserPromptSubmit` hooks 對於 `command`、`http` 和 `mcp_tool` 類型的預設逾時為 30 秒，比其他事件上這些類型的 600 秒預設值更短。因為此 hook 在每個提示之前執行並阻止模型處理直到完成，卡住的 hook 會停滯工作階段。如果您的 hook 需要更多時間，請在 hook 項目中設定 `timeout` 欄位。

達到逾時的 `UserPromptSubmit` hook 被取消，其輸出（包括任何 `additionalContext`）被丟棄。提示仍然到達 Claude，但沒有該上下文。從 v2.1.196 開始，成績單顯示一個通知，命名 hook、觸發的逾時以及輸出被丟棄。較早的版本取消 hook 而不顯示通知。

<h4 id="userpromptsubmit-input">
  UserPromptSubmit 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，UserPromptSubmit hooks 還接收包含使用者提交的文字的 `prompt` 欄位。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}
```

<h4 id="userpromptsubmit-decision-control">
  UserPromptSubmit 決定控制
</h4>

`UserPromptSubmit` hooks 可以控制使用者提示是否被處理並新增上下文。所有 [JSON 輸出欄位](#json-output) 都可用。

有兩種方式在退出代碼 0 時向對話新增上下文：

* **純文字 stdout**：寫入 stdout 的任何非 JSON 文字都被新增為上下文
* **帶有 `additionalContext` 的 JSON**：使用下面的 JSON 格式以獲得更多控制。`additionalContext` 欄位被新增為上下文

純 stdout 在成績單中顯示為 hook 輸出。`additionalContext` 值被注入為系統提醒，Claude 讀取時不會有可見的成績單項目。

要阻止提示，請返回一個 JSON 物件，其中 `decision` 設定為 `"block"`：

| 欄位                       | 描述                                                                       |
| :----------------------- | :----------------------------------------------------------------------- |
| `decision`               | `"block"` 防止提示被處理並從上下文中清除它。省略以允許提示進行                                     |
| `reason`                 | 當 `decision` 為 `"block"` 時向使用者顯示。不新增到上下文                                 |
| `additionalContext`      | 新增到 Claude 上下文的字串，與提交的提示一起。請參閱 [為 Claude 新增上下文](#add-context-for-claude) |
| `sessionTitle`           | 設定工作階段標題。使用此項根據提示內容自動命名工作階段                                              |
| `suppressOriginalPrompt` | 如果在 `decision` 為 `"block"` 時為 `true`，則從向使用者顯示的阻止訊息中省略原始提示文字              |

```json theme={null}
{
  "decision": "block",
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "My additional context here",
    "sessionTitle": "My session title"
  }
}
```

<h3 id="userpromptexpansion">
  UserPromptExpansion
</h3>

當使用者輸入的斜杠命令在到達 Claude 之前展開為提示時執行。使用此項來阻止特定命令的直接呼叫、為特定 skill 注入上下文，或記錄使用者呼叫哪些命令。例如，匹配 `deploy` 的 hook 可以在不存在批准檔案時阻止 `/deploy`，或匹配審查 skill 的 hook 可以將團隊的審查檢查清單附加為 `additionalContext`。

此事件涵蓋 `PreToolUse` 不涵蓋的路徑：匹配 `Skill` 工具的 `PreToolUse` hook 僅在 Claude 呼叫工具時觸發，但直接輸入 `/skillname` 會繞過 `PreToolUse`。`UserPromptExpansion` 在該直接路徑上觸發。

匹配 `command_name`。留空匹配器以針對每個提示類型斜杠命令觸發。

<h4 id="userpromptexpansion-input">
  UserPromptExpansion 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，UserPromptExpansion hooks 還接收 `expansion_type`、`command_name`、`command_args`、`command_source` 和原始 `prompt` 字串。`expansion_type` 欄位對於 skill 和自訂命令為 `slash_command`，或對於 MCP 伺服器提示為 `mcp_prompt`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../00893aaf.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "UserPromptExpansion",
  "expansion_type": "slash_command",
  "command_name": "example-skill",
  "command_args": "arg1 arg2",
  "command_source": "plugin",
  "prompt": "/example-skill arg1 arg2"
}
```

<h4 id="userpromptexpansion-decision-control">
  UserPromptExpansion 決定控制
</h4>

`UserPromptExpansion` hooks 可以阻止展開或新增上下文。所有 [JSON 輸出欄位](#json-output) 都可用。

| 欄位                  | 描述                                                                       |
| :------------------ | :----------------------------------------------------------------------- |
| `decision`          | `"block"` 防止斜杠命令展開。省略以允許它進行                                              |
| `reason`            | 當 `decision` 為 `"block"` 時向使用者顯示                                         |
| `additionalContext` | 新增到 Claude 上下文的字串，與展開的提示一起。請參閱 [為 Claude 新增上下文](#add-context-for-claude) |

```json theme={null}
{
  "decision": "block",
  "reason": "This slash command is not available",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptExpansion",
    "additionalContext": "Additional context for this expansion"
  }
}
```

<h3 id="messagedisplay">
  MessageDisplay
</h3>

在助手訊息流向螢幕時執行。Claude Code 分批顯示訊息：每次一批新完成的行準備好呈現時，hook 執行一次，這些行，Claude Code 在其位置呈現 hook 的替換文字。長訊息產生多個呼叫；短訊息可能只產生一個。

使用 MessageDisplay 來：

* 去除 markdown 以獲得最小顯示
* 轉換 Agent SDK 應用程式向其使用者顯示的文字
* 從 Claude 的回應中編輯 API 金鑰或內部主機名稱

Claude Code 保持每批直到您的 hook 返回，因此請保持 hook 快速。如果 hook 失敗或逾時，Claude Code 顯示原始文字。此事件的預設逾時為 10 秒；如果您的 hook 需要更多時間，請在 hook 項目中設定 `timeout` 欄位。

MessageDisplay 僅用於顯示：替換文字僅改變螢幕上呈現的內容。成績單和 Claude 看到的內容保持原始文字，因此 Claude 永遠看不到替換，詳細模式顯示原始文字。Hook 接收助手訊息文字，因此工具結果和您輸入的文字呈現不變。

MessageDisplay 不支援匹配器，針對每個流向文字的助手訊息觸發；沒有文字的訊息（例如僅工具呼叫回應）不觸發它。

在非互動執行中，包括 Agent SDK 查詢和 `claude -p`，MessageDisplay 每個助手訊息執行一次，而不是每批行執行一次。單一呼叫在訊息完成後到達，並攜帶完整訊息文字：`index` 為 `0`，`final` 為 `true`，`delta` 保存整個訊息。為每個訊息收集 `delta` 文字的 hook 在兩種模式中接收相同的總文字。

<h4 id="messagedisplay-input">
  MessageDisplay 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，MessageDisplay hooks 還接收轉向和訊息的識別碼、此呼叫在訊息中的位置，以及 `delta` 中的新文字。批次邊界取決於文字如何流動，因此使用 `index` 和 `final` 來追蹤通過訊息的進度，而不是期望行以特定方式分組。

| 欄位           | 描述                                                                                                                                                  |
| :----------- | :-------------------------------------------------------------------------------------------------------------------------------------------------- |
| `turn_id`    | 目前轉向的 UUID                                                                                                                                          |
| `message_id` | 被顯示的助手訊息的 UUID。在同一訊息的每批中穩定。這不是 API `msg_…` id，因此無法與成績單訊息 ids 相關聯                                                                                    |
| `index`      | 此批次在訊息中的零基索引                                                                                                                                        |
| `final`      | 在訊息的最後一批上為 `true`。每個訊息恰好有一個最終批次                                                                                                                     |
| `delta`      | 自上一批以來新完成的行，包括終止換行符。始終是完整行，除了最終批次可能在行中結束。在互動執行中，當訊息以換行符結束時，最終批次的 delta 為空，因此將 `final` 而不是非空 delta 視為訊息結束信號。在 Agent SDK 和 `claude -p` 執行中，單一呼叫攜帶整個訊息 |

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../transcript.jsonl",
  "cwd": "/Users/my-project",
  "hook_event_name": "MessageDisplay",
  "turn_id": "0c9e6a2f-7d41-4f4e-9a15-3f4f7c2b8d10",
  "message_id": "5b2a9c8e-1f63-4d8a-b7c4-9e0d2a6f1c3b",
  "index": 0,
  "final": false,
  "delta": "Here is the plan:\n"
}
```

<h4 id="messagedisplay-output">
  MessageDisplay 輸出
</h4>

除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，MessageDisplay hooks 可以返回 `displayContent` 來替換螢幕上的 delta：

| 欄位               | 描述                        |
| :--------------- | :------------------------ |
| `displayContent` | 顯示以代替 delta 的文字。省略以顯示原始文字 |

MessageDisplay hooks 沒有決定控制。它們無法阻止訊息或改變成績單中儲存或發送給 Claude 的內容。

此範例去除 Claude 回應中的 markdown 格式以獲得純文字顯示。指令碼從 stdin 讀取每批，從 `delta` 移除粗體標記和內聯代碼反引號，並將結果作為 `displayContent` 返回。

<Tabs>
  <Tab title="macOS/Linux">
    在您的設定檔中為事件註冊命令 hook：

    ```json theme={null}
    {
      "hooks": {
        "MessageDisplay": [
          {
            "hooks": [
              {
                "type": "command",
                "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/plain-display.sh",
                "args": []
              }
            ]
          }
        ]
      }
    }
    ```

    將此指令碼儲存到您專案中的 `.claude/hooks/plain-display.sh` 並使用 `chmod +x` 使其可執行：

    ```bash theme={null}
    #!/bin/bash
    jq '{hookSpecificOutput: {hookEventName: "MessageDisplay", displayContent: (.delta | gsub("\\*\\*"; "") | gsub("`"; ""))}}'
    ```

    指令碼需要 `jq` 在您的 `PATH` 上。
  </Tab>

  <Tab title="Windows (PowerShell)">
    註冊一個命令 hook，通過 PowerShell 執行指令碼：

    ```json theme={null}
    {
      "hooks": {
        "MessageDisplay": [
          {
            "hooks": [
              {
                "type": "command",
                "command": "powershell.exe",
                "args": [
                  "-NoProfile",
                  "-ExecutionPolicy",
                  "Bypass",
                  "-File",
                  "${CLAUDE_PROJECT_DIR}/.claude/hooks/plain-display.ps1"
                ]
              }
            ]
          }
        ]
      }
    }
    ```

    `-NoProfile` 標誌跳過載入您的 PowerShell 設定檔，以便 hook 快速啟動，`-ExecutionPolicy Bypass` 讓 PowerShell 執行本機指令碼檔案。

    將此指令碼儲存到您專案中的 `.claude/hooks/plain-display.ps1`：

    ```powershell theme={null}
    $batch = [Console]::In.ReadToEnd() | ConvertFrom-Json
    $text = $batch.delta -replace '\*\*', '' -replace '`', ''
    @{
      hookSpecificOutput = @{
        hookEventName = "MessageDisplay"
        displayContent = $text
      }
    } | ConvertTo-Json
    ```
  </Tab>
</Tabs>

沒有 markdown 的批次通過不變。如果指令碼失敗，例如因為 `jq` 遺失，Claude Code 顯示原始文字，並僅在 [偵錯輸出](#debug-hooks) 中注意失敗，而不是在工作階段中。

<h3 id="pretooluse">
  PreToolUse
</h3>

在 Claude 建立工具參數後和處理工具呼叫之前執行。匹配工具名稱：`Bash`、`Edit`、`Write`、`Read`、`Glob`、`Grep`、`Agent`、`WebFetch`、`WebSearch`、`AskUserQuestion`、`ExitPlanMode` 和任何 [MCP 工具名稱](#match-mcp-tools)。

<Warning>
  PreToolUse 僅在 Claude 呼叫工具時執行。您 [在提示中使用 `@` 參考的檔案](/zh-TW/common-workflows#reference-files-and-directories) 被新增而不進行任何工具呼叫：Claude Code 在建立提示時插入其內容，因此沒有 PreToolUse hook 針對它們觸發，包括匹配 `Read` 的 hooks。要阻止特定路徑的 `@` 參考，請改用 [`Read` 拒絕規則](/zh-TW/permissions#read-and-edit)。
</Warning>

使用 [PreToolUse 決定控制](#pretooluse-decision-control) 來允許、拒絕、詢問或延遲工具呼叫。

<h4 id="pretooluse-input">
  PreToolUse 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，PreToolUse hooks 還接收 `tool_name`、`tool_input` 和 `tool_use_id`。`tool_input` 欄位取決於工具：

<h5 id="bash">
  Bash
</h5>

執行 shell 命令。

| 欄位                  | 類型  | 範例                 | 描述            |
| :------------------ | :-- | :----------------- | :------------ |
| `command`           | 字串  | `"npm test"`       | 要執行的 shell 命令 |
| `description`       | 字串  | `"Run test suite"` | 命令執行內容的可選描述   |
| `timeout`           | 數字  | `120000`           | 可選逾時（毫秒）      |
| `run_in_background` | 布林值 | `false`            | 是否在背景執行命令     |

<h5 id="write">
  Write
</h5>

建立或覆寫檔案。

| 欄位          | 類型 | 範例                    | 描述          |
| :---------- | :- | :-------------------- | :---------- |
| `file_path` | 字串 | `"/path/to/file.txt"` | 要寫入的檔案的絕對路徑 |
| `content`   | 字串 | `"file content"`      | 要寫入檔案的內容    |

<h5 id="edit">
  Edit
</h5>

替換現有檔案中的字串。

| 欄位            | 類型  | 範例                    | 描述          |
| :------------ | :-- | :-------------------- | :---------- |
| `file_path`   | 字串  | `"/path/to/file.txt"` | 要編輯的檔案的絕對路徑 |
| `old_string`  | 字串  | `"original text"`     | 要查詢和替換的文字   |
| `new_string`  | 字串  | `"replacement text"`  | 替換文字        |
| `replace_all` | 布林值 | `false`               | 是否替換所有出現次數  |

<h5 id="read">
  Read
</h5>

讀取檔案內容。

| 欄位          | 類型 | 範例                    | 描述          |
| :---------- | :- | :-------------------- | :---------- |
| `file_path` | 字串 | `"/path/to/file.txt"` | 要讀取的檔案的絕對路徑 |
| `offset`    | 數字 | `10`                  | 可選的開始讀取的行號  |
| `limit`     | 數字 | `50`                  | 可選的要讀取的行數   |

<h5 id="glob">
  Glob
</h5>

尋找與 glob 模式匹配的檔案。

| 欄位        | 類型 | 範例               | 描述                |
| :-------- | :- | :--------------- | :---------------- |
| `pattern` | 字串 | `"**/*.ts"`      | 要匹配檔案的 glob 模式    |
| `path`    | 字串 | `"/path/to/dir"` | 可選的搜尋目錄。預設為目前工作目錄 |

<h5 id="grep">
  Grep
</h5>

使用正規表達式搜尋檔案內容。

| 欄位            | 類型  | 範例               | 描述                                                                        |
| :------------ | :-- | :--------------- | :------------------------------------------------------------------------ |
| `pattern`     | 字串  | `"TODO.*fix"`    | 要搜尋的正規表達式模式                                                               |
| `path`        | 字串  | `"/path/to/dir"` | 可選的要搜尋的檔案或目錄                                                              |
| `glob`        | 字串  | `"*.ts"`         | 可選的 glob 模式以篩選檔案                                                          |
| `output_mode` | 字串  | `"content"`      | `"content"`、`"files_with_matches"` 或 `"count"`。預設為 `"files_with_matches"` |
| `-i`          | 布林值 | `true`           | 不區分大小寫的搜尋                                                                 |
| `multiline`   | 布林值 | `false`          | 啟用多行匹配                                                                    |

<h5 id="webfetch">
  WebFetch
</h5>

擷取和處理網路內容。

| 欄位       | 類型 | 範例                            | 描述           |
| :------- | :- | :---------------------------- | :----------- |
| `url`    | 字串 | `"https://example.com/api"`   | 要擷取內容的 URL   |
| `prompt` | 字串 | `"Extract the API endpoints"` | 在擷取的內容上執行的提示 |

<h5 id="websearch">
  WebSearch
</h5>

搜尋網路。

| 欄位                | 類型 | 範例                             | 描述              |
| :---------------- | :- | :----------------------------- | :-------------- |
| `query`           | 字串 | `"react hooks best practices"` | 搜尋查詢            |
| `allowed_domains` | 陣列 | `["docs.example.com"]`         | 可選：僅包含來自這些網域的結果 |
| `blocked_domains` | 陣列 | `["spam.example.com"]`         | 可選：排除來自這些網域的結果  |

<h5 id="agent">
  Agent
</h5>

生成一個 [subagent](/zh-TW/sub-agents)。

| 欄位              | 類型 | 範例                         | 描述            |
| :-------------- | :- | :------------------------- | :------------ |
| `prompt`        | 字串 | `"Find all API endpoints"` | 代理要執行的任務      |
| `description`   | 字串 | `"Find API endpoints"`     | 任務的簡短描述       |
| `subagent_type` | 字串 | `"Explore"`                | 要使用的專門代理類型    |
| `model`         | 字串 | `"sonnet"`                 | 可選的模型別名以覆蓋預設值 |

在 `PostToolUse` 中，已完成的 Agent 呼叫的 `tool_response` 攜帶 subagent 的最終文字以及使用量遙測。讀取這些欄位以從 hook 記錄每個 subagent 的成本：

| 欄位                  | 類型 | 範例                                                    | 描述                                                                                                                                                                           |
| :------------------ | :- | :---------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status`            | 字串 | `"completed"`                                         | 前景 subagents 為 `"completed"`，背景 subagents 為 `"async_launched"`。{/* min-version: 2.1.198 */}從 v2.1.198 開始，subagents 預設在背景執行，因此省略的 `run_in_background` 也會產生 `"async_launched"` |
| `agentId`           | 字串 | `"a4d2c8f1e0b3a297"`                                  | subagent 執行的識別碼                                                                                                                                                              |
| `content`           | 陣列 | `[{"type": "text", "text": "Found 12 endpoints..."}]` | subagent 的最終文字塊                                                                                                                                                              |
| `resolvedModel`     | 字串 | `"claude-sonnet-4-5"`                                 | subagent 執行的模型，可能與請求的模型不同。{/* min-version: 2.1.174 */}需要 Claude Code v2.1.174 或更高版本                                                                                          |
| `totalTokens`       | 數字 | `12450`                                               | 在 subagent 轉向中計費的總令牌數                                                                                                                                                        |
| `totalDurationMs`   | 數字 | `48211`                                               | subagent 執行的掛鐘時間                                                                                                                                                             |
| `totalToolUseCount` | 數字 | `7`                                                   | subagent 進行的工具呼叫計數                                                                                                                                                           |
| `usage`             | 物件 | `{"input_tokens": 8320, ...}`                         | 按類型的令牌細分：`input_tokens`、`output_tokens`、`cache_creation_input_tokens`、`cache_read_input_tokens`                                                                              |

對於背景 subagents，工具在啟動 subagent 後立即返回，因此 `tool_response` 不攜帶使用量欄位。它具有 `status: "async_launched"`、`agentId`、`description`、`prompt`、`outputFile` 和 `resolvedModel`。

`resolvedModel` 欄位命名 subagent 實際執行的模型，可能與 `tool_input` 中的 `model` 值不同，例如當 `availableModels` 或其他覆蓋適用時。它需要 Claude Code v2.1.174 或更高版本。

<a id="askuserquestion" />

<h5 id="askuserquestion">
  AskUserQuestion
</h5>

詢問使用者一到四個多選題。

| 欄位          | 類型 | 範例                                                                                                                 | 描述                                                                         |
| :---------- | :- | :----------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------- |
| `questions` | 陣列 | `[{"question": "Which framework?", "header": "Framework", "options": [{"label": "React"}], "multiSelect": false}]` | 要呈現的問題，每個都有 `question` 字串、簡短 `header`、`options` 陣列和可選的 `multiSelect` 標誌    |
| `answers`   | 物件 | `{"Which framework?": "React"}`                                                                                    | 可選。將問題文字對應到選定的選項標籤。多選答案用逗號連接標籤。Claude 不設定此欄位；通過 `updatedInput` 提供它以以程式方式回答 |

<h5 id="exitplanmode">
  ExitPlanMode
</h5>

呈現一個計劃並要求使用者在 Claude 離開 [plan mode](/zh-TW/permission-modes#analyze-before-you-edit-with-plan-mode) 之前批准它。Claude 在呼叫工具之前將計劃寫入磁碟上的檔案，因此模型的字面 `tool_input` 通常為空。Claude Code 在將輸入傳遞給 hooks 之前注入計劃內容和檔案路徑。

| 欄位               | 類型 | 範例                                          | 描述                                                                                            |
| :--------------- | :- | :------------------------------------------ | :-------------------------------------------------------------------------------------------- |
| `plan`           | 字串 | `"## Refactor auth\n1. Extract..."`         | Markdown 中的計劃內容。從磁碟上的計劃檔案注入                                                                   |
| `planFilePath`   | 字串 | `"/Users/.../plans/refactor-auth.md"`       | 計劃檔案的路徑。注入                                                                                    |
| `allowedPrompts` | 陣列 | `[{"tool": "Bash", "prompt": "run tests"}]` | {/* min-version: 2.1.205 */}已棄用。Claude Code 接受該欄位但忽略它。在 v2.1.205 之前，它攜帶 Claude 要求實施計劃的基於提示的權限 |

在 `PostToolUse` 中，`tool_response` 是一個物件，其中包含 `plan` 和 `filePath` 欄位，保存批准的計劃，加上內部狀態標誌。讀取 `tool_response.plan` 以獲取計劃內容，而不是從磁碟重新讀取檔案。

<h4 id="pretooluse-decision-control">
  PreToolUse 決定控制
</h4>

`PreToolUse` hooks 可以控制工具呼叫是否進行。與使用頂層 `decision` 欄位的其他 hooks 不同，PreToolUse 在 `hookSpecificOutput` 物件內返回其決定。這提供了更豐富的控制：四個結果（允許、拒絕、詢問或延遲）加上在執行前修改工具輸入的能力。

| 欄位                         | 描述                                                                                                                                                                                           |
| :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `permissionDecision`       | `"allow"` 跳過權限提示，除了 [需要使用者互動的工具](#pretooluse-decision-control)。`"deny"` 防止工具呼叫。`"ask"` 提示使用者確認。`"defer"` 優雅地退出，以便稍後可以恢復工具。[拒絕和詢問規則](/zh-TW/permissions#manage-permissions) 仍然適用，無論 hook 返回什麼 |
| `permissionDecisionReason` | 對於 `"allow"` 和 `"ask"`，向使用者顯示但不向 Claude 顯示。對於 `"deny"`，向 Claude 顯示。對於 `"defer"`，被忽略                                                                                                          |
| `updatedInput`             | 在執行前修改工具的輸入參數。替換整個輸入物件，因此包括未修改的欄位以及修改後的欄位。與 `"allow"` 結合以自動批准，或與 `"ask"` 結合以向使用者顯示修改後的輸入。對於 `"defer"`，被忽略                                                                                    |
| `additionalContext`        | 在工具執行前新增到 Claude 上下文的字串。對於 `"defer"`，被忽略。請參閱 [為 Claude 新增上下文](#add-context-for-claude)                                                                                                       |

當多個 PreToolUse hooks 返回不同的決定時，優先順序是 `deny` > `defer` > `ask` > `allow`。

當 hook 返回 `"ask"` 時，向使用者顯示的權限提示包括一個標籤，識別 hook 來自何處：例如 `[User]`、`[Project]`、`[Plugin]` 或 `[Local]`。這幫助使用者了解哪個配置來源正在請求確認。

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "permissionDecisionReason": "My reason here",
    "updatedInput": {
      "field_to_modify": "new value"
    },
    "additionalContext": "Current environment: production. Proceed with caution."
  }
}
```

`AskUserQuestion` 和 `ExitPlanMode` 需要使用者互動，通常在 [非互動模式](/zh-TW/headless) 中使用 `-p` 標誌時阻止。返回 `permissionDecision: "allow"` 以及 `updatedInput` 滿足該要求：hook 從 stdin 讀取工具的輸入，通過您自己的 UI 收集答案，並在 `updatedInput` 中返回它，以便工具執行而不提示。僅返回 `"allow"` 對這些工具不夠。對於 `AskUserQuestion`，回顯原始 `questions` 陣列並新增一個 [`answers`](#askuserquestion) 物件，將每個問題的文字對應到選定的答案。

從 v2.1.199 開始，一個 MCP 工具，其伺服器使用 [`_meta["anthropic/requiresUserInteraction"]`](/zh-TW/mcp#require-approval-for-a-specific-tool) 標記它，更嚴格：hook 無法使用 `"allow"` 跳過其批准提示，無論是否有 `updatedInput`，因為 Claude Code 無法確認 hook 收集了工具需要的互動。

<Note>
  PreToolUse 之前使用頂層 `decision` 和 `reason` 欄位，但這些對此事件已棄用。改用 `hookSpecificOutput.permissionDecision` 和 `hookSpecificOutput.permissionDecisionReason`。棄用的值 `"approve"` 和 `"block"` 對應於 `"allow"` 和 `"deny"`。PostToolUse 和 Stop 等其他事件繼續使用頂層 `decision` 和 `reason` 作為其目前格式。
</Note>

<h4 id="defer-a-tool-call-for-later">
  延遲工具呼叫以供稍後使用
</h4>

`"defer"` 用於執行 `claude -p` 作為子程序並讀取其 JSON 輸出的整合，例如 Agent SDK 應用程式或建立在 Claude Code 之上的自訂 UI。它讓該呼叫程序在工具呼叫處暫停 Claude，通過其自己的介面收集輸入，並從中斷處恢復。Claude Code 僅在 [非互動模式](/zh-TW/headless) 中使用 `-p` 標誌時遵守此值。在互動式工作階段中，它記錄警告並忽略 hook 結果。

`AskUserQuestion` 工具是典型情況：Claude 想要詢問使用者某些事情，但沒有終端來回答。往返工作如下：

1. Claude 呼叫 `AskUserQuestion`。`PreToolUse` hook 觸發。
2. Hook 返回 `permissionDecision: "defer"`。工具不執行。程序以 `stop_reason: "tool_deferred"` 退出，待處理的工具呼叫保留在成績單中。
3. 呼叫程序從 SDK 結果讀取 `deferred_tool_use`，在其自己的 UI 中呈現問題，並等待答案。
4. 呼叫程序執行 `claude -p --resume <session-id>`。相同的工具呼叫再次觸發 `PreToolUse`。
5. Hook 返回 `permissionDecision: "allow"`，答案在 `updatedInput` 中。工具執行，Claude 繼續。

`deferred_tool_use` 欄位攜帶工具的 `id`、`name` 和 `input`。`input` 是 Claude 為工具呼叫生成的參數，在執行前捕獲：

```json theme={null}
{
  "type": "result",
  "subtype": "success",
  "stop_reason": "tool_deferred",
  "session_id": "abc123",
  "deferred_tool_use": {
    "id": "toolu_01abc",
    "name": "AskUserQuestion",
    "input": { "questions": [{ "question": "Which framework?", "header": "Framework", "options": [{"label": "React"}, {"label": "Vue"}], "multiSelect": false }] }
  }
}
```

沒有逾時或重試限制。工作階段保留在磁碟上，直到您恢復它，受到 [`cleanupPeriodDays`](/zh-TW/settings#available-settings) 保留掃描的約束，該掃描在預設 30 天後刪除工作階段檔案。如果恢復時答案還沒有準備好，hook 可以再次返回 `"defer"`，程序以相同的方式退出。呼叫程序控制何時通過最終返回 `"allow"` 或 `"deny"` 從 hook 中斷迴圈。

`"defer"` 僅在 Claude 在轉向中進行單一工具呼叫時有效。如果 Claude 一次進行多個工具呼叫，`"defer"` 會被忽略並顯示警告，工具通過正常權限流程進行。該限制存在是因為恢復只能重新執行一個工具：沒有辦法延遲一個呼叫而不留下其他呼叫未解決。

如果恢復時延遲的工具不再可用，程序以 `stop_reason: "tool_deferred_unavailable"` 和 `is_error: true` 退出，在 hook 觸發之前。這發生在提供工具的 MCP 伺服器對於恢復的工作階段未連接時。`deferred_tool_use` 有效負載仍然包括在內，以便您可以識別哪個工具遺失。

<Note>
  `--resume` 恢復工具被延遲時活動的權限模式，因此您不需要再次傳遞 `--permission-mode`。例外是 `plan` 和 `bypassPermissions`，它們永遠不會被帶過。在恢復時明確傳遞 `--permission-mode` 會覆蓋恢復的值。
</Note>

<h3 id="permissionrequest">
  PermissionRequest
</h3>

在向使用者顯示權限對話框時執行。使用 [PermissionRequest 決定控制](#permissionrequest-decision-control) 代表使用者允許或拒絕。

匹配工具名稱，與 PreToolUse 相同的值。

<h4 id="permissionrequest-input">
  PermissionRequest 輸入
</h4>

PermissionRequest hooks 接收 `tool_name` 和 `tool_input` 欄位，如 PreToolUse hooks，但沒有 `tool_use_id`。可選的 `permission_suggestions` 陣列包含使用者通常在權限對話框中看到的「總是允許」選項。區別在於 hook 何時觸發：PermissionRequest hooks 在權限對話框即將向使用者顯示時執行，而 PreToolUse hooks 在工具執行前執行，無論權限狀態如何。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PermissionRequest",
  "tool_name": "Bash",
  "tool_input": {
    "command": "rm -rf node_modules",
    "description": "Remove node_modules directory"
  },
  "permission_suggestions": [
    {
      "type": "addRules",
      "rules": [{ "toolName": "Bash", "ruleContent": "rm -rf node_modules" }],
      "behavior": "allow",
      "destination": "localSettings"
    }
  ]
}
```

<h4 id="permissionrequest-decision-control">
  PermissionRequest 決定控制
</h4>

`PermissionRequest` hooks 可以允許或拒絕權限請求。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您的 hook 指令碼可以返回一個 `decision` 物件，其中包含這些事件特定欄位：

| 欄位                   | 描述                                                                                                                  |
| :------------------- | :------------------------------------------------------------------------------------------------------------------ |
| `behavior`           | `"allow"` 授予權限，`"deny"` 拒絕它。[拒絕和詢問規則](/zh-TW/permissions#manage-permissions) 仍然適用，所以返回 `"allow"` 的 hook 不會覆蓋匹配的拒絕規則 |
| `updatedInput`       | 僅適用於 `"allow"`：在執行前修改工具的輸入參數。替換整個輸入物件，因此包括未修改的欄位以及修改後的欄位。修改後的輸入會重新評估拒絕和詢問規則                                         |
| `updatedPermissions` | 僅適用於 `"allow"`：應用的 [權限更新項目](#permission-update-entries) 陣列，例如新增允許規則或變更工作階段權限模式                                      |
| `message`            | 僅適用於 `"deny"`：告訴 Claude 為什麼權限被拒絕                                                                                    |
| `interrupt`          | 僅適用於 `"deny"`：如果為 `true`，停止 Claude                                                                                  |

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PermissionRequest",
    "decision": {
      "behavior": "allow",
      "updatedInput": {
        "command": "npm run lint"
      }
    }
  }
}
```

<h4 id="permission-update-entries">
  權限更新項目
</h4>

`updatedPermissions` 輸出欄位和 [`permission_suggestions` 輸入欄位](#permissionrequest-input) 都使用相同的項目物件陣列。每個項目都有一個 `type` 決定其他欄位，以及一個 `destination` 控制變更寫入位置。

| `type`              | 欄位                               | 效果                                                                                                                                                                                |
| :------------------ | :------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `addRules`          | `rules`、`behavior`、`destination` | 新增權限規則。`rules` 是 `{toolName, ruleContent?}` 物件的陣列。省略 `ruleContent` 以匹配整個工具。`behavior` 是 `"allow"`、`"deny"` 或 `"ask"`                                                              |
| `replaceRules`      | `rules`、`behavior`、`destination` | 用提供的 `rules` 替換 `destination` 處給定 `behavior` 的所有規則                                                                                                                                |
| `removeRules`       | `rules`、`behavior`、`destination` | 移除匹配的給定 `behavior` 的規則                                                                                                                                                            |
| `setMode`           | `mode`、`destination`             | 變更權限模式。有效模式為 `default`、`auto`、`acceptEdits`、`dontAsk`、`bypassPermissions`、`plan` 和 {/* min-version: 2.1.200 */}`manual` 作為 `default` 的別名。`manual` 別名需要 Claude Code v2.1.200 或更高版本 |
| `addDirectories`    | `directories`、`destination`      | 新增工作目錄。`directories` 是路徑字串的陣列                                                                                                                                                     |
| `removeDirectories` | `directories`、`destination`      | 移除工作目錄                                                                                                                                                                            |

<Note>
  `setMode` 與 `bypassPermissions` 僅在工作階段已經啟用繞過模式時生效：`--dangerously-skip-permissions`、`--permission-mode bypassPermissions`、`--allow-dangerously-skip-permissions` 或 `permissions.defaultMode: "bypassPermissions"` 在設定中，且模式未被 [`permissions.disableBypassPermissionsMode`](/zh-TW/permissions#managed-settings) 停用。否則更新是無操作。`bypassPermissions` 無論 `destination` 如何都永遠不會被持久化為 `defaultMode`。
</Note>

每個項目上的 `destination` 欄位決定變更是保留在記憶體中還是持久化到設定檔。

| `destination`     | 寫入                            |
| :---------------- | :---------------------------- |
| `session`         | 僅在記憶體中，工作階段結束時丟棄              |
| `localSettings`   | `.claude/settings.local.json` |
| `projectSettings` | `.claude/settings.json`       |
| `userSettings`    | `~/.claude/settings.json`     |

Hook 可以回顯它接收的 `permission_suggestions` 之一作為其自己的 `updatedPermissions` 輸出，這等同於使用者在對話框中選擇該「總是允許」選項。

<h3 id="posttooluse">
  PostToolUse
</h3>

在工具成功完成後立即執行。

匹配工具名稱，與 PreToolUse 相同的值。

<h4 id="posttooluse-input">
  PostToolUse 輸入
</h4>

`PostToolUse` hooks 在工具已經成功執行後觸發。輸入包括 `tool_input`（發送給工具的參數）和 `tool_response`（它返回的結果）。兩者的確切架構取決於工具。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  },
  "tool_use_id": "toolu_01ABC123...",
  "duration_ms": 12
}
```

| 欄位            | 描述                                             |
| :------------ | :--------------------------------------------- |
| `duration_ms` | 可選。工具執行時間（毫秒）。不包括權限提示和 PreToolUse hooks 中花費的時間 |

<h4 id="posttooluse-decision-control">
  PostToolUse 決定控制
</h4>

`PostToolUse` hooks 可以在工具執行後向 Claude 提供反饋。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您的 hook 指令碼可以返回這些事件特定欄位：

| 欄位                     | 描述                                                                             |
| :--------------------- | :----------------------------------------------------------------------------- |
| `decision`             | `"block"` 提示 Claude 使用 `reason`。省略以允許操作進行                                      |
| `reason`               | 當 `decision` 為 `"block"` 時向 Claude 顯示的解釋                                       |
| `additionalContext`    | 新增到 Claude 上下文的字串，與工具結果一起。請參閱 [為 Claude 新增上下文](#add-context-for-claude)        |
| `updatedToolOutput`    | 在將工具的輸出發送給 Claude 之前，用提供的值替換它。該值必須符合工具的輸出形狀                                    |
| `updatedMCPToolOutput` | 僅適用於 [MCP 工具](#match-mcp-tools)：用提供的值替換工具的輸出。優先使用 `updatedToolOutput`，它適用於所有工具 |

下面的範例替換 `Bash` 呼叫的輸出。替換值符合 `Bash` 工具的輸出形狀：

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "Additional information for Claude",
    "updatedToolOutput": {
      "stdout": "[redacted]",
      "stderr": "",
      "interrupted": false,
      "isImage": false
    }
  }
}
```

<Warning>
  `updatedToolOutput` 僅改變 Claude 看到的內容。工具已經在 hook 觸發時執行，因此任何寫入的檔案、執行的命令或發送的網路請求都已生效。遙測（如 OpenTelemetry 工具跨度和分析事件）也會在 hook 執行前捕獲原始輸出。要在執行前防止或修改工具呼叫，請改用 [PreToolUse](#pretooluse) hook。

  替換值必須符合工具的輸出形狀。內建工具返回結構化物件而不是純字串。例如，`Bash` 返回一個具有 `stdout`、`stderr`、`interrupted` 和 `isImage` 欄位的物件。對於內建工具，不符合工具輸出架構的值會被忽略，並使用原始輸出。MCP 工具輸出通過而不進行架構驗證。去除 Claude 需要的錯誤詳細資訊可能會導致它在錯誤的假設下進行。
</Warning>

<h3 id="posttoolusefailure">
  PostToolUseFailure
</h3>

當工具執行失敗時執行。此事件針對拋出錯誤或返回失敗結果的工具呼叫觸發。使用此項來記錄失敗、發送警報或向 Claude 提供更正反饋。

匹配工具名稱，與 PreToolUse 相同的值。

<h4 id="posttoolusefailure-input">
  PostToolUseFailure 輸入
</h4>

PostToolUseFailure hooks 接收與 PostToolUse 相同的 `tool_name` 和 `tool_input` 欄位，以及作為頂層欄位的錯誤資訊：

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PostToolUseFailure",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test",
    "description": "Run test suite"
  },
  "tool_use_id": "toolu_01ABC123...",
  "error": "Command exited with non-zero status code 1",
  "is_interrupt": false,
  "duration_ms": 4187
}
```

| 欄位             | 描述                                             |
| :------------- | :--------------------------------------------- |
| `error`        | 描述出錯的字串                                        |
| `is_interrupt` | 可選的布林值，指示失敗是否由使用者中斷引起                          |
| `duration_ms`  | 可選。工具執行時間（毫秒）。不包括權限提示和 PreToolUse hooks 中花費的時間 |

<h4 id="posttoolusefailure-decision-control">
  PostToolUseFailure 決定控制
</h4>

`PostToolUseFailure` hooks 可以在工具失敗後向 Claude 提供上下文。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您的 hook 指令碼可以返回這些事件特定欄位：

| 欄位                  | 描述                                                                    |
| :------------------ | :-------------------------------------------------------------------- |
| `additionalContext` | 新增到 Claude 上下文的字串，與錯誤一起。請參閱 [為 Claude 新增上下文](#add-context-for-claude) |

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PostToolUseFailure",
    "additionalContext": "Additional information about the failure for Claude"
  }
}
```

<h3 id="posttoolbatch">
  PostToolBatch
</h3>

在批次中的每個工具呼叫都已解決後執行一次，在 Claude Code 向模型發送下一個請求之前。`PostToolUse` 每個工具執行一次，這意味著當 Claude 進行平行工具呼叫時它並發執行。`PostToolBatch` 恰好執行一次，包含完整批次，因此它是注入取決於執行的工具集而不是任何單一工具的上下文的正確位置。此事件沒有匹配器。

<h4 id="posttoolbatch-input">
  PostToolBatch 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，PostToolBatch hooks 還接收 `tool_calls`，一個描述批次中每個工具呼叫的陣列：

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "PostToolBatch",
  "tool_calls": [
    {
      "tool_name": "Read",
      "tool_input": {"file_path": "/.../ledger/accounts.py"},
      "tool_use_id": "toolu_01...",
      "tool_response": "     1\tfrom __future__ import annotations\n     2\t..."
    },
    {
      "tool_name": "Read",
      "tool_input": {"file_path": "/.../ledger/transactions.py"},
      "tool_use_id": "toolu_02...",
      "tool_response": "     1\tfrom __future__ import annotations\n     2\t..."
    }
  ]
}
```

`tool_response` 包含與模型在相應 `tool_result` 塊中接收的內容相同的內容。該值是序列化的字串或內容塊陣列，完全如工具發出的那樣。對於 `Read`，這意味著行號前綴的文字而不是原始檔案內容。回應可能很大，因此僅解析您需要的欄位。

<Note>
  `tool_response` 形狀與 `PostToolUse` 的不同。`PostToolUse` 傳遞工具的結構化 `Output` 物件，例如 `Write` 的 `{filePath: "...", success: true}`；`PostToolBatch` 傳遞序列化的 `tool_result` 內容模型看到的。
</Note>

<h4 id="posttoolbatch-decision-control">
  PostToolBatch 決定控制
</h4>

`PostToolBatch` hooks 可以為 Claude 注入上下文。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您的 hook 指令碼可以返回這些事件特定欄位：

| 欄位                  | 描述                                                                                                      |
| :------------------ | :------------------------------------------------------------------------------------------------------ |
| `additionalContext` | 在下一個模型呼叫之前注入一次的上下文字串。請參閱 [為 Claude 新增上下文](#add-context-for-claude) 以了解傳遞詳細資訊、要放入其中的內容，以及恢復的工作階段如何處理過去的值 |

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PostToolBatch",
    "additionalContext": "These files are part of the ledger module. Run pytest before marking the task complete."
  }
}
```

返回 `decision: "block"` 或 `continue: false` 在下一個模型呼叫之前停止代理迴圈。

<h3 id="permissiondenied">
  PermissionDenied
</h3>

當 [自動模式](/zh-TW/permission-modes#eliminate-prompts-with-auto-mode) 分類器拒絕工具呼叫時執行。此 hook 僅在自動模式中觸發：當您手動拒絕權限對話框、當 `PreToolUse` hook 阻止呼叫或當 `deny` 規則匹配時，它不執行。使用它來記錄分類器拒絕、調整配置或告訴模型它可能重試工具呼叫。

匹配工具名稱，與 PreToolUse 相同的值。

<h4 id="permissiondenied-input">
  PermissionDenied 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，PermissionDenied hooks 還接收 `tool_name`、`tool_input`、`tool_use_id` 和 `reason`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "auto",
  "hook_event_name": "PermissionDenied",
  "tool_name": "Bash",
  "tool_input": {
    "command": "rm -rf /tmp/build",
    "description": "Clean build directory"
  },
  "tool_use_id": "toolu_01ABC123...",
  "reason": "Auto mode denied: command targets a path outside the project"
}
```

| 欄位       | 描述              |
| :------- | :-------------- |
| `reason` | 分類器拒絕工具呼叫的原因的解釋 |

<h4 id="permissiondenied-decision-control">
  PermissionDenied 決定控制
</h4>

PermissionDenied hooks 可以告訴模型它可能重試被拒絕的工具呼叫。返回一個 JSON 物件，其中 `hookSpecificOutput.retry` 設定為 `true`：

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PermissionDenied",
    "retry": true
  }
}
```

當 `retry` 為 `true` 時，Claude Code 向對話新增一條訊息，告訴模型它可能重試工具呼叫。拒絕本身不被反轉。如果您的 hook 不返回 JSON，或返回 `retry: false`，拒絕成立，模型接收原始拒絕訊息。

<h3 id="notification">
  Notification
</h3>

當 Claude Code 發送通知時執行。匹配通知類型。省略匹配器以針對所有通知類型執行 hooks。

| 匹配器                    | 何時觸發                                                        |
| :--------------------- | :---------------------------------------------------------- |
| `permission_prompt`    | Claude 需要您批准工具使用                                            |
| `idle_prompt`          | Claude 完成並等待您的下一個提示                                         |
| `auth_success`         | 驗證完成                                                        |
| `elicitation_dialog`   | MCP 伺服器開啟徵詢表單                                               |
| `elicitation_complete` | MCP 徵詢表單被提交或關閉                                              |
| `elicitation_response` | MCP 徵詢回應被發送回伺服器                                             |
| `agent_needs_input`    | 背景工作階段開始等待您的輸入。僅在 [agent view](/zh-TW/agent-view) 在終端中開啟時觸發 |
| `agent_completed`      | 背景工作階段完成或失敗。僅在 [agent view](/zh-TW/agent-view) 在終端中開啟時觸發    |

`agent_needs_input` 和 `agent_completed` 類型需要 Claude Code v2.1.198 或更高版本。

使用單獨的匹配器根據通知類型執行不同的處理程式。此配置在 Claude 需要權限批准時觸發權限特定的警報指令碼，在 Claude 閒置時觸發不同的通知：

```json theme={null}
{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/permission-alert.sh"
          }
        ]
      },
      {
        "matcher": "idle_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/idle-notification.sh"
          }
        ]
      }
    ]
  }
}
```

<h4 id="notification-input">
  Notification 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，Notification hooks 還接收包含通知文字的 `message`、可選的 `title` 和指示哪個類型觸發的 `notification_type`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "Notification",
  "message": "Claude needs your permission",
  "title": "Permission needed",
  "notification_type": "permission_prompt"
}
```

Notification hooks 無法阻止或修改通知。它們用於副作用，例如將通知轉發到外部服務。[通用 JSON 輸出欄位](#json-output)（例如 `systemMessage`）適用。

<h3 id="subagentstart">
  SubagentStart
</h3>

當通過 Agent 工具生成 Claude Code subagent 時執行。支援匹配器以按代理類型名稱篩選。對於內建代理，這是代理名稱，如 `general-purpose`、`Explore` 或 `Plan`。對於 [自訂 subagents](/zh-TW/sub-agents)，這是代理 frontmatter 中的 `name` 欄位，而不是檔案名稱。

對於由 [plugin](/zh-TW/plugins) 提供的 subagents，代理類型是外掛程式範圍的識別碼，例如 `my-plugin:reviewer`，而不是裸露的 frontmatter 名稱。冒號將外掛程式範圍的名稱放在正規表達式路徑上，因此使用 `^` 和 `$` 錨定匹配器以進行精確匹配：`^my-plugin:reviewer$`。

<h4 id="subagentstart-input">
  SubagentStart 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，SubagentStart hooks 還接收 `agent_id`（subagent 的唯一識別碼）和 `agent_type`（代理名稱，匹配器篩選的值）。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "SubagentStart",
  "agent_id": "agent-abc123",
  "agent_type": "Explore"
}
```

SubagentStart hooks 無法阻止 subagent 建立，但它們可以將上下文注入到 subagent 中。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您可以返回：

| 欄位                  | 描述                                                                             |
| :------------------ | :----------------------------------------------------------------------------- |
| `additionalContext` | 新增到 subagent 上下文開始處的字串，在其第一個提示之前。請參閱 [為 Claude 新增上下文](#add-context-for-claude) |

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "SubagentStart",
    "additionalContext": "Follow security guidelines for this task"
  }
}
```

<h3 id="subagentstop">
  SubagentStop
</h3>

當 Claude Code subagent 完成回應時執行。匹配代理類型，與 SubagentStart 相同的值。

<h4 id="subagentstop-input">
  SubagentStop 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，SubagentStop hooks 還接收 `stop_hook_active`、`agent_id`、`agent_type`、`agent_transcript_path` 和 `last_assistant_message`。`agent_type` 欄位是用於匹配器篩選的值。`transcript_path` 是主工作階段的成績單，而 `agent_transcript_path` 是 subagent 自己的成績單，存儲在嵌套的 `subagents/` 資料夾中。`last_assistant_message` 欄位包含 subagent 最終回應的文字內容，因此 hooks 可以存取它而無需解析成績單檔案。

SubagentStop hooks 也接收 [Stop 輸入](#stop-input) 中描述的 `background_tasks` 和 `session_crons` 陣列，在 Claude Code v2.1.145 或更高版本中可用。兩個陣列都限定於父工作階段，而不是 subagent。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../abc123.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "SubagentStop",
  "stop_hook_active": false,
  "agent_id": "def456",
  "agent_type": "Explore",
  "agent_transcript_path": "~/.claude/projects/.../abc123/subagents/agent-def456.jsonl",
  "last_assistant_message": "Analysis complete. Found 3 potential issues...",
  "background_tasks": [],
  "session_crons": []
}
```

SubagentStop hooks 使用與 [Stop hooks](#stop-decision-control) 相同的決定控制格式，包括 `hookSpecificOutput.additionalContext`，其中 `hookEventName` 設定為 `"SubagentStop"`，用於非錯誤反饋，使 subagent 保持執行。返回 `decision: "block"` 與 `reason` 會保持 subagent 執行並將 `reason` 作為其下一個指令傳遞給 subagent。要在 subagent 返回後將上下文注入到父工作階段，請改用 `Agent` 工具上的 [`PostToolUse`](#posttooluse) hook。

<h3 id="taskcreated">
  TaskCreated
</h3>

當任務通過 `TaskCreate` 工具被建立時執行。使用此項來強制執行命名慣例、要求任務描述或防止某些任務被建立。

當 `TaskCreated` hook 以代碼 2 退出時，任務不被建立，stderr 訊息被反饋給模型作為反饋。要完全停止隊友而不是重新執行它，請返回 JSON，其中 `{"continue": false, "stopReason": "..."}`。TaskCreated hooks 不支援匹配器，在每次出現時觸發。

<h4 id="taskcreated-input">
  TaskCreated 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，TaskCreated hooks 還接收 `task_id`、`task_subject` 和可選的 `task_description`、`teammate_name` 和 `team_name`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "TaskCreated",
  "task_id": "task-001",
  "task_subject": "Implement user authentication",
  "task_description": "Add login and signup endpoints",
  "teammate_name": "implementer",
  "team_name": "session-a1b2c3d4"
}
```

| 欄位                 | 描述                        |
| :----------------- | :------------------------ |
| `task_id`          | 被建立的任務的識別碼                |
| `task_subject`     | 任務的標題                     |
| `task_description` | 任務的詳細描述。可能不存在             |
| `teammate_name`    | 建立任務的隊友的名稱。可能不存在          |
| `team_name`        | 已棄用。工作階段衍生的團隊名稱；將在未來版本中移除 |

<h4 id="taskcreated-decision-control">
  TaskCreated 決定控制
</h4>

TaskCreated hooks 支援兩種方式來控制任務建立：

* **退出代碼 2**：任務不被建立，stderr 訊息被反饋給模型作為反饋。
* **JSON `{"continue": false, "stopReason": "..."}`**：完全停止隊友，匹配 `Stop` hook 行為。`stopReason` 向使用者顯示。

此範例阻止主題不遵循所需格式的任務：

```bash theme={null}
#!/bin/bash
INPUT=$(cat)
TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')

if [[ ! "$TASK_SUBJECT" =~ ^\[TICKET-[0-9]+\] ]]; then
  echo "Task subject must start with a ticket number, e.g. '[TICKET-123] Add feature'" >&2
  exit 2
fi

exit 0
```

<h3 id="taskcompleted">
  TaskCompleted
</h3>

當任務被標記為已完成時執行。這在兩種情況下觸發：當任何代理通過 TaskUpdate 工具明確標記任務為已完成時，或當 [agent team](/zh-TW/agent-teams) 隊友完成其輪次並有進行中的任務時。使用此項來強制執行完成條件，例如通過測試或 lint 檢查，然後任務才能關閉。

當 `TaskCompleted` hook 以代碼 2 退出時，任務不被標記為已完成，stderr 訊息被反饋給模型作為反饋。要完全停止隊友而不是重新執行它，請返回 JSON，其中 `{"continue": false, "stopReason": "..."}`。TaskCompleted hooks 不支援匹配器，在每次出現時觸發。

<h4 id="taskcompleted-input">
  TaskCompleted 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，TaskCompleted hooks 還接收 `task_id`、`task_subject` 和可選的 `task_description`、`teammate_name` 和 `team_name`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "TaskCompleted",
  "task_id": "task-001",
  "task_subject": "Implement user authentication",
  "task_description": "Add login and signup endpoints",
  "teammate_name": "implementer",
  "team_name": "session-a1b2c3d4"
}
```

| 欄位                 | 描述                        |
| :----------------- | :------------------------ |
| `task_id`          | 被完成的任務的識別碼                |
| `task_subject`     | 任務的標題                     |
| `task_description` | 任務的詳細描述。可能不存在             |
| `teammate_name`    | 完成任務的隊友的名稱。可能不存在          |
| `team_name`        | 已棄用。工作階段衍生的團隊名稱；將在未來版本中移除 |

<h4 id="taskcompleted-decision-control">
  TaskCompleted 決定控制
</h4>

TaskCompleted hooks 支援兩種方式來控制任務完成：

* **退出代碼 2**：任務不被標記為已完成，stderr 訊息被反饋給模型作為反饋。
* **JSON `{"continue": false, "stopReason": "..."}`**：完全停止隊友，匹配 `Stop` hook 行為。`stopReason` 向使用者顯示。

此範例執行測試並在失敗時阻止任務完成：

```bash theme={null}
#!/bin/bash
INPUT=$(cat)
TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')

# 執行測試套件
if ! npm test 2>&1; then
  echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&2
  exit 2
fi

exit 0
```

<h3 id="stop">
  Stop
</h3>

當主 Claude Code 代理完成回應時執行。如果停止是由於使用者中斷，則不執行。API 錯誤會觸發 [StopFailure](#stopfailure)。

<Tip>
  [`/goal`](/zh-TW/goal) 命令是工作階段範圍提示型 Stop hook 的內建快捷方式。當您想要 Claude 繼續工作直到條件成立而不編寫 hook 配置時，請使用它。
</Tip>

<h4 id="stop-input">
  Stop 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，Stop hooks 還接收 `stop_hook_active`、`last_assistant_message`、`background_tasks` 和 `session_crons`。`stop_hook_active` 欄位在 Claude Code 已經作為 stop hook 的結果繼續時為 `true`。檢查此值或處理成績單以防止 Claude Code 無限執行。Claude Code 在 8 次連續阻止後覆蓋 hook 並結束轉向。`last_assistant_message` 欄位包含 Claude 最終回應的文字內容，因此 hooks 可以存取它而無需解析成績單檔案。

`background_tasks` 和 `session_crons` 陣列在 Claude Code v2.1.145 或更高版本中可用，讓 hooks 區分「工作階段完成」和「工作階段暫停等待背景工作喚醒它」。當任務登錄表可達時，兩個陣列都存在，當沒有任何內容在進行中或計劃時為空。

`background_tasks` 中的每個項目描述一個進行中的任務，並使用這些欄位：

| 欄位            | 描述                                                                                                                                           |
| :------------ | :------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`          | 任務識別碼                                                                                                                                        |
| `type`        | 友好的任務類型標籤，例如 `shell`、`subagent`、`monitor`、`workflow`、`teammate`、`cloud session` 或 `MCP task`。每個標籤識別哪個 Claude Code 功能建立了任務。對於無法識別的類型，回退到原始判別式 |
| `status`      | 目前任務狀態                                                                                                                                       |
| `description` | 自由文字描述，上限為 1000 個字元，當被剪裁時在字串中有 `… [+N chars]` 標記                                                                                             |
| `command`     | Shell 命令行，上限為 1000 個字元。僅針對 `shell` 任務出現                                                                                                      |
| `agent_type`  | Subagent 類型名稱。僅針對 `subagent` 任務出現                                                                                                            |
| `server`      | MCP 伺服器名稱。僅針對 `monitor` 和 `MCP task` 任務出現                                                                                                    |
| `tool`        | MCP 工具名稱。僅針對 `monitor` 和 `MCP task` 任務出現                                                                                                     |
| `name`        | 工作流名稱。僅針對 `workflow` 任務出現                                                                                                                    |

`session_crons` 中的每個項目描述一個工作階段範圍的計劃喚醒，來自 `CronCreate`、`ScheduleWakeup` 和 `/loop`：

| 欄位          | 描述                                                   |
| :---------- | :--------------------------------------------------- |
| `id`        | Cron 任務識別碼                                           |
| `schedule`  | Cron 表達式，例如 `0 9 * * 1-5`                            |
| `recurring` | `false` 用於一次性喚醒，其計劃編碼單一觸發時間，`true` 用於在每次匹配時重新觸發的任務   |
| `prompt`    | 當 cron 觸發時提交的提示，上限為 1000 個字元，具有相同的 `… [+N chars]` 標記 |

此範例顯示一個 Stop 輸入，其中有一個進行中的 shell 任務和一個循環 cron：

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "Stop",
  "stop_hook_active": true,
  "last_assistant_message": "I've completed the refactoring. Here's a summary...",
  "background_tasks": [
    {
      "id": "task-001",
      "type": "shell",
      "status": "running",
      "description": "tail logs",
      "command": "tail -f /var/log/syslog"
    }
  ],
  "session_crons": [
    {
      "id": "cron-001",
      "schedule": "0 9 * * 1-5",
      "recurring": true,
      "prompt": "check the build"
    }
  ]
}
```

<h4 id="stop-decision-control">
  Stop 決定控制
</h4>

`Stop` 和 `SubagentStop` hooks 可以控制 Claude 是否繼續。除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，您的 hook 指令碼可以返回這些事件特定欄位：

| 欄位                                     | 描述                                                                                            |
| :------------------------------------- | :-------------------------------------------------------------------------------------------- |
| `decision`                             | `"block"` 防止 Claude 停止。省略以允許 Claude 停止                                                        |
| `reason`                               | 當 `decision` 為 `"block"` 時必需。告訴 Claude 為什麼它應該繼續                                               |
| `hookSpecificOutput.additionalContext` | 非錯誤反饋給 Claude。對話繼續，以便 Claude 可以對其採取行動，但與 `decision: "block"` 不同，它在成績單中顯示為 hook 反饋，而不是 hook 錯誤 |

```json theme={null}
{
  "decision": "block",
  "reason": "Must be provided when Claude is blocked from stopping"
}
```

當 hook 的設計目的是提供指導時，使用 `additionalContext`，例如「在完成前執行測試套件」。它通過與 `decision: "block"` 相同的迴圈保護（即 `stop_hook_active` 輸入和 8 次連續繼續上限）保持對話進行，但成績單將其標籤為 `Stop hook feedback`，不顯示 hook 錯誤通知：

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "Stop",
    "additionalContext": "Please run the test suite before finishing"
  }
}
```

<h3 id="stopfailure">
  StopFailure
</h3>

當轉向因 API 錯誤而結束時執行，而不是 [Stop](#stop)。輸出和退出代碼被忽略。使用此項來記錄失敗、發送警報或在 Claude 因速率限制、驗證問題或其他 API 錯誤而無法完成回應時採取恢復操作。

<h4 id="stopfailure-input">
  StopFailure 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，StopFailure hooks 還接收 `error`、可選的 `error_details` 和可選的 `last_assistant_message`。`error` 欄位識別錯誤類型，用於匹配器篩選。

| 欄位                       | 描述                                                                                                                                                                                |
| :----------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `error`                  | 錯誤類型：`rate_limit`、`overloaded`、`authentication_failed`、`oauth_org_not_allowed`、`billing_error`、`invalid_request`、`model_not_found`、`server_error`、`max_output_tokens` 或 `unknown` |
| `error_details`          | 有關錯誤的其他詳細資訊（如果可用）                                                                                                                                                                 |
| `last_assistant_message` | 在對話中顯示的呈現錯誤文字。與 `Stop` 和 `SubagentStop` 不同，其中此欄位包含 Claude 的對話輸出，對於 `StopFailure`，它包含 API 錯誤字串本身，例如 `"API Error: Rate limit reached"`                                              |

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "StopFailure",
  "error": "rate_limit",
  "error_details": "429 Too Many Requests",
  "last_assistant_message": "API Error: Rate limit reached"
}
```

StopFailure hooks 沒有決定控制。它們僅用於通知和記錄目的執行。

<h3 id="teammateidle">
  TeammateIdle
</h3>

當 [agent team](/zh-TW/agent-teams) 隊友在完成其輪次後即將閒置時執行。使用此項來在隊友停止工作之前強制執行品質閘道，例如要求通過 lint 檢查或驗證輸出檔案存在。

當 `TeammateIdle` hook 以代碼 2 退出時，隊友會收到 stderr 訊息作為反饋，並繼續工作而不是閒置。要完全停止隊友而不是重新執行它，請返回 JSON，其中 `{"continue": false, "stopReason": "..."}`。TeammateIdle hooks 不支援匹配器，在每次出現時觸發。

<h4 id="teammateidle-input">
  TeammateIdle 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，TeammateIdle hooks 還接收 `teammate_name` 和 `team_name`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "TeammateIdle",
  "teammate_name": "researcher",
  "team_name": "session-a1b2c3d4"
}
```

| 欄位              | 描述                        |
| :-------------- | :------------------------ |
| `teammate_name` | 即將閒置的隊友的名稱                |
| `team_name`     | 已棄用。工作階段衍生的團隊名稱；將在未來版本中移除 |

<h4 id="teammateidle-decision-control">
  TeammateIdle 決定控制
</h4>

TeammateIdle hooks 支援兩種方式來控制隊友行為：

* **退出代碼 2**：隊友會收到 stderr 訊息作為反饋，並繼續工作而不是閒置。
* **JSON `{"continue": false, "stopReason": "..."}`**：完全停止隊友，匹配 `Stop` hook 行為。`stopReason` 向使用者顯示。

此範例在允許隊友閒置之前檢查建置成品是否存在：

```bash theme={null}
#!/bin/bash

if [ ! -f "./dist/output.js" ]; then
  echo "Build artifact missing. Run the build before stopping." >&2
  exit 2
fi

exit 0
```

<h3 id="configchange">
  ConfigChange
</h3>

當配置檔案在工作階段期間變更時執行。使用此項來稽核設定變更、強制執行安全原則或阻止對配置檔案的未授權修改。

ConfigChange hooks 針對設定檔、受管理的原則設定和 skill 檔案的變更觸發。輸入中的 `source` 欄位告訴您哪種類型的配置變更，可選的 `file_path` 欄位提供變更檔案的路徑。

匹配器篩選配置來源：

| 匹配器                | 何時觸發                             |
| :----------------- | :------------------------------- |
| `user_settings`    | `~/.claude/settings.json` 變更     |
| `project_settings` | `.claude/settings.json` 變更       |
| `local_settings`   | `.claude/settings.local.json` 變更 |
| `policy_settings`  | 受管理的原則設定變更                       |
| `skills`           | `.claude/skills/` 中的 skill 檔案變更  |

此範例記錄所有配置變更以進行安全稽核：

```json theme={null}
{
  "hooks": {
    "ConfigChange": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/audit-config-change.sh",
            "args": []
          }
        ]
      }
    ]
  }
}
```

<h4 id="configchange-input">
  ConfigChange 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，ConfigChange hooks 還接收 `source` 和可選的 `file_path`。`source` 欄位指示哪種配置類型變更，`file_path` 提供被修改的特定檔案的路徑。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "ConfigChange",
  "source": "project_settings",
  "file_path": "/Users/.../my-project/.claude/settings.json"
}
```

<h4 id="configchange-decision-control">
  ConfigChange 決定控制
</h4>

ConfigChange hooks 可以阻止配置變更生效。使用退出代碼 2 或 JSON `decision` 來防止變更。被阻止時，新設定不會應用於執行中的工作階段。

| 欄位         | 描述                                  |
| :--------- | :---------------------------------- |
| `decision` | `"block"` 防止配置變更被應用。省略以允許變更         |
| `reason`   | 當 `decision` 為 `"block"` 時向使用者顯示的解釋 |

```json theme={null}
{
  "decision": "block",
  "reason": "Configuration changes to project settings require admin approval"
}
```

`policy_settings` 變更無法被阻止。Hooks 仍然針對 `policy_settings` 來源觸發，因此您可以使用它們進行稽核記錄，但任何阻止決定都會被忽略。這確保企業管理的設定始終生效。

<h3 id="cwdchanged">
  CwdChanged
</h3>

當工作目錄在工作階段期間變更時執行，例如當 Claude 執行 `cd` 命令時。使用此項來對目錄變更做出反應：重新載入環境變數、啟動專案特定的工具鏈或自動執行設定指令碼。與 [FileChanged](#filechanged) 配對，用於 [direnv](https://direnv.net/) 等管理每個目錄環境的工具。

CwdChanged hooks 可以存取 `CLAUDE_ENV_FILE`。寫入該檔案的變數會持久化到工作階段的後續 Bash 命令中，就像在 [SessionStart hooks](#persist-environment-variables) 中一樣。

CwdChanged 不支援匹配器，在每次目錄變更時觸發。

<h4 id="cwdchanged-input">
  CwdChanged 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，CwdChanged hooks 還接收 `old_cwd` 和 `new_cwd`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../transcript.jsonl",
  "cwd": "/Users/my-project/src",
  "hook_event_name": "CwdChanged",
  "old_cwd": "/Users/my-project",
  "new_cwd": "/Users/my-project/src"
}
```

<h4 id="cwdchanged-output">
  CwdChanged 輸出
</h4>

除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，CwdChanged hooks 還可以返回 `watchPaths` 來動態設定 [FileChanged](#filechanged) 監視的檔案路徑：

| 欄位           | 描述                                                                    |
| :----------- | :-------------------------------------------------------------------- |
| `watchPaths` | 絕對路徑的陣列。替換目前的動態監視清單。來自您 `matcher` 配置的路徑始終被監視。返回空陣列會清除動態清單，這在進入新目錄時很典型 |

CwdChanged hooks 沒有決定控制。它們無法阻止目錄變更。

<h3 id="filechanged">
  FileChanged
</h3>

當監視的檔案在磁碟上變更時執行。適用於在專案配置檔案被修改時重新載入環境變數。

`matcher` 對於此事件有兩個角色：

* **建立監視清單**：值在 `|` 上分割，每個段被註冊為工作目錄中的檔案名稱，因此 `".envrc|.env"` 監視恰好這兩個檔案。正規表達式模式在這裡沒有用：像 `^\.env` 這樣的值會監視一個字面上名為 `^\.env` 的檔案。
* **篩選哪些 hooks 執行**：當監視的檔案變更時，相同的值使用標準 [匹配器規則](#matcher-patterns) 針對變更檔案的基本名稱篩選哪些 hook 群組執行。

FileChanged hooks 可以存取 `CLAUDE_ENV_FILE`。寫入該檔案的變數會持久化到工作階段的後續 Bash 命令中，就像在 [SessionStart hooks](#persist-environment-variables) 中一樣。

<h4 id="filechanged-input">
  FileChanged 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，FileChanged hooks 還接收 `file_path` 和 `event`。

| 欄位          | 描述                                                        |
| :---------- | :-------------------------------------------------------- |
| `file_path` | 變更檔案的絕對路徑                                                 |
| `event`     | 發生的情況：`"change"`（檔案被修改）、`"add"`（檔案被建立）或 `"unlink"`（檔案被刪除） |

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../transcript.jsonl",
  "cwd": "/Users/my-project",
  "hook_event_name": "FileChanged",
  "file_path": "/Users/my-project/.envrc",
  "event": "change"
}
```

<h4 id="filechanged-output">
  FileChanged 輸出
</h4>

除了所有 hooks 可用的 [JSON 輸出欄位](#json-output) 外，FileChanged hooks 還可以返回 `watchPaths` 來動態更新監視的檔案路徑：

| 欄位           | 描述                                                                               |
| :----------- | :------------------------------------------------------------------------------- |
| `watchPaths` | 絕對路徑的陣列。替換目前的動態監視清單。來自您 `matcher` 配置的路徑始終被監視。當您的 hook 指令碼根據變更的檔案發現要監視的其他檔案時，使用此項 |

FileChanged hooks 沒有決定控制。它們無法阻止檔案變更的發生。

<h3 id="worktreecreate">
  WorktreeCreate
</h3>

當您執行 `claude --worktree` 或 [subagent 使用 `isolation: "worktree"`](/zh-TW/sub-agents#choose-the-subagent-scope) 時，Claude Code 使用 `git worktree` 建立隔離的工作副本。如果您配置 WorktreeCreate hook，它會替換預設的 git 行為，讓您使用不同的版本控制系統，如 SVN、Perforce 或 Mercurial。

因為 hook 完全替換預設行為，[`.worktreeinclude`](/zh-TW/worktrees#copy-gitignored-files-into-worktrees) 不被處理。如果您需要將本機配置檔案（如 `.env`）複製到新 worktree，請在您的 hook 指令碼內執行。

Hook 必須返回建立的 worktree 目錄的絕對路徑。Claude Code 使用此路徑作為隔離工作階段的工作目錄。請參閱 [WorktreeCreate 輸出](#worktreecreate-output) 以了解每個 hook 類型如何返回路徑。

此範例建立 SVN 工作副本並列印路徑供 Claude Code 使用。將儲存庫 URL 替換為您自己的：

```json theme={null}
{
  "hooks": {
    "WorktreeCreate": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'NAME=$(jq -r .name); DIR=\"$HOME/.claude/worktrees/$NAME\"; svn checkout https://svn.example.com/repo/trunk \"$DIR\" >&2 && echo \"$DIR\"'"
          }
        ]
      }
    ]
  }
}
```

Hook 從 stdin 上的 JSON 輸入讀取 worktree `name`，將新副本簽出到新目錄，並列印目錄路徑。最後一行的 `echo` 是 Claude Code 讀取的 worktree 路徑。將任何其他輸出重定向到 stderr，以免干擾路徑。

<h4 id="worktreecreate-input">
  WorktreeCreate 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，WorktreeCreate hooks 還接收 `name` 欄位。這是新 worktree 的 slug 識別碼，由使用者指定或自動生成，例如 `bold-oak-a3f2`。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "WorktreeCreate",
  "name": "feature-auth"
}
```

<h4 id="worktreecreate-output">
  WorktreeCreate 輸出
</h4>

WorktreeCreate hooks 不使用標準的允許/阻止決定模型。相反，hook 的成功或失敗決定結果。Hook 必須返回建立的 worktree 目錄的絕對路徑：

* **命令 hooks**（`type: "command"`）：在 stdout 上列印路徑。Claude Code 在讀取該行之前去除 ANSI 逃逸代碼，因此在您的 `echo` 之前列印的 shell 啟動橫幅被忽略。將任何其他 hook 輸出重定向到 stderr。
* **HTTP hooks**（`type: "http"`）：在回應正文中返回 `{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }`。

如果 hook 失敗或不產生路徑，worktree 建立失敗並出現錯誤。

Claude Code 根據 hook 執行的目錄解析相對路徑。如果結果路徑不是 Claude Code 可以進入的目錄，工作階段列印一個命名路徑的錯誤並以代碼 1 退出。在 v2.1.205 之前，相對路徑或磁碟上不存在的路徑會在啟動時使工作階段崩潰，使用 `-p` 時會停滯約 30 秒，然後以代碼 0 退出。

<h3 id="worktreeremove">
  WorktreeRemove
</h3>

當 worktree 被移除時執行，要麼當您退出 `--worktree` 工作階段並選擇移除它時，要麼當具有 `isolation: "worktree"` 的 subagent 完成時。這是 [WorktreeCreate](#worktreecreate) 的清理對應項。對於基於 git 的 worktrees，Claude Code 使用 `git worktree remove` 自動處理清理。如果您為非 git 版本控制系統配置了 WorktreeCreate hook，請將其與 WorktreeRemove hook 配對以處理清理。沒有它，worktree 目錄會留在磁碟上。

Claude Code 將 WorktreeCreate 返回的路徑作為 `worktree_path` 在 hook 輸入中傳遞。此範例讀取該路徑並移除目錄：

```json theme={null}
{
  "hooks": {
    "WorktreeRemove": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "bash -c 'jq -r .worktree_path | xargs rm -rf'"
          }
        ]
      }
    ]
  }
}
```

<h4 id="worktreeremove-input">
  WorktreeRemove 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，WorktreeRemove hooks 還接收 `worktree_path` 欄位，這是被移除的 worktree 的絕對路徑。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "WorktreeRemove",
  "worktree_path": "/Users/.../my-project/.claude/worktrees/feature-auth"
}
```

WorktreeRemove hooks 沒有決定控制。它們無法阻止 worktree 移除，但可以執行清理任務，如移除版本控制狀態或存檔變更。Hook 失敗僅在偵錯模式中記錄。

<h3 id="precompact">
  PreCompact
</h3>

在 Claude Code 即將執行壓縮操作之前執行。

匹配器值指示壓縮是手動觸發還是自動觸發：

| 匹配器      | 何時觸發         |
| :------- | :----------- |
| `manual` | `/compact`   |
| `auto`   | 當上下文視窗滿時自動壓縮 |

退出代碼 2 以阻止壓縮。對於手動 `/compact`，stderr 訊息向使用者顯示。您也可以通過返回帶有 `"decision": "block"` 的 JSON 來阻止。

阻止自動壓縮有不同的效果，取決於何時觸發。如果壓縮在上下文限制之前主動觸發，Claude Code 會跳過它，對話繼續未壓縮。如果壓縮被觸發以從已由 API 返回的上下文限制錯誤恢復，基礎錯誤會浮出並且目前請求失敗。

<h4 id="precompact-input">
  PreCompact 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，PreCompact hooks 還接收 `trigger` 和 `custom_instructions`。對於 `manual`，`custom_instructions` 包含使用者傳遞到 `/compact` 的內容。對於 `auto`，`custom_instructions` 為空。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}
```

<h3 id="postcompact">
  PostCompact
</h3>

在 Claude Code 完成壓縮操作後執行。使用此事件來對新的壓縮狀態做出反應，例如記錄生成的摘要或更新外部狀態。

與 `PreCompact` 相同的匹配器值適用：

| 匹配器      | 何時觸發           |
| :------- | :------------- |
| `manual` | 在 `/compact` 後 |
| `auto`   | 在上下文視窗滿時自動壓縮後  |

<h4 id="postcompact-input">
  PostCompact 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，PostCompact hooks 還接收 `trigger` 和 `compact_summary`。`compact_summary` 欄位包含壓縮操作生成的對話摘要。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PostCompact",
  "trigger": "manual",
  "compact_summary": "Summary of the compacted conversation..."
}
```

PostCompact hooks 沒有決定控制。它們無法影響壓縮結果，但可以執行後續任務。

<h3 id="sessionend">
  SessionEnd
</h3>

當 Claude Code 工作階段結束時執行。適用於清理任務、記錄工作階段統計資訊或儲存工作階段狀態。支援匹配器以按退出原因篩選。

輸入中的 `reason` 欄位指示工作階段為何結束：

| 原因                            | 描述                     |
| :---------------------------- | :--------------------- |
| `clear`                       | 使用 `/clear` 命令清除工作階段   |
| `resume`                      | 通過互動式 `/resume` 切換工作階段 |
| `logout`                      | 使用者登出                  |
| `prompt_input_exit`           | 使用者在提示輸入可見時退出          |
| `bypass_permissions_disabled` | 繞過權限模式被停用              |
| `other`                       | 其他退出原因                 |

<h4 id="sessionend-input">
  SessionEnd 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，SessionEnd hooks 還接收指示工作階段為何結束的 `reason` 欄位。有關所有值，請參閱上面的原因表。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "SessionEnd",
  "reason": "other"
}
```

SessionEnd hooks 沒有決定控制。它們無法阻止工作階段終止，但可以執行清理任務。

SessionEnd hooks 的預設逾時為 1.5 秒。這適用於工作階段退出、`/clear` 和通過互動式 `/resume` 切換工作階段。如果 hook 需要更多時間，請在 hook 配置中設定每個 hook 的 `timeout`。整體預算會自動提高到設定檔中配置的最高每個 hook 逾時，最高 60 秒。在外掛程式提供的 hooks 上設定的逾時不會提高預算。要明確覆蓋預算，請在毫秒中設定 `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` 環境變數。

```bash theme={null}
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
```

<h3 id="elicitation">
  Elicitation
</h3>

當 MCP 伺服器在任務中途請求使用者輸入時執行。預設情況下，Claude Code 顯示互動式對話框供使用者回應。Hooks 可以攔截此請求並以程式方式回應，完全跳過對話框。

匹配器欄位與 MCP 伺服器名稱匹配。

<h4 id="elicitation-input">
  Elicitation 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，Elicitation hooks 還接收 `mcp_server_name`、`message` 和可選的 `mode`、`url`、`elicitation_id` 和 `requested_schema` 欄位。

對於表單模式徵詢（最常見的情況）：

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "Elicitation",
  "mcp_server_name": "my-mcp-server",
  "message": "Please provide your credentials",
  "mode": "form",
  "requested_schema": {
    "type": "object",
    "properties": {
      "username": { "type": "string", "title": "Username" }
    }
  }
}
```

對於 URL 模式徵詢（基於瀏覽器的驗證）：

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "Elicitation",
  "mcp_server_name": "my-mcp-server",
  "message": "Please authenticate",
  "mode": "url",
  "url": "https://auth.example.com/login"
}
```

<h4 id="elicitation-output">
  Elicitation 輸出
</h4>

要以程式方式回應而不顯示對話框，請返回帶有 `hookSpecificOutput` 的 JSON 物件：

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "Elicitation",
    "action": "accept",
    "content": {
      "username": "alice"
    }
  }
}
```

| 欄位        | 值                           | 描述                                   |
| :-------- | :-------------------------- | :----------------------------------- |
| `action`  | `accept`、`decline`、`cancel` | 是否接受、拒絕或取消請求                         |
| `content` | 物件                          | 要提交的表單欄位值。僅在 `action` 為 `accept` 時使用 |

退出代碼 2 拒絕徵詢並向使用者顯示 stderr。

<h3 id="elicitationresult">
  ElicitationResult
</h3>

在使用者回應 MCP 徵詢後執行。Hooks 可以觀察、修改或阻止回應，然後將其發送回 MCP 伺服器。

匹配器欄位與 MCP 伺服器名稱匹配。

<h4 id="elicitationresult-input">
  ElicitationResult 輸入
</h4>

除了 [通用輸入欄位](#common-input-fields) 外，ElicitationResult hooks 還接收 `mcp_server_name`、`action` 和可選的 `mode`、`elicitation_id` 和 `content` 欄位。

```json theme={null}
{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "permission_mode": "default",
  "hook_event_name": "ElicitationResult",
  "mcp_server_name": "my-mcp-server",
  "action": "accept",
  "content": { "username": "alice" },
  "mode": "form",
  "elicitation_id": "elicit-123"
}
```

<h4 id="elicitationresult-output">
  ElicitationResult 輸出
</h4>

要覆蓋使用者的回應，請返回帶有 `hookSpecificOutput` 的 JSON 物件：

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "ElicitationResult",
    "action": "decline",
    "content": {}
  }
}
```

| 欄位        | 值                           | 描述                                  |
| :-------- | :-------------------------- | :---------------------------------- |
| `action`  | `accept`、`decline`、`cancel` | 覆蓋使用者的操作                            |
| `content` | 物件                          | 覆蓋表單欄位值。僅在 `action` 為 `accept` 時有意義 |

退出代碼 2 阻止回應，將有效操作變更為 `decline`。

<h2 id="prompt-based-hooks">
  基於提示的 hooks
</h2>

除了命令、HTTP 和 MCP tool hooks 外，Claude Code 還支援基於提示的 hooks（`type: "prompt"`），使用 LLM 評估是否允許或阻止操作，以及代理 hooks（`type: "agent"`），生成具有工具存取權限的代理驗證器。並非所有事件都支援每種 hook 類型。

支援所有五種 hook 類型（`command`、`http`、`mcp_tool`、`prompt` 和 `agent`）的事件：

* `PermissionDenied`
* `PermissionRequest`
* `PostToolBatch`
* `PostToolUse`
* `PostToolUseFailure`
* `PreToolUse`
* `Stop`
* `SubagentStop`
* `TaskCompleted`
* `TaskCreated`
* `TeammateIdle`
* `UserPromptExpansion`
* `UserPromptSubmit`

支援 `command`、`http` 和 `mcp_tool` hooks 但不支援 `prompt` 或 `agent` 的事件：

* `ConfigChange`
* `CwdChanged`
* `Elicitation`
* `ElicitationResult`
* `FileChanged`
* `InstructionsLoaded`
* `Notification`
* `PostCompact`
* `PreCompact`
* `SessionEnd`
* `StopFailure`
* `SubagentStart`
* `WorktreeCreate`
* `WorktreeRemove`

`SessionStart` 和 `Setup` 支援 `command` 和 `mcp_tool` hooks。它們不支援 `http`、`prompt` 或 `agent` hooks。

<h3 id="how-prompt-based-hooks-work">
  基於提示的 hooks 如何工作
</h3>

基於提示的 hooks 不執行 Bash 命令，而是：

1. 將 hook 輸入和您的提示發送到 Claude 模型，預設為 Haiku
2. LLM 以包含決定的結構化 JSON 回應
3. Claude Code 自動處理決定

<h3 id="prompt-hook-configuration">
  提示 hook 配置
</h3>

將 `type` 設定為 `"prompt"` 並提供 `prompt` 字串而不是 `command`。使用 `$ARGUMENTS` 佔位符將 hook 的 JSON 輸入資料注入到您的提示文字中。Claude Code 將組合的提示和輸入發送到快速 Claude 模型，該模型返回 JSON 決定。

此 `Stop` hook 詢問 LLM 在允許 Claude 完成之前是否應該停止：

```json theme={null}
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
          }
        ]
      }
    ]
  }
}
```

| 欄位                | 必需 | 描述                                                                                                                                           |
| :---------------- | :- | :------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`            | 是  | 必須為 `"prompt"`                                                                                                                               |
| `prompt`          | 是  | 要發送到 LLM 的提示文字。使用 `$ARGUMENTS` 作為 hook 輸入 JSON 的佔位符。如果 `$ARGUMENTS` 不存在，輸入 JSON 會附加到提示                                                       |
| `model`           | 否  | 用於評估的模型。預設為快速模型                                                                                                                              |
| `timeout`         | 否  | 逾時（秒）。預設值：30                                                                                                                                 |
| `continueOnBlock` | 否  | 當提示返回 `ok: false` 時，將原因反饋給 Claude 並繼續轉換而不是停止。預設值：`false`。在結果 `decision: "block"` 上實現為 `continue: true`。請參閱[回應架構](#response-schema)以了解每個事件的行為 |

<h3 id="response-schema">
  回應架構
</h3>

LLM 必須以包含以下內容的 JSON 回應：

```json theme={null}
{
  "ok": true | false,
  "reason": "Explanation for the decision"
}
```

| 欄位       | 描述                                                      |
| :------- | :------------------------------------------------------ |
| `ok`     | `true` 允許操作。`false` 產生 `decision: "block"`。請參閱下面的每個事件行為 |
| `reason` | 當 `ok` 為 `false` 時必需。用作阻止原因                             |

`ok: false` 時發生的情況取決於事件：

* `Stop` 和 `SubagentStop`：原因被反饋給 Claude 作為其下一個指令，轉換繼續
* `PreToolUse`：工具呼叫被拒絕，原因作為工具錯誤返回給 Claude，相當於命令 hook 的 `permissionDecision: "deny"`
* `PostToolUse`：預設情況下轉換結束，原因在聊天中顯示為警告行。設定 `continueOnBlock: true` 以將原因反饋給 Claude 並繼續轉換
* `PostToolBatch`、`UserPromptSubmit` 和 `UserPromptExpansion`：轉換結束，原因顯示為警告行。這些事件在 `decision: "block"` 上結束轉換，無論 `continue` 如何
* `PostToolUseFailure`、`TaskCreated` 和 `TaskCompleted`：原因作為工具錯誤返回給 Claude，類似於 `PreToolUse`
* `TeammateIdle`：預設情況下隊友停止，原因顯示為警告行。設定 `continueOnBlock: true` 以將原因反饋給隊友並保持其工作狀態
* `PermissionRequest`：`ok: false` 沒有效果。要從 hook 拒絕批准，請使用[命令 hook](#command-hook-fields)返回 `hookSpecificOutput.decision.behavior: "deny"`
* `PermissionDenied`：`ok: false` 沒有效果，因為拒絕已經發生。此事件讀取的唯一輸出是 `hookSpecificOutput.retry`，提示和代理 hooks 無法設定。它們在此事件上執行，但其輸出被丟棄。使用[命令 hook](#command-hook-fields)返回 `retry`

如果您需要對任何事件進行更精細的控制，請使用[命令 hook](#command-hook-fields)，其中包含[決定控制](#decision-control)中描述的每個事件欄位。

<h3 id="check-multiple-conditions-before-stopping">
  在停止前檢查多個條件
</h3>

此 `Stop` hook 使用詳細提示在允許 Claude 停止之前檢查三個條件。`SubagentStop` hooks 使用相同的格式來評估 [subagent](/zh-TW/sub-agents) 是否應該停止。如果 `"ok"` 為 `false`，Claude 繼續工作，提供的原因作為其下一個指令：

```json theme={null}
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "prompt",
            "prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"your explanation\"} to continue working.",
            "timeout": 30
          }
        ]
      }
    ]
  }
}
```

<h2 id="agent-based-hooks">
  基於代理的 hooks
</h2>

<Warning>
  代理 hooks 是實驗性的。行為和配置可能在未來版本中變更。對於生產工作流程，建議使用[命令 hooks](#command-hook-fields)。
</Warning>

基於代理的 hooks（`type: "agent"`）類似於基於提示的 hooks，但具有多輪工具存取。代理 hook 不是單一 LLM 呼叫，而是生成一個可以讀取檔案、搜尋程式碼和檢查程式碼庫以驗證條件的 subagent。代理 hooks 支援與基於提示的 hooks 相同的事件。

<h3 id="how-agent-hooks-work">
  代理 hooks 如何工作
</h3>

當代理 hook 觸發時：

1. Claude Code 生成一個 subagent，使用您的提示和 hook 的 JSON 輸入
2. Subagent 可以使用 Read、Grep 和 Glob 等工具進行調查
3. 在最多 50 輪後，subagent 返回結構化的 `{ "ok": true/false }` 決定
4. Claude Code 以與提示 hook 相同的方式處理決定

代理 hooks 在驗證需要檢查實際檔案或測試輸出時很有用，而不僅僅是評估 hook 輸入資料。

<h3 id="agent-hook-configuration">
  代理 hook 配置
</h3>

將 `type` 設定為 `"agent"` 並提供 `prompt` 字串。配置欄位與[提示 hooks](#prompt-hook-configuration) 相同，但逾時更長：

| 欄位        | 必需 | 描述                                               |
| :-------- | :- | :----------------------------------------------- |
| `type`    | 是  | 必須為 `"agent"`                                    |
| `prompt`  | 是  | 描述要驗證的內容的提示。使用 `$ARGUMENTS` 作為 hook 輸入 JSON 的佔位符 |
| `model`   | 否  | 要使用的模型。預設為快速模型                                   |
| `timeout` | 否  | 逾時（秒）。預設值：60                                     |

回應架構與提示 hooks 相同：`{ "ok": true }` 允許或 `{ "ok": false, "reason": "..." }` 阻止。

此 `Stop` hook 驗證所有單元測試通過，然後允許 Claude 完成：

```json theme={null}
{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "agent",
            "prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
            "timeout": 120
          }
        ]
      }
    ]
  }
}
```

<h2 id="run-hooks-in-the-background">
  在背景執行 hooks
</h2>

預設情況下，hooks 會阻止 Claude 的執行，直到它們完成。對於長時間執行的任務，如部署、測試套件或外部 API 呼叫，設定 `"async": true` 以在背景執行 hook，同時 Claude 繼續工作。非同步 hooks 無法阻止或控制 Claude 的行為：回應欄位，如 `decision`、`permissionDecision` 和 `continue` 沒有效果，因為它們會控制的操作已經完成。

<h3 id="configure-an-async-hook">
  配置非同步 hook
</h3>

將 `"async": true` 新增到命令 hook 的配置以在背景執行它而不阻止 Claude。此欄位僅在 `type: "command"` hooks 上可用。

此 hook 在每個 `Write` 工具呼叫後執行測試指令碼。Claude 立即繼續工作，同時 `run-tests.sh` 執行最多 120 秒。當指令碼完成時，其輸出在下一個對話輪次上傳遞：

```json theme={null}
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/run-tests.sh",
            "async": true,
            "timeout": 120
          }
        ]
      }
    ]
  }
}
```

`timeout` 欄位設定背景程序的最大時間（秒）。如果未指定，非同步 hooks 使用與同步 hooks 相同的 10 分鐘預設值。

<h3 id="how-async-hooks-execute">
  非同步 hooks 如何執行
</h3>

當非同步 hook 觸發時，Claude Code 啟動 hook 程序並立即繼續，而不等待它完成。Hook 在 stdin 上接收與同步 hook 相同的 JSON 輸入。

背景程序退出後，如果 hook 產生了帶有 `additionalContext` 欄位的 JSON 回應，該內容會在下一個對話輪次上作為上下文傳遞給 Claude。`systemMessage` 欄位會顯示給你，而不是 Claude。

Claude Code 驗證該 JSON 回應是否符合與同步 hooks 相同的[輸出結構](#json-output)，並捨棄任何值類型錯誤的欄位，例如不是字串的 `systemMessage`，而不是傳遞它。使用 `--debug` 執行以查看命名每個捨棄欄位的警告。在 v2.1.202 之前，來自非同步 hook 的格式不正確的 JSON 輸出可能會導致工作階段崩潰，每次恢復工作階段時都會重複發生崩潰。

非同步 hook 完成通知預設被抑制。要查看它們，請使用 `Ctrl+O` 啟用詳細模式或使用 `--verbose` 啟動 Claude Code。

<h3 id="run-tests-after-file-changes">
  檔案變更後執行測試
</h3>

此 hook 在 Claude 寫入檔案時在背景啟動測試套件，然後在測試完成時將結果報告回 Claude。將此指令碼儲存到專案中的 `.claude/hooks/run-tests-async.sh` 並使用 `chmod +x` 使其可執行：

```bash theme={null}
#!/bin/bash
# run-tests-async.sh

# 從 stdin 讀取 hook 輸入
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# 僅針對原始檔案執行測試
if [[ "$FILE_PATH" != *.ts && "$FILE_PATH" != *.js ]]; then
  exit 0
fi

# 執行測試並通過 additionalContext 報告結果給 Claude
RESULT=$(npm test 2>&1)
EXIT_CODE=$?

if [ $EXIT_CODE -eq 0 ]; then
  MSG="Tests passed after editing $FILE_PATH"
else
  MSG="Tests failed after editing $FILE_PATH: $RESULT"
fi
jq -nc --arg msg "$MSG" '{hookSpecificOutput: {hookEventName: "PostToolUse", additionalContext: $msg}}'
```

然後將此配置新增到專案根目錄中的 `.claude/settings.json`。`async: true` 標誌讓 Claude 在測試執行時繼續工作：

```json theme={null}
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/run-tests-async.sh",
            "args": [],
            "async": true,
            "timeout": 300
          }
        ]
      }
    ]
  }
}
```

<h3 id="limitations">
  限制
</h3>

非同步 hooks 與同步 hooks 相比有幾個限制：

* 僅 `type: "command"` hooks 支援 `async`。基於提示的 hooks 無法非同步執行。
* 非同步 hooks 無法阻止工具呼叫或返回決定。到 hook 完成時，觸發操作已經進行。
* Hook 輸出在下一個對話輪次上傳遞。如果工作階段閒置，回應會等待直到下一個使用者互動。例外：`asyncRewake` hook 在退出代碼 2 時喚醒 Claude，即使工作階段閒置。
* 每次執行都會建立一個單獨的背景程序。同一非同步 hook 的多次觸發之間沒有去重。

<h2 id="security-considerations">
  安全考慮
</h2>

<h3 id="disclaimer">
  免責聲明
</h3>

命令 hooks 以您的系統使用者的完整權限執行。

<Warning>
  命令 hooks 以您的完整使用者權限執行 shell 命令。它們可以修改、刪除或存取您的使用者帳戶可以存取的任何檔案。在將任何 hook 命令新增到您的配置之前，請審查並測試它們。
</Warning>

<h3 id="security-best-practices">
  安全最佳實踐
</h3>

編寫 hooks 時，請記住這些實踐：

* **驗證和清理輸入**：永遠不要盲目信任輸入資料
* **始終引用 shell 變數**：使用 `"$VAR"` 而不是 `$VAR`
* **阻止路徑遍歷**：檢查檔案路徑中的 `..`
* **使用絕對路徑**：為指令碼指定完整路徑。在 exec 形式中，使用 `${CLAUDE_PROJECT_DIR}` 且路徑不需要引用。在 shell 形式中，將其包裝在雙引號中
* **跳過敏感檔案**：避免 `.env`、`.git/`、金鑰等

<h2 id="windows-powershell-tool">
  Windows PowerShell 工具
</h2>

在 Windows 上，您可以通過在命令 hook 上設定 `"shell": "powershell"` 在 PowerShell 中執行個別 hooks。Hooks 直接生成 PowerShell，因此無論是否設定 `CLAUDE_CODE_USE_POWERSHELL_TOOL` 都有效。Claude Code 自動偵測 `pwsh.exe`（PowerShell 7 及更新版本的可執行檔），並回退到 `powershell.exe`（Windows PowerShell 5.1）。

```json theme={null}
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "shell": "powershell",
            "command": "Write-Host 'File written'"
          }
        ]
      }
    ]
  }
}
```

若要從 PowerShell shell 形式命令參考專案根目錄，請寫入 `${CLAUDE_PROJECT_DIR}` 或 `$env:CLAUDE_PROJECT_DIR`。自 v2.1.198 起，Claude Code 會在 PowerShell shell 形式命令中將 `${CLAUDE_PROJECT_DIR}`、`${CLAUDE_PLUGIN_ROOT}` 和 `${CLAUDE_PLUGIN_DATA}` 佔位符重寫為 PowerShell 的 `${env:NAME}` 形式，無論 hook 是在 `settings.json`、plugin 或 skill 中定義。PowerShell 會在解析後從匯出的環境中解析該值，因此佔位符在雙引號字串內有效，但在單引號字串內無效，因為 PowerShell 永遠不會在單引號字串中展開變數。

在 v2.1.198 之前，此重寫僅適用於 plugin hooks。在較早的版本上，`settings.json` hook 需要 `$env:` 形式或 [exec 形式](#exec-form-and-shell-form)，其中 `${CLAUDE_PROJECT_DIR}` 會在每個 `args` 元素中被替換，無論 hook 在何處定義。

不要在 PowerShell hook 中寫入裸露的 `$CLAUDE_PROJECT_DIR` 拼寫。PowerShell 會將其解析為未定義的本機變數，並將其解析為 `$null`，這會導致指令碼路徑沒有其專案根目錄前綴。Claude Code 不會重寫該形式；它會在 [debug log](#debug-hooks) 中記錄警告。

下面的範例顯示了一個 `settings.json` hook，它使用 `$env:` 形式執行專案指令碼，該形式在每個版本上都有效：

```json theme={null}
{
  "type": "command",
  "shell": "powershell",
  "command": "& \"$env:CLAUDE_PROJECT_DIR\\.claude\\hooks\\check.ps1\""
}
```

<h2 id="debug-hooks">
  偵錯 hooks
</h2>

Hook 執行詳細資訊，包括哪些 hooks 匹配、它們的退出代碼和完整 stdout 和 stderr，被寫入詳細日誌檔案。使用 `claude --debug-file <path>` 啟動 Claude Code 以將日誌寫入已知位置，或執行 `claude --debug` 並在 `~/.claude/debug/<session-id>.txt` 讀取日誌。`--debug` 標誌不列印到終端。

```text theme={null}
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 600000ms
[DEBUG] Hook command completed with status 0: <Your stdout>
```

有關更細粒度的 hook 匹配詳細資訊，設定 `CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose` 以查看額外的日誌行，例如 hook 匹配器計數和查詢匹配。

有關故障排除常見問題，如 hooks 不觸發、Stop hooks 持續阻擋或配置錯誤，請參閱指南中的 [限制和故障排除](/zh-TW/hooks-guide#limitations-and-troubleshooting)。有關涵蓋 `/context`、`/doctor` 和設定優先順序的更廣泛診斷逐步解說，請參閱 [偵錯您的配置](/zh-TW/debug-your-config)。
