Claude Code 实战入门(五):Hooks,让你不再担心 Yolo 模式
Hooks 是每次工具调用前后跑的 shell 脚本。PreToolUse 可以阻止。PostToolUse 可以格式化、Lint、记日志。我每个 Repo 都用的 5 个 Hook,加上一个把所有人都坑过的反模式。
如果 MCP 是 Claude 伸出去的手,Hooks 是你伸进来的手。它是把你在意的规则从"希望"变成"强制"的方式。
模型
Hook 是 shell 命令。Claude Code 在几个良好定义的时刻跑它。常用两个:
PreToolUse——在工具调用之前。退出码 0 放行;非 0 阻止。PostToolUse——在工具返回之后。退出码仅作信息;可用于格式化文件、跑 Lint、记日志。
还有别的(UserPromptSubmit、Stop、Notification、SubagentStop)。日常这两个是 90% 的价值。
Hook 住哪
.claude/settings.json(或 .local 变体)里。最小例子:
| |
matcher 决定 Hook 应用到哪些工具。"Bash" 匹内置 Bash。"Write" 匹文件写入。"mcp__playwright__.*" 匹所有 Playwright MCP 工具。支持正则——通配很常见。
Hook 命令通过 stdin 拿到工具输入的 JSON,对话上下文以环境变量给出。最简 Hook 就是读 stdin、判断、用合适退出码退出。
Hook 1:禁危险命令
.claude/hooks/check-bash.sh:
| |
PreToolUse matcher Bash。阻止以 1 退出;stderr 上的消息回到模型,让它知道为什么并能调整。这就是"Agent 静默崩溃"和"Agent 学会要权限"的差别。
Hook 2:写入时自动格式化
.claude/hooks/format-on-write.sh:
| |
PostToolUse matcher Write|Edit。Claude 每次动文件,下一轮之前文件已被格式化。Agent 永远不需要被告知格式——你的房屋风格被代码强制。
Hook 3:记每一次工具调用
| |
PostToolUse matcher .*。每次工具调用一行 JSON 写到文件。出问题——或没出问题——的时候你有完整审计轨迹。
我精确用过它三次。三次都是事后复盘,需要知道"那 40 分钟会话里 Claude 到底干了什么"。值它占的硬盘。
Hook 4:commit 前强制测试通过
| |
PreToolUse matcher Bash。拦 git commit,先跑测试。挂了就拦下来,告诉模型为什么。给 Agent 自己的 pre-commit hook。
听起来挺霸道,是的。重点是你不能意外提交破坏代码。模型必须主动绕开 Hook 才能做错事,而它不会。
Hook 5:擦工具输出里的密钥
| |
PostToolUse matcher Read|Bash。在 Agent 看到工具输出之前过一遍流式擦除器。如果你不小心 cat 了带密钥的文件,模型永远读不到——它们就地变成 [REDACTED]。
这是处理真实代码库时单条最重要的安全 Hook。
反模式:相对路径
最常见的 Hook Bug 是命令用相对路径:
| |
Claude Code 在你不控制的工作目录跑 Hook。永远用绝对路径或 $CLAUDE_PROJECT_DIR:
| |
脚本内部同理:别 cd、别用相对路径。
Hook 在团队工作流里的位置
提交进 .claude/settings.json 的 Hook 对所有人生效。这就是重点。新队友克隆 Repo、跑 claude,自动继承你的安全栏和格式化策略。零配置、零选择加入。
仅个人用的 Hook(依赖你独有工具的)放 .claude/settings.local.json。它们留在你机器上。
Hook 不是什么
- 不是权限的替代。 Hook 可以补充权限,但不能替代。权限是声明式、显式;Hook 是可执行、易写错。
- 不是免费检查。 每个 Hook 给每次工具调用加延迟。5 个 Hook 各 100ms 就是每工具 0.5 秒。盯预算。
- 不是图灵完备配置。 当 Hook 开始像小程序时,你应该写一个 MCP 服务器。
下一篇是 SDK 与 GitHub 集成——程序化的 Claude Code,跑在 CI 里、对 PR 工作。系列结尾,也是最强的一篇。