Hooks:打造你的 专属工作流
在 Claude Code 工具调用的每个环节插入自定义逻辑——代码格式化、测试运行、安全检查,一切自动化
什么是 Claude Code Hooks?
Hooks 是 Claude Code 的事件钩子系统,允许你在工具调用前后执行自定义 shell 脚本。通过 Hooks,你可以在文件保存后自动运行 linter、在代码提交前执行测试、在操作敏感文件时触发告警——无需手动干预,完全自动化。
配置分三层:先挑事件,再用 matcher 过滤工具,处理脚本写在最内层的 hooks 数组里。脚本从标准输入读这次事件的 JSON,再用退出码表态:0 表示没有异议,2 在允许拦的事件上直接挡下这次调用;下面四种事件上,命令型钩子默认 600 秒才超时。这四种是最常用的,官方参考列出的时点不止它们(核于 2026-09-22)。
Hook 类型详解
Claude Code 的 Hook 覆盖工具调用、会话与压缩等生命周期节点,可挂命令、HTTP 与 agent 三类处理器
PreToolUse 工具调用前
工具执行前触发,可用于参数校验、权限检查、自动审批或拒绝操作
PostToolUse 工具调用后
工具执行后触发,可用于自动格式化、运行测试、发送通知
Notification 通知发出时
Claude Code 发送通知时触发,可集成 Slack、邮件等外部通知渠道
Stop 回合结束时
Claude Code 结束响应时触发,可用于自动记录日志或执行清理操作
常见自动化场景三例
下面三个场景走的是同一套结构:选定事件、用 matcher 收窄到具体工具、把脚本放进内层 hooks 数组。片段只示意意图,字段名与嵌套以官方参考为准;脚本要判断的东西,都从标准输入那份 JSON 里取。
提交前先跑格式化
Claude 准备执行 git commit 时,PreToolUse 先把参数交给你的脚本。脚本认出提交命令就先跑格式化,再用退出码表态:0 放行这次调用,2 直接挡下。这一切发生在命令执行之前,所以被挡住时工作目录没有被改过。
{
"hooks": {
"PreToolUse": [{
"matcher": "Bash",
"command": "if echo \"$TOOL_INPUT\" | grep -q 'git commit'; then npm run format; fi"
}]
}
}
测试跑完发通知
命令成功返回之后 PostToolUse 才触发,脚本认出 pytest 或 npm test 就发一条桌面通知。这个事件拦不回已经跑完的调用,命令失败时它也不响,所以通知的含义是「结果可以看了」,不是「测试通过了」。
{
"hooks": {
"PostToolUse": [{
"matcher": "Bash",
"command": "if echo \"$TOOL_INPUT\" | grep -q 'pytest\\|npm test'; then notify-send 'Tests completed'; fi"
}]
}
}
拦住改敏感文件的写入
给 Edit 和 Write 挂上 PreToolUse,脚本从标准输入拿到目标路径,命中 .env、credentials 这类名字就返回退出码 2。写入在落盘之前就被拒,不用事后回滚。matcher 写 Edit|Write 就能同时盯住两个工具。
{
"hooks": {
"PreToolUse": [{
"matcher": "Edit|Write",
"command": "if echo \"$TOOL_INPUT\" | grep -qE '\\.env|credentials|secrets'; then exit 2; fi"
}]
}
}
Headless 模式与 CI/CD
使用 claude -p 标志在 CI/CD 管道中运行 Claude Code,实现无人值守的自动化任务
-p 非交互模式
给 claude 命令加上 -p(即 --print),跳过交互界面直接跑完,把结果一次性输出。
接进 CI 管道
非交互模式读 stdin、写 stdout,成功返回退出码 0,构建脚本可据此判断下一步。
--output-format 结构化输出
输出形式由 --output-format 控制;选 json 时,结果会带上会话 ID 等元数据,方便脚本解析。
# 非交互跑一次审查:JSON 输出,最多 5 轮
claude -p "Review this PR and suggest improvements" \
--output-format json \
--max-turns 5
settings.json 配置示例
在 .claude/settings.json 中定义你的 Hooks
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"command": "~/scripts/pre-bash-hook.sh"
},
{
"matcher": "Edit|Write",
"command": "~/scripts/protect-sensitive-files.sh"
}
],
"PostToolUse": [
{
"matcher": "Bash",
"command": "~/scripts/post-bash-hook.sh"
}
],
"Notification": [
{
"command": "~/scripts/send-notification.sh"
}
],
"Stop": [
{
"command": "~/scripts/on-stop.sh"
}
]
}
}
Hooks 编写最佳实践
下面四条按 Claude Code 官方 Hooks 文档整理,含其中的安全实践一节,核于 2026-09-22;讲的是脚本本身怎么写,配置形状见上面 settings.json 一节。
拦截请用退出码 2
官方写明,多数 Hook 事件里只有退出码 2 能凭自身拦下操作,其余退出码算非阻塞错误,动作照常进行。真要执行策略的脚本,失败时得显式 exit 2。
用 matcher 收窄触发
matcher 决定脚本在哪些调用上跑。官方说明它是过滤机制:只有名字本身时按精确匹配,掺进其他字符就当成未锚定的 JavaScript 正则求值。举例 Edit.* 会同时命中 Edit 与 NotebookEdit,要整串匹配得自己加首尾锚点。
超时不等于拦住
Claude Code 会取消到达超时的 Hook 并丢弃输出,多数事件上等于没给出决定;官方点名 PreToolUse 上超时的命令类 Hook 不拦这次调用,而 PreModelSwitch 上超时反而拦住切换。排查看 debug 日志,执行细节都写在里面。
把输入当成不可信
官方安全实践列了几条:别盲信输入数据、shell 变量一律加引号、检查 ../ 这类路径穿越、跳过 .env 与 .git 等敏感文件。Hook 拿到的输入本来就是一段 JSON,字段里可能塞着外部内容。
常见问题
Hook 脚本怎么拿到输入 JSON?
命令类 Hook 通过标准输入收到一段 JSON。公共字段有 session_id、transcript_path、cwd、hook_event_name 等,各事件再叠加自己的字段,工具类事件里就是 tool_name 与 tool_input。
怎么让 Hook 拦下一次工具调用?
把脚本挂到 PreToolUse 上,遇到不该放行的调用就返回退出码 2。官方事件表把 PreToolUse 标为可拦,退出码 2 直接挡住这次调用;想带条件放行,可以改输出含 permissionDecision 的 JSON。退出码 1 在多数事件上挡不住。
Hook 超时或脚本报错会怎样?
到超时的 Hook 会被取消、输出被丢弃,多数事件上等于没给出任何决定,只有 PreModelSwitch 会因超时被拦住。脚本路径写错也只算非阻塞错误,动作照常进行,官方建议策略 Hook 第一次跑就确认这条提示。
Hooks 配置写在哪个文件里?
作用范围由定义位置决定:~/.claude/settings.json 覆盖你的全部项目但只留在本机;项目里的 .claude/settings.json 只作用于单个项目,可以提交进仓库;.claude/settings.local.json 同样按项目走,Claude Code 往里存设置时会被 gitignore。
QCode.cc 企业自动化
结合 QCode.cc 开发者工具与 Hooks 系统,打造企业级 AI 编程自动化流水线
ANTHROPIC_BASE_URL 网关接入
Claude Code 官方变量表写明,ANTHROPIC_BASE_URL 可把 API 端点指向代理或网关;QCode 站内有一篇专讲这条链路的配置指南(核于 2026-09-22)。
先装刹车,再谈自动化
自动化上线前先装刹车:官方示例演示脚本按受保护模式清单检查目标路径,用退出码 2 拦下对敏感文件的编辑。
团队共用同一份配置
官方配置位置表说明 .claude/settings.json 可随项目提交进仓库;配一把团队共用的 QCode 密钥,全组的 Hook 口径就一致了。
QCode 同时支持 OpenAI Codex / GPT-5.6
你的 QCode 套餐配额可同时用于 Claude Code 与 OpenAI Codex CLI,共享额度,无需重复购买。
更新于 2026-09-22