news 2026/9/28 19:26:13

【Claude Code理论篇】Hooks 事件驱动自动化钩子:settings.json 配置骨架与触发验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Claude Code理论篇】Hooks 事件驱动自动化钩子:settings.json 配置骨架与触发验证

1. 为什么你的 Claude Code 需要 Hooks

如果你已经在用 Claude Code 写代码,大概率遇到过这几个场景:Claude 改完一个 TypeScript 文件,你手动跑一遍 ESLint 才发现它引入了一个未使用的变量;Claude 准备往.env里写东西,你眼疾手快按了 Esc;一个长任务跑完,你盯着终端等它结束,就为了确认有没有报错。

这些问题的共同点是:它们不是"对话"能解决的。你可以在 CLAUDE.md 里写"改完文件记得跑 lint",但 Claude 不一定每次都照做;你可以每次手动检查,但你不可能永远记得。真正需要的是——当某个事件发生时,自动触发一段你写好的逻辑。这就是 Claude Code Hooks 要干的事。

Hooks 是 Claude Code 的事件驱动自动化机制:当 Claude Code 内部发生特定事件(调用工具、发送通知、结束回复等)时,自动执行你指定的 shell 命令。它和 Git 的 pre-commit / post-commit 钩子思路一致,只是把触发对象从 Git 操作换成了 Claude Code 的操作。更关键的是,Hook 的退出码可以反向影响 Claude 的行为——返回非零退出码时,Claude 的操作会被拦截,它会收到你的反馈并调整后续动作。这不是被动日志,而是主动的流程控制。

这篇是理论篇,重点放在 settings.json 的配置骨架、事件触发链路和逐条验证方法上。我会给出可直接复制的配置片段,以及每个 Hook 怎么确认它真的被触发了。适合已经用过 Claude Code、想进一步做自动化的开发者。

2. TaoToken 前置:把模型接入层先跑通

在配 Hooks 之前,得先确保 Claude Code 本身能正常跑起来。Claude Code 需要一个可用的模型接入端点,TaoToken 提供的就是这一层——它兼容 Anthropic 的接口协议,你拿到 API Key 后填进环境变量即可。

官网入口:https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=

API 地址(不带 UTM):https://taotoken.net/api

具体操作分两步。第一步,去控制台创建 API Key:

  • 控制台:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
  • API Keys 管理页:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite

第二步,把 Key 写进环境变量。Claude Code 读取的是ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL这两个变量:

export ANTHROPIC_API_KEY="你的_taotoken_key" export ANTHROPIC_BASE_URL="https://taotoken.net/api"

如果你用的是 zsh,把这两行加到~/.zshrc;bash 就加到~/.bashrc。加完执行source ~/.zshrc让它生效。验证接入是否正常,可以直接跑一次模型对话:

  • 模型对话入口:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite

能正常返回内容,说明接入层没问题,接下来配 Hooks 才有意义。如果你打算长期用 Claude Code 做编码和 Agent 任务,Coding Plan 会更划算:

  • Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite

3. settings.json 配置骨架:从零搭一个可用的 Hook

Hooks 的配置全部写在settings.json里,有两个位置可选:

位置作用域适合放什么
~/.claude/settings.json全局,所有项目生效安全类规则,如敏感文件保护
项目根目录.claude/settings.json仅当前项目生效项目特定规则,如跑某个 linter

两个位置都配了同一类 Hook 时,两边都会执行,不会互相覆盖。安全类的建议放全局,项目相关的放项目级。

3.1 最小配置结构

一个完整的 Hook 配置长这样:

{ "hooks": { "PreToolUse": [ { "matcher": "Edit", "hooks": [ { "type": "command", "command": "bash ~/.claude/hooks/guard-sensitive.sh" } ] } ] } }

层级看起来深,其实只回答三个问题:外层 key 是"什么时候触发"(这里是 PreToolUse,Claude 动手之前);matcher是"对哪个工具触发"(这里是 Edit,只在编辑文件时);command是"触发后执行什么"(跑你写的脚本)。matcher可以不写,不写表示不管 Claude 用什么工具都触发。

3.2 五种事件与触发链路

Claude Code 目前支持五种 Hook 事件,它们不是平级的:

事件触发时机典型用途
PreToolUseClaude 调用工具之前拦截危险操作、校验参数
PostToolUseClaude 调用工具之后自动 lint、格式化、测试
NotificationClaude 发送通知时转发到 Slack、桌面通知
StopClaude 结束回复时自动化收尾工作
SubagentStop子代理结束时监控子任务完成状态

PreToolUse 和 PostToolUse 围绕"工具执行"这条主线,是最精细的控制点。Claude Code 的大部分操作——编辑文件用 Edit 工具、写新文件用 Write 工具、跑命令用 Bash 工具——都是工具调用,你可以在这些操作前后精确插入逻辑。Notification 和 Stop 则是独立于具体工具的全局事件,适合做收尾和通知。

3.3 脚本的输入与输出

Hook 触发时,Claude Code 会往你的脚本 stdin 输入一段 JSON,告诉你"我正在做什么"。比如 Claude 要编辑文件,你收到的数据大概是这样:

{ "tool_name": "Edit", "tool_input": { "file_path": "/path/to/file.ts", "old_string": "...", "new_string": "..." } }

你的脚本从这段 JSON 里提取信息(比如取出file_path判断是不是敏感文件),然后通过两种方式给 Claude 反馈。第一种是打印文字,脚本里echo出来的内容会被 Claude 看到。第二种是退出码,这是最关键的控制信号:

退出码PreToolUse(动手前)PostToolUse(做完后)
0允许操作反馈给 Claude
非 0阻止操作(文件不会被改)告诉 Claude 有问题(但操作已执行)

注意这个区别:PreToolUse 的非零退出码会真正阻止操作,文件不会被修改;PostToolUse 的非零退出码只是告诉 Claude"后处理发现了问题",因为操作已经执行完了。

4. 可复制配置:三个实战 Hook 片段

下面给三个能直接用的配置,覆盖拦截、后处理和通知三类场景。

4.1 拦截敏感文件写入

在全局~/.claude/settings.json里配一个 PreToolUse,拦截对.env、.pem等敏感文件的编辑:

{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "bash ~/.claude/hooks/guard-sensitive.sh" } ] } ] } }

对应的~/.claude/hooks/guard-sensitive.sh:

#!/usr/bin/env bash set -euo pipefail input=$(cat) file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty') if [[ -z "$file_path" ]]; then exit 0 fi case "$file_path" in *.env|*.env.*|*.pem|*.key|*id_rsa*) echo "拦截:$file_path 属于敏感文件,不允许自动修改。请人工确认。" exit 2 ;; *) exit 0 ;; esac

matcher用了Edit|Write,表示编辑和写文件都触发。退出码用 2 而不是 1,是因为 Claude Code 对非零退出码都会拦截,但 2 在部分版本里会作为"阻塞性错误"处理,反馈更明确。

4.2 编辑后自动跑 lint

在项目级.claude/settings.json里配 PostToolUse,Claude 改完.ts文件后自动跑 ESLint:

{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "bash .claude/hooks/lint-changed.sh" } ] } ] } }

.claude/hooks/lint-changed.sh:

#!/usr/bin/env bash set -euo pipefail input=$(cat) file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty') if [[ "$file_path" != *.ts && "$file_path" != *.tsx ]]; then exit 0 fi if [[ ! -f "$file_path" ]]; then exit 0 fi if ! npx eslint "$file_path" 2>&1; then echo "ESLint 在 $file_path 上发现问题,请修复后再继续。" exit 1 fi exit 0

这里退出码用 1,因为 PostToolUse 阶段文件已经改完了,非零退出码的作用是让 Claude 知道"后处理有问题",它会读到 ESLint 的输出并尝试修复。

4.3 任务结束发通知

Stop 事件在 Claude 结束回复时触发,适合做收尾通知:

{ "hooks": { "Stop": [ { "hooks": [ { "type": "command", "command": "bash ~/.claude/hooks/notify-done.sh" } ] } ] } }

~/.claude/hooks/notify-done.sh:

#!/usr/bin/env bash set -euo pipefail input=$(cat) session_id=$(echo "$input" | jq -r '.session_id // "unknown"') # macOS 桌面通知 if command -v osascript >/dev/null 2>&1; then osascript -e "display notification \"会话 $session_id 已完成\" with title \"Claude Code\"" fi # Linux 桌面通知 if command -v notify-send >/dev/null 2>&1; then notify-send "Claude Code" "会话 $session_id 已完成" fi exit 0

Stop 事件的 Hook 不需要matcher,因为它不针对具体工具。

5. 逐条触发验证:确认 Hook 真的跑了

配好不等于生效。下面给每个 Hook 的验证动作,确保触发链路是通的。

5.1 先手动模拟脚本

在写进配置之前,先用管道模拟一次输入,确认脚本能正确解析 JSON、返回正确退出码:

echo '{"tool_name":"Edit","tool_input":{"file_path":"/tmp/test.env"}}' | bash ~/.claude/hooks/guard-sensitive.sh echo "退出码: $?"

预期输出是拦截信息,退出码为 2。如果退出码是 0,说明case匹配没生效,检查file_path的提取是否正确。

5.2 验证 PreToolUse 拦截

在 Claude Code 里让它编辑一个.env文件,比如:

帮我在 .env 里加一行 DEBUG=true

如果 Hook 生效,Claude 会收到拦截反馈,不会真的修改文件。你可以用cat .env确认内容没变。如果文件被改了,说明 Hook 没触发——检查settings.json的 JSON 格式是否合法(用jq . ~/.claude/settings.json验证),以及matcher是否写对。

5.3 验证 PostToolUse 后处理

让 Claude 改一个.ts文件,故意引入一个未使用变量:

在 src/utils.ts 里加一个 const unused = 1;

如果 lint Hook 生效,Claude 会在编辑后收到 ESLint 的报错,并尝试修复。你可以在 Claude 的回复里看到它引用了 ESLint 的输出。如果没反应,先确认npx eslint在项目里能跑通,再检查脚本里的文件路径判断。

5.4 验证 Stop 通知

随便让 Claude 完成一个小任务,比如"列出当前目录的文件"。任务结束后,桌面应该弹出通知。如果没弹,检查osascript或notify-send是否可用,以及脚本是否有执行权限(chmod +x)。

5.5 用日志确认触发

如果以上都不确定,可以在脚本开头加一行日志:

echo "$(date) Hook triggered: $0" >> /tmp/claude-hooks.log

跑几次操作后cat /tmp/claude-hooks.log,能看到记录就说明 Hook 被调用了,问题出在脚本逻辑而不是配置。

6. 常见错排查:Hook 不触发怎么办

配 Hooks 最容易踩的坑集中在几个地方,按这个顺序排查基本能定位。

JSON 格式错误。settings.json对格式很严格,多一个逗号、少一个引号都会导致整个文件被忽略。用jq . ~/.claude/settings.json验证,报错就说明格式有问题。注意hooks是顶层 key,不要嵌套错位置。

matcher 写错。matcher匹配的是工具名,不是文件名。Edit 工具对应"Edit",Write 对应"Write",Bash 对应"Bash"。想匹配多个用|分隔,比如"Edit|Write"。写成"*.ts"是无效的,它不会按文件扩展名匹配。

脚本没有执行权限。用bash script.sh调用时不需要执行权限,但如果你在command里直接写脚本路径(不带bash),就需要chmod +x。建议统一用bash /path/to/script.sh的形式,避免权限问题。

jq 没装。几乎所有 Hook 脚本都依赖 jq 解析 JSON。Ubuntu 用sudo apt install jq,macOS 用brew install jq。脚本里jq命令找不到时,set -e会让脚本直接退出,表现为 Hook "没反应"。

执行时间过长。Hook 是同步执行的,跑完之前 Claude 会一直等。一个 3 秒的 lint 没问题,30 秒的全量测试就不合适了。长时间检查应该放到 CI,Hook 里只做快速校验。如果发现 Claude 响应变慢,先检查 Hook 脚本的执行时间。

全局和项目配置冲突。两边都配了同一事件时都会执行,不会冲突,但如果你只想让项目级生效,记得全局那份要删掉或改条件。安全类 Hook 建议放全局,项目特定的放项目级。

退出码理解错。PreToolUse 返回非零会阻止操作,PostToolUse 返回非零不会撤销已执行的操作,只是给 Claude 反馈。如果你在 PostToolUse 里期望"拦截",那是做不到的,得用 PreToolUse。

排查完还是不行,可以去接入文档对照配置示例:

  • 接入文档:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite

如果你在用 Claude Code 做长期编码或 Agent 任务,Hooks 配合 Coding Plan 能把重复性监督真正交出去:

  • Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite

配 Hooks 的顺序建议是:先手动模拟脚本确认逻辑,再写进 settings.json,然后用日志确认触发,最后才依赖它做拦截。跳过手动验证直接配,出问题时你分不清是配置错还是脚本错。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 19:25:38

前端持续交付与全链路质量守卫周盘点:OpenTelemetry 跨端 Trace、全链路压测染色与 Playwright 视觉回归

在现代高频敏捷交付与微服务持续集成的工程实践中,研发团队最渴望达成的终极交付目标是:“代码每天持续合入上百次,但线上系统永远如磐石般稳定,零视觉样式退化、零未感知性能滑坡、零未经验证的容量盲区”。 在过去的一周中&…

作者头像 李华
网站建设 2026/9/28 19:25:34

DeltaV VE4022 Profibus DP主站卡:选型、组态与现场排查实战

上个月在西南一个精细化工项目上做开车前检查,业主仪表车间主任指着机柜间里一条刚敷设好的紫红色通信电缆问我:DeltaV里面明明有FF H1卡,为啥还要单独装这块VE4022,它到底是管什么的?这个问题问得挺典型。很多做了好几…

作者头像 李华
网站建设 2026/9/28 19:25:22

DCS现场控制站八大核心硬件详解:从控制器到I/O卡件

DCS现场控制站是分散控制系统中最贴近生产过程的一层,也是决定系统可靠性、实时性和控制品质的核心节点。很多朋友刚接触DCS时,第一眼看到机柜里密密麻麻的卡件往往一头雾水:电源模块、控制器、通信卡、AI/AO、DI/DO,每样东西干什…

作者头像 李华