共计 3758 个字符,预计需要花费 10 分钟才能阅读完成。
文章目录[显示]
Claude Code 从入门到脱发 · Day 5
昨天聊了权限管理,那是 " 不让它做什么 "。今天聊 Hooks,这是 " 让它做完之后自动做点什么 "。
你有没有这样的经历:Claude Code 帮你改了一个文件,你看了一眼——缩进乱了。于是你手动跑一下 Prettier。然后它又改了一个文件,缩进又乱了。你又跑 Prettier。如此反复,你开始怀疑人生。
Hooks 就是解决这类问题的。它让你在 Claude Code 的操作前后,自动执行自定义的脚本。编辑文件后自动格式化、执行命令前自动检查、每次提交前自动跑 lint——全自动,你不用动手。
本文你将学到:
- Hooks 的三种类型:PreToolUse、PostToolUse、Stop
- 如何配置实用的 Hooks
- 常见 Hooks 示例(格式化、类型检查、安全扫描)
- Hooks 的调试技巧
阅读时间 :8 分钟 | 实操时间 :20 分钟 | 难度:中级
Hooks 是什么
Hooks 是 Claude Code 在执行操作前后自动触发的脚本。你定义好规则,它自动执行,不需要你每次手动干预。
三种 Hook 类型:
| 类型 | 触发时机 | 典型用途 |
|---|---|---|
| PreToolUse | 工具执行 前 | 拦截危险操作、修改参数 |
| PostToolUse | 工具执行 后 | 自动格式化、检查结果 |
| Stop | 会话结束时 | 最终审计、清理 |
配置文件
Hooks 配置在 ~/.claude/settings.json(全局)或 .claude/settings.json(项目级)的 hooks 字段里。
基本结构:
{
"hooks": {
"PreToolUse": [
{
"matcher": "工具匹配规则",
"hooks": [
{
"type": "command",
"command": "要执行的命令"
}
]
}
],
"PostToolUse": [...],
"Stop": [...]
}
}
matcher 决定什么时候触发,可以匹配工具名(如 Edit、Write、Bash)。
实用 Hooks 示例
示例一:编辑文件后自动格式化
这是最常用的 Hook。每次 Claude Code 编辑 JS/TS 文件后,自动跑 Prettier。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "filepath=\"$CLAUDE_FILE_PATH\"; if echo \"$filepath\"| grep -qE'\\.(js|ts|jsx|tsx)$'; then npx prettier --write \"$filepath\"2>/dev/null; fi"
}
]
}
]
}
}
效果:Claude Code 改完文件,Prettier 自动格式化。你再也不用手动跑了。
示例二:编辑 TypeScript 后自动类型检查
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "filepath=\"$CLAUDE_FILE_PATH\"; if echo \"$filepath\"| grep -qE'\\.tsx?$'; then npx tsc --noEmit 2>&1 | head -20; fi"
}
]
}
]
}
}
效果:每次改完 .ts/.tsx 文件,自动跑类型检查。如果有类型错误,Claude Code 会看到错误信息并尝试修复。
示例三:拦截 console.log
你不想让代码里留下调试用的 console.log,配一个检查 Hook:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "filepath=\"$CLAUDE_FILE_PATH\"; if echo \"$filepath\"| grep -qE'\\.(js|ts|jsx|tsx)$'&& grep -n'console\\.log'\"$filepath\"2>/dev/null; then echo'WARNING: console.log detected in '$filepath; fi"
}
]
}
]
}
}
效果:编辑后如果检测到 console.log,会输出警告。Claude Code 看到警告后通常会主动移除。
示例四:长时间命令提醒
有些命令(npm install、docker build)可能跑很久,用 PreToolUse Hook 提醒使用 tmux:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "cmd=\"$CLAUDE_BASH_COMMAND\"; if echo \"$cmd\"| grep -qE'^(npm|pnpm|yarn|cargo|docker) (install|build|run)'; then echo'TIP: Consider running long commands in tmux or background'; fi"
}
]
}
]
}
}
示例五:Session 结束时审计
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "git diff --name-only | xargs grep -l'console.log'2>/dev/null && echo'Audit: Found console.log in modified files'|| echo'Audit: Clean'"
}
]
}
]
}
}
效果:每次对话结束时,检查被修改的文件里有没有遗留的 console.log。
Hook 的环境变量
Hook 脚本可以使用 Claude Code 提供的环境变量:
| 变量 | 说明 |
|---|---|
$CLAUDE_FILE_PATH |
被操作的文件路径 |
$CLAUDE_BASH_COMMAND |
Bash 工具要执行的命令 |
$CLAUDE_TOOL_NAME |
当前工具名称 |
这些变量让你的 Hook 脚本能够根据具体操作做出不同反应。
Hook 的返回值
Hook 脚本的退出码和输出有特殊含义:
- 退出码 0:操作继续
- 退出码非 0(PreToolUse):阻止操作执行
- stdout 输出:会显示给 Claude Code 看,它会据此调整行为
这意味着 PreToolUse Hook 可以真正 " 拦截 " 操作。比如阻止向超过 500 行的文件继续添加代码:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "filepath=\"$CLAUDE_FILE_PATH\"; if [-f \"$filepath\"] && [$(wc -l < \"$filepath\") -gt 500 ]; then echo \"BLOCKED: File exceeds 500 lines. Split first.\"; exit 1; fi"
}
]
}
]
}
}
这比在 CLAUDE.md 里写 " 不要超过 500 行 " 强硬多了。CLAUDE.md 是建议,Hook 是铁门。
调试 Hooks
Hook 不生效?几个排查步骤:
-
检查 JSON 语法:配置文件一个逗号错了整个都不工作。用
cat ~/.claude/settings.json | python3 -m json.tool验证语法。 -
手动测试命令:把 Hook 里的命令单独在终端跑一下,看有没有报错。
-
检查 matcher:matcher 是正则表达式。
Edit|Write匹配 Edit 或 Write 工具。确保工具名拼写正确。 -
查看输出:Hook 的 stdout 会显示在 Claude Code 的输出中,看看有没有意外的输出。
常见问题 Q&A
Q1:Hooks 会拖慢 Claude Code 吗?
轻量级的 Hook(格式化、grep 检查)基本没感觉。但如果你的 Hook 跑一个完整的测试套件,那确实会卡住。建议 Hook 脚本控制在几秒内完成。
Q2:Hook 报错了会怎样?
PreToolUse Hook 报错(非 0 退出码)会阻止操作。PostToolUse Hook 报错不会回滚操作,只会显示错误信息。
Q3:能不能用 Python 或 Node.js 写 Hook?
可以。command 字段可以执行任何 shell 命令,包括 python3 script.py 或 node script.js。对于复杂逻辑,建议写成独立脚本文件,Hook 里只调用脚本。
小结
今天学了 Hooks 系统:
- 三种类型:PreToolUse(执行前)、PostToolUse(执行后)、Stop(结束时)
- 实用场景:自动格式化、类型检查、console.log 拦截、文件行数限制
- PreToolUse 返回非 0 可以阻止操作,是真正的 " 硬约束 "
- CLAUDE.md 是建议,Hooks 是规则——两者配合使用效果最好
到目前为止,Claude Code 已经能在你的终端里读代码、改代码、遵守你的规范、自动执行检查。但它还是个 " 单机游戏 "——只能操作本地文件和命令。
如果它能连数据库查数据呢?能操作浏览器测试页面呢?能调用 Slack 发通知呢?
明天 Day 6,我们聊 MCP——Model Context Protocol,让 Claude Code 拥有连接外部世界的能力。
系列进度:5/10