Mindket
Claude Code 入门课第 4 节,共 4 节

Claude Code hooks 怎么用:一步步写出第一个 hook

黑色横幅,带有 Claude 标志,标题是“Claude Code 入门课”,下面一行是“4 节免费课:安装、计划模式、斜杠命令与 hooks”。

Claude Code hooks 是 Claude Code 在会话的固定节点自动运行的 shell 命令,比如工具调用之前,或者 Claude 需要你输入的时候。你在 ~/.claude/settings.json 这类设置文件里加一段 hooks,用 /hooks 检查,再触发对应事件。hook 每次都会运行,所以很适合那些不能有例外的规则。

本节内容

  • hook 是绑定在某个事件上的 shell 命令,所以有些动作一定会发生,不用指望模型自己选择去做。
  • 你在设置文件里用 JSON 写 hook:一个事件,一个过滤它的匹配器,以及要运行的处理程序。/hooks 能显示已经加载了什么。
  • PreToolUse hook 退出码为 2,会拦下这次工具调用,并把你写到 stderr 的消息交给 Claude。退出码 0 表示没有异议。
  • 命令型 hook 以你的完整用户权限运行,每条命令加进去之前都要读一遍。
全部课程
本页目录
  1. 开始之前
  2. 写出第一个 hook:Claude 需要你时发通知
  3. 事件、匹配器,以及 hook 放在哪里
  4. 会说“不”的 hook:保护文件不被修改
  5. hook 怎么回答:退出码和输入
  6. Claude Code 的作者怎么用格式化 hook 和通知
  7. 常见错误
  8. 动手试试
  9. 下一课:Agent Skills
  10. 自测一下
  11. 常见问题
  12. 资料来源

开始之前

你需要有第 1 课装好的 Claude Code,以及一个能编辑的设置文件。第一个 hook 发桌面通知,所以适合有桌面的机器。第二个 hook 是调用 jq 的 Bash 脚本,Anthropic 的 hooks 指南给的装法是:macOS 用 brew install jq,Debian 和 Ubuntu 用 apt-get install jq。

写任何 hook 都要记住一条规则。Anthropic 的参考文档提醒了它们能碰到什么。

命令型 hook 会以你的完整用户权限执行 shell 命令。它们可以修改、删除或读取你的用户账号能访问的任何文件。把 hook 命令加进配置之前,请逐条审查并测试。

Anthropic, Claude Code 官方文档(此处为中文译文) · Claude Code 文档:Hooks 参考 (2026年11月4日 查阅)

写出第一个 hook:Claude 需要你时发通知

Anthropic 自己的演示就从通知开始,这样 Claude 在等你时,你不必一直盯着终端。下面这段是 macOS 版本。它用 Notification 事件,这个事件在 Claude 等你输入或批准权限时触发。

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
  1. 打开 ~/.claude/settings.json,没有就新建,把上面这段加进去。Linux 上把 command 换成 notify-send 'Claude Code' 'Claude Code needs your attention'。Windows 上,从 hooks 指南的 Windows 标签页复制 PowerShell 命令。
  2. 如果文件里已经有 hooks 这个键,就把 Notification 加在现有事件名旁边。每个事件都是同一个 hooks 对象里的一个键,不要把整个对象换掉。
  3. 保存,然后在 Claude Code 提示符下输入 /hooks。你的 hook 会出现在列表里的 Notification 下面。
  4. 按 Esc 回到提示符。按 Shift+Tab 直到状态栏显示 ⏸ manual mode on,让 Claude 做一件需要权限的事,然后切到别的窗口。应该会收到一条桌面通知。这里要用手动模式,因为自动模式下由分类器审查操作,不再问你(第 2 课讲过)。

事件、匹配器,以及 hook 放在哪里

按参考文档的说法,hook 有三层。先是事件,比如 PreToolUse 或 Stop。再是决定何时触发的匹配器组,比如“只对 Bash 工具”。最后是处理程序,也就是那条 shell 命令。你的第一个 hook 用的是空匹配器 "",对所有通知类型都触发。把它改成 permission_prompt,就只在 Claude 需要批准、并且提示已经等了大约六秒时才触发。

对工具类事件,匹配器就是工具名。Bash 匹配 Bash 工具,Edit|Write 匹配两个工具中的任意一个。指南说匹配器区分大小写,必须和工具名完全一致。

这段配置存在哪里,决定谁能用到这个 hook。

Anthropic 参考文档里的 hooks 数字

33

个 hook 事件,从 SessionStart 到 SessionEnd

来源:Claude Code docs: Hooks reference (2026年11月5日 查阅)

5

种处理程序:command、http、mcp_tool、prompt 和 agent

来源:Claude Code docs: Hooks reference (2026年11月5日 查阅)

600 s

是 command、http 和 mcp_tool 类 hook 在大多数事件上的默认超时

来源:Claude Code docs: Hooks reference (2026年11月5日 查阅)

1.5 s

是你退出或运行 /clear 时,SessionEnd hook 默认能用的全部时间

来源:Claude Code docs: Hooks reference (2026年11月5日 查阅)

  • ~/.claude/settings.json:你所有的项目,不和任何人共享。
  • .claude/settings.json:单个项目,可以提交到仓库,团队也就有了。
  • .claude/settings.local.json:单个项目,不提交。
  • 插件的 hooks/hooks.json,或者技能的 frontmatter:hook 跟着那个插件或技能走。
八个 hook 事件,来自 Anthropic 的 hooks 参考文档
事件何时触发匹配器过滤什么
SessionStart会话开始或恢复时启动方式,比如 startup 或 resume
UserPromptSubmit提交提示词时,在 Claude 处理之前不过滤,总会触发
PreToolUse工具调用执行之前,并且可以拦下这次调用工具名
PostToolUse工具调用成功之后工具名
NotificationClaude Code 发出通知时通知类型
StopClaude 回答完毕时不过滤,总会触发
PreCompact上下文压缩之前manual 或 auto
SessionEnd会话结束时结束的原因

会说“不”的 hook:保护文件不被修改

通知只负责报告,PreToolUse hook 却能拦下动作。下面这个脚本来自指南,它读出 Claude 将要修改的文件路径,拒绝 .env、package-lock.json 和 .git/ 下的任何文件。它写到 stderr 的消息会交还给 Claude,让 Claude 调整做法。

它用 jq 解析 JSON,用退出码 2 来拦截。把它存成 .claude/hooks/protect-files.sh。

#!/bin/bash
# protect-files.sh

INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# Normalize Windows backslash separators so the patterns below match
FILE_PATH="${FILE_PATH//\\//}"

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
  1. 在 macOS 和 Linux 上用 chmod +x .claude/hooks/protect-files.sh 让脚本可执行。不可执行的 hook 脚本,Claude Code 运行不了。
  2. 在 .claude/settings.json 里把它登记成 PreToolUse hook,匹配器写 Edit|Write。command 是 "$CLAUDE_PROJECT_DIR"/.claude/hooks/protect-files.sh,写在 JSON 字符串里时,引号要加转义。
  3. 让 Claude 往你的 .env 文件里加一行注释。Claude Code 会在修改执行之前拦下它,并把 Blocked: 那条消息交给 Claude。

hook 怎么回答:退出码和输入

Claude Code 把事件以 JSON 的形式,从标准输入送给 hook。每个事件都带有 session_id 和 cwd 这样的字段,各类事件再加上自己的字段。针对 Bash 的 PreToolUse hook 能看到工具名和命令,就像下面的例子。这也是上面的脚本为什么去读修改操作的 .tool_input.file_path。

hook 用退出码回答。PreToolUse hook 退出码为 0 并不是批准,工具调用仍然要走正常的权限流程。如果 hook 要做更细的决定,退出码为 0 时,Claude Code 还会读取 stdout 里的一个 JSON 对象。每个 hook 选一种方式,要么退出码 2,要么 JSON,不要混用。

{
  "session_id": "abc123",
  "cwd": "/Users/sarah/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}
各个退出码的效果,来自 hooks 参考文档
退出码Claude Code 的做法你的消息去哪里
0成功,动作继续执行纯文本 stdout 只在 UserPromptSubmit、UserPromptExpansion、SessionStart 和 PostModelSwitch 上才会交给 Claude
2阻断性错误,在能拦截的事件上,动作会被停下你的 stderr 成为理由,大多数事件上 Claude 会把它当作反馈收到
其他非阻断性错误,动作继续执行会出现一条 hook 错误提示,显示 stderr 的第一行,前面带 “Failed with non-blocking status code:”

Claude Code 的作者怎么用格式化 hook 和通知

Boris Cherny 在 Anthropic 做出了 Claude Code。他 2026 年 1 月在 X 上的配置串里说,团队用一个 PostToolUse hook 来格式化 Claude 写的代码。Claude 写出的代码通常已经很规整,剩下的由 hook 补齐,免得 CI 检查到时才报错。下面“动手试试”里的自动格式化 hook 是同一个思路:PostToolUse、匹配器 Edit|Write,再加 Prettier。

那串帖子的第一条讲的是等待。他在编了号的终端标签页里同时跑五个 Claude 会话,靠系统通知知道哪个在等他输入。这一课的第一个 hook 在任何终端里都能给你这个提醒,把匹配器改成 permission_prompt,就只在需要批准时提醒。

Claude 写出的代码通常开箱就格式规整,剩下最后那 10% 由 hook 处理,免得以后在 CI 里出现格式错误。

Boris Cherny, Claude Code 的作者,Anthropic,引文为译文 · X (2026年11月5日 查阅)
Boris Cherny(@bcherny)2026 年 1 月 2 日在 X 上的配置串第 9 条:我们用一个 PostToolUse hook 来格式化 Claude 的代码。Claude 写出的代码通常开箱就格式规整,剩下最后那 10% 由 hook 处理,免得以后在 CI 里出现格式错误。
Boris Cherny 在 X 上,2026 年 1 月 2 日
Boris Cherny(@bcherny)2026 年 1 月 2 日在 X 上的配置串第 1 条:我在终端里同时跑 5 个 Claude,标签页编号 1 到 5,用系统通知知道哪个 Claude 需要我输入。
Boris Cherny 在 X 上,2026 年 1 月 2 日

X 官方嵌入卡片的截图,拍摄于 2026 年 11 月 5 日,时间为 UTC。点击截图可到 X 上打开原帖。

常见错误

  • 匹配器对不上。匹配器区分大小写,比对的是工具名,不是你提示词里的字。检查拼写,再用 /hooks 看这个 hook 是不是出现在你想要的事件下面。
  • 把 hooks 对象整个换掉,而不是往里添加。每个事件名都是同一个 hooks 对象里并列的键。
  • 设置文件里的 JSON 不合法。结尾多余的逗号和注释都不允许,文件一坏,/hooks 里就什么都没有。改动通常会自动读取。过几秒还没出现,就重启会话。
  • 脚本不可执行,或者找不到。给它加 chmod +x,路径用 $CLAUDE_PROJECT_DIR 来指。如果记录里写着 jq: command not found,就装上 jq。
  • 指望成功的 hook 会说点什么。它什么都不显示,所以看它的效果,比如文件被重新格式化了,或者按 Ctrl+O 打开记录视图。
  • 指望 PostToolUse 能撤销什么。工具已经运行完了。匹配器为 Edit|Write 的格式化 hook,也看不到被 Bash 命令改写的文件。

动手试试

  • 把通知 hook 的匹配器改成 permission_prompt,再测一遍。然后改回 "",对比两者各在什么时候触发。
  • 在信任保护脚本之前,先手动测试:echo '{"tool_input":{"file_path":".env"}}' | .claude/hooks/protect-files.sh,然后 echo $?。你应该看到 Blocked 那一行,以及一个 2。
  • 打开 /hooks,选列表末尾的 All events,浏览所有事件,包括还没有 hook 的。
  • 把指南里的自动格式化 hook 加进 .claude/settings.json。它是匹配器为 Edit|Write 的 PostToolUse hook,对改过的文件运行 Prettier,需要 jq 和 Prettier。让 Claude 往一个 JavaScript 文件里加几个单引号字符串,然后打开那个文件看看。

下一课:Agent Skills

Claude Code 这门课到这里就讲完了:安装、计划模式、斜杠命令和 hooks。下一门课 Agent Skills 会深入讲第 3 课里你写的那些命令背后的 SKILL.md 格式。

hooks 也能装进插件里一起带走,Mindket 的插件指南讲了做法。项目的常驻说明,仍然应该放进 CLAUDE.md 文件,因为 hook 负责强制执行,CLAUDE.md 负责解释。

自测一下

  1. PreToolUse 钩子的脚本要拦住一次修改,应该用哪个退出码?

    查看答案

    C. 退出码 2 退出码 2 会拦下这次工具调用,并把你写到 stderr 的信息交给 Claude,而退出码 1 只是非阻塞错误,操作照常进行。

  2. 想让一个钩子只对当前项目生效,并且你提交之后团队也能拿到,该把它保存在哪里?

    查看答案

    A. .claude/settings.json 这个文件只属于一个项目,可以提交,而 ~/.claude/settings.json 管你所有的项目,也不会共享。

  3. 哪个 matcher 能让 PreToolUse 钩子对 Edit 工具或 Write 工具都生效?

    查看答案

    D. Edit|Write Edit|Write 能匹配两个工具中的任意一个,而且 matcher 区分大小写,必须和工具名完全一致。

  4. 设置文件里已经有 hooks 键,你想再加一个事件,该怎么做?

    查看答案

    B. 在同一个 hooks 对象里,把新事件名加在原有事件旁边 每个事件名都是同一个 hooks 对象里的并列键,所以只能往里添加,不能整个替换。

常见问题

Claude Code hooks 是拿来做什么的?

它们在会话的某些节点运行 shell 命令,比如编辑之后格式化文件,命令执行之前拦截它,Claude 需要输入时发通知,或者在会话开始时补充上下文。Anthropic 说它的好处是确定性的控制:有些动作一定会发生,不用指望模型自己选择去运行。

怎么查看当前有哪些 hook 在生效?

输入 /hooks。它会打开一个只读的浏览器,列出你配置的 hook,每个都标明来源,比如用户设置、项目设置或插件。选中某个 hook,就能看到完整命令和定义它的文件。

hook 能拦住 Claude 不让它做某件事吗?

能。PreToolUse hook 以退出码 2 结束,或者返回拒绝决定,就会取消这次工具调用。这个拦截在所有权限模式下都有效,包括 bypassPermissions,因为 PreToolUse hook 在权限模式检查之前就触发了。

怎么关掉 hooks?

在设置文件里设 "disableAllHooks": true,或者只想关这一次,就传 --settings '{"disableAllHooks": true}'。没办法只停用某一个 hook 而把它留在配置里。托管设置里的 hook 照常运行,除非在托管层面也开了这个设置。

网上抄来的 hook 安全吗?

读过之后才算。命令不管做什么,都是以你的身份、对你的账号够得着的任何文件去做。在交互式会话里,Claude Code 还会扣住所有设置文件里的 hook,直到你接受该文件夹的工作区信任对话框。

改了 hook 之后要重启 Claude Code 吗?

通常不用。Claude Code 运行时你编辑设置文件,文件监视器一般会自动读到 hook 的改动。如果几秒后 /hooks 里还是没有你的改动,就重启会话,强制重新加载。

技能或插件能带自己的 hook 吗?

能。插件把 hook 放在 hooks/hooks.json 里,技能可以在 frontmatter 里声明 hook,技能被调用之后,这些 hook 在会话剩下的时间里一直运行。子智能体的 frontmatter 也可以,那些 hook 在这个子智能体运行期间生效。

资料来源

  1. Claude Code docs: Automate actions with hooks (2026年11月4日 查阅)https://code.claude.com/docs/en/hooks-guide
  2. Claude Code docs: Hooks reference (2026年11月5日 查阅)https://code.claude.com/docs/en/hooks
  3. Boris Cherny on X: tip 9, a PostToolUse format hook, 2 January 2026 (2026年11月5日 查阅)https://x.com/bcherny/status/2007179852047335529
  4. Boris Cherny on X: tip 1, five sessions and notifications, 2 January 2026 (2026年11月5日 查阅)https://x.com/bcherny/status/2007179833990885678

分享本节课

下一门课:Agent Skills

深入了解 SKILL.md,也就是你那些自定义命令背后的格式。

打开 Agent Skills 课程

本节课的 Markdown 版本 · Claude Code 入门课 · 全部课程