钩子(Hooks)
在 17 个生命周期事件上执行 shell 命令,钩子还能放行、拦下或把动作改成问你。
钩子是在固定生命周期点上执行的 shell 命令,比如工具调用前、一轮结束后。用它可以把格式化、测试、通知这类动作接进 Klaus 的循环。
- 可挂的事件共 17 个:会话开始/结束、你发出提示词、工具调用前/后、工具失败、一轮停下、子代理开始/结束、压缩前/后、通知、Setup、任务创建/完成、工作树创建/移除。事件名写错的条目会被直接丢掉,不报错,所以看起来就像钩子没写一样。
- 存放位置:全局
~/.klaus/hooks.json,项目<项目>/.klaus/hooks.json。文件形状是「事件 → 若干组 → 每组一个可选 matcher 加一串钩子」,matcher 属于组而不是单条钩子。同一事件先跑全局再跑项目,同一文件内按书写顺序跑。 - 只有
type: "command"的条目会真的执行;同组里其他类型被跳过,不影响旁边的命令条目;缺command的同样跳过。timeout写的是秒,不写默认 30 秒;async: true的钩子不阻塞这一轮。 - 执行方式:引擎起一个
bash -c进程,把一份 JSON 从标准输入喂给它;如果标准输出是 JSON 就按结构解析。退出码非零或输出不是 JSON 时,这次钩子记为失败但不会拦住工具调用。 - 钩子不只是旁观者:工具调用前的钩子可以在输出里直接给出放行、拦下或「改成问你」,拦下时这次调用直接失败、连权限卡片都不会弹;提示词钩子可以挡掉你这一整条消息;停下钩子可以不让这一轮结束。多个钩子同时表态时,拦下最硬(第一个拦下的说了算),其次是改成问你,最后才是放行。
- 钩子清单在会话启动时随初始化一并交给引擎,引擎自己不读
hooks.json。所以改完钩子要开一个新会话才生效,已经开着的会话还按旧清单跑。 - 插件带的钩子不走这条路:引擎直接从插件账本里加载它们(客户端如果也报一遍,每个插件钩子会每个事件触发两次)。
- 钩子只从
hooks.json读。从其他客户端导入时,写在settings.json的hooks键里的那些只是导入来源,它们本身不会被执行。