- AI 插件
- 开发工具
- 插件系统
【免费下载链接】claude-plugins-official
Official, Anthropic-managed directory of high quality Claude Code Plugins.
导读
本文聚焦 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 事件的特殊性:
| 规则文件 | event | action | 判定目标 | 触发结果 |
|---|---|---|---|---|
| dangerous-rm.local.md | bash | block | Bash 命令(rm\s+-rf) | 拒绝工具执行 |
| console-log-warning.local.md | file | warn | 写入内容(console\.log\() | 提示但放行 |
| sensitive-files-warning.local.md | file | warn | file_path + new_text 多条件 | 提示但放行 |
| require-tests-stop.local.md | stop | block | 会话 transcript | 拒绝结束会话 |
可以看出,本规则是四者中唯一的"会话级完成度校验":它不拦截任何单个工具调用,而是在任务的"出口"把关。这类规则特别适合用于CI 前置的质量保障、交付物完整性校验,或对 Agent 纪律性有硬性要求的自动化流程。
五、使用前提与注意事项
- 严格模式,谨慎开启:原文档特别注明"Enable this rule only when you want strict test enforcement"。一旦开启,Agent 未运行测试将无法停止,若项目没有测试脚本,可能导致会话无法正常收尾;
- 规则文件位置:必须位于项目根目录
.claude/,Hookify 通过glob.glob('.claude/hookify.*.local.md')扫描(见 config_loader.py);删除某条规则只需删除对应的.local.md文件; - 匹配是子串级、大小写敏感:
not_contains不做正则与大小写归一,编写 pattern 时需覆盖实际命令形态; - 无需重启:所有规则的增删改都在下一次事件触发时生效;
- 环境要求: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.
相关推荐
ECC Hookify 实战指南:从会话分析到自动生成 Claude Code 防呆钩子规则
ECC Hookify 实战指南:从会话分析到自动生成 Claude Code 防呆钩子规则 在 ECC(Everything Claude Code)Agen
人工智能AI 技能AI 插件AI 评测Agent 评测MCP Clients开发工具ECC Hookify 规则系统实战:用 /hookify 将 Claude Code 的不良行为固化为可管理的钩子规则
ECC Hookify 规则系统实战:用 /hookify 将 Claude Code 的不良行为固化为可管理的钩子规则 ECC Everything Clau
人工智能AI 技能AI 插件AI 评测Agent 评测MCP Clients开发工具Hookify 插件实战指南:用 Markdown 规则文件为 Claude Code 自定义 Hook
Hookify 插件实战指南:用 Markdown 规则文件为 Claude Code 自定义 Hook 本指南完整讲解 Claude Code 官方插件目录中
AI 插件开发工具插件系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考