“Claude Code 写代码确实快,但它万一执行了个
rm -rf /怎么办?”
这是很多刚上手 Claude Code 的开发者最真实的焦虑。
AI 编程工具越来越强,自动读文件、写代码、跑命令,效率确实起飞。但问题也随之而来 —— 你没法控制它的每一个动作。它改了代码你希望自动格式化,它执行 Bash 命令你希望做安全检查,它写完文件你希望扫描有没有泄露密钥……
如果你有前端经验,你一定熟悉 Vue 的 mounted、beforeDestroy 这些生命周期钩子;如果你写过后端,Spring 的 @Before、@After AOP 切面肯定不陌生。它们的共同本质是:在特定事件节点,注入自定义逻辑。 Claude Code 的 Hook 机制,做的正是这件事。
今天这篇文章,我会基于 Anthropic 官方文档和 GitHub 热门教程 claude-howto,用你最熟悉的前后端概念做类比,带你彻底搞懂 Claude Code 的 Hook 机制,并给出 6 个可以直接复制使用的实战配置。
Hook = 在特定事件发生时,自动执行你预设的逻辑。
不管是 Vue、Spring 还是 Claude Code,核心思想一模一样:
mounted()、
updated() 组件生命周期的回调函数 React
useEffect(() => {}, []) 函数组件的副作用钩子 Spring
@Before、
@AfterReturning AOP 切面,拦截方法调用前后
Claude Code
PreToolUse、
PostToolUse
工具调用生命周期的事件钩子
用一张图理解 Claude Code 的 Hook 工作流:

看到了吗?这和 Spring AOP 的 @Before → 方法执行 → @After 思路非常相似。
Claude Code 提供了四种 Hook 类型,满足不同场景:
重点区别:prompt 只能”想”,agent 能”想”还能”做”。比如你要验证代码是否通过测试,prompt 只能看文本判断,agent 可以真的跑一遍测试。
上下文获取方式:不同类型获取事件上下文的方式不同:
command 通过
stdin 接收 JSON(用
cat 读取)
input=\((cat)
http POST 请求的
body 中携带 JSON 服务端从 request body 解析
prompt 模板变量
\)ARGUMENTS 自动注入
“prompt”: “检查任务是否完成。\(ARGUMENTS"
agent 模板变量
\)ARGUMENTS 自动注入
“prompt”: “跑一遍测试。\(ARGUMENTS"
其中 \)ARGUMENTS 是 Claude Code 的内置模板变量,运行时会被替换为当前 Hook 事件的 JSON 输入数据(包含会话 ID、工具名、工具参数等字段,具体内容因事件类型而异)。如果 prompt 字符串中没有写 $ARGUMENTS,JSON 输入会自动追加到 prompt 末尾。这样 LLM 就能基于真实的事件上下**判断,而不是只靠你写的静态 prompt。
Claude Code 目前支持 26 个 Hook 事件,按阶段分为 7 组。先看全景图,有个整体印象:

上图从上到下就是一次 Claude Code 会话的完整生命周期。我按组快速过一下各自的职责:
🔄 会话生命周期(6 个):管理会话本身的状态 —— 启动、结束、加载配置、切换目录、监听文件变化。大多数不可拦截,属于”通知型”事件。
🔧 工具调用生命周期(5 个):这是最核心的一组。PreToolUse 在工具执行前拦截(类比 @Before),PostToolUse 在执行后追加上下文(类比 @AfterReturning),PostToolUseFailure 处理异常(类比 @AfterThrowing)。日常 80% 的 Hook 都挂在这里。
🤖 子代理与团队(3 个):当 Claude Code 启动子代理或团队协作时触发。SubagentStop 可以拦截子代理的输出,TeammateIdle 可以在队友空闲时分配新任务。
📝 用户交互(2 个):UserPromptSubmit 是用户提交提示词时的”入口检查”,可以在这里拦截危险操作意图(比如”删库跑路”)。
🛑 停止与收尾(4 个):Stop 是 Claude Code 完成回复时的”出口检查”,可以用 prompt 类型让 AI 自己审查是否真的完成了任务。
🌲 Worktree 与压缩(4 个):管理 Git Worktree 和上下文压缩。PreCompact 可以在压缩前注入需要保留的关键信息。
🔗 MCP 交互(2 个):当 MCP 服务器请求用户输入时触发,适合做输入校验或自动填充。
记忆技巧:安全拦截和自动化这块,重点掌握
PreToolUse、PostToolUse、UserPromptSubmit和Stop这四个事件就能覆盖大部分场景。但其他事件同样有实战价值 —— 比如SessionStart常被用来注入会话历史上下文,Notification用来做桌面通知提醒,SubagentStop用来审查子代理输出。按需取用就好。
🛡️ 场景一:PreToolUse 拦截危险 Bash 命令
类比:Spring 的 @Before 权限校验切面,方法执行前先检查权限。
在 Claude Code 执行 Bash 命令之前,先检查命令是否危险。
配置 settings.json:
{ “hooks”: {
"PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "bash "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-check.sh"" } ] } ]
} }
对应的拦截脚本:
#!/bin/bash # 文件:.claude/hooks/pre-tool-check.sh
input=\((cat) command=\)(echo “$input” | jq -r ’.tool_input.command’)
# 🚫 直接拦截的危险命令(使用 grep -F 做字面量匹配) blocked_patterns=( “rm -rf /” “rm -rf /*” ”:(){ :|:& };:” “mkfs.” “dd if=/dev/zero” “dd if=/dev/random” )
for pattern in “\({blocked_patterns[@]}"; do if echo "\)command” | grep -qF “$pattern”; then
echo "}" exit 0
fi done
# ⚠️ 警告但放行的命令(使用 grep -E 做正则匹配) warn_patterns=(“rm -rf” “git push –force” “git reset –hard” “DROP TABLE” “sudo rm”)
for pattern in “\({warn_patterns[@]}"; do if echo "\)command” | grep -qE “$pattern”; then
echo "}" exit 0
fi done
exit 0
✨ 场景二:PostToolUse 自动格式化代码
类比:Vue 的 updated() 钩子,DOM 更新后自动执行副作用。
每次 Claude Code 用 Write 或 Edit 工具修改文件后,自动运行格式化工具:
{ “hooks”: {
"PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "bash "$CLAUDE_PROJECT_DIR/.claude/hooks/format-code.sh"" } ] } ]
} }
对应的格式化脚本:
#!/bin/bash # 文件:.claude/hooks/format-code.sh
input=\((cat) file_path=\)(echo “\(input" | jq -r '.tool_input.file_path') ext="\){file_path*.}”
case “\(ext" in js|ts|jsx|tsx) npx prettier --write "\)file_path” 2>/dev/null ;; py) python3 -m black “\(file_path" 2>/dev/null ;; go) gofmt -w "\)file_path” 2>/dev/null ;; java) google-java-format -i “\(file_path" 2>/dev/null ;; rs) rustfmt "\)file_path” 2>/dev/null ;; esac
exit 0
效果:Claude Code 写的代码永远保持格式统一,再也不用人工跑 formatter。
🔍 场景三:PostToolUse 安全扫描
类比:Spring 的 @AfterReturning 日志切面,方法正常返回后记录日志。
扫描 Claude Code 写入的文件,检测是否包含硬编码的密钥和密码。
配置 settings.json:
{ “hooks”: {
"PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "bash "$CLAUDE_PROJECT_DIR/.claude/hooks/security-scan.sh"" } ] } ]
} }
对应的安全扫描脚本:
#!/bin/bash # 文件:.claude/hooks/security-scan.sh
input=\((cat) file_path=\)(echo “$input” | jq -r ’.tool_input.file_path’)
# 跳过敏感目录 [[ “$file_path” =~ .env|.git/ ]] && exit 0
warnings=””
# 检查常见密钥模式(注意:macOS BSD grep 不支持 x27,用单引号变量代替) QUOTE=”‘” if grep -qE ”(password|passwd|pwd)s=s[“\({QUOTE}][^"\){QUOTE}]+[”\({QUOTE}]" "\)file_path“ 2>/dev/null; then warnings+=“⚠️ 发现硬编码密码 ” fi
if grep -qE ”(api_key|apikey|secret_key|access_token)s=s[“\({QUOTE}][^"\){QUOTE}]+[”\({QUOTE}]" "\)file_path“ 2>/dev/null; then warnings+=“⚠️ 发现硬编码 API 密钥 ” fi
if grep -qE ’—–BEGIN (RSA |EC )?PRIVATE KEY—–’ “$file_path” 2>/dev/null; then warnings+=“🚨 发现私钥文件 ” fi
if [ -n “$warnings” ]; then # 以 additionalContext 形式返回,不阻断流程 echo ”}” fi
exit 0
📊 场景四:Stop 用 prompt hook 检查任务完成度
类比:这在 Vue/Spring 中没有直接对应,这是 Claude Code 独有的 —— 让 AI 自己审自己。
当 Claude Code 认为自己完成工作时,让 LLM 再评估一遍:
{ “hooks”: {
"Stop": [ { "hooks": [ { "type": "prompt", "prompt": "请评估 Claude 是否完成了用户要求的所有任务。检查以下几点:1) 是否所有文件都已修改 2) 是否有遗漏的功能 3) 测试是否通过。如果任务未完成,说明还差什么。$ARGUMENTS", "timeout": 30 } ] } ]
} }
更强大的 agent 版本:真的跑一遍测试来验证:
{ “hooks”: {
"Stop": [ { "hooks": [ { "type": "agent", "prompt": "运行项目测试套件,验证所有测试是否通过。如果有失败的测试,报告失败原因。$ARGUMENTS", "timeout": 120 } ] } ]
} }
🔔 场景五:Notification 桌面通知
类比:Vue 的 watch 响应式监听,数据变化时触发回调。
当 Claude Code 需要你的注意时(比如权限弹窗、长时间等待),发送 macOS 桌面通知:
] } ]
} }
Linux 用户替换为:
“command”: “notify-send ‘Claude Code’ ‘需要你的关注’”
📝 场景六:UserPromptSubmit 拦截危险提示词
在用户提交提示词时就拦截危险操作意图。
配置 settings.json:
{ “hooks”: {
"UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "bash "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-prompt.sh"" } ] } ]
} }
对应的提示词校验脚本:
#!/bin/bash # 文件:.claude/hooks/validate-prompt.sh
input=\((cat) prompt=\)(echo “$input” | jq -r ’.prompt’)
blocked_keywords=(“删除数据库” “drop database” “rm -rf /” “format c:” “删库跑路”)
for keyword in “\({blocked_keywords[@]}"; do if echo "\)prompt” | grep -qi “$keyword”; then
echo "{"decision":"block","reason":"⛔ 你的提示词包含危险操作: $keyword,已被安全钩子拦截。"}" >&2 exit 2
fi done
exit 0
配置文件位置
Hooks 可以配置在多个位置,优先级从高到低:
~/.claude/settings.json 所有项目 否(个人设置)
.claude/settings.json 当前项目 是(团队共享)
.claude/settings.local.json 当前项目 否(本地覆盖)
核心配置结构
{ “hooks”: {
"事件名称": [ { "matcher": "工具名模式", "hooks": [ { "type": "command", "command": "你的脚本路径", "timeout": 60 } ] } ]
} }
Matcher 模式规则
注意:
UserPromptSubmit、Stop、TeammateIdle、TaskCreated、TaskCompleted、WorktreeCreate、WorktreeRemove、CwdChanged这些事件不支持 matcher,每次触发时都会执行,配置了 matcher 也会被静默忽略。Matcher 主要用于工具类事件(如PreToolUse、PostToolUse等)。
“Write” 多选匹配 管道符分隔
“Edit|Write” 正则匹配 包含特殊字符则按正则解析
”^Notebook” 通配符 匹配所有
“” 或
”” MCP 工具 匹配 MCP 服务器工具
“mcpmemory.”
Hook 脚本的核心机制
输入:通过 stdin 接收 JSON,包含工具名、参数、会话 ID 等。
输出:通过 exit code 和 JSON stdout 控制行为:
exit 0→ 继续(stdout 会被解析为 JSON,可通过hookSpecificOutput返回决策)exit 2→ 阻断操作(stderr 会显示为错误信息)- 其他 exit code → 非阻断错误,继续执行
环境变量:
\(CLAUDE_PROJECT_DIR— 项目根目录的绝对路径(所有 command hook 均可用)\)CLAUDE_ENV_FILE— 用于持久化环境变量的文件路径(仅在SessionStart、CwdChanged、FileChanged事件的 command hook 中可用)
快速上手步骤
# 1. 创建 hooks 目录 mkdir -p .claude/hooks
# 2. 复制你需要的脚本 # (从上面六个场景中选)
# 3. 赋予执行权限 chmod +x .claude/hooks/*.sh
# 4. 配置 settings.json # (把对应的 JSON 配置加进去)
# 5. 测试 Hook echo ’{“tool_name”:“Bash”,“tool_input”:{“command”:“rm -rf /”}}’ | bash .claude/hooks/pre-tool-check.sh echo $? # 应该输出 2(被拦截)
Hook 机制是 Claude Code 从”AI 黑盒”变成”可控流程”的关键桥梁。
回顾一下我们今天讲的:
- Hook 的本质就是事件驱动的回调,和你熟悉的 Vue 生命周期、Spring AOP 是同一个思路
- 四个核心事件覆盖 80% 场景:
PreToolUse(执行前拦截)、PostToolUse(执行后处理)、UserPromptSubmit(输入校验)、Stop(完成检查) - 四种 Hook 类型满足不同需求:command(最通用)、http(对接外部系统)、prompt(AI 自评)、agent(AI 自验证)
- 六个实战配置可以直接复制到你的项目中使用
正如 Spring AOP 让企业级应用有了统一的事务管理和安全控制,Claude Code 的 Hook 让 AI 编程有了安全网和质量门。
你不需要每件事都盯着 AI 做 —— 配好 Hook,让它在你设定的规则里自由发挥就好。
参考资料:
欢迎关注公众号 FishTech Notes,一块交流使用心得!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/265755.html