Install
openclaw skills install @snowsonz/agent-constraints给 coding agent 设置和治理约束——决定一条规则该落到 hook、AGENTS.md/CLAUDE.md、Skill、path-scoped rule 还是 prompt。当用户要写或改 AGENTS.md、CLAUDE.md、hooks、权限规则、Skill,或者问"agent 老犯某个错该怎么办"、"这条规则该放哪"、"我的 CLAUDE.md 太长了"、"怎么禁止 agent 动某个目录"、"怎么强制它跑完测试再结束"时使用。
openclaw skills install @snowsonz/agent-constraints上下文文件是行为杠杆,不是性能增强器。实测:无配置文件时目标指令执行率 0%,有文件时 67.7%;但任务成功率变化不显著,推理成本必然上升约 20%。
写下的每一条都会被真的执行——包括在不该执行的任务上。
同时,文件层会系统性失守:需要反复应用的规则,约 65% 的运行至少违反一次,首次失守通常在第 4 次应用附近,改存量代码场景单次命中率仅 45%。
这两件事共同决定了:约束必须分层,每条规则放在能承载它的最低层。
需要用数字说服人时读 EVIDENCE.md。
| 层 | 机制 | 性质 | 详见 |
|---|---|---|---|
| 1 执行层 | 执行门:hooks、permissions.deny、CI required check、pre-commit;检查器:linter、formatter、类型系统、测试 | 执行门确定性;检查器须接入执行门 | LAYER1-ENFORCEMENT.md |
| 2 常驻层 | AGENTS.md / CLAUDE.md | 每会话付费,建议性;单次应用命中 45%–84%,主要看任务类型 | LAYER2-INSTRUCTIONS.md |
| 3 按需层 | Skill、path-scoped rule | 只在相关时进上下文 | LAYER3-ONDEMAND.md |
| 4 会话层 | prompt、plan mode、SPEC.md、/goal | 一次性,最灵活 | 本文末尾 |
官方定性:settings 规则"由客户端强制执行,与 Claude 的决定无关";CLAUDE.md"塑造行为但不是硬强制层"。
检查器不是执行门。 linter、formatter、类型系统和测试只有接入 CI required check、pre-commit、PostToolUse 或 Stop hook 后,才构成第 1 层约束。单独存在的配置只能判定结果,不能保证它会被运行。
任何"要不要加这条""该放哪"的问题都走这个流程。默认答案不是"加到 AGENTS.md"。
候选规则
↓
① agent 读代码能自己知道吗? ──────────── 能 ──→ 不写。删。
↓ 不能
② 能在检查器中表达规则吗? ───────────── 能 ──→ 先在检查器中表达规则,再按执行时机和失败成本选择门禁(第 1 层)
↓ 不能
③ 是"必须发生、零例外"的动作或禁令吗? ─── 是 ──→ hook 或 permissions(第 1 层)
↓ 否
④ 删掉它,会导致一个你能具体命名的错误吗? 不能 ─→ 不写。这是投机性规则。
↓ 能
⑤ 每个任务上都该被执行吗? ───────────── 不是 ─→ 第 3 层
↓ 是 ├ 只在某类文件上成立 → path-scoped rule
↓ └ 是多步流程/检查清单 → Skill
⑥ 需要被反复应用吗(每个函数/每个文件/每次提交)?
↓ 是 ──→ 写进第 2 层,**并且**配 hook 兜底
↓ 否
写进 AGENTS.md,一行祈使句,HTML 注释里记下触发它的那次失败
第 ⑥ 步不是保守,是算术:反复应用的规则在文件层必然漏,hook 接住的正是那条尾巴。
第 ⑤ 步只认一个判据:「每个任务上都该被执行吗」。 不要用"这是不是项目知识"来替代它——通用的工程纪律如果对本仓库每个实现任务都成立,它就属于第 2 层,哪怕它一点也不"项目特有"。搬别处的结论而不重跑这一步,是最容易犯的错。
判到第 3 层之后再验一道:这条规则的触发词有辨识度吗? Skill 靠模型判断 description 匹配来唤醒,"写代码"这类默认活动唤不醒(见 LAYER3-ONDEMAND.md)。唤不醒就退回第 2 层。
另外单独问一句:这条规则会引发多少读取? 五问只审规则本身的字数,审不出它的连带成本。"实现前先读 A、B、C"本身两行,引发的可能是每会话几万 token——而且指令会被真的执行,这个成本是实打实的。这类规则要么改成"遇到某类问题时再参考",要么直接删。
只在这一次任务里成立的,根本不要进任何文件——直接写在 prompt 里(第 4 层)。
三种机制,按"能不能被绕过"排序:
| 需求 | 机制 |
|---|---|
| 禁止读/改某路径 | permissions.deny 的 Read(...) / Edit(...) 规则 |
| 禁止某类命令 | permissions.deny 的 Bash(...) 规则 |
| 编辑后必须跑检查 | PostToolUse hook,matcher Write|Edit |
| 按内容动态拦截 | PreToolUse hook,退出码 2 阻止 |
| 结束前必须验证通过 | Stop hook,退出码 2 阻止结束回合 |
| 任何进程都不许碰 | 开启 sandbox(权限规则管不到子进程;不要只用 CI 替代这个客户端隔离) |
检查器(linter / 类型检查 / 测试)本身不在这张表里——它要先接进一道门才算数。四道门(PostToolUse / Stop / pre-commit / CI required check)按执行时机和失败成本怎么选,见 LAYER1-ENFORCEMENT.md 的「把检查器接成执行门」。要点:pre-commit 一个 --no-verify 就绕过,红线只能靠 CI required check;而 CI 看不到 agent 在本地干的活,会话内要拦还得配 hook。
最常踩的三个坑(详见 LAYER1-ENFORCEMENT.md):
Edit(...) 和 Read(...)。写 Write(docs/**) 会被接受但永不生效。Bash(command:rm *) 这种参数形式会被忽略并告警,要写 Bash(rm *)。只放无法自动化、又无法从代码推断、且全局恒真的内容。
准入之后的写法:祈使句 + 精确命令、可验证的完成标准、显式 Never、最多一处强调、零冲突。
绝不要写:目录结构、技术栈概览、架构说明、README 复述——实证判定无收益且制造双事实源。
模板在 templates/,完整写作规范、修剪流程和反模式清单在 LAYER2-INSTRUCTIONS.md。
| 内容形态 | 机制 |
|---|---|
| 只在某类文件上成立的规则 | .claude/rules/*.md + paths: frontmatter(Copilot 用 applyTo) |
| 多步骤流程、检查清单 | Skill |
| 大段参考资料、API 规格 | Skill 的附属文件(不进 SKILL.md 主体) |
判据:如果一段内容在多数任务里都用不到,它就不该每次进上下文。 CLAUDE.md 里长成流程的那一节,应当搬到 Skill。
写法见 LAYER3-ONDEMAND.md。
不需要持久化的东西留在这里,别污染前三层:
SPEC.md,然后开新会话执行(干净上下文 + 书面规格)/goal,独立评估器每回合复查/clear 重开,带着学到的东西重写 prompt,比在污染的上下文里继续纠正更有效templates/AGENTS.md,先删后填——删掉所有还没遇到过对应失败的条目。宁可从三行开始。/init 然后直接提交。自动生成的内容大多复述既有文档,实测降低成功率。触发条件是第二次犯同一个错,不是"想到一条好规则"。走定层流程。多数情况下正确出口是第 1 层,不是加一行文字。
用户说"CLAUDE.md 太长了""agent 不听指令"时用这个。
读所有相关文件。两类都要读,缺一不可:
AGENTS.md、CLAUDE.md、.claude/rules/、.claude/skills/.gitignore、.pre-commit-config.yaml、CI 配置、linter/formatter 配置、.claude/settings*.json 及已有 hooks不读第 1 层就无法执行"已被覆盖 → 删"这条判定——那是产出最高的一条。
逐条重新定层——多数积累下来的条目本该在别的层。判定表见 LAYER2-INSTRUCTIONS.md。
检查缺什么:安全与性能边界只有约 15% 的项目写,却最不可能从代码推断。
检查冲突:父子目录文件之间、CLAUDE.md 与 rules 之间。矛盾时模型可能任意挑一条。
输出建议清单(删除/迁移/补充,各自附理由),让用户确认后再改。
编写约束是一件与当前编码任务无关、且需要独立验证的工作。放在主线程里做会污染上下文,也容易草草了事。
什么时候委派:确认了要新增/修改第 1 层或第 3 层的产物(hook、权限规则、Skill、path rule),且当前主任务尚未完成。第 2 层的一行文字改动不值得开子 agent,直接改。
交给子 agent 的任务描述必须自包含,它看不到你的对话:
验证要求(这一段必须写进任务描述,否则会得到"写好了"而没被验证过):
| 产物 | 怎么验证 | 陷阱 |
|---|---|---|
| 权限规则 | 跑 claude doctor 看 resolved settings;启动时的无效设置告警 | 静默失效的规则不会报错,只会告警(见 LAYER1-ENFORCEMENT.md 的三个坑) |
| hook | 实际触发一次匹配的工具调用,确认它 fire 了 | 退出码语义搞反是最常见错误:PostToolUse 阻止不了已执行的调用 |
| Skill | 一律新开会话验证——新装、改 description、改正文都是 | 正文走异步缓存,比磁盘落后一拍:改完立刻重调用拿到的是上一版,中间那次还会回 "instructions unchanged"。在旧会话里改一版调一次,验的不是你刚写的东西 |
| path-scoped rule | 读一个匹配的文件,确认规则进了上下文 | 没有 paths 的规则是无条件加载的,等于第 2 层 |
要求它带回来的是证据,不是结论:跑了什么命令、输出是什么。「已验证通过」这四个字没有信息量。
边界:子 agent 只负责写和验证约束产物,不要让它顺手改业务代码。主线程收到结果后自己决定是否采纳。
约束的触发条件是「第二次犯同一个错」,这是跨会话的信号,所以不做实时判断,只做记录 + 定期复盘。记录机制的装法见 hooks/README.md。
建议节奏:每周,或每积累 15–20 个会话一次。不要每个会话都做——噪声大于信号。
~/.claude/constraint-review.log(SessionEnd hook 的记录)——哪些会话值得回看~/.claude/projects/<project>/memory/ 下 type: feedback 的文件——auto memory 已经消化过的纠正复盘时要一并检查的:第 2 层文件是否又长了?有没有已被 CI 覆盖、可以删的条目?(这类文件会像配置代码一样通过频繁小幅增补持续膨胀,熵增是默认的。)
单文件目标 100 行以内。Claude Code 建议 CLAUDE.md 控制在 200 行内;Codex 合并上限默认 32 KiB,达到上限后停止继续加入文件;Copilot 建议不超过两页。
写短的理由是成本和"少拉杠杆",不是"短则遵从度高"——两项研究都没测到长度与遵从度的关系,数据趋势甚至相反。不要为压行数删掉真正有用的约束。
以 AGENTS.md 为单一事实源,CLAUDE.md 用 @AGENTS.md 导入并承载 Claude 专属内容。绝不维护两份。
验证加载:/context 看 Memory files;Codex 用 codex --ask-for-approval never "Summarize current instructions"。
任务类型对合规率的影响达 39 个百分点、模型 12.8 个、代码库 11.0 个——都远大于文件怎么写。别人的结论不可移植,包括本 Skill 的。
有规则与无规则各跑至少三次代表性任务,记录是否达成、步数、token、是否触发了担心的那个错误。没有可观测差异就删掉——成本确定,收益不确定。
但要诚实告知用户:原研究用每条件 50 次运行才对 15 个百分点的差异达到足够功效。跑三次看不出 10 个百分点的差别,小规模验证只能筛掉完全无效的规则。
第 1 层的约束不需要这样验证——它是确定性的,写对了就一定生效。这也是它优先于第 2 层的另一个理由。