📒 学霸笔记:11|事件驱动:详解 Hooks 机制,让 AI 在关键节点自动触发
Top Student Notes: 11 | Event-Driven Automation: Understanding Hooks So AI Can Trigger at Key Moments Automatically
课程 / Course: AI 原生开发工作流实战 / AI-Native Development Workflow in Practice
讲师 / Instructor: Tony Bai
章节 / Chapter: 11
主题 / Topic: Hooks、事件驱动、Claude Code 生命周期、PreToolUse、PostToolUse、Notification、自动化编排、Hook 调试
一、这一讲在解决什么问题?
What Problem Does This Lecture Solve?
前面我们已经学了很多让 AI 更强的能力:
@:给 AI 上下文!:让 AI 执行动作CLAUDE.md:给 AI 长期记忆- Slash Commands:把高频工作流封装成命令
- Permissions / Sandbox / Checkpointing:给 AI 安全边界与反悔能力
但即使这样,我们和 AI 的协作方式,很多时候仍然是:
你触发一下,它动一下。
也就是说,本质上仍是:
- 你先发起
- AI 响应
- 你再补一个动作
- AI 再继续
于是会出现很多“机械但必须做”的尾部操作:
- AI 改完 Go 文件后,你还要手动
gofmt - AI 修完 Bug 后,你还要手动
git add - AI 长时间任务结束了,你还要自己时不时回来查看
- AI 正在等你批准权限,你却不知道它已经停在那里了
这些动作并不难,但非常烦,而且会打断流。
所以这一讲要解决的问题是:
能不能让系统在 AI 生命周期的关键节点上,自动触发预设动作?
答案就是:
Hooks 机制
二、本讲核心结论
Core Conclusion of This Lecture
一句话总结
Hooks 本质上是 Claude Code 的事件驱动自动化机制:不是“我命令 AI 做什么”,而是“当 AI 做了某件事时,系统自动响应什么”。
三、这一讲的真正升级点
The Real Upgrade in This Lecture
Tony 在这一讲里,真正推动的是一次协作模式升级:
从交互式调用,升级到事件驱动编排。
以前的模式
你像一个“微操型玩家”:
- AI 改完文件
- 你再手动格式化
- AI 跑完任务
- 你再手动检查
- AI要调用工具
- 你再手动决定后续处理
这种方式虽然可控,但不够顺滑。
Hooks 带来的变化
你开始预先埋好“触发器”:
- 文件一改完,就自动格式化
- AI 空闲下来,就自动通知你
- AI 想改主分支文件,就自动被拦下
- 会话一启动,就自动做初始化动作
这意味着你不再只是一个“操作员”,而更像:
AI 行为编排者 / 自动化流程设计者

四、必须先分清:Hooks vs Slash Commands
First, Distinguish Hooks vs Slash Commands
这是本讲最重要的认知点之一。
Tony 特别强调:
Slash Commands 和 Hooks 代表两种完全不同的自动化哲学。
五、Slash Commands 是“人驱动”
Slash Commands Are Human-Driven
Slash Commands 的特点是:
- 你主动调用
- 你决定何时执行
- 它像一个工具箱里的工具
例如:
/commit/review-go-code/gen-test
这些都是:
人发起、AI执行
类比
Tony 的比喻很形象:
Slash Commands 像电动螺丝刀。你得先拿起来,再对准目标,再按开关。
六、Hooks 是“事件驱动”
Hooks Are Event-Driven
Hooks 不是你每次手动调用的命令。
它更像:
埋在 AI 生命周期里的传感器和响应器。
当某个事件发生时:
- AI 刚写完文件
- AI 即将调用工具
- AI 进入等待状态
- 会话刚开始 / 刚结束
Hook 就会自动触发。
类比
Hooks 不是工具本身,而像自动门、烟雾报警器、流水线感应器。
事件一发生,系统自己反应。
七、两者怎么配合?
How Do Hooks and Slash Commands Work Together?
Tony 提出一个非常成熟的工作流观念:
成熟的 AI 原生工作流 = Slash Commands 启动任务 + Hooks 负责自动收尾和过程联动。
例子
你可以:
- 用
/review-go-code发起一个复杂分析任务 - AI 在过程中修改文件
PostToolUse自动跑格式化- AI 完成后,
Notification自动给你系统提醒
这才是完整的工程自动化。
八、Claude Code 生命周期:你要知道 AI 在哪里会“触发事件”
Claude Code Lifecycle: You Need to Know Where Events Happen
要用好 Hooks,你必须先理解:
AI 在一次工作流程中,经过哪些关键生命周期节点。
因为 Hook 本质就是:
对生命周期事件的监听与响应。
九、核心 Hook 事件概览
Overview of Core Hook Events
这一讲列出了多个 Claude Code 开放的关键事件。
1. SessionStart
时机
Claude Code 会话启动时
价值
适合做初始化
例如:
- 切换 Node 版本
- 初始化环境变量
- 打印项目状态
- 做会话级准备工作
2. SessionEnd
时机
会话退出时
价值
适合做清理工作
例如:
- 写日志
- 收尾统计
- 清理临时文件
- 结束时通知
3. UserPromptSubmit
时机
用户提交 Prompt 之后,AI 开始处理之前
价值
适合做 Prompt 前置检查或预处理
例如:
- 检查敏感词
- 发现危险请求则阻止提交
- 自动注入额外上下文
- 记录用户输入
4. PreToolUse
时机
AI 决定调用某个工具,但还没真正执行前
价值
这是最强控制点之一
你可以:
- 看 AI 准备调用什么工具
- 看工具参数
- 在执行前做检查
- 直接阻止这次调用
为什么它很强?
因为这是:
行动发生之前的拦截点
所以非常适合:
- 安全策略
- 行为约束
- 组织规则强制执行
5. PostToolUse
时机
工具调用完成之后,AI 获得结果之前
价值
这是自动化收尾工作的黄金位置
适合:
- 自动格式化
- 自动跑 Linter
- 自动补充分析
- 写日志
- 做后置加工
6. Notification
时机
AI 等待你下一步输入,或者等待你批准某个权限时
价值
解决“AI是不是在等我”的问题
非常适合:
- 系统通知
- 桌面提醒
- 响铃提示
7. Stop
时机
一个主回合结束时
价值
适合做“回合结束”型动作
例如:
- 记录 token 消耗
- 汇总一次任务结果
- 输出摘要日志
8. SubagentStop
时机
一个 Sub-agent 子任务结束时
价值
适合对子任务做收尾和观察

十、最值得记住的两个事件
The Two Most Important Hook Events to Remember
虽然事件很多,但本讲实战重点其实集中在两个:
PostToolUsePreToolUse
为什么?
因为这两个恰好分别代表两种最常见价值:
PostToolUse:自动化收尾PreToolUse:安全与策略拦截
一个偏效率,一个偏治理。
十一、Hooks 的配置位置
Where Hooks Are Configured
所有 Hooks 都配置在:
settings.json
可以是:
- User 级
- Project 级
Project 级更适合什么?
- 团队共享规则
- 项目自动化规范
- 强制性流程
例如:
- 修改 Go 文件后自动格式化
- 禁止直接改 main 分支
User 级更适合什么?
- 个人提醒
- 个人工作习惯
- 私有通知逻辑
十二、Hooks 的核心结构
Core Structure of Hooks
大体结构是:
{
"hooks": {
"<EventName>": [
{
"matcher": "<ToolPattern>",
"hooks": [
{
"type": "command",
"command": "<your-shell-command>",
"timeout": 60
}
]
}
]
}
}
关键字段理解
EventName
表示监听哪个生命周期事件
例如:
PreToolUsePostToolUse
matcher
只对工具型事件有意义,表示匹配哪些工具调用
hooks
真正要执行的动作列表
type
当前主要是 command
command
要执行的 shell 命令或脚本
timeout
超时限制,避免 Hook 卡死整个流程
十三、matcher 是 Hooks 的过滤器
matcher Is the Filter for Hooks
matcher 决定:
不是所有事件都响应,而是只对特定工具调用响应。
例子
"Edit|Write"
表示:
- 匹配
Edit - 或匹配
Write
"Bash(go:test:*)"
表示:
- 只匹配
go test相关命令
"*" 或空字符串
表示:
- 匹配所有工具
学霸理解
matcher 决定的是:
“谁触发我”
十四、Hook 命令如何拿到上下文?
How Does a Hook Command Receive Context?
这是一个关键实现点。
Claude Code 会把当前事件的信息:
通过 stdin 以 JSON 格式传给你的 Hook 命令。
也就是说,Hook 脚本可以从标准输入读取:
- 当前事件名
- 当前工具名
- 工具输入
- 工具输出
- 当前工作目录
- 会话 ID
- transcript 路径
这意味着什么?
你的 Hook 不是“盲执行”的,而是:
知道发生了什么,再决定怎么响应。
十五、实战一:PostToolUse 自动格式化 Go 文件
Practical Example 1: PostToolUse for Automatic Go Formatting
这是一个非常典型的“事件驱动自动收尾”场景。
目标
当 AI 用这些工具改了文件:
EditWriteMultiEdit
并且目标是 .go 文件时:
自动运行:
gofmt -wgoimports -w
这个实战体现了什么思想?
把“修改完成后的规范化处理”从手工步骤升级为事件响应。
步骤拆解
第一步:进入 /hooks
使用交互式界面配置 Hook
第二步:选 PostToolUse
因为你关心的是:
- 工具已经执行完
- 文件已经改完
- 可以开始收尾
第三步:设置 matcher
Edit|Write|MultiEdit
表示只对编辑类工具做反应。
第四步:命令的本质
命令要做三件事:
- 从 stdin 读 JSON
- 解析出
tool_input.file_path - 判断是不是
.go文件 - 如果是,则运行
gofmt和goimports
jq 的作用
Tony 强调这里 jq 很重要。
因为 Hook 上下文是 JSON,jq 可以非常方便地提取字段,例如:
tool_input.file_path
学霸理解
这个例子真正要学的不是记命令,而是掌握模式:
读取事件 JSON → 提取关键字段 → 做条件判断 → 调用后置动作
这套模式以后可以推广到很多自动化场景。
十六、这个自动格式化 Hook 的意义
Why This Auto-Formatting Hook Matters
它解决了一个典型的“低价值人工步骤”:
- AI 写了代码
- 人再补格式化
- 经常忘
- 忘了又会污染 diff
有了 Hook 之后:
格式化成为“修改成功后的系统默认反应”,而不是开发者额外记忆负担。
这就是事件驱动自动化的价值。
十七、如何调试 Hook?
How to Debug Hooks?
Hook 不工作时,最怕的就是:
- 不知道有没有触发
- 不知道 matcher 是否命中
- 不知道命令有没有跑
- 不知道 stdout / stderr 返回了什么
Tony 给了标准方法:
claude --debug
启动后会得到什么?
Claude Code 会告诉你 debug 日志文件路径。
然后你可以用 tail 之类命令去观察日志。
Debug 日志能看到什么?
例如:
- 工具是否匹配了某个 Hook
- 匹配了几个 Hook
- Hook 命令输出了什么
- 返回内容是否被解析成功
学霸理解
调试 Hook 的核心链路是:
事件有没有发生
→ matcher 有没有命中
→ command 有没有执行
→ 输出是否符合预期
十八、实战二:PreToolUse 阻止在 main 分支直接改代码
Practical Example 2: PreToolUse to Prevent Direct Edits on the Main Branch
这是一个比自动格式化更“治理型”的案例。
目标
当 AI 准备用:
EditWriteMultiEdit
修改文件时,先检查当前 Git 分支。
如果在:
mainmaster
上,就直接阻止这次修改。
这类 Hook 解决了什么问题?
这是典型的:
把团队工程纪律,变成系统强制执行规则。
不再只是文档里写:
- “不要直接改主分支”
而是真正做到:
- 主分支禁止 AI 直接改
十九、为什么这个案例推荐用脚本文件而不是一长串 Bash?
Why a Script File Is Better Than a Long Bash One-Liner
Tony 这里非常实用地提醒了一点:
对复杂 Hook 逻辑,最好封装成脚本文件,而不是写一大串 Bash 管道命令。
原因
长 Bash 命令容易:
- 难读
- 难调试
- 难维护
- 容易转义出错
而独立脚本:
- 更清晰
- 更易扩展
- 可以写注释
- 可以本地单独测试
推荐位置
放在:
.claude/hooks/
例如:
.claude/hooks/check_main_branch.py
这是非常好的项目结构实践。
二十、这个 Python Hook 脚本的核心逻辑
Core Logic of the Python Hook Script
这个脚本做了几件事:
- 从 stdin 读取 JSON
- 看当前工具是不是
Edit/Write/MultiEdit - 调用:
获取当前分支git rev-parse --abbrev-ref HEAD - 如果分支是
main/master- 输出错误信息到
stderr exit 2
- 输出错误信息到
- 否则
exit 0
为什么 stderr 很重要?
因为 Tony 强调:
输出到
stderr的错误信息,不只给用户看,也会让 Claude 理解“为什么这次操作被阻止”。
于是 AI 可能会进一步智能调整行为,比如:
- 主动建议你先建 feature branch
这很关键。
二十一、退出码的语义很关键
Exit Code Semantics Matter
在 Hook 体系里:
exit 0:允许继续- 非 0:表示失败 / 拦截
特别是案例里:
exit 2:阻止工具调用,并把错误信息展示给 Claude 和用户
学霸理解
PreToolUse 里,脚本的退出码相当于:
是否放行工具调用的裁决结果
所以这其实是一个很强的“策略执行点”。
二十二、$CLAUDE_PROJECT_DIR 很实用
$CLAUDE_PROJECT_DIR Is Very Useful
Tony 提到的这个环境变量非常有价值:
"$CLAUDE_PROJECT_DIR"/.claude/hooks/check_main_branch.py
它会自动展开为项目根目录路径。
好处
这样你的 Hook 配置:
- 不依赖硬编码绝对路径
- 可以跨机器
- 可以跟项目一起提交
- 团队成员可复用
二十三、这两个实战分别代表什么?
What Do the Two Practical Examples Represent?
这两个例子很有代表性,因为它们分别体现 Hooks 的两种核心价值。
实战一:PostToolUse 自动格式化
代表:
效率型自动化
核心目标:
- 减少重复劳动
- 自动做收尾工作
- 把规范执行“无感化”
实战二:PreToolUse 阻止改 main
代表:
治理型自动化
核心目标:
- 在关键点前拦截危险动作
- 强制执行团队纪律
- 把规则从文档变成系统机制
二十四、Hooks 的本质总结
The Essence of Hooks
到这里可以把 Hooks 总结成一句话:
Hooks 是把“规则、习惯、最佳实践”嵌入 AI 生命周期关键节点的自动响应机制。
更通俗一点
以前:
- 规范靠记忆
- 流程靠自觉
- 收尾靠手动
- 安全靠盯着
现在:
- 规范靠 Hook 自动执行
- 流程靠事件自动推进
- 收尾靠系统自动完成
- 安全靠关键节点自动拦截
二十五、这一讲的真正方法论价值
The Methodological Value of This Lecture
这讲不是单纯多学了一个配置功能,而是在方法论上完成一次升级:
从 Prompt 工程,走向流程工程。
为什么这么说?
前面很多内容都在优化:
- 你怎么问
- AI 怎么答
- 上下文怎么组织
- 命令怎么复用
而 Hooks 开始优化的是:
AI 运行过程中的事件流。
也就是说,关注点从“单次交互质量”转向:
整个协作流程如何自动流动。
二十六、这一讲和前面课程的关系
How This Lecture Connects to Earlier Lessons
可以这样串起来看:
@/!:建立感知-行动闭环CLAUDE.md/constitution.md:建立规则与原则- Slash Commands:把高频协作封装成显式命令
- Permissions / Sandbox / Checkpointing:建立安全与可反悔机制
- Hooks:把 AI 生命周期变成可响应的事件流
这意味着什么?
你已经不只是“跟 AI 对话”,而是在:
设计一个带触发器、带约束、带收尾逻辑、带自动响应的 AI 工作流系统。
二十七、Hooks 最适合做哪些事?
What Are Hooks Best Suited For?
1. 自动收尾
- 格式化代码
- 运行 linter
- 同步生成附加文件
2. 安全拦截
- 禁止改主分支
- 禁止危险文件写入
- 检查敏感命令
3. 通知提醒
- AI 完成任务提醒
- AI 等待你批准提醒
4. 会话初始化
- 加载环境
- 切版本
- 打印项目状态
5. 记录与审计
- 写日志
- 统计 token
- 记录关键行为
二十八、使用 Hooks 的设计原则
Design Principles for Using Hooks
Tony 虽然没有专门列成条,但从实战里能总结出几个原则。
原则 1:让 Hook 做“高频、可预测、重复”的事
因为这些最适合自动化。
原则 2:复杂逻辑尽量写成脚本文件
不要把复杂业务判断堆进一长串 shell one-liner。
原则 3:收尾动作适合 PostToolUse
例如格式化、lint、日志。
原则 4:拦截与治理适合 PreToolUse
例如安全控制、流程保护、策略执行。
原则 5:团队共享规则优先放项目级
这样才真正形成工程实践,而不是个人偏好。
二十九、本讲知识结构图
Knowledge Structure of This Lecture
当前协作仍以“人触发 AI”为主
↓
出现大量机械收尾与监视动作
↓
需要事件驱动自动化
↓
Hooks
↓
两种自动化哲学对比
├── Slash Commands:人驱动
└── Hooks:事件驱动
↓
Claude Code 生命周期事件
├── SessionStart / SessionEnd
├── UserPromptSubmit
├── PreToolUse
├── PostToolUse
├── Notification
├── Stop
└── SubagentStop
↓
配置方式
├── settings.json
├── matcher 匹配工具
├── command 执行响应命令
└── stdin 传 JSON 上下文
↓
两类核心应用
├── PostToolUse:自动收尾
│ └── 例:Go 文件自动格式化
└── PreToolUse:行为拦截
└── 例:阻止在 main 分支直接改文件
↓
最终目标
把最佳实践、规范、安全策略嵌入 AI 生命周期
三十、学霸速记表
Quick Revision Table
| 知识点 | 结论 |
|---|---|
| Hooks 本质 | 事件驱动自动化机制 |
| Slash Commands vs Hooks | 前者人驱动,后者事件驱动 |
| Hooks 配置位置 | settings.json |
| 核心字段 | hooks / matcher / command / timeout |
| 上下文传递方式 | Claude Code 通过 stdin 传 JSON |
SessionStart |
会话启动时触发 |
SessionEnd |
会话结束时触发 |
UserPromptSubmit |
用户提交 Prompt 后、AI 处理前 |
PreToolUse |
工具执行前,可拦截 |
PostToolUse |
工具执行后,适合收尾 |
Notification |
AI 等待用户时触发 |
Stop / SubagentStop |
回合 / 子任务结束时触发 |
| 自动格式化案例 | PostToolUse + `Edit |
| 主分支保护案例 | PreToolUse + 分支检查脚本 |
| 调试方式 | claude --debug 查看 Hook 执行日志 |
三十一、学霸自检题
Self-Check Questions
基础题
- Hooks 和 Slash Commands 的根本区别是什么?
PreToolUse和PostToolUse分别在什么时候触发?- Hook 命令如何获取事件上下文?
进阶题
- 为什么自动格式化更适合用
PostToolUse而不是PreToolUse? - 为什么保护主分支更适合用
PreToolUse? - 为什么复杂 Hook 逻辑推荐封装成独立脚本文件?
思辨题
- 在你的项目里,哪些重复动作最适合用 Hooks 自动化?
- 你是否会把团队规范写成 Hook,而不只写在文档中?为什么?
- 如果为一个前端项目设计 Hooks,你会在哪些事件节点做自动格式化、测试提醒和通知?
三十二、学霸总结
Top-Student Summary
这一讲讲的是 Claude Code 中非常关键、也非常“工程化”的能力:Hooks。
它解决的不是 AI 会不会写代码,而是:
如何让 AI 生命周期中的关键节点,自动触发我们预设的系统响应。
Tony 首先区分了两种自动化哲学:
- Slash Commands:用户驱动,由人主动调用
- Hooks:事件驱动,由系统在事件发生时自动响应
这意味着,Hooks 的价值不在于替代 Slash Commands,而在于把单次 AI 行动之间那些重复、机械、可预测的“胶水步骤”自动化,从而把零散的交互连接成流畅的工作流。
Claude Code 暴露了多个关键生命周期事件,其中最重要的包括:
PreToolUse:工具执行前,可用于安全拦截与策略治理PostToolUse:工具执行后,适合自动格式化、lint 等收尾动作Notification:AI 等待用户时触发通知SessionStart / SessionEnd:适合会话级初始化与清理
在配置层面,Hooks 定义于 settings.json,通过 matcher 指定监听哪些工具,通过 command 执行具体 shell 命令或脚本。Claude Code 还会通过 stdin 以 JSON 形式把事件上下文传给 Hook,使 Hook 具备“感知发生了什么”再作反应的能力。
两个实战例子非常典型:
-
PostToolUse自动格式化 Go 文件
把“AI 修改代码后再手动 gofmt / goimports”的重复劳动,升级成无感自动执行的后置流程。 -
PreToolUse阻止在 main/master 分支直接修改文件
把团队纪律从文档里的提醒,升级成真正可执行、可阻断的系统规则。
因此,Hooks 的真正价值在于:
让规范、最佳实践和安全策略,不再依赖人的记忆和自觉,而是成为一个永远在线、自动执行的事件响应系统。
这标志着开发者角色再次升级:
你不再只是 AI 的提问者、指令设计者,而正在成为:
AI 行为流程的编排者。
三十三、一句话记忆
One-Sentence Memory Hook
Slash Commands 是“我让 AI 做什么”,Hooks 是“当 AI 做了什么,系统自动接着做什么”;前者是人驱动,后者是事件驱动。