Claude Code settings.json 详解(三):hooks 钩子全解析
hooks 是什么
Claude 每次执行工具(读文件、写文件、运行命令……)都会经历几个固定的生命周期节点:执行前、执行后、会话结束时。hooks 让你在这些节点上挂载自己的脚本——在 Claude 动手之前检查一遍,或者在它写完代码后自动跑一次 lint。
这是 Claude Code 配置里自动化程度最高的部分,也是最能体现”按你的规矩办事”的地方。
配置结构
hooks 是 settings.json 的顶层字段,与 permissions 平级:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo '即将执行 Bash 命令' >> /tmp/claude.log"
}
]
}
],
"PostToolUse": [...],
"Stop": [...],
"Notification": [...]
}
}
结构是三层嵌套:
hooks
└── 事件名(如 PreToolUse)
└── [] HookMatcher 数组
├── matcher: 匹配规则(可选)
└── hooks: [] HookCommand 数组
每个事件下可以挂多个 matcher,每个 matcher 下可以挂多条命令。
四种 HookCommand 类型
| 类型 | 说明 | 适用场景 |
|---|---|---|
command | 执行 shell 命令 | 日志、lint、通知、阻断检查 |
prompt | 调用 LLM 做判断 | 智能审查、语义检查 |
agent | 启动子代理处理 | 复杂自动化流程 |
http | 向指定 URL 发送 HTTP POST | Webhook、外部系统集成 |
日常使用最多的是 command,其他三种适合更高级的场景。
command 类型的完整字段:
{
"type": "command",
"command": "your-shell-command",
"shell": "bash",
"timeout": 30,
"statusMessage": "正在检查...",
"async": false,
"asyncRewake": false,
"once": false
}
timeout:超时秒数statusMessage:执行时显示的 spinner 提示文字async: true:后台异步执行,不阻塞 ClaudeasyncRewake: true:后台执行,若 exit code 为 2 则唤醒模型once: true:只执行一次后自动移除
核心事件详解
Claude Code 共有 26 个以上的 hook 事件,以下是日常最实用的四个。
PreToolUse — 工具执行前
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "/path/to/check.sh" }]
}
]
何时触发:Claude 即将调用某个工具,尚未执行时。
stdin 收到的 JSON:
{
"hook_event_name": "PreToolUse",
"session_id": "...",
"cwd": "/your/project",
"transcript_path": "/tmp/transcript.jsonl",
"tool_name": "Bash",
"tool_input": { "command": "rm -rf dist/" },
"tool_use_id": "..."
}
stdout 可输出的 JSON:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"additionalContext": "禁止删除 dist 目录"
}
}
permissionDecision 支持 "allow" / "deny" / "ask" 三个值。
exit code 语义:
| exit code | 效果 |
|---|---|
0 | 正常,不显示任何输出 |
2 | 阻断工具执行,将 stderr 内容告知模型 |
| 其他 | 仅将 stderr 显示给用户,工具继续执行 |
关键能力:exit code 2 配合 JSON output 的 permissionDecision: "deny" 可以完全阻断工具调用,比 permissions 规则更灵活,因为可以在脚本里写任意逻辑。
PostToolUse — 工具执行后
"PostToolUse": [
{
"matcher": "Write",
"hooks": [{ "type": "command", "command": "pnpm lint --fix" }]
}
]
何时触发:工具成功执行完毕之后。
stdin 收到的 JSON:
{
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"inputs": { "file_path": "src/foo.ts", "content": "..." },
"response": { "type": "text", "text": "文件写入成功" },
"tool_use_id": "..."
}
stdout 可输出的 JSON:
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "lint 已自动修复"
}
}
exit code 语义:
| exit code | 效果 |
|---|---|
0 | 正常,输出显示在 transcript 模式中 |
2 | 将 stderr 立即告知模型 |
| 其他 | 仅将 stderr 显示给用户 |
Stop — 会话结束前
"Stop": [
{
"hooks": [{ "type": "command", "command": "osascript -e 'display notification \"Claude 已完成\"'" }]
}
]
何时触发:Claude 即将结束本轮回复时。
stdin 收到的 JSON:
{
"hook_event_name": "Stop",
"stop_hook_active": false,
"last_assistant_message": "好的,我已经完成了修改。"
}
exit code 为 2 时:Claude 会读取 stderr 内容并继续对话,适合实现”Claude 停止前自动检查,发现问题就继续”的效果。
Stop 事件没有 matcher,对所有停止事件都生效。
Notification — 通知事件
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [{ "type": "command", "command": "afplay /System/Library/Sounds/Ping.aiff" }]
}
]
何时触发:Claude 发出权限请求、认证提示等通知时。
matcher 匹配 notification_type,常见值有 permission_prompt、auth_success 等。
这个事件是即发即忘的,不阻塞执行,适合做声音提醒、系统通知等副作用操作。
stdin/stdout 协议
每个 hook 脚本通过标准 IO 与 Claude Code 通信:
- stdin:收到一行 JSON,包含事件名、session_id、cwd、transcript_path 以及事件特有字段
- stdout:可以输出 JSON 来控制行为,也可以输出纯文本(会被记录到 transcript)
如果脚本第一行输出 {"async":true},则立即后台化,Claude 不等待结果继续执行。
可用的环境变量
hook 脚本执行时,可以访问以下环境变量:
| 变量 | 说明 |
|---|---|
CLAUDE_PROJECT_DIR | 稳定的项目根目录(非 worktree 路径) |
CLAUDE_ENV_FILE | 可写入 export VAR=val 的 .sh 文件(仅 bash) |
CLAUDE_PLUGIN_ROOT | 插件/skill 目录路径 |
matcher 格式
matcher 复用 permissions 里的规则语法,可以是:
"Write"— 精确匹配 Write 工具"Bash(git *)"— 匹配带 git 命令的 Bash 调用"Bash(npm:*)"— 旧式前缀匹配- 留空或省略 — 匹配所有调用
实用配置示例
写文件后自动 lint:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "cd $CLAUDE_PROJECT_DIR && pnpm lint --fix",
"timeout": 30
}
]
}
]
}
}
阻断危险 Bash 命令:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash /path/to/guard.sh"
}
]
}
]
}
}
guard.sh 里读取 stdin JSON,判断 tool_input.command 是否包含危险操作,危险则 exit 2 并向 stderr 输出原因。
Claude 完成时发送系统通知(macOS):
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude 已完成任务\" with title \"Claude Code\"'"
}
]
}
]
}
}
记录所有 Bash 命令到日志:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.command' >> /tmp/claude-bash.log",
"async": true
}
]
}
]
}
}
async: true 让日志写入在后台进行,不影响 Claude 的执行速度。
注意事项
- 工作区信任:所有 hook 都需要工作区处于受信任状态才会执行,在不信任的工作区中 hook 会被跳过
- 来源优先级:
policySettings(企业策略)>projectSettings>userSettings>localSettings> 插件 hooks;各层的 hooks 会合并执行,而不是互相覆盖 - 超时控制:建议给每个 hook 设置合理的
timeout,避免因脚本卡住而阻塞 Claude
小结
hooks 是 Claude Code 配置体系里最强大的扩展点:
- 四种类型(
command/prompt/agent/http)覆盖从简单脚本到复杂自动化的需求 PreToolUse+ exit code2可以在 Claude 动手之前做任意检查和阻断PostToolUse可以在工具执行后触发自动修复或验证Stop可以在 Claude 结束前插入额外逻辑,或触发通知- stdin/stdout JSON 协议让 hook 脚本可以精确控制 Claude 的下一步行为
下一篇将介绍 settings.json 中的 env 和其他杂项字段。
更多同类文章
- AI-first 创业公司,为什么只需要一种编程语言?
- cc-ping:一行命令 Ping 所有 Claude Code 配置
- 震惊!程序员用这个工具,4分钟干完95分钟的活!效率暴涨24倍
- CCBot - 研发提效 24 倍
- Claude Code /add-dir:被低估的 Monorepo 神器
- Claude Code 省 Token 小技巧:感叹号的妙用
- 我做了个机器人,让团队在飞书里用 Claude Code
- Claude Code /btw 命令详解:不打扰主线的快问快答
- Claude Code /compact:释放上下文,不丢进度
- Claude Code /config:一文搞懂所有可调设置
- Claude Code /context:你的上下文都被什么吃了?
- Claude Code /diff:这次对话改了什么,一目了然
- Claude Code /fast:同样的 Opus,两倍速——值不值?
- Claude Code 引用外部知识的最佳实践:GitHub MCP + Context7
- Claude Code /hooks:让 AI 按你的规矩办事
- Claude Code /init:10 秒自动生成 CLAUDE.md
- Claude Code MCP:让 AI 连接 GitHub、数据库等一切工具
- Claude Code /memory 详解:让 AI 真正记住你的项目
- Claude Code /model:Opus、Sonnet、Haiku 怎么选?
- Claude Code /permissions:谁能干什么,你说了算
- Claude Code /plan 详解:先想清楚再动手
- Claude Code + Playwright MCP:AI 终于能"看见"页面了
- Claude Code /resume 命令详解:别让对话白聊
- Claude Code /review:让 AI 帮你做 Code Review
- Claude Code Skills 详解:打造你的专属命令库
- Claude Code /stats:看看 AI 到底帮你写了多少代码
- Claude Code /status 命令详解:一眼看清会话全貌
- Claude Code /tasks 命令详解:后台任务尽在掌控
- Claude Code /usage 命令详解:你的额度还剩多少
- Claude Code /vim:在 AI 编程助手里用 Vim 键位
- Claude Code 使用指南:从安装到实战,一篇就够(2026)
- Claude 全家桶:从聊天到写代码到自动办公,一文讲清楚
- Claude Code /agents 详解:自定义 AI 子代理,各司其职
- Claude Code /doctor 详解:一键诊断你的开发环境
- Claude Code /effort 详解:控制 AI 思考的深度
- Claude Code /cost 详解:你的 AI 编程到底花了多少钱
- Claude Code /export 详解:把 AI 对话带走
- Claude Code /rewind 详解:AI 改错了?一键回退
- Claude Code /plugin 详解:给你的 AI 编程助手装插件
- Claude Code /theme 详解:给你的终端换个好看的皮肤
- Claude Code /insights 详解:用 AI 分析你自己用 AI 的方式
- Claude Code /rename 详解:给你的会话取个有意义的名字
- Claude Code settings.json 详解(一):配置文件在哪里、谁说了算
- Claude Code settings.json 详解(二):permissions 权限系统全解析
- Claude Code settings.json 详解(四):env、模型、认证与其他实用字段