Claude Code Hooks 实操:13 个钩子事件让 AI 编码行为可控可审计
【免费下载链接】claude-code-hooks-masteryMaster Claude Code Hooks项目地址: https://gitcode.com/GitHub_Trending/cl/claude-code-hooks-mastery
你盯着屏幕让 AI 跑一遍"清理临时目录",它反手就是一个rm -rf——这是很多用过 Claude Code 的人真实经历过的惊吓。Claude Code Hooks 是内置于 Claude Code 生命周期的 13 个确定性拦截点:在用户提交输入前、工具调用前后、会话与子代理启停时触发,让你用自己的代码而不是模型的"自觉"来接管关键动作。本文基于 claude-code-hooks-mastery 这个仓库,它把这 13 个钩子全部实现了一遍,顺带示范了子代理、团队化校验、状态栏等配套玩法,是学习 Claude Code Hooks 机制的完整样本。
它替你想好了哪几件烦心事
- 以前你得手动盯着 AI 写的每一行代码、逐条确认危险命令;现在 PreToolUse 钩子直接拦截
rm -rf和.env访问,PostToolUse 钩子写完文件立刻跑 Ruff 和 Ty 校验。 - 以前"任务完成"只是模型的一句话,没有凭证;现在 Stop 钩子可以校验完成条件,不达标就强制 AI 继续干。
- 以前会话上下文丢失就找不回来了;现在 SessionStart / PreCompact 钩子负责注入开发上下文、在压缩前备份转录。
- 以前多代理协作要自己写脚本协调;现在 builder 与 validator 两个代理靠任务系统并行开工,钩子在每个环节做质量门禁。
从 clone 到看到第一次拦截
- 装两个前置工具:Astral 的 UV(快速 Python 脚本运行器,负责跑每个钩子)和 Claude Code 本体。
- 用文末的
git clone命令克隆 claude-code-hooks-mastery,进入项目目录。 - 启动
claude,随便提交一个正常提示词——UserPromptSubmit 钩子立刻把它记进logs/目录。 - 接着试着让它执行
rm -rf类命令,PreToolUse 钩子当场拦下,你在对话里会看到 BLOCKED 提示。 - 不用任何额外配置:仓库自带的
.claude/settings.json已经注册了全部 13 个钩子,跑起来即生效。
核心机制拆解
13 个钩子事件:每个都是一个确定性拦截点
钩子的本质是"在固定时机执行你的命令",而不是把决定权交给模型。13 个实现全部位于.claude/hooks/,每个都是独立 Python 脚本,文件头内嵌依赖声明,靠 UV 单文件脚本机制直接运行,不碰项目依赖树。流程控制靠两样东西:退出码 2 表示拦截(stderr 内容会自动反馈给 Claude 让它自行调整);退出码 0 加 stdout 输出,则把你写的内容作为上下文注入,拼在用户提示词前面。README 里有一张完整的"退出码 × 各钩子能力"对照表,值得先翻一遍。
PreToolUse 拦截:危险命令根本执行不到
这是防御层里最硬的一环。.claude/hooks/pre_tool_use.py里用一组正则匹配rm -rf的各种变体,并拦截对.env的读取和改写(.env.sample除外),命中就退出码 2 直接阻断:
if is_dangerous_rm_command(command): print("BLOCKED: Dangerous rm command detected", file=sys.stderr) sys.exit(2)对 AI 来说这不是"被拒绝了",而是收到了一条必须处理并绕开的路由——拦截之后它通常会换一个安全方案继续。
团队校验流:builder 写代码,validator 只读验收
.claude/agents/team/下两个代理构成"用算力换信任"的配对:builder 负责实现,它的 PostToolUse 钩子绑定了 Ruff 和 Ty 两个校验器,每次 Write/Edit 之后自动检查,不过就回滚重来;validator 只有读权限,专门验收 builder 的产出。两者由任务系统调度,可并行、可挂依赖,不需要 bash sleep 轮询。
实战:三个典型卡点的解法
当 AI 要删你不敢删的东西时,什么都不用做——pre_tool_use.py已经替你把关。想加自己的规则,把正则加进拦截列表即可,例如封掉某个目录的写操作。
当 AI 报"完成"但测试还红着时,Stop 钩子就是那道门禁。输出{"decision": "block", "reason": "..."}这样的 JSON 并返回 0,Claude 会收到 reason 继续干活,而不是提前收工。
当任务大到需要分工时,在 Claude Code 里输入:
/plan_w_team 更新钩子文档并补齐缺失的状态栏 为每个 hook 建一组 builder + validator它会生成一份带团队编排和依赖关系的计划文档存入specs/,然后 builder 与 validator 按计划并行推进。
进阶:规则、校验器与自己的代理
- 拦截规则:改
.claude/hooks/pre_tool_use.py里的正则列表,加一条、验证一次。 - 代码质量标准:
ruff.toml与ty.toml决定 Ruff、Ty 校验的严格程度,团队里可以按项目调。 - 自定义子代理:在
.claude/agents/新建 markdown,YAML 头写name、description(告诉主代理何时委派)、tools、model,正文写清角色和汇报格式。 - 钩子开关与参数:全部注册在
.claude/settings.json,命令尾部的--log-only、--notify、--validate等标志位控制行为;另附 9 版状态栏(.claude/status_lines/)和 8 种输出风格(.claude/output-styles/)开箱即用。
高频问题与避坑
Q:钩子注册了为什么没触发?A:按顺序查三处——.claude/settings.json的hooks里是否注册了该事件;命令路径是否用了$CLAUDE_PROJECT_DIR前缀(裸相对路径在不同工作目录下会解析失败);UV 是否已安装(uv --version验证)。
Q:钩子跑起来了,但就是拦不住?A:大概率是退出码没给对。返回 0 只会被当作"通过",拦截必须返回 2(stderr 反馈给 Claude)或输出带decision字段的 JSON。另外注意时机:PostToolUse 触发时工具已经执行完,它只能反馈和校验,无法撤销,真正想"防"要用 PreToolUse。
Q:TTS 提示音没声音?A:.env里没配 ElevenLabs 等服务的 API key,通知类钩子会静默降级,但logs/里的日志依然正常写入。不想听声音可以不加--notify标志。
Q:Stop 钩子会不会把 AI 锁死?A:会,如果无条件 block 就是死循环。判断输入里的stop_hook_active标志,避免二次拦截,样本代码里就是这么写的。
一小时上手路径:把"盯屏幕"变成"定规则"
回到开头那个场景:AI 依然会想跑危险命令,但它跑不到——规则已经写在钩子里。这套仓库的价值在于把钩子注册、退出码语义、团队化校验这几个最容易踩坑的地方全部铺成了可运行的示例,你照着改就能长出自己的版本。
下一步可以这样做:
- 先 clone 仓库,提交一个普通提示词,确认
logs/里开始产生记录。 - 挑一个钩子(建议从
pre_tool_use.py入手),加一条只属于你项目的拦截规则。 - 跑一次
/plan_w_team,观察 builder 与 validator 的协作节奏。
git clone https://gitcode.com/GitHub_Trending/cl/claude-code-hooks-mastery【免费下载链接】claude-code-hooks-masteryMaster Claude Code Hooks项目地址: https://gitcode.com/GitHub_Trending/cl/claude-code-hooks-mastery
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考