收藏、记忆、苹果核上线了看看 →
LuoLuoLuoLuo Wiki

Hooks 系统

用 Hooks 在 Claude Code 生命周期里自动跑你自己的规则,洛洛版讲解

核对于 2026-09-14

hihi,洛洛又来了。

这篇要讲的东西叫 Hooks,洛洛第一次听到的时候以为是钩子毛线的那种钩针。

后来默子老师给我解释:就是在 Claude Code 干活的固定节点上,塞一段你自己的脚本,让它必须跑、一定跑、每次都跑。不靠模型自觉,靠规则。

souga,原来是这样。所以它不是"跟 AI 商量一下能不能每次都帮我格式化",而是"你没得选,写完文件就格式化"。

Hooks 是 Claude Code 的生命周期脚本。它适合做确定性的项目规则,例如格式化、审计命令、阻止敏感文件读取,而不是再让模型临场猜应该怎么处理。

Hooks 在一次会话里的 8 个触发节点

常用事件

先看一眼有哪些节点可以插。洛洛看这张表的时候是一脸懵的,但看完之后大概明白了:从会话一开始到最后收尾,每个环节都留了口子。

事件触发时机常见用途
SessionStart会话开始或恢复注入本机上下文、检查环境
UserPromptSubmit用户提示词提交后拦截敏感请求、补充上下文
PreToolUse工具执行前阻止危险命令、要求确认
PostToolUse工具执行后自动格式化、记录审计日志
NotificationClaude 需要通知用户桌面提醒、IM 通知
Stop主 Agent 完成响应收尾检查、总结状态
SubagentStop子 Agent 完成响应汇总子任务状态
PreCompact上下文压缩前保存关键信息

具体事件会随 Claude Code 版本扩展(截至 2026-09-14 官方已列出 30 多个,比如 SessionEnd、PermissionRequest、PostCompact),最终以 /hooks 菜单和官方文档为准。

配置结构

知道有哪些节点了,接下来是怎么写进去。这里就是洛洛最想哭的部分,因为它是 JSON。

Hooks 写在 settings.json 的 hooks 字段下。每个事件对应一个数组,数组里可以配置 matcher 和真正执行的 hooks。

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/format-written-file.py"
          }
        ]
      }
    ]
  }
}

注意这里是内层的 "hooks" 数组,不是旧版草稿里常见的单个处理器对象。

洛洛老实说:这个结构洛洛看第一眼是不懂的,外面一个 hooks 里面又一个 hooks,套娃之。但照着抄真的能跑,抄的时候记得数好括号就行。

洛洛碎碎念

JSON 少一个逗号、多一个逗号,整份配置直接不生效!!!

洛洛在这里卡了半小时,一直以为是自己脚本写错了,最后发现是最后一项后面多打了个逗号。害怕之。

实在不确定的话,找个 JSON 校验的网页贴进去看一眼,比自己盯着数括号快多了。

交互式配置

其实!有不用手写 JSON 的办法!洛洛知道这个的时候拍桌子了。

在 Claude Code 中输入:

/hooks

截至 2026-09-14 官方文档已改为:/hooks 是只读的浏览菜单,用来查看每个事件下配了哪些 Hook、来自哪个文件;要新增或修改,直接让 Claude 帮你改 settings JSON。对团队项目来说,让 Claude 生成后再把最终配置整理到项目级 .claude/settings.json,比自己手写整段 JSON 更稳。

Command Hook

菜单帮你生成的东西,本质上就是下面这一小块。

当前最常用、也最容易版本兼容的是 command hook:

{
  "type": "command",
  "command": "python3 .claude/hooks/check-bash.py"
}

Hook 命令会通过 stdin 收到一段 JSON,里面包含事件名、工具名、工具输入等上下文。复杂逻辑建议放进脚本里解析 JSON,不要把很长的 shell 管道塞进 settings.json。

翻译成洛洛能听懂的话:Claude Code 会把"我现在正在干什么"打包成一张纸条递给你的脚本,脚本自己拆开看。所以复杂判断都写在脚本里,配置文件只负责说"跑这个脚本"。

Matcher

matcher 用来限制 Hook 对哪些工具生效:

  • "Bash":匹配 Bash 工具
  • "Edit|Write":匹配编辑和写入
  • "Read|Grep|Glob":匹配只读工具
  • "mcp__github__.*":匹配某个 MCP server 的工具

PreToolUse 和 PostToolUse 通常需要 matcher;会话类事件可以不写 matcher。

洛洛的理解是:matcher 就是筛子。不写筛子,它对所有工具都触发,连读个文件都要跑一遍你的脚本,慢死。

示例

理论说完了,直接上洛洛看得懂的三个场景。这三个配置洛洛都是原样抄的,能跑。

写文件后格式化

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/format-written-file.py"
          }
        ]
      }
    ]
  }
}

脚本里可以从 stdin JSON 取出被写入的文件路径,只对支持的后缀运行格式化器。这样比依赖 $FILE 这类隐式环境变量更可靠。

执行命令前审计

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/check-bash-command.py"
          }
        ]
      }
    ]
  }
}

这类脚本适合阻止:

  • git push --force
  • rm -rf
  • 生产数据库迁移
  • 上传 .env、私钥、证书
  • 没有测试保护的发布命令

这个列表洛洛是看着后背发凉的。上面每一条,只要有一次手滑就够你哭一整晚。默子老师说过,能用规则挡住的事情,就不要指望自己当时清醒。

会话开始时检查环境

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "python3 .claude/hooks/session-start.py"
          }
        ]
      }
    ]
  }
}

可以在这里检查 Node、pnpm、Python、当前分支、未提交改动等环境信息,再把结果打印给 Claude。

返回结果

最后一个概念:脚本跑完了,怎么告诉 Claude Code "过"还是"不过"。

不同事件支持的返回语义不完全一样。实务上可以按这个原则设计:

  • 退出码 0 表示通过;退出码 2 表示阻断,stderr 会交给 Claude;其他非零退出码算非阻断错误,只提示一下,操作照常继续
  • PreToolUse:可以阻断工具调用,适合安全策略
  • 需要精细控制时:优先使用官方支持的结构化 JSON 输出,而不是只靠 stderr 文案

Hook 是确定性自动化,不是权限系统的替代品。高风险操作仍然应该配合 permissions.deny、permissions.ask、沙盒和人工确认一起使用。

洛洛碎碎念

这句"不是权限系统的替代品"洛洛一开始跳过去了,后来才反应过来它在说什么。

Hook 是你自己写的脚本,写漏了它就漏了。真正的红线要在 permissions 里也堵一遍,两层一起上。

安全这块洛洛真的是纯外行,所以官方原话怎么说洛洛就怎么记,一个字都不敢改。

洛洛的总结

Hooks 说白了就是:把你嘴上反复叮嘱的那几句话,变成一段电脑必须执行的脚本。

洛洛现在写代码不多,但把"写完自动格式化"配上之后,那种再也不用管的感觉,牛逼之。

想让 Claude 记住的东西不止规则,还有项目本身长什么样,那种事情要写进CLAUDE.md 配置,下一篇就是它。

洛洛先去补个觉,昨天数括号数到三点。

参考来源

查阅日期 2026-09-14。

On this page