☰
Hookify Stop 事件钩子实战:用 Claude Code 规则强制“测试通过才能结束会话“
2026/9/30 2:27:48 网站建设 项目流程
  • AI 插件
  • 开发工具
  • 插件系统

【免费下载链接】claude-plugins-official

Official, Anthropic-managed directory of high quality Claude Code Plugins.

项目地址:https://gitcode.com/GitHub_Trending/cl/claude-plugins-official
点击查看免费下载

导读

本文聚焦 Claude Code 插件 Hookify 中的一条实战规则示例——require-tests-stop.local.md(查看原示例文件)。该规则利用 Hookify 的Stop 事件钩子,在 Agent 准备结束会话时检查整个会话记录(transcript),若其中没有出现npm test、pytest或cargo test等测试命令,就以block动作阻止会话结束,从而形成一道"测试门禁"。读完本文,你将掌握:Stop 事件规则的完整 frontmatter 字段含义、transcript字段与not_contains运算符的底层求值逻辑、decision: block的响应协议,以及如何在自己项目中启用、测试与调试这条规则。


一、规则文件全貌:逐字段拆解

require-tests-stop.local.md采用 Hookify 的标准"Markdown + YAML frontmatter"格式,规则声明与提示消息分离。完整内容如下:

--- name: require-tests-run enabled: false event: stop action: block conditions: - field: transcript operator: not_contains pattern: npm test|pytest|cargo test --- **Tests not detected in transcript!** Before stopping, please run tests to verify your changes work correctly. Look for test commands like: - `npm test` - `pytest` - `cargo test` **Note:** This rule blocks stopping if no test commands appear in the transcript. Enable this rule only when you want strict test enforcement.

1.name:规则名称

require-tests-run。该名称会出现在 Hookify 的规则列表(/hookify:list)与触发时的提示前缀中(如**[require-tests-run]**),建议使用 kebab-case 且以动作动词开头(require / block / warn),便于语义化管理。

2.enabled: false:默认关闭

这是一个默认关闭(disabled)的示例规则,因为它属于"严格模式"——一旦开启,Agent 在没跑过测试的情况下将无法正常结束会话。启用方式有两种:

  • 手动编辑该文件,将enabled: false改为enabled: true;
  • 运行/hookify:configure交互式切换。

3.event: stop:绑定 Stop 事件

stop是 Hookify 支持的五个事件类型之一(bash、file、stop、prompt、all),含义是当 Claude 准备停止(结束本轮任务)时触发,常用于完成度检查、交付前校验等场景。

4.action: block:阻止会话结束

在 Stop 事件中,block表示拒绝 Agent 停止,并要求它先完成条件(本例即先运行测试)。这与 PreToolUse 事件中的block(拒绝工具执行)含义一致:都是"拦截",只是拦截对象不同。若只想提示而不强制,可改为warn(这也是默认值)。

5.conditions+transcript+not_contains:核心判定逻辑

  • field: transcript:匹配目标不是某个工具参数,而是本次会话的完整记录文本;
  • operator: not_contains:要求 transcript不包含pattern 所指定的子串(Python 的pattern in field_value取反,见 rule_engine.py);
  • pattern: npm test|pytest|cargo test:这是字面子串匹配(非正则),|只是普通字符的一部分,用于覆盖三类主流测试命令。

注意:conditions 列表内所有条件必须全部命中(AND 关系),规则才会触发。本例只有一条条件,即"transcript 中没有任何一条测试命令字样"时触发。

6. 消息体:提示给 Agent 看的内容

frontmatter 之后的内容会被解析为规则消息(message字段)。当规则触发时,RuleEngine 会以**[require-tests-run]**\n{message}的形式注入 systemMessage,明确告知 Agent:"会话记录中未检测到测试命令,结束前请先运行测试,检查npm test/pytest/cargo test。"


二、源码级原理:从 Stop 事件到 transcript 读取的完整调用链

要真正理解这条规则,需要沿着 Hookify 的钩子执行链路走一遍(对应文件:hooks.json、stop.py、rule_engine.py、config_loader.py)。

第 1 步:注册 Stop 钩子

在 hooks.json 中,Stop事件被注册为:

"Stop": [ { "hooks": [ { "type": "command", "command": "python3 \"${CLAUDE_PLUGIN_ROOT}/hooks/stop.py\"", "timeout": 10 } ] } ]

即每次 Agent 准备停止时,Claude Code 都会以 JSON(stdin)方式调用stop.py。

第 2 步:stop.py 加载规则并评估

stop.py 的核心流程是:

input_data = json.load(sys.stdin) rules = load_rules(event='stop') engine = RuleEngine() result = engine.evaluate_rules(rules, input_data) print(json.dumps(result), file=sys.stdout)
  • load_rules(event='stop'):只加载event为stop或all且enabled: true的规则(见 config_loader.py)。这解释了为什么enabled: false的示例规则默认不生效——加载阶段就直接被过滤掉了;
  • 无论结果如何,脚本finally中始终sys.exit(0),即 Hookify 自身出错不会导致流程被意外卡死,属于"故障时放行"的安全设计。

第 3 步:RuleEngine 对 Stop 事件的求值

rule_engine.py 的evaluate_rules中,blocking 规则命中的响应格式与事件类型强相关。对于 Stop 事件:

if hook_event == 'Stop': return { "decision": "block", "reason": combined_message, "systemMessage": combined_message }

也就是说,action: block+ Stop 事件命中时,Claude Code 会收到decision: block,从而不允许 Agent 结束会话,并把reason/systemMessage中的"请先运行测试"提示交给 Agent 继续执行。这正是"测试门禁"的落地机制。

第 4 步:transcript 字段的取值逻辑

field: transcript并不存在于工具参数中,它由_extract_field特殊处理(见 rule_engine.py):

elif field == 'transcript': transcript_path = input_data.get('transcript_path') if transcript_path: with open(transcript_path, 'r') as f: return f.read()

即:Stop 事件的 hook 输入中带有transcript_path,Hookify 会读取该文件全文作为匹配文本,再交给not_contains判断。若文件读取失败(不存在、无权限、编码问题等),会返回空字符串并打印 warning——此时not_contains对空串必然为真,规则将触发。这一点在调试"为什么一直拦截我停止"时需要特别留意。

第 5 步:not_contains 的运算符语义

条件求值在 rule_engine.py 中完成,not_contains即pattern not in field_value——是大小写敏感的子串判断,并非正则匹配。因此若 Agent 实际执行了NPM TEST(大写)或pytest --cov,仍可能被判定为"未检测到测试命令"。需要更宽松或更精确的匹配时,可改用regex_match运算符配合忽略大小写的正则(Hookify 编译正则时使用re.IGNORECASE,见 rule_engine.py)。


三、实战:启用、验证与调试"测试门禁"

1. 启用规则

将规则文件放入项目根目录的.claude/目录(注意:不是插件自身目录),命名遵循hookify.*.local.md,例如复制为:

.claude/hookify.require-tests.local.md

然后把 frontmatter 改为enabled: true。规则即刻生效,无需重启——下一次 Stop 事件触发时stop.py会自动加载它。

2. 验证触发

在一个尚未运行过任何测试的会话中,让 Claude 完成任务并尝试停止。预期行为:

  • Hookify 返回decision: block,Agent 收到类似"Tests not detected in transcript!"的 systemMessage;
  • Agent 会被引导先去执行npm test/pytest/cargo test,之后再次请求停止,此时 transcript 中已包含测试命令,规则不再命中,会话正常结束。

3. 调试技巧

  • 确认规则被加载:运行/hookify:list,检查规则是否出现且enabled状态正确;
  • 单独验证 pattern 语义:not_contains是子串匹配,可用python3 -c "print('npm test' in 'your transcript text')"之类的方式先行验证你的判断逻辑;
  • 规则频繁误拦:优先检查是否因 transcript 文件读取失败(权限、路径)导致匹配文本为空;
  • 觉得太严格:把action: block改为action: warn,此时命中后只注入 systemMessage 提示,不阻止停止(对应evaluate_rules中仅返回 systemMessage 的分支)。

4. 多语言 / 多场景变体

示例 patternnpm test|pytest|cargo test覆盖了 Node、Python、Rust 三种生态。你可以按项目需要扩展,例如加入go test、mvn test、./gradlew test;如果希望精确匹配而不误伤其他文本,可将运算符改为regex_match并写成\b(npm test|pytest|cargo test)\b(配合\s转义处理命令中的多空格)。


四、与其他示例规则的对比定位

Hookify 在 examples/ 目录下还提供了另外三条典型规则,可与本规则对照理解 Stop 事件的特殊性:

规则文件eventaction判定目标触发结果
dangerous-rm.local.mdbashblockBash 命令(rm\s+-rf)拒绝工具执行
console-log-warning.local.mdfilewarn写入内容(console\.log\()提示但放行
sensitive-files-warning.local.mdfilewarnfile_path + new_text 多条件提示但放行
require-tests-stop.local.mdstopblock会话 transcript拒绝结束会话

可以看出,本规则是四者中唯一的"会话级完成度校验":它不拦截任何单个工具调用,而是在任务的"出口"把关。这类规则特别适合用于CI 前置的质量保障、交付物完整性校验,或对 Agent 纪律性有硬性要求的自动化流程。


五、使用前提与注意事项

  1. 严格模式,谨慎开启:原文档特别注明"Enable this rule only when you want strict test enforcement"。一旦开启,Agent 未运行测试将无法停止,若项目没有测试脚本,可能导致会话无法正常收尾;
  2. 规则文件位置:必须位于项目根目录.claude/,Hookify 通过glob.glob('.claude/hookify.*.local.md')扫描(见 config_loader.py);删除某条规则只需删除对应的.local.md文件;
  3. 匹配是子串级、大小写敏感:not_contains不做正则与大小写归一,编写 pattern 时需覆盖实际命令形态;
  4. 无需重启:所有规则的增删改都在下一次事件触发时生效;
  5. 环境要求:Hookify 依赖 Python 3.7+,且仅使用标准库,无第三方依赖(见 README)。

结语

require-tests-stop.local.md是 Hookify 插件中极具代表性的一条 Stop 事件规则,它用不足 20 行的 frontmatter 实现了"测试通过才能结束会话"的工程化约束。配合 stop.py、rule_engine.py、config_loader.py 的源码阅读,你不仅能直接复制这条规则投入使用,更能举一反三:将transcript+not_contains+action: block的组合推广到"提交前必须格式化""发布前必须更新文档"等任何基于会话历史的完成度门禁场景。更多规则书写语法(多条件、运算符与字段参考、pattern 技巧)可进一步阅读 writing-rules 技能 与 Hookify README。

  • AI 插件
  • 开发工具
  • 插件系统

【免费下载链接】claude-plugins-official

Official, Anthropic-managed directory of high quality Claude Code Plugins.

项目地址:https://gitcode.com/GitHub_Trending/cl/claude-plugins-official
点击查看免费下载

相关推荐

上一篇:SteamAutoCrack离线破解教程:4步摘掉SteamStub枷锁,断网也能畅玩已购游戏
下一篇:mpv_PlayKit 快速上手指南:300 余款着色器与全中文配置,Windows 播放器一次调到位

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询