Claude Code 中的 Hooks 机制

Claude Code 中的 Hooks 机制 一、Hooks 的核心定位Claude Code Hooks 是一套面向 AI Agent 执行生命周期的事件驱动扩展机制。它允许在工具执行、任务创建、执行前后等关键节点注入自定义逻辑从而实现对 Claude 工作流的约束与自动化增强。其运行机制如下● 事件监听Claude 在特定 Agent 生命周期节点如工具调用前后、任务创建等触发 Hook 事件● 脚本执行系统根据配置调用本地或远程脚本● 上下文注入脚本通过标准 JSON 输入获取当前执行上下文● 结果反馈脚本通过退出码与结构化输出影响工具执行结果如阻断执行、修改参数或返回提示信息二、hooks配置文件项目级别的 Claude Code 的 Hooks 配置通常放在.claude/settings.json示例json:{ hooks: { 事件名: [ { matcher: 工具匹配, if: 条件过滤, hooks: [ { type: command, command: 执行脚本, timeout: 10 } ] } ] } }matcher 与 if 的区别matcher监听哪个工具表示 只监听 Bash 工具matcher: Bash表示 监听文件写入类工具matcher: Write|Edit表示监听 GitHub MCP 工具matcher: mcp__github__.*if这个工具的哪些调用才触发表示Bash 工具里 只有 git push 才触发if: Bash(git push*)二者同时满足才执行matcher 工具级过滤 if 调用级过滤三、核心的Hook Event3.1 Hook的输入机制Claude 内部事件发生 ↓ 构造 JSON payload ↓ 写入 hook 程序 stdin ↓ 执行你的脚本 ↓ 读取 stdout/exit code/stderr ↓ 决定是否阻断/附加信息/继续执行 exitcode2表示阻止执行 exitcode0继续执行3.2 PreToolUse主要在工具执行前触发用于校验、拦截、做安全限制例如禁止 rm -rf禁止生产库操作禁止 git push main限制 curl 外网setting.json{ hooks: { PreToolUse: [ { matcher: Bash, hooks: [ { type: command, command: python3 .claude/hooks/check-dangerous.py } ] } ] } }check-dangerous.pyimportjsonimportsysimportos datajson.load(sys.stdin)cmddata.get(tool_input,{}).get(command,)log_pathos.path.join(os.path.dirname(__file__),hook.log)withopen(log_path,a,encodingutf-8)asf:f.write(f[HOOK RUNNING] cmd{cmd}\n)f.write(f[RAW DATA]{json.dumps(data,ensure_asciiFalse)}\n)dangerous[rm -rf,sudo ,git push origin main]fordindangerous:ifdincmd:withopen(log_path,a,encodingutf-8)asf:f.write(f[BLOCKED] dangerous command:{cmd}\n)print(fBlocked dangerous command:{cmd},filesys.stderr)sys.exit(2)withopen(log_path,a,encodingutf-8)asf:f.write(f[ALLOWED] cmd{cmd}\n)sys.exit(0)如果Claude 想执行rm -rf node_modules直接被拦截Blocked dangerous command3.3 PostToolUse主要在工具执行后触发。当 Claude 调用的某个 tool如 Bash / Write / Edit / MCP执行完成之后立刻触发。 主要用于自动 lint自动 format自动记录自动补充上下文setting.json{hooks:{PostToolUse:[{matcher:Write|Edit,hooks:[{type:command,command:bash .claude/hooks/auto-lint.sh}]}]}}auto-lint.sh#!/bin/bash npm run eslint npm run prettier3.4 UserPromptSubmit用户输入后、Claude 处理前触发。主要用于Prompt 改写自动注入规范自动增加上下文敏感词过滤setting.json{hooks:{UserPromptSubmit:[{matcher:.*,hooks:[{type:command,command:python3 .claude/hooks/inject-rules.py}]}]}}inject-rules.pyimportjsonimportsys datajson.loads(sys.stdin.read())promptdata.get(prompt,)rules 【团队规范】 1. 不允许修改 public API 2. 必须兼容 Vue2 3. 必须写中文注释 if【团队规范】notinprompt:data[prompt]promptrulesprint(json.dumps(data),flushTrue)3.5 StopClaude 回复结束后触发。主要用于最终检查自动测试自动总结自动提交日志setting.json{hooks:{Stop:[{matcher:.*,hooks:[{type:command,command:bash .claude/hooks/run-test.sh}]}]}}run-test.sh#!/bin/bash echo Running tests... mvn test3.6 CwdChanged主要用于目录变化触发 自动切换环境例如自动切换 Python venv自动加载 .env自动切换 MCP 配置settings.json{ hooks: { CwdChanged: [ { matcher: .*, hooks: [ { type: command, command: bash .claude/hooks/load-env.sh } ] } ] } }load-env.sh#!/bin/bash if [ -f .env ]; then export $(cat .env | xargs) fi3.7 TaskCreated创建子任务时触发。setting.json{hooks:{TaskCreated:[{matcher:.*,hooks:[{type:command,command:python3 .claude/hooks/log-task.py}]}]}}log-task.pyimportjsonimportsys datajson.load(sys.stdin)print( Task Created )print(json.dumps(data,indent2))3.8 WorktreeCreate当 Claude 遇到复杂任务比如 它可能不会在一个环境里做而是拆成多个“并行 Agent”例如Agent A重构 serviceAgent B修 bugAgent C写测试Agent D性能优化每个 Agent 会有不同的worktreesetting.json{hooks:{WorktreeCreate:[{matcher:.*,hooks:[{type:command,command:python3 .claude/hooks/log-worktree.py}]}]}}log-worktree.pyimportjsonimportsys datajson.load(sys.stdin)wtdata.get(worktree,{})print(Worktree created:)print(Path:,wt.get(path))print(Branch:,wt.get(branch))print(Task:,wt.get(task_id))3.9 PreCompactClaude context 满了会压缩。PreCompact压缩前触发也可以阻止压缩主要用于snapshot保存上下文防止关键上下文丢失setting.json{ hooks: { PreCompact: [ { matcher: auto, hooks: [ { type: command, command: python3 .claude/hooks/prevent-compact.py } ] } ] } }** prevent-compact.py **importjsonprint(json.dumps({decision:block,reason:大型重构进行中禁止压缩上下文}))四、Hook TypeHook 的执行方式Claude Hooks 目前支持 5 类型command prompt agent http mcp_tool4.1 command hook用于执行本地的命令比如shellpythonnodebash4.2 prompt hook它不是跑脚本而是再调用一次模型来做判断Claude执行任务完成了但你想强制它检查有没有改完所有文件测试有没有通过是否遗漏 TODO{ hooks: { Stop: [ { hooks: [ { type: prompt, prompt: 检查当前任务是否真的完成1.所有相关文件是否修改完整2.是否遗漏测试3.是否存在未解决的 TODO 或报错如果未完成请列出缺失点并要求继续工作。, timeout: 30 } ] } ] } }4.3 agent hook这个是 直接启动一个“子agent”去完成一整套验证流程 比较重量级。比如Claude 改完代码后开启一个自动重构验证 agent。{ hooks: { Stop: [ { hooks: [ { type: agent, prompt: 检查当前代码是否符合 Clean ArchitectureController/Service/Repository 是否分层正确是否存在跨层调用如果不符合请指出具体文件和修改建议。 } ] } ] } }4.4. http hook把 hook 事件“转发到远程 HTTP 服务”的机制 POST JSON 到远程服务{ hooks: { PostToolUse: [ { hooks: [ { type: http, url: https://api.my-company.com/claude/hooks } ] } ] } }4.5 mcp_tool hook用 Claude 的 MCP 工具系统来执行 hook 动作 。比如 Claude 完成任务后发 Slack 消息 。{ hooks: { Stop: [ { hooks: [ { type: mcp_tool, server: slack, tool: send_message, input: { channel: #deploys, text: Claude finished the task } } ] } ] } }五、Skill Scoped HooksHook 不一定是全局生效的它可以只在某个 Claude Skill 运行期间才触发的 Hooks5.1 普通 Hook vs Skill Hook1. 全局 Hook默认任何 Bash 都会触发{ hooks: { PreToolUse: [ { matcher: Bash, hooks: [ { type: command, command: ./check.sh } ] } ] } }2. Skill Scoped Hook局部在 Skill 内定义--- name: production-deploy hooks: PreToolUse: - matcher: Bash hooks: - type: command command: ./scripts/production-safety-check.sh once: true ---执行范围类型作用范围Global hook所有对话Skill hook仅当前 skill六、once: true这个 hook 在一个 session会话里只执行一次 防止这个 hook 在同一轮 Claude 工作流里重复触发{ type: command, command: ./init-check.sh, once: true }主要用于环境检查初始化login初始化环境检查{ hooks: { PreToolUse: [ { matcher: Bash, hooks: [ { type: command, command: ./scripts/check-env.sh, once: true } ] } ] } }check-env.sh#!/bin/bashechoChecking environment...if[!-f.env];thenechoMissing .env fileexit2fi