> ## Documentation Index
> Fetch the complete documentation index at: https://ccb.agent-aura.top/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks 生命周期钩子 - 执行引擎与拦截协议

> 从源码角度解析 Claude Code Hooks 系统：27 种 Hook 事件、6 种 Hook 类型、同步/异步执行协议、JSON 输出 schema、if 条件匹配、以及 Hook 如何注入上下文和拦截工具调用。

## 27 种 Hook 事件

Claude Code 定义了 27 种 Hook 事件（`HOOK_EVENTS` 数组，`src/entrypoints/sdk/coreTypes.ts`），覆盖完整的 Agent 生命周期：

| 阶段          | 事件                                  | 触发时机             | 匹配字段                |
| ----------- | ----------------------------------- | ---------------- | ------------------- |
| **会话**      | `SessionStart`                      | 会话启动             | `source`            |
|             | `SessionEnd`                        | 会话结束             | `reason`            |
|             | `Setup`                             | 初始化完成            | `trigger`           |
| **用户交互**    | `UserPromptSubmit`                  | 用户提交消息           | —                   |
|             | `Stop`                              | Agent 停止响应       | —                   |
|             | `StopFailure`                       | Agent 停止失败       | `error`             |
| **工具执行**    | `PreToolUse`                        | 工具调用前            | `tool_name`         |
|             | `PostToolUse`                       | 工具调用后（成功）        | `tool_name`         |
|             | `PostToolUseFailure`                | 工具调用后（失败）        | `tool_name`         |
| **权限**      | `PermissionRequest`                 | 权限请求             | `tool_name`         |
|             | `PermissionDenied`                  | 权限被拒             | `tool_name`         |
| **子 Agent** | `SubagentStart`                     | 子 Agent 启动       | `agent_type`        |
|             | `SubagentStop`                      | 子 Agent 停止       | `agent_type`        |
| **压缩**      | `PreCompact`                        | 上下文压缩前           | `trigger`           |
|             | `PostCompact`                       | 上下文压缩后           | `trigger`           |
| **协作**      | `TeammateIdle`                      | Teammate 空闲      | —                   |
|             | `TaskCreated`                       | 任务创建             | —                   |
|             | `TaskCompleted`                     | 任务完成             | —                   |
| **MCP**     | `Elicitation`                       | MCP 服务器请求用户输入    | `mcp_server_name`   |
|             | `ElicitationResult`                 | Elicitation 结果返回 | `mcp_server_name`   |
| **通知**      | `Notification`                      | 系统通知事件           | `notification_type` |
| **环境**      | `ConfigChange`                      | 配置变更             | `source`            |
|             | `CwdChanged`                        | 工作目录变更           | —                   |
|             | `FileChanged`                       | 文件变更             | `file_path`         |
|             | `InstructionsLoaded`                | 指令加载             | `load_reason`       |
|             | `WorktreeCreate` / `WorktreeRemove` | Worktree 操作      | —                   |

## 6 种 Hook 类型

Hooks 配置支持 6 种执行方式，类型定义分布在 3 个文件中：

* **可持久化类型**（`command`、`prompt`、`agent`、`http`）— Zod schema 定义在 `src/schemas/hooks.ts`，通过 `z.discriminatedUnion('type', [...])` 声明
* **callback 类型** — TypeScript 接口定义在 `src/types/hooks.ts`，用于 SDK 注册的内部 JS 函数
* **function 类型** — 定义在 `src/utils/hooks/sessionHooks.ts`，用于运行时动态注册的函数 Hook

| 类型         | 执行方式                      | 适用场景             |
| ---------- | ------------------------- | ---------------- |
| `command`  | Shell 命令（bash/PowerShell） | 通用脚本、CI 检查       |
| `prompt`   | 注入到 AI 上下文                | 代码规范提醒           |
| `agent`    | 启动子 Agent 执行              | 复杂分析任务           |
| `http`     | HTTP 请求                   | 远程服务、Webhook     |
| `callback` | 内部 JS 函数                  | 系统内置 Hook        |
| `function` | 运行时注册的函数 Hook             | Agent/Skill 内部使用 |

## 执行引擎：execCommandHook

`execCommandHook()`（`src/utils/hooks.ts`，`execCommandHook` 函数）是命令型 Hook 的执行核心：

```
execCommandHook(hook, hookEvent, hookName, jsonInput, signal)
  ├── Shell 选择: hook.shell ?? DEFAULT_HOOK_SHELL
  │   ├── bash: spawn(cmd, [], { shell: gitBashPath | true })
  │   └── powershell: spawn(pwsh, ['-NoProfile', '-NonInteractive', '-Command', cmd])
  ├── 变量替换
  │   ├── ${CLAUDE_PLUGIN_ROOT} → pluginRoot 路径
  │   ├── ${CLAUDE_PLUGIN_DATA} → plugin 数据目录
  │   └── ${user_config.X} → 用户配置值
  ├── 环境变量注入
  │   ├── CLAUDE_PROJECT_DIR
  │   ├── CLAUDE_ENV_FILE（SessionStart/Setup/CwdChanged/FileChanged）
  │   └── CLAUDE_PLUGIN_OPTION_*（plugin options）
  ├── stdin 写入: jsonInput + '\n'
  ├── 超时: hook.timeout * 1000 ?? 600000ms（10分钟）
  └── 异步检测: 检查 stdout 首行是否为 {"async":true}
```

### 异步 Hook 的检测协议

Hook 进程的 stdout 第一行如果是 `{"async":true}`，系统将其转为后台任务（`isAsyncHookJSONOutput` 检测 + `executeInBackground` 调用）：

```typescript theme={null}
const firstLine = firstLineOf(stdout).trim()
if (isAsyncHookJSONOutput(parsed)) {
  executeInBackground({
    processId: `async_hook_${child.pid}`,
    asyncResponse: parsed,
    ...
  })
}
```

后台 Hook 通过 `registerPendingAsyncHook()` 注册到 `AsyncHookRegistry`，完成后通过 `enqueuePendingNotification()` 通知主线程。

### asyncRewake：Hook 唤醒模型

`asyncRewake` 模式的 Hook 绕过 `AsyncHookRegistry`。当 Hook 退出码为 2 时，通过 `enqueuePendingNotification()` 以 `task-notification` 模式注入消息，唤醒空闲的模型（通过 `useQueueProcessor`）或在忙碌时注入 `queued_command` 附件。

## Hook 输出的 JSON Schema

同步 Hook 的输出遵循严格的 Zod schema（`syncHookResponseSchema`，定义在 `src/types/hooks.ts`，`hookJSONOutputSchema` 定义在 `src/schemas/hooks.ts`）：

```json theme={null}
{
  "continue": false,                    // 是否继续执行
  "suppressOutput": true,               // 隐藏 stdout
  "stopReason": "安全检查失败",           // continue=false 时的原因
  "decision": "approve" | "block",      // 全局决策
  "reason": "原因说明",                   // 决策原因
  "systemMessage": "警告内容",           // 注入到上下文的系统消息
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow" | "deny" | "ask",
    "permissionDecisionReason": "匹配了安全规则",
    "updatedInput": { ... },            // 修改后的工具输入
    "additionalContext": "额外上下文"     // 注入到对话
  }
}
```

### 各事件的 hookSpecificOutput

| 事件                   | 专有字段                                                                                  | 作用               |
| -------------------- | ------------------------------------------------------------------------------------- | ---------------- |
| `PreToolUse`         | `permissionDecision`, `permissionDecisionReason`, `updatedInput`, `additionalContext` | 拦截/修改工具输入        |
| `PostToolUse`        | `additionalContext`, `updatedMCPToolOutput`                                           | 修改 MCP 工具输出      |
| `PostToolUseFailure` | `additionalContext`                                                                   | 失败后注入上下文         |
| `UserPromptSubmit`   | `additionalContext`                                                                   | 注入额外上下文          |
| `SessionStart`       | `additionalContext`, `initialUserMessage`, `watchPaths`                               | 设置初始消息和文件监控      |
| `PermissionRequest`  | `decision`（含 `allow`/`deny` 子字段）                                                      | 权限请求的 Hook 决策    |
| `PermissionDenied`   | `retry`                                                                               | 指示是否重试           |
| `SubagentStart`      | `additionalContext`                                                                   | 子 Agent 启动时注入上下文 |
| `Elicitation`        | `action`, `content`                                                                   | 控制用户输入对话框        |
| `ElicitationResult`  | `action`, `content`                                                                   | Elicitation 结果处理 |
| `Notification`       | `additionalContext`                                                                   | 通知事件注入上下文        |
| `Setup`              | `additionalContext`                                                                   | 初始化时注入上下文        |
| `CwdChanged`         | `watchPaths`                                                                          | 目录变更后更新监控路径      |
| `FileChanged`        | `watchPaths`                                                                          | 文件变更后更新监控路径      |
| `WorktreeCreate`     | `worktreePath`                                                                        | Worktree 创建通知    |

## Hook 匹配机制：getMatchingHooks

`getMatchingHooks()`（`src/utils/hooks.ts`，`getMatchingHooks` 函数）负责从所有来源中查找匹配的 Hook：

### 多来源合并

```
getHooksConfig()
  ├── getHooksConfigFromSnapshot()    ← settings.json 中的 Hook（user/project/local）
  ├── getRegisteredHooks()            ← SDK 注册的 callback Hook
  ├── getSessionHooks()               ← Agent/Skill 前置注册的 session Hook
  └── getSessionFunctionHooks()       ← 运行时 function Hook
```

### 匹配规则

`matcher` 字段支持三种模式（`matchesPattern()` 函数，`src/utils/hooks.ts`）：

```
"Write"              → 精确匹配
"Write|Edit"         → 管道分隔的多值匹配
"^Bash(git.*)"       → 正则匹配
"*" 或 ""            → 通配（匹配所有）
```

### if 条件过滤

Hook 可以指定 `if` 条件，只在特定输入时触发。`prepareIfConditionMatcher()`（`src/utils/hooks.ts`，`prepareIfConditionMatcher` 函数）预编译匹配器：

```json theme={null}
{
  "hooks": [{
    "command": "check-git-branch.sh",
    "if": "Bash(git push*)"
  }]
}
```

`if` 条件使用 `permissionRuleValueFromString` 解析，支持与权限规则相同的语法（工具名 + 参数模式）。Bash 工具还会使用 tree-sitter 进行 AST 级别的命令解析。

### Hook 去重

同一个 Hook 命令在不同配置层级（user/project/local）可能重复。系统按四部分复合键做 Map 去重：`${pluginRoot}\0${shell}\0${command}\0${ifCondition}`（由 `hookDedupKey()` 函数构建），保留**最后合并的层级**。

## 工作区信任检查

**所有 Hook 都要求工作区信任**（`shouldSkipHookDueToTrust()` 函数，`src/utils/hooks.ts`）。这是纵深防御措施——防止恶意仓库的 `.claude/settings.json` 在未信任的情况下执行任意命令。

```typescript theme={null}
// 交互模式下，所有 Hook 要求信任
const hasTrust = checkHasTrustDialogAccepted()
return !hasTrust
```

SDK 非交互模式下信任是隐式的（`getIsNonInteractiveSession()` 为 true 时跳过检查）。

## 四种 Hook 能力的源码映射

### 1. 拦截操作（PreToolUse）

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny"
  }
}
```

`processHookJSONOutput()` 将 `permissionDecision` 映射为 `result.permissionBehavior = 'deny'`，并设置 `blockingError`，阻止工具执行。

### 2. 修改行为（updatedInput / updatedMCPToolOutput）

```json theme={null}
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "updatedInput": { "command": "npm test -- --bail" }
  }
}
```

`updatedInput` 替换原始工具输入；`updatedMCPToolOutput`（PostToolUse 事件）替换 MCP 工具的返回值——可用于过滤敏感数据。

### 3. 注入上下文（additionalContext / systemMessage）

* `additionalContext` → 通过 `createAttachmentMessage({ type: 'hook_additional_context' })` 注入为用户消息
* `systemMessage` → 注入为系统警告，直接显示给用户

### 4. 控制流程（continue / stopReason）

```json theme={null}
{ "continue": false, "stopReason": "构建失败，停止执行" }
```

`continue: false` 设置 `preventContinuation = true`，阻止 Agent 继续执行后续操作。

## Session Hook 的生命周期

Agent 和 Skill 的前置 Hook 通过 `registerFrontmatterHooks()` 注册（调用位置：`packages/builtin-tools/src/tools/AgentTool/runAgent.ts`；定义位置：`src/utils/hooks/registerFrontmatterHooks.ts`），绑定到 agent 的 session ID。Agent 结束时通过 `clearSessionHooks()`（定义位置：`src/utils/hooks/sessionHooks.ts`）清理。

```typescript theme={null}
// runAgent.ts — 注册 agent 的前置 Hook
registerFrontmatterHooks(rootSetAppState, agentId, agentDefinition.hooks, ...)

// runAgent.ts — finally 块清理
clearSessionHooks(rootSetAppState, agentId)
```

这确保 Agent A 的 Hook 不会泄漏到 Agent B 的执行中。
