主题
Hooks 实操指南
用 shell 命令在 Claude Code 生命周期节点自动执行,确定性地控制其行为。
是什么
Hooks 是用户自定义的 shell 命令,在 Claude Code 生命周期的特定节点执行。相比依赖 LLM 自行选择,它提供确定性控制,确保某些动作一定发生,可用于强制项目规则、自动化重复任务、把 Claude Code 接入现有工具链。
除确定性规则外,对需要判断的决策还可用 prompt-based hooks(type: "prompt",由 Claude 模型做单轮判断)和实验性的 agent-based hooks(type: "agent",子代理可读文件、跑命令做多轮校验)。本指南覆盖常见用例与上手;完整事件 schema、JSON 输入输出、async/MCP tool hooks 见 Hooks reference。
怎么工作
- 在 settings 文件里加 hooks 块;每个事件名是单个 hooks 对象里的一个 key,多个事件名互为同级,不要整体替换
- 事件触发时,所有匹配的 hooks 并行运行,相同命令会自动去重;全部跑完后 Claude Code 合并结果
- hook 通过 stdin/stdout/stderr 和 exit code 与 Claude Code 通信:事件数据以 JSON 传入 stdin(含 session_id、cwd、hook_event_name、tool_name、tool_input 等)
- exit 0 = 无异议正常继续(PreToolUse 不等于批准,仍走正常 permission 流程);exit 2 = 阻断并把 stderr 作为反馈给 Claude;其他 exit code = 动作继续但显示 hook error
- 需更精细控制时 exit 0 并向 stdout 打印 JSON(如 PreToolUse 的 permissionDecision: allow/deny/ask);不要把 exit 2 与 JSON 混用
- matcher 用于按事件字段过滤(如 PostToolUse 的 Edit|Write 按工具名);为空则该事件每次都触发
- type 决定运行方式:command(默认 shell)、http、mcp_tool、prompt、agent
怎么配置 / 用法
上手(macOS 桌面通知,编辑 ~/.claude/settings.json):
json
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'" }
]
}
]
}
}步骤:1) 把 hooks 块加入 settings 文件(也可让 Claude 帮你写);2) 输入 /hooks 打开浏览器确认 hook 已注册(菜单只读,增删改要直接编辑 JSON 或让 Claude 改);3) 触发一个需要权限的动作来测试。
编辑后自动格式化(项目根 .claude/settings.json):
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }]
}
]
}
}什么时候用
- 强制项目规则(如 PreToolUse + exit 2 阻断对 .env、package-lock.json、.git/ 等受保护文件的修改)
- 自动化重复任务(编辑后自动跑 Prettier、记录每条 Bash 命令到日志)
- Claude 需要输入时发桌面通知,便于切去做别的事
- 会话开始或 compaction 后用 SessionStart 重新注入上下文/项目约定
- 审计配置变更(ConfigChange)、按目录/文件变化重载环境变量(CwdChanged/FileChanged 配 CLAUDE_ENV_FILE)
限制 / 坑
- command hooks 只能通过 stdout/stderr/exit code 通信,不能触发 / 命令或工具调用
- PostToolUse hooks 无法撤销已执行的动作
- PermissionRequest hooks 在非交互模式(-p)下不触发,应改用 PreToolUse
- Stop hooks 在 Claude 每次结束响应时都触发(非仅任务完成),用户中断时不触发;连续阻断 8 次后会被覆盖
- 多个 PreToolUse hook 用 updatedInput 改写同一工具参数时,因并行执行顺序不确定,最后完成者生效
硬事实速查(12 条)
- 合并规则:PreToolUse 权限决策取最严结果,deny 覆盖 ask 覆盖 allow;一个 hook 返回 deny 不会阻止同级其他 hook 继续执行
- hook 返回 allow 只跳过交互式提示,不能绕过 settings 里的 deny 规则;managed settings 的 deny 始终优先
- PreToolUse hook 在权限模式检查之前触发:返回 deny 可在 bypassPermissions 或 --dangerously-skip-permissions 下仍阻断,可强制用户无法绕过的策略
- 作用域由位置决定:~/.claude/settings.json 全部项目、.claude/settings.json 单项目可提交、.claude/settings.local.json 单项目且 gitignore、managed policy 组织级、plugin 与 skill/agent frontmatter 各有作用域
- matcher 大小写敏感;MCP 工具命名为 mcp__<server><tool>,可用正则如 mcp__github.* 匹配
- if 字段(需 v2.1.85+)用 permission rule 语法按工具名+参数过滤,仅对 PreToolUse/PostToolUse/PostToolUseFailure/PermissionRequest/PermissionDenied 生效
- 超时按类型:command/http/mcp_tool 为 10 分钟(UserPromptSubmit 降到 30 秒),prompt 30 秒,agent 60 秒;可用 timeout 字段(秒)覆盖
- Stop hook 应解析 stop_hook_active,为 true 时提早 exit 0 避免触顶 8 次阻断上限;可用 CLAUDE_CODE_STOP_HOOK_BLOCK_CAP 提高上限
- 设为 "disableAllHooks": true 可禁用 hooks;直接编辑 settings 时文件监听通常自动生效,未生效可重启会话
- 调试:Ctrl+O 看 transcript 每个 hook 的单行摘要;用 claude --debug-file /tmp/claude.log 或会话中 /debug 看完整执行细节
- JSON 校验失败常因 shell profile 里无条件的 echo 把输出混入;用 if [[ $- == i ]] 仅在交互式 shell 执行 echo
- 可手动测试:echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh 并检查 echo $?;脚本需 chmod +x,路径用绝对路径或 $CLAUDE_PROJECT_DIR