Claude Code hooks 是 Claude Code 在会话中的固定节点自动执行的命令(也可以是 HTTP 调用、prompt 等其他几种 handler 类型),比如工具运行前、需要权限时,或 Claude 完成回复时。你可以在 ~/.claude/settings.json 等设置文件的 hooks 键下定义它们。每个 hook 会从 stdin 收到描述事件的 JSON,并通过退出码或 stdout 上的 JSON 对象作出回应,从而实现记录日志、发送通知、阻止操作或代你作答。
01hook 的结构
hook 配置分为三层:
- hook 事件,例如
PreToolUse或Stop。 - matcher 组,用于筛选触发时机,例如“仅限 Bash 工具”。
- 一个或多个 hook handler,即实际执行的内容。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
下面的配置会在 Claude 写入或编辑文件后运行 lint 脚本。要添加第二个事件,在同一个 hooks 对象里再加一个同级键即可。
02hook 存放位置
~/.claude/settings.json你的所有项目否,仅限本机.claude/settings.json单个项目是,可提交到仓库.claude/settings.local.json单个项目否hooks/hooks.json插件启用期间是不同文件中的 hook 会叠加,而不是互相覆盖。在 Claude Code 中输入 /hooks,可以查看所有生效的 hook 及其来源。
在交互式会话中,在你接受该文件夹的工作区信任对话框之前,Claude Code 不会运行任何 hook,包括你自己的。
03Handler 类型
大多数 hook 是 "type": "command",即运行一条 shell 命令。另外还有四种:
http:将事件 JSON 以 POST 方式发送到某个 URL,并读取响应体。mcp_tool:调用你已配置的 MCP 服务器上的工具。prompt:向 Claude 模型发起单轮提问,并读取 JSON 格式的决策。agent:启动一个 subagent,它可以先读取文件再做决定(实验性)。
命令 hook 以你的完整用户权限运行:在 macOS 和 Linux 上通过 sh -c,在 Windows 上通过 Git Bash(或 PowerShell)。加上 "async": true 可让它在后台运行,但这样它就无法再做决策了。
04Matcher
matcher 决定事件的哪些触发会运行该 hook。匹配对象取决于事件:工具事件匹配工具名,Notification 匹配通知类型,SessionStart 匹配会话的启动方式,以此类推。
"*"、""或不写 matcher 都表示匹配全部。- 只包含字母、数字、
_、-、空格、|和,时按精确名称匹配。Edit|Write会匹配这两个工具中的任意一个。 - 其他情况都按 JavaScript 正则表达式处理,因此
mcp__memory__.*会匹配某个 MCP 服务器的所有工具。
Matcher 区分大小写。部分事件(包括 Stop 和 UserPromptSubmit)会忽略 matcher。对于工具事件,可以用带权限规则的 if 字段(如 "Bash(git *)")进一步限定单个 handler。
05输入:hook 收到的内容
每个 hook 都会从 stdin 收到 JSON,其中包含一些通用字段,如 session_id、transcript_path、cwd 和 hook_event_name,以及该事件特有的字段。例如,针对 Bash 调用的 PreToolUse hook 还会收到 tool_name 和 tool_input.command。可以用 jq 或任意 JSON 解析器读取:
#!/bin/bash
input=$(cat)
cmd=$(jq -r '.tool_input.command // empty' <<<"$input")
echo "Claude wants to run: $cmd" >> ~/claude-commands.log
exit 0
06输出:退出码与 JSON
hook 有两种方式向 Claude Code 反馈结果。
退出码。0 表示成功。2 表示阻断性错误:在可以阻断的事件上,该操作会被中止,stderr 的内容会作为原因。其他任何退出码(包括常见的 1)都是非阻断性错误,操作会继续执行,你会看到一条 hook 错误提示。如果 hook 是用来强制执行规则的,请用 2 退出,而不是 1。
在 stdout 输出 JSON。以 0 退出并打印一个 JSON 对象,可以实现更精细的控制。有些字段在所有事件中都可用,例如用 continue: false 让 Claude 完全停止。另一些字段则因事件而异:Stop 使用 decision: "block" 加上 reason,而 PreToolUse 和 PermissionRequest 则把决定放在 hookSpecificOutput 中。stdout 上不要输出任何其他内容:shell 配置文件里多打印的一行就会导致 Claude Code 无法读取 JSON。
07所有 hook 事件
SessionStart会话开始或恢复时否(可添加上下文)Setup使用 --init-only 启动,或将 --init / --maintenance 与 -p 一起使用时否InstructionsLoaded加载 CLAUDE.md 或 .claude/rules/*.md 文件时否UserPromptSubmit提交 prompt 后、Claude 看到之前是UserPromptExpansion输入的命令展开为 prompt 时是PreToolUse任何工具调用之前是PermissionRequest工具调用需要权限决定时通过 JSON 允许或拒绝PermissionDenied自动模式拒绝工具调用时否PostToolUse工具调用成功之后否(工具已执行)PostToolUseFailure工具调用失败之后否PostToolBatch一批并行工具调用完成后、下一次模型调用之前是NotificationClaude Code 发送通知时否MessageDisplay显示 Claude 的回复文本时否(可修改显示内容)SubagentStart / SubagentStopsubagent 启动或结束时仅 SubagentStopTaskCreated / TaskCompleted任务被创建或标记为完成时是StopClaude 完成回复时是(让 Claude 继续工作)StopFailure本轮因 API 错误结束时否TeammateIdleagent team 中的某个队友即将进入空闲时是ConfigChange会话期间设置文件发生变化时是CwdChanged工作目录变化时否DirectoryAdded通过 /add-dir 添加目录时否FileChanged被监视的文件在磁盘上发生变化时否WorktreeCreate / WorktreeRemove创建或删除 worktree 时是PreCompact / PostCompact上下文压缩之前和之后仅 PreCompactPreModelSwitch / PostModelSwitch切换模型之前和之后仅 PreModelSwitchElicitation / ElicitationResultMCP server 请求输入时,以及你回答之后是SessionEnd会话结束时否Anthropic 会不时新增事件,最新列表和各事件的输入字段请查看 hooks 参考文档。
08哪些事件和通知有关
下面四个事件基本涵盖了大家想收到提醒的所有场景:
Stop:“Claude 已完成”。参见 Stop hook 指南。Notification:“Claude 在等你”,类型包括permission_prompt和idle_prompt等。参见 Notification hook 指南。PermissionRequest:需要权限时第一时间收到提醒,或直接作答。参见 PermissionRequest 指南。- 针对
AskUserQuestion工具的PreToolUse:查看或回答 Claude 的选择题。参见 在手机上回答问题。
想要可直接粘贴的桌面端配置,可以先看 如何在 Claude Code 完成时收到通知。
09Claude Code Notifier 的定位
Claude Code Notifier 完全基于这些 hook 构建。它的免费命令行工具 ccn 支持 Mac、Windows 和 Linux。安装时会在 ~/.claude/settings.json 中添加七个 hook 条目,每个都运行 ccn hook,并对该文件做一次性备份。ccn 每个事件只运行几毫秒就退出,不会常驻后台。
单独使用时,它会显示桌面通知。配对 iPhone 或 Android app 后,同样的 hook 还能把你的回复传回去:允许或拒绝权限、回答问题,或在 Claude 停下后发送下一条指令。它是独立开发的,并非 Anthropic 出品。如果你只需要记日志或跑 lint,自己写几行更简单。详情见 ccn 页面。
10常见问题
怎样不等 Claude 触发就测试 hook?
把示例 JSON 通过管道传给脚本,再检查退出码:echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh; echo $?。然后在 Claude Code 中运行 /hooks,确认它注册在正确的事件下。
为什么我的 hook 没有运行?
常见原因有:settings.json 的 JSON 无效(尾随逗号、注释)、matcher 没有精确匹配(区分大小写)、脚本没有可执行权限,或者文件夹还没被信任。用 claude --debug 启动 Claude Code,查看调试日志确认运行了什么。完整列表见 故障排查清单。
如何暂时关闭所有 hook?
在设置文件中设置 "disableAllHooks": true。如果只想跳过一次,用 --settings '{"disableAllHooks": true}' 启动 Claude Code。没有单独关闭某个 hook 的开关,只能删除对应条目。这两种方式都无法关闭组织在 managed settings 中配置的 hook。
hook 的默认超时时间是多少?
command、HTTP 和 MCP tool hook 为十分钟(600 秒),prompt hook 为 30 秒,agent hook 为 60 秒。少数事件默认值更短,你也可以在任意 handler 上用 timeout 设置秒数。