Hooks 是用户自定义的 shell 命令、HTTP 端点、LLM 提示词或 Agent 验证器,在特定生命周期事件触发时执行。它们让你无需修改核心代码,即可实现自动化、审计、流程拦截和功能扩展。
概述
核心源文件:
src/utils/hooks.ts--- Hook 执行引擎src/types/hooks.ts--- Hook 结果类型和响应 Schemasrc/schemas/hooks.ts--- Hook 命令与匹配器的 Zod Schemasrc/entrypoints/sdk/coreSchemas.ts--- 全部 30 个 Hook 事件输入 Schema
Hook 配置
Hooks 在 settings.json 的 hooks 键下配置:
json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo 'Bash 即将运行' >> ~/.claude/audit.log"
}
]
}
],
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$TOOL_INPUT_PATH\""
}
]
}
]
}
}
配置文件位置与作用域:
~/.claude/settings.json--- 全局(适用于所有项目).claude/settings.json--- 项目级(团队共享).claude/settings.local.json--- 本地个人级(已加入 .gitignore)
Hooks 也可以在 Skill 或 Agent 的 frontmatter 中配置。
所有 Hook 事件
会话生命周期
| 事件 | 触发时机 | 关键输入字段 |
|---|---|---|
Setup |
CLI 首次安装或维护运行 | `trigger: "init" |
SessionStart |
会话开始(启动、恢复、清空、压缩后) | source, model, agent_type |
SessionEnd |
会话结束 | exit_reason |
Stop |
模型完成响应 | stop_hook_active, last_assistant_message |
StopFailure |
模型响应以错误结束 | error, error_details, last_assistant_message |
Stop Hook 特殊能力: 返回 { "continue": true } 可重新激活模型------它会将 Hook 的输出作为新消息来处理。这让 Hook 可以驱动自主循环。
工具生命周期
| 事件 | 触发时机 | 关键输入字段 |
|---|---|---|
PreToolUse |
任意工具执行前 | tool_name, tool_input, tool_use_id |
PostToolUse |
工具执行成功后 | tool_name, tool_input, tool_response, tool_use_id |
PostToolUseFailure |
工具执行失败后 | tool_name, tool_input, error, is_interrupt |
PreToolUse Hook 特殊能力:
decision: "block"→ 阻止工具运行updatedInput: {...}→ 在执行前静默改写工具输入additionalContext: "..."→ 向模型注入额外上下文
权限系统
| 事件 | 触发时机 | 关键输入字段 |
|---|---|---|
PermissionRequest |
工具需要用户授权 | tool_name, tool_input, permission_suggestions |
PermissionDenied |
工具被拒绝执行 | tool_name, tool_input, reason |
PermissionRequest Hook 特殊能力: 可在不询问用户的情况下自动批准或拒绝:
json
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": { "behavior": "allow" }
}
}
用户交互
| 事件 | 触发时机 | 关键输入字段 |
|---|---|---|
UserPromptSubmit |
用户发送消息 | prompt |
Notification |
Claude 发送桌面通知 | message, title, notification_type |
Elicitation |
MCP 服务器请求用户输入 | mcp_server_name, message, mode, requested_schema |
ElicitationResult |
用户响应 MCP 请求 | mcp_server_name, action, content |
UserPromptSubmit Hook 能力: 可向模型注入 additionalContext,或提供 initialUserMessage 覆盖。
压缩(Compaction)
| 事件 | 触发时机 | 关键输入字段 |
|---|---|---|
PreCompact |
上下文压缩前 | `trigger: "manual" |
PostCompact |
压缩完成后 | trigger, compact_summary |
文件系统与配置
| 事件 | 触发时机 | 关键输入字段 |
|---|---|---|
CwdChanged |
工作目录变更 | old_cwd, new_cwd |
FileChanged |
监听的文件在磁盘上发生变化 | file_path, `event: "change" |
InstructionsLoaded |
CLAUDE.md 文件被加载 | file_path, memory_type, load_reason |
ConfigChange |
settings.json 发生变更 | source, file_path |
FileChanged 配置方法: 在 SessionStart 或 CwdChanged Hook 的输出中注册监听路径:
json
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"watchPaths": ["/path/to/watch", "/another/path"]
}
}
多 Agent 与 Worktree
| 事件 | 触发时机 | 关键输入字段 |
|---|---|---|
SubagentStart |
Agent 子进程启动 | agent_id, agent_type |
SubagentStop |
Agent 子进程结束 | agent_id, agent_type, agent_transcript_path, last_assistant_message |
TeammateIdle |
协作 Agent 进入空闲 | teammate_name, team_name |
TaskCreated |
后台任务被创建 | task_id, task_subject, teammate_name |
TaskCompleted |
后台任务完成 | task_id, task_subject |
WorktreeCreate |
Git worktree 被创建 | name |
WorktreeRemove |
Git worktree 被移除 | worktree_path |
Hook 类型
1. 命令 Hook(type: "command")
运行一个 shell 命令。Hook 输入 JSON 以环境变量和 $STDIN 的形式提供。
json
{
"type": "command",
"command": "python3 ~/.claude/hooks/audit.py",
"shell": "bash",
"timeout": 30,
"statusMessage": "审计中...",
"async": false,
"asyncRewake": false,
"once": false,
"if": "Bash(git *)"
}
关键字段说明:
shell---"bash"(默认)或"powershell"timeout--- Hook 被强制终止前等待的秒数statusMessage--- 运行时 UI 加载动画显示的文字async: true--- 在后台运行,不阻塞模型asyncRewake: true--- 异步运行 + 退出码为 2 时唤醒模型once: true--- 运行一次后自动从 Hook 列表删除if--- 权限规则过滤器(见下文)
命令 Hook 中可用的环境变量:
| 变量名 | 内容 |
|---|---|
CLAUDE_TOOL_NAME |
被调用的工具名(PreToolUse) |
CLAUDE_TOOL_USE_ID |
唯一工具调用 ID |
CLAUDE_SESSION_ID |
当前会话 ID |
CLAUDE_CWD |
当前工作目录 |
CLAUDE_TRANSCRIPT_PATH |
会话记录文件路径 |
TOOL_INPUT_* |
工具输入字段(大写,嵌套字段用 _ 分隔) |
所有工具输入也以 JSON 格式通过 stdin 传入。
退出码含义:
| 退出码 | 含义 |
|---|---|
0 |
成功------正常继续 |
1 |
非阻塞错误------记录日志但继续 |
2 |
阻塞错误------停止 Claude,向用户显示错误 |
2. 提示词 Hook(type: "prompt")
使用轻量 Claude 模型评估一段自然语言提示。提示词通过 $ARGUMENTS 接收 Hook 输入 JSON。
json
{
"type": "prompt",
"prompt": "检查这个 bash 命令是否安全:$ARGUMENTS。以 JSON 格式回复:{\"decision\": \"allow\" 或 \"block\", \"reason\": \"...\"}",
"model": "claude-haiku-4-5-20251001",
"timeout": 60,
"statusMessage": "检查安全性...",
"if": "Bash"
}
提示词 Hook 的输出被解析为 JSON,并作为同步 Hook 响应处理。适用于正则表达式无法处理的语义/上下文感知决策。
3. Agent Hook(type: "agent")
运行完整的 Claude Agent 来验证或处理 Hook 上下文。比提示词 Hook 更重量级,但支持多步推理和工具调用。
json
{
"type": "agent",
"prompt": "验证变更文件的单元测试是否已运行并通过:$ARGUMENTS",
"model": "claude-sonnet-4-6",
"timeout": 120,
"statusMessage": "验证测试中..."
}
默认模型为 Haiku,以控制成本。
4. HTTP Hook(type: "http")
将 Hook 输入 JSON 以 POST 请求发送到外部端点。
json
{
"type": "http",
"url": "https://my-audit-service.internal/claude-hooks",
"headers": {
"Authorization": "Bearer $MY_API_TOKEN"
},
"allowedEnvVars": ["MY_API_TOKEN"],
"timeout": 10,
"statusMessage": "通知审计服务..."
}
安全说明: allowedEnvVars 控制哪些环境变量可以在 headers 中被插值。未列出的变量将被替换为空字符串。
Hook 匹配器
每个事件的 Hook 列表包含匹配器(matchers)------用于决定何时触发的过滤器:
json
{
"PreToolUse": [
{
"matcher": "Bash", ← 只在 Bash 工具调用时触发
"hooks": [...]
},
{
"matcher": "Write(src/)", ← 只在写入 src/ 目录时触发
"hooks": [...]
},
{
"matcher": "", ← 所有工具都触发
"hooks": [...]
}
]
}
匹配器语法与权限规则语法一致:
"Bash"--- 精确匹配工具名"Bash(git *)"--- 工具名 + 命令前缀通配符"Write(src/)"--- 工具名 + 路径前缀""或省略 --- 匹配所有
if 字段(单个 Hook 过滤器)
匹配器内的单个 Hook 可以添加 if 条件进行更精细的控制:
json
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "log-dangerous.sh",
"if": "Bash(rm *)" ← 只在 rm 命令时运行
}
]
}
Hook 响应协议
Hooks 通过 stdout JSON 与 Claude Code 通信。
同步响应
json
{
"continue": true,
"suppressOutput": false,
"stopReason": "",
"decision": "approve",
"reason": "操作安全",
"systemMessage": "警告:检测到破坏性操作",
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": { "command": "safe-version-of-command" },
"additionalContext": "注入模型的额外上下文"
}
}
异步响应
用于不需要阻塞的长时间运行 Hook:
json
{
"async": true,
"asyncTimeout": 300
}
Hook 进程继续运行。若以退出码 2 退出,模型会被唤醒并收到错误信息。
各事件专属 hookSpecificOutput
每个 Hook 事件都有自己的输出 Schema。关键示例:
PreToolUse --- 改写输入、注入上下文或强制批准:
json
{
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": { "command": "更安全的命令" },
"additionalContext": "已根据安全策略修改"
}
SessionStart --- 注册文件监听路径:
json
{
"hookEventName": "SessionStart",
"additionalContext": "项目上下文已加载",
"watchPaths": ["/project/src", "/project/tests"],
"initialUserMessage": "开始运行:npm test"
}
PermissionRequest --- 自动批准或拒绝:
json
{
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow",
"updatedInput": { "command": "已审计的命令" }
}
}
PermissionDenied --- 重试其他方案:
json
{
"hookEventName": "PermissionDenied",
"retry": true
}
Hook 执行顺序
对于有多个匹配器的特定事件:
- 收集所有匹配的匹配器下的 Hooks
- 每个匹配器内的 Hooks 顺序执行
- 多个匹配器的 Hooks 可能并行运行(实现细节)
- 第一个阻塞结果(
exit 2或continue: false)停止后续执行 - 所有 Hooks 的
additionalContext被拼接后注入
回调 Hooks(内部机制)
除了基于文件的 Hooks,Claude Code 内部还使用回调 Hooks(Callback Hooks) 。这些是通过 registerPostSamplingHook() 等 API 注册的 TypeScript 函数,遵循相同的 HookInput → HookJSONOutput 契约,但在进程内运行,无子进程开销。
typescript
type HookCallback = {
type: 'callback'
callback: (input: HookInput, toolUseID: string | null, abort: AbortSignal) => Promise<HookJSONOutput>
timeout?: number
internal?: boolean // 排除在分析指标之外
}
实战示例
文件写入后自动格式化
json
{
"PostToolUse": [{
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "npx prettier --write \"$TOOL_INPUT_FILE_PATH\" 2>/dev/null || true"
}]
}]
}
拦截危险 shell 命令
json
{
"PreToolUse": [{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash -c 'if echo \"$TOOL_INPUT_COMMAND\" | grep -qE \"rm -rf|DROP TABLE\"; then echo \"{\\\"decision\\\": \\\"block\\\", \\\"reason\\\": \\\"危险命令已被拦截\\\"}\"; exit 2; fi'"
}]
}]
}
会话结束时发送通知
json
{
"Stop": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "osascript -e 'display notification \"Claude 已完成\" with title \"Claude Code\"'",
"async": true
}]
}]
}
代码编辑后运行测试(Agent Hook)
json
{
"PostToolUse": [{
"matcher": "Edit",
"hooks": [{
"type": "agent",
"prompt": "检查被编辑的文件是否有测试。如果有,运行测试并报告通过/失败状态。输入:$ARGUMENTS",
"timeout": 120
}]
}]
}
会话启动时注入环境上下文
json
{
"SessionStart": [{
"matcher": "",
"hooks": [{
"type": "command",
"command": "echo \"{\\\"hookSpecificOutput\\\": {\\\"hookEventName\\\": \\\"SessionStart\\\", \\\"additionalContext\\\": \\\"分支:$(git branch --show-current),PR:$(gh pr view --json number -q .number 2>/dev/null || echo 无)\\\"}}\"",
"statusMessage": "加载 git 上下文..."
}]
}]
}
Hook 信任与安全
- 定义在
~/.claude/settings.json中的 Hooks 首次执行前需要一次性信任确认对话 .claude/settings.json(项目配置)中的 Hooks 受项目信任机制约束CLAUDE_CODE_DISABLE_HOOKS=true全局禁用所有 Hooks- Hook 输出注入的
systemMessage会作为警告显示给用户,而非静默执行 - 响应字段
suppressOutput: true会从会话记录中隐藏 stdout,但不会抑制 Hook 的实际效果