你有没有想过:能不能在Claude Code执行某些操作前,自动跑一些检查?或者在会话结束时,自动提交代码?
Hooks系统就是干这个的。它让你在AI Agent的生命周期关键节点"插一脚",执行自定义逻辑。
什么是Hooks?自定义拦截点
Hooks就像机场的安检关卡:在特定位置设置检查点,符合条件的旅客(操作)要经过检查才能通过。
Claude Code支持26个Hook事件,覆盖整个生命周期:
会话生命周期:
SessionStart:会话开始Setup:仓库初始化SessionEnd:会话结束
工具执行生命周期:
PreToolUse:工具执行前PostToolUse:工具执行成功PostToolUseFailure:工具执行失败PermissionRequest:权限请求时PermissionDenied:权限被拒绝
响应生命周期:
UserPromptSubmit:用户提交提示词Stop:AI即将结束响应StopFailure:API错误导致回合结束
多Agent生命周期:
SubagentStart:子Agent启动SubagentStop:子Agent结束TeammateIdle:队友进入空闲TaskCreated/Completed:任务创建/完成
文件与配置变更:
FileChanged:监听文件变更CwdChanged:工作目录变更ConfigChange:配置变更InstructionsLoaded:CLAUDE.md加载
其他:
PreCompact/PostCompact:压缩前后Elicitation/ElicitationResult:MCP交互WorktreeCreate/Remove:工作树操作
四种Hook类型
Hooks支持四种执行方式:
1. command类型:Shell命令
最基础的方式,执行Shell脚本:
{
"type": "command",
"command": "echo 'Hello from hook'",
"shell": "bash",
"timeout": 60,
"if": "Bash(git *)"
}
特点:
- 支持
bash和powershell - 可以用
if条件过滤(权限规则语法) - 超时默认10分钟,
SessionEnd默认1.5秒
2. prompt类型:LLM评估
把Hook输入发给轻量级LLM评估:
{
"type": "prompt",
"prompt": "检查这个操作是否安全: $ARGUMENTS",
"model": "claude-haiku-4-5"
}
$ARGUMENTS会被替换为Hook输入的JSON。
3. agent类型:Agent验证器
启动完整Agent循环来验证条件:
{
"type": "agent",
"prompt": "检查单元测试是否通过",
"timeout": 120,
"model": "claude-sonnet-4-6"
}
这是最强大的类型,可以执行复杂验证。
4. http类型:Webhook
POST到指定URL:
{
"type": "http",
"url": "https://example.com/hook",
"headers": {"Authorization": "Bearer $TOKEN"},
"allowedEnvVars": ["TOKEN"]
}
注意:HTTP Hook不支持SessionStart和Setup事件。
退出码语义:Hook如何与Claude Code通信
Hook通过退出码传递决策:
| 退出码 | 含义 | 行为 |
|---|---|---|
| 0 | 成功/允许 | stdout/stderr不显示(或仅在transcript模式显示) |
| 2 | 阻塞错误 | stderr发送给模型,阻塞当前操作 |
| 其他 | 非阻塞错误 | stderr仅显示给用户,操作继续 |
不同事件的退出码2有特殊行为:
- PreToolUse:阻止工具调用,stderr给模型
- Stop:stderr给模型,但继续对话(实现"继续编码"模式)
- UserPromptSubmit:阻塞处理,擦除原始提示词,仅显示stderr
- SessionStart/Setup:阻塞错误被忽略(不允许阻塞启动)
JSON输出协议
除了退出码,Hook可以通过stdout输出JSON传递结构化信息:
{
"continue": false,
"decision": "block",
"reason": "代码格式不符合prettier",
"systemMessage": "请格式化代码后再提交"
}
对于PreToolUse事件,还可以修改工具输入:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"updatedInput": {
"file_path": "/new/path.ts"
}
}
}
实战配置示例
示例1:PreToolUse格式检查
在写入TypeScript文件前自动检查格式:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "FILE=$(echo $ARGUMENTS | jq -r '.file_path') && prettier --check \"$CLAUDE_PROJECT_DIR/$FILE\" || echo '{\"decision\":\"block\",\"reason\":\"格式检查失败\"}'",
"if": "Write(*.ts)",
"statusMessage": "检查格式..."
}
]
}
]
}
}
示例2:自动提交
会话结束时自动提交未保存的更改:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "检查是否有未提交的更改,如果有,创建合适的commit并提交",
"timeout": 120
}
]
}
]
}
}
示例3:环境初始化
会话开始时设置开发环境:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "echo 'export NODE_ENV=development' >> $CLAUDE_ENV_FILE",
"statusMessage": "设置开发环境..."
}
]
}
]
}
}
异步与后台执行
Hook可以通过两种方式后台执行:
配置声明
{
"type": "command",
"command": "long-running-task",
"async": true
}
或:
{
"asyncRewake": true
}
asyncRewake特殊:后台Hook退出码为2时,会唤醒模型继续处理。
运行时声明
Hook在第一行输出{"async": true},立即进入后台。
信任门控
Hooks执行需要信任确认:
- 非交互模式(SDK):信任隐含,直接执行
- 交互模式:需要信任对话框确认
这是纵深防御:即使有人恶意配置了危险Hook,用户不点"信任"就不会执行。
配置来源与合并
Hooks可以来自多个来源:
- 配置快照(settings.json)
- 注册式Hook(SDK callback、插件原生Hook)
- 会话Hook(Agent frontmatter注册)
- 会话函数Hook(结构化输出强制器)
来源按优先级合并,支持allowManagedHooksOnly策略限制。
模式提炼
模式1:退出码即协议
Shell命令与宿主进程之间需要轻量级语义通信。定义明确的退出码契约:
- 0 = 成功/允许
- 2 = 阻塞错误
- 其他 = 非阻塞错误
模式2:配置快照隔离
配置文件可能在运行时修改。在启动时捕获快照,运行时使用快照而非实时读取。用户显式修改时更新快照。
模式3:命名空间化去重
同一Hook可能出现在多个配置源。去重键包含来源上下文,同一命令在不同插件保持独立,在同一来源层级合并。
总结
Hooks系统是Claude Code的可扩展性核心:
- 26个事件点:覆盖完整生命周期
- 四种类型:command、prompt、agent、http
- 退出码语义:简单有效的通信协议
- 信任门控:安全的默认行为
- 配置合并:多来源支持
这就像:
- 机场安检(拦截检查)
- 自动驾驶的接管机制(人工介入)
- CI/CD的流水线(自动化流程)
理解Hooks,你就能:
- 自定义Claude Code的行为
- 实现项目特定的自动化
- 在自己的AI Agent中设计扩展点
下篇咱们聊聊Agent集群——当AI开始"组队打怪"。
