executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
gateguard强制事实的门控,阻止编辑/写入/Bash(包括MultiEdit),并要求在允许操作之前进行具体调查(导入器、数据模式、用户指令)。与无门控代理相比,可测量地将输出质量提高2.25分。
Independent GitHub snapshot · Automated classification · Original documentation governs
一个 PreToolUse 钩子,强制 Claude 在编辑前进行调查。不同于自我评估("你确定吗?"),它要求具体的事实。调查行为本身创造了自我评估永远无法带来的认知。
LLM 的自我评估不起作用。问"你是否违反了任何策略?"答案永远是"没有"。这已通过实验验证。
但问"列出所有导入此模块的文件"会迫使 LLM 运行 Grep 和 Read。调查本身创造了改变输出的上下文。
三阶段门控:
1. DENY — 阻止首次编辑/写入/Bash 尝试
2. FORCE — 明确告知模型需要收集哪些事实
3. ALLOW — 在事实呈现后允许重试
没有竞争对手能同时做到这三步。大多数止步于拒绝。
两个独立的 A/B 测试,相同的代理,相同的任务:
| 任务 | 有门控 | 无门控 | 差距 |
|---|---|---|---|
| 分析模块 | 8.0/10 | 6.5/10 | +1.5 |
| Webhook 验证器 | 10.0/10 | 7.0/10 | +3.0 |
| 平均 | 9.0 | 6.75 | +2.25 |
两个代理生成的代码都能运行并通过测试。区别在于设计深度。
多编辑的处理方式相同——批次中的每个文件都单独进行门控。
在编辑 {file_path} 之前,请先呈现以下事实:
1. 列出所有导入/引用此文件的文件(在代码树中搜索——Glob/Grep,或通过 Bash 用 find/grep)
2. 列出受此更改影响的公共函数/类
3. 如果此文件读取/写入数据文件,请显示字段名称、结构以及日期格式(使用脱敏或合成值,而非原始生产数据)
4. 逐字引用用户当前的指令
在创建 {file_path} 之前,请先说明以下事实:
1. 命名将调用此新文件的文件及行号
2. 确认没有现有文件具有相同功能(在代码树中搜索——Glob/Grep,或通过 Bash 用 find/grep)
3. 如果此文件读取/写入数据文件,请展示字段名称、结构及日期格式(使用脱敏或合成值,而非原始生产数据)
4. 逐字引用用户当前的指令
触发条件:rm -rf、git reset --hard、git push --force、drop table 等。
1. 列出此命令将修改或删除的所有文件/数据
2. 编写一行回滚步骤
3. 逐字引用用户当前的指令
1. 当前用户请求的一句话概括
2. 此特定命令验证或生成的内容
以上编辑/写入门控的问题适用于 code 类目标。完整规则见英文版 skills/gateguard/SKILL.md,要点如下:
.claude/worktrees/<name>/)依次判定为 instruction(CLAUDE.md、AGENTS.md、SKILL.md、.mdc、.cursorrules、.github/copilot-instructions.md 等)、test、prose(.md 等)、config(.json、.yaml、.env / .env.* 等,.env.example.ts 仍属 code)或 code,并提出相应的问题。Glob、Grep、LS 或 rg/grep/find 等搜索命中该文件,则以附注代替拒绝。Read 从不计入;与被门控调用同批次的搜索、重复的 tool_use id、压缩(compaction)之前的搜索均不计入。文件名词干须按单词边界匹配(测试目标先去掉一个测试词缀:.test、.spec,以及 Python/Go 的 test_/_test,因此 rg tokenizer src tests 可抵免 tests/tokenizer.test.js,而 index.test.js 仍是通用词干 index),且目标须位于所搜索目录之内(shell 片段按其路径参数或 cwd 判定范围;参数前的输入重定向 < 视为读取 stdin)。仅"创建尚不存在的文件"的写入可按目录匹配,且 shell 参数须是真实存在的目录;回合内出现 cd 等切换目录命令时不再按 shell 目录匹配。相对路径按工具的 cwd 解析。排除规则从不计入:Grep 的 glob 中以 ! 开头的项,以及 shell 中 rg -g '!x'、grep --exclude/--exclude-dir、fd -E、ls -I、tree -I、git ls-files -x、git :!x 路径规格、带 -not/! 或后接 -prune 的 find -name/-path、PowerShell -Exclude 都不作为词干来源;若排除项覆盖目标(文件名、路径上的目录或词干),该搜索完全不能为其抵免(rg -g '!widget.py' TODO . 不抵免 widget.py,rg -g '!*.md' widget . 仍抵免)。含 --exclude-from/--ignore-file 的片段不抵免;用 *.py、--include、find -name 等文件名 glob 限定的搜索,只有在其匹配目标文件名时词干才计入。trivial_allows,但不标记为已检查,下一次改动代码的编辑仍按首次触碰门控(写入、Python 缩进变化、多行字符串等从不算作此类编辑)。Read 等非搜索、文件名过于通用);细节经净化并截断至 60 个字符。. 开头的路径段(点文件和所有点目录)或 8.3 短文件名下的文件从不合并;目录按解析符号链接后的真实位置判定和记录;有 transcript 路径但文件缺失、无法读取或得不到回合 ID 时不合并;编辑从不合并。GATEGUARD_FACT_FORCE_MAX_DENIALS 后,会话内首次触碰的拒绝次数达到该值后,新路径直接放行(计入 cap_allows)。GATEGUARD_FACT_FORCE_FULL_DENIALS 只决定消息详略(消息预算),而此变量决定是否拦截(拒绝预算)。事先搜索抵免和同级合并先于上限判定,不消耗上限;格式错误的值视为无上限,并在 stderr 警告一次。.env/.env.*、*.pem/*.key/*.p12/*.pfx、id_rsa*/id_ed25519*/id_ecdsa*/id_dsa*/.netrc/.pgpass/credentials*/secrets.*、任一路径段恰为 auth、authn、authz、security、secrets、payment、payments、billing、migrations,以及 .github/workflows/ 下的文件,不适用抵免、合并和上限,首次触碰总是拒绝。按字面路径和解析符号链接后的真实位置同时判定(src/tools -> ../auth 时 src/tools/login.py 也是敏感目标),真实位置无法解析时视为敏感。判定顺序:exempt → subagent → checked → 敏感或硬链接? → 抵免 → 同级合并 → 上限 → 拒绝。GATEGUARD_EXEMPT_GLOBS 的豁免优先于一切规则,对敏感目标和硬链接目标同样生效。notebook_path 的编辑门控(相同的类别、已检查键、抵免与上限规则;不读取单元格内容,因此总是完整问题,也从不按仅注释放行)。ls、cat、rg、git status/log/diff、Get-ChildItem 等,不含重定向、替换、tee、xargs 或未知命令)直接放行且不消耗门控,计入 routine_readonly_passes;以会话 ID 或 transcript 路径为键的状态空闲 8 小时失效,项目目录回退键仍为 30 分钟;子代理对敏感目标每个路径拒绝一次(不会为父会话解锁)。GATEGUARD_METRICS=1 后,每次判定向 <GATEGUARD_STATE_DIR>/metrics.jsonl 追加一行(不记录路径、命令或内容,超过 1 MiB 轮转为 .1);用 node scripts/gateguard-report.js [--dir <path>] [--json] 汇总。GATEGUARD_FACT_FORCE_MAX_DENIALS 和 GATEGUARD_METRICS;除子代理首次触碰敏感或硬链接目标、以及每个笔记本的首次 NotebookEdit(此前不受门控)外,以前允许的操作不会变为拒绝,且从不返回 permissionDecision: "allow"。scripts/hooks/gateguard-fact-force.js 处的钩子已包含在此插件中。通过 hooks.json 启用它。
如果 GateGuard 阻止了设置或修复工作,请使用
ECC_GATEGUARD=off 启动会话。如需钩子级别的控制,请继续使用
ECC_DISABLED_HOOKS 配合 GateGuard 钩子 ID。
pip install gateguard-ai
gateguard init
这会添加 .gateguard.yml 用于按项目配置(自定义消息、忽略路径、门控开关)。
%Y/%m/%d %H:%M。检查数据结构(使用脱敏值)可以防止这类错误。.gateguard.yml 忽略 .venv/、node_modules/、.git/ 等路径。safety-guard — 运行时安全检查(互补,不重叠)code-reviewer — 编辑后审查(GateGuard 是编辑前调查)