返回 FEED
AGENT2026-05-25

别再指望 AI 自觉了:用 Hooks 把 Claude Code 管起来

我最早接触 hooks 这个词,是在 Git 里。比如 .git/hooks/pre-commit,提交前自动跑一遍格式化。当时只觉得"挺方便",没多想。

直到去年开始重度用 Claude Code,有一天我心血来潮翻文档,翻到 hooks 那一节愣了半天。这玩意儿,原来才是把 AI 真正"管住"的核心机制。

我才意识到,自己之前所有跟 AI 协作的"约定",都是建立在它"听话"的假设上的。

什么是钩子

hook(钩子)就是预先挂在某个"位置"的一段动作。程序走到那里,这段动作就自动执行,不依赖它"记得"要做。

举个例子:我家楼道里有那种感应灯。我不用记得按开关,人走到那个位置,灯自动就亮了。开关一直挂在那儿,等我经过,到点触发。

为什么要专门搞这么个机制?因为现在用的 AI coding agent(Claude Code、Codex、Cursor 这些),已经不只是"回答问题"了。它会读文件、改代码、跑 Bash 命令、调用各种工具;但它决定下一步干什么,逻辑根本上还是"理解你的话"。

你在 CLAUDE.md 里写一句"改完代码记得跑测试",它大概率会照做。问题就出在"大概率"这三个字上。它今天听话,明天可能就忘了,或者理解偏了。你还不一定能复现。

prompt 是软约束,是"我希望你这么做"。hook 是比 prompt 更硬的执行约束,是"你做这件事的时候,这段检查或动作会自动发生"。

Claude Code 的钩子机制

一个 hook 的配置,拆开看就三层:

  1. 事件(Event):在生命周期的哪个时刻触发?比如会话刚开始的时候、用户刚提交一句话的时候、工具调用之前、工具调用之后、AI 这一轮干完想停的时候。

  2. 匹配器(Matcher):一个过滤条件,决定"什么情况下才真的触发"。在工具事件里,它通常匹配的是工具名;更细的参数级判断,现在更多会交给 if 规则。

  3. 处理器(Handler):命中之后,实际跑的那段东西。最常见的就是一段你自己写的脚本。

事件触发 → 匹配器过滤 → 处理器执行。就这么一条流水线。

Claude Code 提供的事件相当多,但你只需要先认得这几个:

  • SessionStart —— 会话开始时
  • UserPromptSubmit —— 你刚提交一句话、还没发给模型时
  • PostToolUse —— 每次工具调用之后
  • Stop —— AI 这一轮回答完、准备停下时
  • SessionEnd —— 整个会话结束时
  • PreToolUse —— 每次工具调用之前

特别记住 PreToolUse:如果你要拦截一次工具调用,它是最关键的入口,因为它发生在工具真正执行之前。想做"保护"、"拦截"、"先问过我再动手"这类事,通常都得挂在它身上。

边界:钩子能干什么,不能干什么

能干的:确定性触发、拦写入、留痕、注入上下文。

不能干的:绝对隔离敏感文件。

你拦住了 Claude 的"读文件"工具,它还能用 Bash 绕:cat secrets.env、grep 一下、tail 一下,甚至写个一行 Python 脚本去读。你要真想堵死,就得连 Bash 命令一起拦,去匹配命令里有没有碰到那些敏感路径。可你一旦开始拦命令,就掉进一场正则军备竞赛:cat 堵了还有 less、head、xxd、python -c "open(...)" …… 堵不完的。

所以这里有一条特别重要的认知:靠 hook 拦读取,本质是"提高门槛",不是"绝对隔离"。

真想保护敏感文件,hook 是最后一道,不是第一道。第一道应该是让 AI 根本接触不到:用权限规则或 sandbox 把读取路径挡住,把敏感信息放进环境变量或密钥管理系统。

别把护栏当围墙。 hook 是"提高门槛 + 出事报警",不是"绝对禁止"。

claude-mem:它是怎么"记住"你的

用过早期 Claude Code 的人多半知道一个痛点:它没有记性。这个会话里你跟它磨了半天达成的共识、踩过的坑、定下的约定,关掉窗口,下次再开,它一问三不知,一切从头来过。

claude-mem 这个插件就是来治这个病的:跨会话的持久记忆。它能"记住"你之前干过什么,下次开新会话时,把相关的上下文悄悄塞回来。

它凭什么能记住?入口和闭环主要靠 hooks。claude-mem 几乎把一段会话的完整生命周期都架在了 hook 上:

  • SessionStart(会话开始)→ 加载:从数据库里捞出跟当前工作相关的历史记忆,压缩成一个索引,悄悄注入到这次会话的上下文里
  • UserPromptSubmit(你提交一句话)→ 记意图:把你这次想干嘛记下来
  • PostToolUse(每次工具调用后)→ 观察:AI 每读一个文件、跑一条命令、改一段代码,都被记成一条观察
  • Stop(这一轮停下时)→ 总结:生成这一段的会话摘要——干了什么、学到了什么、下一步该干嘛
  • SessionEnd(会话结束)→ 收尾:做最后的清理和归档

加载、记意图、观察、总结、收尾。一段记忆的完整闭环,全是用生命周期事件钉出来的。

一个值得抄进所有 hook 设计的解法

hook 必须快。它卡在 AI 的工作流当中,AI 干完一步要等 hook 放行才能下一步。所以一个 hook 最好在一秒以内返回。慢了,整个 AI 就跟着卡顿。

可问题来了:claude-mem 要做的"记忆压缩",是要喊 AI 把一堆原始记录嚼碎、提炼成精华的。这事要花 5 到 30 秒。

claude-mem 的解法:hook 本身只做一件极快的事——把要处理的东西塞进一个队列里(几毫秒搞定),然后立刻返回放行。真正耗时的 AI 压缩,交给一个在后台常驻的独立服务(worker)去慢慢做。

hook 和 worker 一快一慢,彻底解耦。两个八竿子打不着的应用,一个做记忆,一个做可视化,架构却长得一模一样。这不是巧合,是被"hook 必须快"这条铁律逼出来的结果。

你以后但凡要写稍微复杂点的 hook,记住这条:别在 hook 里干重活。hook 只负责把事件接住、扔出去,剩下的交给后台。

收个尾

hooks 这个机制的内核其实特别朴素:它承认了一件事——AI 是不能完全信任的。 所以真正重要的约束,不能只写在你跟它说的话里(它可能不听),还得放进工具链和运行环境里,让系统替你执行。

这背后是一个我一直信奉的次序:先让它可观测,再谈约束它,最后才轮到自动化。 顺序错了,你建起来的不是护栏,是幻觉。

如果只带走三件事:

  1. hook 是挂在 agent 生命周期里的自动动作。某个事件发生了,它就会触发。
  2. PreToolUse 适合拦工具调用,PostToolUse 适合记录和观察。一个管事前,一个管事后。
  3. hook 不是安全沙箱。敏感文件要靠权限规则、sandbox、密钥管理先挡住;复杂任务要交给后台服务慢慢做。