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

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

Mindket 编辑部 · 发布于 2026-11-04 · 更新于 2026-11-05 · https://mindket.com/cn/learn/claude-code/claude-code-hooks

## 要点

- hook 是绑定在某个事件上的 shell 命令，所以有些动作一定会发生，不用指望模型自己选择去做。
- 你在设置文件里用 JSON 写 hook：一个事件，一个过滤它的匹配器，以及要运行的处理程序。`/hooks` 能显示已经加载了什么。
- `PreToolUse` hook 退出码为 2，会拦下这次工具调用，并把你写到 stderr 的消息交给 Claude。退出码 0 表示没有异议。
- 命令型 hook 以你的完整用户权限运行，每条命令加进去之前都要读一遍。

## 开始之前

你需要有第 1 课装好的 Claude Code，以及一个能编辑的设置文件。第一个 hook 发桌面通知，所以适合有桌面的机器。第二个 hook 是调用 `jq` 的 Bash 脚本，[Anthropic 的 hooks 指南](https://code.claude.com/docs/en/hooks-guide)给的装法是：macOS 用 `brew install jq`，Debian 和 Ubuntu 用 `apt-get install jq`。

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

> 命令型 hook 会以你的完整用户权限执行 shell 命令。它们可以修改、删除或读取你的用户账号能访问的任何文件。把 hook 命令加进配置之前，请逐条审查并测试。
>
> Anthropic, Claude Code 官方文档（此处为中文译文）, [Claude Code 文档：Hooks 参考](https://code.claude.com/docs/en/hooks) (2026-11-04 查阅)

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

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

````json
{
  "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 指南](https://code.claude.com/docs/en/hooks-guide)的 Windows 标签页复制 PowerShell 命令。
2. 如果文件里已经有 `hooks` 这个键，就把 `Notification` 加在现有事件名旁边。每个事件都是同一个 `hooks` 对象里的一个键，不要把整个对象换掉。
3. 保存，然后在 Claude Code 提示符下输入 `/hooks`。你的 hook 会出现在列表里的 `Notification` 下面。
4. 按 `Esc` 回到提示符。按 `Shift+Tab` 直到状态栏显示 `⏸ manual mode on`，让 Claude 做一件需要权限的事，然后切到别的窗口。应该会收到一条桌面通知。这里要用手动模式，因为自动模式下由分类器审查操作，不再问你（第 2 课讲过）。

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

按[参考文档](https://code.claude.com/docs/en/hooks)的说法，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](https://code.claude.com/docs/en/hooks), 2026-11-05 查阅)
- **5** 种处理程序：`command`、`http`、`mcp_tool`、`prompt` 和 `agent` (来源：[Claude Code docs: Hooks reference](https://code.claude.com/docs/en/hooks), 2026-11-05 查阅)
- **600 s** 是 `command`、`http` 和 `mcp_tool` 类 hook 在大多数事件上的默认超时 (来源：[Claude Code docs: Hooks reference](https://code.claude.com/docs/en/hooks), 2026-11-05 查阅)
- **1.5 s** 是你退出或运行 `/clear` 时，`SessionEnd` hook 默认能用的全部时间 (来源：[Claude Code docs: Hooks reference](https://code.claude.com/docs/en/hooks), 2026-11-05 查阅)

- `~/.claude/settings.json`：你所有的项目，不和任何人共享。
- `.claude/settings.json`：单个项目，可以提交到仓库，团队也就有了。
- `.claude/settings.local.json`：单个项目，不提交。
- 插件的 `hooks/hooks.json`，或者技能的 frontmatter：hook 跟着那个插件或技能走。

| 事件 | 何时触发 | 匹配器过滤什么 |
| --- | --- | --- |
| `SessionStart` | 会话开始或恢复时 | 启动方式，比如 `startup` 或 `resume` |
| `UserPromptSubmit` | 提交提示词时，在 Claude 处理之前 | 不过滤，总会触发 |
| `PreToolUse` | 工具调用执行之前，并且可以拦下这次调用 | 工具名 |
| `PostToolUse` | 工具调用成功之后 | 工具名 |
| `Notification` | Claude Code 发出通知时 | 通知类型 |
| `Stop` | Claude 回答完毕时 | 不过滤，总会触发 |
| `PreCompact` | 上下文压缩之前 | `manual` 或 `auto` |
| `SessionEnd` | 会话结束时 | 结束的原因 |

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

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

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

````bash
#!/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，不要混用。

````json
{
  "session_id": "abc123",
  "cwd": "/Users/sarah/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}
````

| 退出码 | 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 上的配置串](https://x.com/bcherny/status/2007179852047335529)里说，团队用一个 `PostToolUse` hook 来格式化 Claude 写的代码。Claude 写出的代码通常已经很规整，剩下的由 hook 补齐，免得 CI 检查到时才报错。下面“动手试试”里的自动格式化 hook 是同一个思路：`PostToolUse`、匹配器 `Edit|Write`，再加 Prettier。

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

> Claude 写出的代码通常开箱就格式规整，剩下最后那 10% 由 hook 处理，免得以后在 CI 里出现格式错误。
>
> Boris Cherny, Claude Code 的作者，Anthropic，引文为译文, [X](https://x.com/bcherny/status/2007179852047335529) (2026-11-05 查阅)

[![Boris Cherny（@bcherny）2026 年 1 月 2 日在 X 上的配置串第 9 条：我们用一个 PostToolUse hook 来格式化 Claude 的代码。Claude 写出的代码通常开箱就格式规整，剩下最后那 10% 由 hook 处理，免得以后在 CI 里出现格式错误。](https://mindket.com/blog/shots/x-bcherny-posttooluse-hook.webp?v=9841d5ab371b)](https://x.com/bcherny/status/2007179852047335529)

Boris Cherny 在 X 上，2026 年 1 月 2 日

[![Boris Cherny（@bcherny）2026 年 1 月 2 日在 X 上的配置串第 1 条：我在终端里同时跑 5 个 Claude，标签页编号 1 到 5，用系统通知知道哪个 Claude 需要我输入。](https://mindket.com/blog/shots/x-bcherny-five-claudes.webp?v=d9904b875672)](https://x.com/bcherny/status/2007179833990885678)

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](https://mindket.com/cn/learn/agent-skills) 会深入讲第 3 课里你写的那些命令背后的 SKILL.md 格式。

hooks 也能装进插件里一起带走，Mindket 的插件指南讲了做法。项目的常驻说明，仍然应该放进 [CLAUDE.md 文件](https://mindket.com/cn/blog/claude-md-file)，因为 hook 负责强制执行，CLAUDE.md 负责解释。

## 自测一下

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

   A. 退出码 0
   B. 退出码 1
   C. 退出码 2

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

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

   A. `.claude/settings.json`
   B. `~/.claude/settings.json`
   C. `.claude/settings.local.json`
   D. 插件里的 `hooks/hooks.json`

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

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

   A. `edit|write`
   B. `Edit Write`
   C. `Edit&Write`
   D. `Edit|Write`

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

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

   A. 用新的 `hooks` 对象整个替换原来的
   B. 在同一个 `hooks` 对象里，把新事件名加在原有事件旁边
   C. 在文件顶部再写第二个 `hooks` 键

   答案：B。 每个事件名都是同一个 `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 在这个子智能体运行期间生效。

## 资料来源

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

[打开 Agent Skills 课程](https://mindket.com/cn/learn/agent-skills)
