$catMANUAL||~26 min

Claude Code Hooks 实战:5 个让我效率翻倍的自动化配置

advertisement

Claude Code Hooks 实战:5 个让我效率翻倍的自动化配置

用 Claude Code 写代码已经几个月了,最大的感受不是它有多聪明,而是它有多"听话"——你让它干啥它就干啥,但问题是,有些事情你得反复提醒它。

比如每次改完代码不格式化、动了 .env 文件你都不知道、context 压缩之后关键信息丢了……这些事你当然可以每次都手动处理,但说实话,烦。

直到我发现了 Hooks。

Hooks 是什么

简单说,Hooks 就是 Claude Code 生命周期里的"钩子"。你可以在特定时间点自动执行 shell 命令,比如:

  • Claude 改完文件后自动跑格式化
  • Claude 要执行危险命令前自动拦截
  • Claude 等你输入时发桌面通知
  • 上下文压缩后自动注入关键信息

跟 Git Hooks 是一个思路——你不用每次手动 git addgit commit,pre-commit hook 帮你干了。Claude Code Hooks 也是这个逻辑:把重复性的、需要强制执行的操作自动化掉。

我的 5 个实战 Hook

下面这 5 个是我每天都在用的,配置文件放在 ~/.claude/settings.json 里(全局生效)或者项目目录的 .claude/settings.json(只对当前项目生效)。

1. 桌面通知:再也不用盯着终端了

这是我配的第一个 Hook。用 Claude Code 写代码的时候,经常是让它跑着,我切到浏览器查东西。结果它早就跑完了,在那等我输入,我过了五分钟才切回终端看到。效率拉满。

配了通知之后,Claude 一完成任务或者需要我确认权限,系统就弹通知,我秒切回去。

json
1
{
2
  "hooks": {
3
    "Notification": [
4
      {
5
        "matcher": "",
6
        "hooks": [
7
          {
8
            "type": "command",
9
            "command": "notify-send 'Claude Code' '等你输入了'"
10
          }
11
        ]
12
      }
13
    ]
14
  }
15
}

Linux 用 notify-send,macOS 用 osascript -e 'display notification "Claude Code 等你了" with title "Claude Code"',Windows 用 PowerShell。

matcher 留空表示所有通知类型都触发。你也可以只监听特定类型:

  • permission_prompt:需要你批准工具调用
  • idle_prompt:完成任务等你下一步指令
  • auth_success:认证完成

2. 自动格式化:改完代码不用手动 prettier

Claude 写代码挺快的,但格式不一定完全符合你的项目规范。以前我都是它改完文件,我再手动跑一遍 prettier --write。现在不用了。

json
1
{
2
  "hooks": {
3
    "PostToolUse": [
4
      {
5
        "matcher": "Edit|Write",
6
        "hooks": [
7
          {
8
            "type": "command",
9
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
10
          }
11
        ]
12
      }
13
    ]
14
  }
15
}

PostToolUse 是工具调用之后触发,matcherEdit|Write,意思是只在 Claude 编辑或写入文件后才跑。jq 从 hook 的输入 JSON 里提取文件路径,然后传给 prettier。

这个配置用下来最大的好处是:Claude 改什么文件,什么文件就自动格式化,完全无感。你不配这个的话,要么手动跑,要么在 CLAUDE.md 里写"每次改完文件都要跑 prettier"——但那是靠 LLM 自觉,不如 hook 靠谱。

3. 保护敏感文件:不让 Claude 动 .env 和 lock 文件

这个是我踩过坑之后加的。有一次让 Claude 重构项目,它顺手把 .env 里的环境变量也"优化"了——把我的 API Key 格式化了一下,然后整个项目跑不起来了。

从那以后,我配了一个 PreToolUse hook,在 Claude 编辑文件之前检查目标路径,如果是敏感文件就拦截。

json
1
{
2
  "hooks": {
3
    "PreToolUse": [
4
      {
5
        "matcher": "Edit|Write",
6
        "hooks": [
7
          {
8
            "type": "command",
9
            "command": "python3 /home/user/scripts/check_protected.py"
10
          }
11
        ]
12
      }
13
    ]
14
  }
15
}

check_protected.py 的逻辑很简单:

python
1
import sys, json
2
 
3
data = json.load(sys.stdin)
4
path = data.get("tool_input", {}).get("file_path", "")
5
 
6
protected = [".env", ".env.local", "package-lock.json", "pnpm-lock.yaml", ".git/"]
7
 
8
for p in protected:
9
    if p in path:
10
        print(f"被拦截了:{path} 是受保护文件,不能改", file=sys.stderr)
11
        sys.exit(2)  # exit code 2 = 拒绝操作
12
 
13
sys.exit(0)

exit code 的含义:

  • 0:允许,继续执行
  • 2:拒绝,Claude 会收到你 stderr 里的拒绝原因,然后调整方案

这个 hook 救了我好几次。有一次 Claude 想删 node_modules 再重新安装来解决依赖问题,被我拦下来了——那可是一个 monorepo,重新装要二十分钟。

4. 上下文注入:压缩后不丢关键信息

用 Claude Code 写复杂功能的时候,对话会越来越长,context window 快满了就会触发压缩。压缩之后很多关键信息就丢了——比如你之前说的项目规范、当前在做什么任务、要用哪个分支。

SessionStart hook 可以在压缩后自动注入这些信息:

json
1
{
2
  "hooks": {
3
    "SessionStart": [
4
      {
5
        "matcher": "compact",
6
        "hooks": [
7
          {
8
            "type": "command",
9
            "command": "cat /home/user/.claude/context-reminder.md"
10
          }
11
        ]
12
      }
13
    ]
14
  }
15
}

context-reminder.md 长这样:

code
1
## 项目规范
2
- 用 Bun 不用 npm
3
- 测试用 vitest
4
- 提交前跑 bun test && bun lint
5
 
6
## 当前任务
7
- 在 feat/auth 分支做用户认证重构
8
- 优先用 JWT + httpOnly cookie
9
- 不要动现有的 session 逻辑

matcher: "compact" 表示只在压缩后触发。cat 的输出会直接注入到 Claude 的 context 里,相当于压缩后自动"恢复记忆"。

还有一个骚操作:用 git log --oneline -5 作为 command,这样压缩后 Claude 能看到最近 5 次提交,知道你做到哪了。

5. 权限自动批准:计划模式不用每次确认

Claude Code 有个计划模式(plan mode),它会先给你看执行方案,然后问你"可以开始吗?"每次都要手动点确认,烦。

json
1
{
2
  "hooks": {
3
    "PermissionRequest": [
4
      {
5
        "matcher": "ExitPlanMode",
6
        "hooks": [
7
          {
8
            "type": "command",
9
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
10
          }
11
        ]
12
      }
13
    ]
14
  }
15
}

这个 hook 只自动批准 ExitPlanMode(退出计划模式开始执行)的权限请求,其他权限请求(比如执行 shell 命令、写文件)还是正常弹窗让你确认。

警告:matcher 千万别用 .* 或者留空,那会自动批准所有权限请求,包括执行任意 shell 命令。Claude 想跑 rm -rf / 你都不拦着。一定要把 matcher 缩到最小范围。

Hook 的生命周期事件

上面 5 个 Hook 涵盖了最常用的事件类型,但 Claude Code 支持的事件远不止这些。完整列表:

  • SessionStart:会话开始或恢复
  • UserPromptSubmit:你提交 prompt 之后、Claude 处理之前
  • PreToolUse:工具调用之前(可以拦截)
  • PostToolUse:工具调用之后
  • PostToolUseFailure:工具调用失败之后
  • Notification:Claude 发通知时
  • Stop:Claude 完成回复时
  • ConfigChange:配置文件变更时
  • CwdChanged:工作目录变更时
  • FileChanged:监听的文件变更时
  • PreCompact / PostCompact:上下文压缩前后
  • PermissionRequest:权限弹窗出现时
  • SubagentStart / SubagentStop:子 agent 启动/结束
  • SessionEnd:会话结束

每个事件都有自己的输入数据(通过 stdin 传给你的脚本,JSON 格式),你的脚本可以通过 stdout 返回控制指令。

高级玩法:Prompt 和 Agent 类型的 Hook

除了 command 类型(跑 shell 命令),还有两种高级 hook 类型:

Prompt Hook

用 LLM 做判断。比如你想在 Claude 写代码之前,让另一个模型检查你的 prompt 是否合理:

json
1
{
2
  "type": "prompt",
3
  "prompt": "检查用户的请求是否涉及敏感操作(删除数据库、修改生产环境配置等)。如果是,返回 deny。"
4
}

适合做安全审计、质量检查这种需要"理解"而非"规则匹配"的场景。

Agent Hook

多轮对话 + 工具调用。比 prompt hook 更强,可以调用工具、做多步推理。目前还是实验性功能。

我个人觉得这两个高级类型用得不多,command 类型已经能覆盖 90% 的场景了。但如果你在做企业级的 Claude Code 部署,prompt hook 做安全审计还是很有价值的。

配置文件放哪里

Hook 配置有三个层级:

  • ~/.claude/settings.json:全局生效,所有项目都用
  • 项目根目录的 .claude/settings.json:只对当前项目生效
  • .claude/settings.local.json:本地配置,不进 git

我的建议:

  • 通知类的 hook 放全局(你总需要通知)
  • 格式化 hook 放项目级(不同项目可能用不同的格式化工具)
  • 保护文件的 hook 放全局(所有项目都应该保护 .env
  • 上下文注入放项目级(每个项目的规范不同)

调试 Hook

Hook 配错了不会报明显错误,就是不触发,挺难排查的。几个调试技巧:

  1. 在 Claude Code 里输入 /hooks 看当前注册了哪些 hook
  2. 手动跑你的命令看看能不能正常执行
  3. set -x 看 shell 脚本的执行过程
  4. jq 验证你的 JSON 配置格式是否正确
bash
1
# 验证 settings.json 格式
2
cat ~/.claude/settings.json | jq .
3
 
4
# 测试 hook 命令能不能跑
5
echo '{"tool_input":{"file_path":"/tmp/test.py"}}' | jq -r '.tool_input.file_path'

进阶:HTTP Hook 发 Webhook 通知

除了跑 shell 命令,hook 还能直接发 HTTP 请求。比如你想在 Claude 完成任务后发个消息到 Slack 或者企业微信:

json
1
{
2
  "hooks": {
3
    "Stop": [
4
      {
5
        "matcher": "",
6
        "hooks": [
7
          {
8
            "type": "http",
9
            "url": "https://hooks.slack.com/services/YOUR/WEBHOOK/URL",
10
            "method": "POST",
11
            "headers": {
12
              "Content-Type": "application/json"
13
            },
14
            "body": {
15
              "text": "Claude Code 完成了一个任务"
16
            }
17
          }
18
        ]
19
      }
20
    ]
21
  }
22
}

这个比 command 类型干净——不用写脚本,直接在配置里声明 HTTP 请求。如果你团队用 Slack/飞书/钉钉做通知,这个很实用。

不过要注意,HTTP hook 的 body 里可以引用事件数据(用模板语法),但具体支持哪些字段得看官方文档。我目前还没深入用这个,主要是 command 类型已经够灵活了。

跟 MCP 配合使用

Hooks 和 MCP 是两个独立的扩展机制,但可以配合使用。比如你有一个 MCP server 提供了代码审查工具,可以用 mcp_tool 类型的 hook 在特定时机调用它:

json
1
{
2
  "hooks": {
3
    "PostToolUse": [
4
      {
5
        "matcher": "Write",
6
        "hooks": [
7
          {
8
            "type": "mcp_tool",
9
            "server": "code-review",
10
            "tool": "review_changes",
11
            "arguments": {
12
              "file": "{{file_path}}"
13
            }
14
          }
15
        ]
16
      }
17
    ]
18
  }
19
}

这样每次 Claude 写入新文件,自动调用 MCP 服务做代码审查。比在 CLAUDE.md 里写"每次写完文件都要检查一遍"靠谱得多——hook 是确定性执行的,不会被 LLM 忽略。

在 CI/CD 中用 Hooks

Claude Code 有个 Setup 事件,专门给 CI 和脚本用。当 Claude Code 以 --init-only-p 模式启动时触发:

json
1
{
2
  "hooks": {
3
    "Setup": [
4
      {
5
        "matcher": "",
6
        "hooks": [
7
          {
8
            "type": "command",
9
            "command": "echo 'Setting up CI environment...' && npm ci"
10
          }
11
        ]
12
      }
13
    ]
14
  }
15
}

适合在自动化流水线里用 Claude Code 的场景——每次启动前自动安装依赖、设置环境变量、生成配置文件。

实际场景:一个完整的 hooks 配置

把上面讲的都整合起来,这是我目前在用的完整配置(项目级 .claude/settings.json):

json
1
{
2
  "hooks": {
3
    "Notification": [
4
      {
5
        "matcher": "",
6
        "hooks": [
7
          {
8
            "type": "command",
9
            "command": "notify-send 'Claude Code' '等你输入了'"
10
          }
11
        ]
12
      }
13
    ],
14
    "PostToolUse": [
15
      {
16
        "matcher": "Edit|Write",
17
        "hooks": [
18
          {
19
            "type": "command",
20
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write 2>/dev/null || true"
21
          }
22
        ]
23
      }
24
    ],
25
    "PreToolUse": [
26
      {
27
        "matcher": "Edit|Write",
28
        "hooks": [
29
          {
30
            "type": "command",
31
            "command": "python3 /home/user/scripts/check_protected.py"
32
          }
33
        ]
34
      }
35
    ],
36
    "SessionStart": [
37
      {
38
        "matcher": "compact",
39
        "hooks": [
40
          {
41
            "type": "command",
42
            "command": "cat /home/user/.claude/context-reminder.md 2>/dev/null || echo 'No context file found'"
43
          }
44
        ]
45
      }
46
    ],
47
    "PermissionRequest": [
48
      {
49
        "matcher": "ExitPlanMode",
50
        "hooks": [
51
          {
52
            "type": "command",
53
            "command": "echo '{\"hookSpecificOutput\": {\"hookEventName\": \"PermissionRequest\", \"decision\": {\"behavior\": \"allow\"}}}'"
54
          }
55
        ]
56
      }
57
    ]
58
  }
59
}

注意格式化那个 hook 加了 2>/dev/null || true——如果 prettier 不支持某个文件类型会报错,加这个让它静默失败,不影响 Claude 的工作流。

踩过的坑

Hook 命令路径问题

Hook 执行时的工作目录不一定是你的项目目录。如果你的脚本用了相对路径,可能会找不到文件。建议用绝对路径,或者在脚本里先 cd 到项目目录。

jq 不是所有系统都预装

PostToolUse 的 hook 经常用 jq 解析 JSON。Linux 一般有,macOS 装了 Homebrew 也有,但有些 CI 环境可能没有。提前确认一下。

exit code 2 不是报错

在 hook 里 exit 2 的意思是"拒绝操作",不是"脚本报错"。exit 1 才是真正的错误。别搞混了。

多个 hook 的执行顺序

如果同一个事件有多个匹配的 hook,它们会并行执行,不是按顺序。一个 hook 拒绝不会阻止其他 hook 执行。最严格的结果生效(deny > defer > ask > allow)。

Hooks vs CLAUDE.md vs Skills:该用哪个

很多人会问:我想让 Claude 自动格式化代码,是用 hook 还是在 CLAUDE.md 里写规则?

区别在于确定性。CLAUDE.md 里写"每次改完文件都要跑 prettier",Claude 大概率会遵守,但不是 100%。有时候它会忘,有时候它觉得不需要。Hook 是确定性的——只要触发条件满足,命令一定会执行,没有"LLM 觉得不需要"这回事。

我的建议:

  • 需要强制执行的规则(保护文件、格式化、安全检查)→ 用 Hook
  • 需要 Claude 理解的指导(代码风格偏好、架构决策)→ 用 CLAUDE.md
  • 可复用的工作流(特定语言的开发流程、测试策略)→ 用 Skills

三者不冲突,可以同时用。Hook 管"必须做"的事,CLAUDE.md 管"应该怎么做"的事,Skills 管"怎么做得好"的事。

写在后面

Hooks 是 Claude Code 里比较低调但实用性很高的功能。用好它能省掉很多重复操作,也能避免一些危险情况。

我现在基本是"能 hook 的就 hook",让 Claude 专注在它擅长的事情上——理解需求、写代码、做架构。格式化、保护文件、通知这种"体力活"交给 hook 自动处理。

有啥问题评论区聊。后面打算试试 prompt hook 做代码审查,搞完了再写一篇。

advertisement

Claude Code Hooks 实战:5 个让我效率翻倍的自动化配置 — AI Hub