# 第六阶段 · 模块六 · 第一节:Hooks 概述与类型
什么是 Hooks?Claude Code 支持哪些 Hook 事件?每个事件的触发时机和作用是什么?
Claude Code 全局架构
┌─────────────────────────────────────────────────────────────────────┐
│ Hooks 系统 ← 本节 │
│ │
│ HookEvent ──> 事件类型定义 │
│ HookHandler ──> 事件处理器 │
│ hookEvents.ts ──> 事件常量 │
└─────────────────────────────────────────────────────────────────────┘
Hooks = 生命周期钩子
在 Claude Code 运行过程中的特定时机插入自定义逻辑
┌─────────────────────────────────────────────────────────────────────┐
│ 用户输入 ──> UserPromptSubmit Hook ──> AI 处理 │
│ │
│ AI 决定 ──> ToolCall ──> PreToolUse Hook ──> 工具执行 │
│ │
│ 工具执行 ──> PostToolUse Hook ──> 返回结果 │
└─────────────────────────────────────────────────────────────────────┘
// Hooks 可以:
// 1. 在事件前后执行自定义逻辑
// 2. 修改输入/输出
// 3. 阻止或允许操作
// 4. 记录日志或指标
// 5. 触发副作用
问 1:Hooks 和插件的区别?
// Hooks:事件驱动的拦截点
// 插件:功能模块的扩展
// Hook 适合:
// - 修改行为(拦截工具调用)
// - 添加验证(日志、审计)
// - 注入逻辑(修改输入输出)
// 插件适合:
// - 添加新功能
// - 打包多个 Hooks
// - 分发独立模块
源码位置:`src/entrypoints/sdk/coreTypes.ts` 第 25 行
export const HOOK_EVENTS = [
// 工具相关
'PreToolUse', // 工具执行前
'PostToolUse', // 工具执行后
'PostToolUseFailure', // 工具执行失败
// 消息相关
'UserPromptSubmit', // 用户提交消息
'Notification', // 通知
// 会话相关
'SessionStart', // 会话开始
'SessionEnd', // 会话结束
// 控制流
'Stop', // 停止生成
'StopFailure', // 停止失败
// 子代理
'SubagentStart', // 子代理启动
'SubagentStop', // 子代理停止
// 压缩相关
'PreCompact', // 压缩前
'PostCompact', // 压缩后
// 权限相关
'PermissionRequest', // 权限请求
'PermissionDenied', // 权限被拒绝
// 任务相关
'TaskCreated', // 任务创建
'TaskCompleted', // 任务完成
// 其他
'Elicitation', // 提示用户选择
'ElicitationResult', // 选择结果
'Setup', // 初始化设置
'ConfigChange', // 配置变更
'CwdChanged', // 工作目录变更
'WorktreeCreate', // Git worktree 创建
'WorktreeRemove', // Git worktree 删除
'InstructionsLoaded', // 指令加载
'TeammateIdle', // 队友空闲
]
// 触发时机:工具执行前
// 源码位置:src/types/hooks.ts 第 73 行
type PreToolUseHook = {
hookEventName: 'PreToolUse'
toolName: string // 工具名
toolInput: object // 工具输入
sessionId: string // 会话 ID
invocationId: string // 调用 ID
}
// 可返回
{
continue?: boolean // 是否继续执行
updatedInput?: object // 修改后的输入
additionalContext?: string // 额外上下文
permissionDecision?: {
behavior: 'allow' | 'deny' | 'pause'
reason?: string
}
}
// 触发时机:工具执行后(成功)
// 源码位置:src/types/hooks.ts 第 101 行
type PostToolUseHook = {
hookEventName: 'PostToolUse'
toolName: string
toolInput: object
toolOutput: unknown // 工具返回结果
wasRateLimited?: boolean // 是否被限流
invocationId: string
}
// 可返回
{
continue?: boolean
updatedMCPToolOutput?: unknown // 修改 MCP 工具输出
additionalContext?: string
}
// 触发时机:工具执行失败
// 源码位置:src/types/hooks.ts 第 109 行
type PostToolUseFailureHook = {
hookEventName: 'PostToolUseFailure'
toolName: string
toolInput: object
error: string // 错误消息
errorCode?: string // 错误码
invocationId: string
}
问 1:PreToolUse 和 PostToolUse 的区别?
// PreToolUse:在工具执行前
// - 可以修改输入参数
// - 可以阻止执行
// - 可以决定权限(allow/deny/pause)
// PostToolUse:在工具执行后
// - 可以读取输出
// - 可以修改输出(仅 MCP 工具)
// - 不能阻止执行(已执行完)
// 触发时机:用户提交消息后,发送给 AI 前
// 源码位置:src/types/hooks.ts 第 80 行
type UserPromptSubmitHook = {
hookEventName: 'UserPromptSubmit'
userPrompt: string // 用户输入
promptElicitation?: { // 提示选择
id: string
message: string
options: Array<{
key: string
label: string
description?: string
}>
}
}
// 可返回
{
continue?: boolean
userPrompt?: string // 修改后的 prompt
additionalContext?: string
}
// SessionStart:会话开始时
// SessionEnd:会话结束时
type SessionHook = {
hookEventName: 'SessionStart' | 'SessionEnd'
sessionId: string
initialUserMessage?: string // 初始消息(仅 SessionStart)
additionalContext?: string
}
问 1:SessionStart 可以做什么?
// 初始化操作
export const sessionStart: HookHandler = async (input) => {
// 加载会话特定配置
await loadSessionConfig(input.sessionId)
// 初始化资源
await initializeResources()
// 添加会话上下文
return {
continue: true,
additionalContext: 'Session initialized at ' + new Date().toISOString()
}
}
// 触发时机:工具需要权限时
// 源码位置:src/types/hooks.ts 第 121 行
type PermissionRequestHook = {
hookEventName: 'PermissionRequest'
toolName: string
toolInput: object
permission: {
type: string // 权限类型
reason: string // 为什么需要
}
prompt?: string // 提示用户的信息
invocationId: string
}
// 可返回
{
decision: {
behavior: 'allow' | 'deny' | 'pause'
updatedInput?: object // 修改输入
updatedPermissions?: PermissionUpdate[]
message?: string
interrupt?: boolean // 是否中断
}
}
// 触发时机:权限被拒绝时
type PermissionDeniedHook = {
hookEventName: 'PermissionDenied'
toolName: string
toolInput: object
permission: {
type: string
reason: string
}
retry?: boolean // 是否可以重试
}
问 1:allow、deny、pause 的区别?
// allow:自动批准,继续执行
// deny:拒绝执行,记录拒绝
// pause:暂停,等待用户确认
// interrupt: true:在 pause 时也中断流程
// PreCompact:上下文压缩前
// PostCompact:上下文压缩后
type CompactHook = {
hookEventName: 'PreCompact' | 'PostCompact'
messages: Message[] // 当前消息列表
reason: string // 压缩原因
additionalContext?: string
}
答案:
// 需要修改输入 → PreToolUse
// 需要读取输出 → PostToolUse
// 需要验证权限 → PermissionRequest
// 需要记录日志 → PostToolUse
// 需要修改 prompt → UserPromptSubmit
答案:
// 按配置顺序执行
// 如果某个 Hook 返回 continue: false,后续 Hook 不执行
// 配置
hooks:
PreToolUse:
- hook1.ts // 先执行
- hook2.ts // 后执行
// hook1 返回 continue: false
// → hook2 不执行
答案:
// 取决于错误类型
// - 同步错误:可能中断
// - 返回 { continue: true } 即使出错:继续
// 最佳实践
export const myHook: HookHandler = async (input) => {
try {
return await process(input)
} catch (error) {
logError(error)
return { continue: true } // 不阻塞流程
}
}
| 文件 | 核心内容 |
| `src/entrypoints/sdk/coreTypes.ts` | HOOK_EVENTS 定义 |
| `src/types/hooks.ts` | Hook 类型定义 |
| `src/utils/hooks/hookEvents.ts` | 事件发射逻辑 |
下一节我们将深入 内置 Hooks 详解:
- PreToolUse 完整参数
- PostToolUse 完整参数
- PermissionRequest 完整参数
*- 第一轮:□ 事实准确性*
*- 第二轮:□ 深度与洞见*
*- 第三轮:□ 可读性与价值*