关于 harness-eval
Harness Eval 是用于评估代码仓库中 Agent harness 内容的技能,适合需要检查其正确性、冗余度或实用性的团队。它先生成报告,默认不修改文件,并要求用户批准成本较高的评估轨道。
主要功能
- 01提取仓库清单与声明
- 02脚本检查引用路径和命令
- 03可选双评审冗余度评估
- 04可选双评审实用性评估
- 05检查精简内容的依赖方
适用场景
- 01检查 Agent 指南中的路径和命令是否存在
- 02评估技能内容是否冗余或值得保留
- 03审阅评估报告后再决定是否精简 harness
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tech-leads-club/ agent-skills --skill harness-eval安装后在 Claude Code 中输入/harness-eval确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/claims.schema.jsonGLOSSARY.mdjudge-prompts.mdPROTOCOL.mdscripts/doc_scope.pyinventory_extract.pymerge_agreement.pymerge_usefulness.pyslim_fanin.pysurfaces_extract.pytrack_a_correctness.py详细介绍
Harness Eval
运行一次完整的、与技术栈无关的 Harness 评估,并在生成报告后停止。除非用户审阅 Ship/Slim 后明确提出要求,否则不要自动编辑 AGENTS.md 或 skills。
用户问卷(高优先级)
继续之前先停下来询问。 不要跳过这些关卡。不要静默纳入可选文档,也不要启动 B/C 评审。
清点之后的顺序:Q1(如有需要)→ Q2 → 然后执行 Track A(始终运行 A)→ 仅在获批后运行 B/C。
Q1 — 可选项目文档(清点之后)
当 optional-docs-candidates.md 列出可选类型时,在 Q2 / Track A 之前询问:
Inventory found cited project docs outside the agent skill trees.
- **Always in scope:** skill-tree files (`.agents/skills`, `.cursor/skills`, `.claude/skills`)
- **Always excluded:** ADRs / RFCs / decision-record trees (never scored as T2)
- **Optional (default: omit):** see types/paths in `optional-docs-candidates.md`
Include any optional doc types or paths in this run?
Reply with: `none` (default), type ids (e.g. `docs`), and/or specific paths.
只有在用户回答后,才使用 --include-doc-type / --include-doc 重新清点。如果没有可选类型,则跳过 Q1。
Q2 — Tracks B 和 C(Track A 之前——预算)
在 Track A 之前询问,方便用户预先设定预算。接下来始终运行 Track A(确定性流程,约 0 个模型 token)。只有获批后才运行 B/C。
Choose eval scope for this run (before Track A).
| Track | Question | Certainty | Token consumption |
|-------|----------|-----------|-------------------|
| **A — Correctness** | Cited path/command exists? | **Highest** — script only, no LLM. Prefers false negatives over false BROKEN. | **~0 model tokens** (always runs next) |
| **B — Redundancy** | Would an agent rediscover this cheaply without the harness? | **Medium** — dual LLM + plants; Ship only if trap PASS and both agree. Disagree → Hold. Less model-sensitive than C. | **High** — 2 judges × every claim (~N in this inventory). Each may spot-check the repo. |
| **C — Usefulness** | Does this surface change behavior vs theory/demo/overlap? | **Lowest / most subjective** — dual LLM + plants + fan-in; **model-sensitive**. Slim/Mixed need gates; prefer second-model check before large deletes. | **Highest** — 2 judges × every surface (whole files; often dominates the run). |
Notes: Ship (B) ≠ Slim (C). Rediscoverable ≠ useless. A always runs; B/C are optional.
Reply with one of: `A only`, `B`, `C`, or `B+C`.
已知时,从 claims.md 填入声明数量;提取后显示约有 T0+T1+T2 项 Markdown 表面内容(如果尚未运行,则说明“运行 surfaces_extract 后”)。
A only: 运行 Track A;展示04;停止(不运行 B/C 评审)。B: 运行 Track A,然后执行步骤 4–6。C: 运行 Track A,然后执行步骤 7–10(C 不需要 B)。B+C: 运行 Track A,然后执行步骤 4–11。
如果用户在触发消息中已经要求运行 B/C / full eval,则视为已获批准——仍需展示一次 Q2 表格,让用户了解费用。
加载此技能的文件
此技能自包含。协议、脚本和评审提示词均位于此技能目录下(即包含 SKILL.md 的文件夹)。将该目录解析为 SKILL_DIR——绝不要假定其他安装路径。
- 首次运行之前(以及脚本失败时),完整阅读 references/PROTOCOL.md。
- 启动 Track B 或 Track C 评审时,阅读 references/judge-prompts.md。
- 通俗术语参见 references/GLOSSARY.md(也嵌入
04/07/10报告开头)。 - 声明记录格式参见 references/claims.schema.json(供工具使用;Agent 不必每次运行都加载)。
- 按如下形式运行脚本:
python3 "$SKILL_DIR/scripts/<name>.py" ...。
运行输出(非协议)写入目标仓库的 .harness-eval/runs/<run-id>/。
关键规则
- 默认仅报告。 判断 ≠ 修复。
- README 不在范围内,既不是测试框架表面,也不是重新发现能力或实用性的证据。
- 与技术栈无关。 提示词或方案中绝不硬编码包管理器、数据库、框架或目录布局。发现实际存在的清单(JS、Python、Make/Task、Rust、Go、PHP、Ruby/Rails、Java/Gradle/Maven,以及
bin/*)。 - 文档范围。 T2 始终包含 Agent 技能树引用(
.agents/skills、.cursor/skills、.claude/skills)。ADR / RFC(决策记录树)始终不纳入 T2 表面。 其他引用的项目文档为可选项——默认省略;在此技能顶部通过 Q1 询问,然后使用--include-doc-type/--include-doc重新运行。 - 清点后始终运行 Track A(确定性高精度)。宁可漏报,也不要误报 BROKEN。占位符(
SPEC_FOLDER、{x}、[feature])绝不判为 BROKEN。绝不使用str.lstrip('./')规范化路径。 - Track B 和 C 必须先通过 Q2 获得用户批准,且 Q2 须在 Track A 之前。 用户选择加入前,不得启动 B/C 评审者。用户可批准仅运行 B、仅运行 C、同时运行两者,或仅运行 A。
- Track B 需要双评审者和植入项。 Judge2 必须盲评(不得读取 Judge1 评分或
trap-key.json)。只有陷阱门禁 PASS 且双评审结果为 REDUNDANT,且 Judge2 成本 ≤ 1 时才可发布。 - Track C 需要双评审者和植入项。 盲评的 Judge2 不得读取
08-usefulness-j1.md或usefulness-trap-key.json。只有陷阱门禁 PASS、双评审结果为 SLIM/ROUTING-ONLY,且扇入检查 PASS(没有其他测试框架表面将该路径作为 SoT 硬加载——合并时会检查完整技能树,而不仅是--seed)时才可精简。实用性对模型敏感——在两个评分文件中记录model: <id>;单次运行中尽量使用相同模型;大规模删除 Slim 内容前,换用第二个模型重新评审。 - KEEP / KEEP-CORE 植入项不得是评分材料中已有声明/表面的逐字副本。
- 子代理: 使用允许列表中的非 fast 模型(策略允许时优先选用与父代理相同系列的模型)。不得使用
*-fast模型。 - 不得混淆不同轨道。 Track B Ship ≠ Track C Slim。可重新发现 ≠ 无用;有用 ≠ 不冗余。
- Slim 应用 / 扇入。 除非在同一变更中更新相应消费者,否则绝不为“被 Slim 扇入阻止”下列出的路径创建存根或删除这些路径(或当
python3 "$SKILL_DIR/scripts/slim_fanin.py" --path <P>报告存在引用者时)。 - Mixed/Slim 应用必须保持自包含。 删除 REPO-DEMONSTRATED / THEORY 内容意味着从测试框架表面删除或压缩这些内容。绝不要用
See app/.../lib/.../test/...替换围栏中的教学代码片段(或其承载的约定)——这会用代码树指针替换 SoT。评审证据路径只能保留在评分表中;若必须保留会改变行为的约定,则保留一条简短的技能内规则或代码片段。 - Mixed 应用是机械操作。 仅有双 MIXED 结果还不够。Merge 会生成
11-mixed-apply.md,其中按 ID 列出 KEEP(来自 Keep-core 列)和 CUT(来自 Slim 列)。应用代理必须只遵循该文件——不得重新评审、重新设计或另行发明与 KEEP 不同的模式。Keep-core/Slim 单元格为空时,跳过该路径(Hold)。
说明
步骤 1:解析 SKILL_DIR
将 SKILL_DIR 设置为包含此 SKILL.md 的目录。验证以下文件存在:
$SKILL_DIR/references/PROTOCOL.md$SKILL_DIR/scripts/inventory_extract.py$SKILL_DIR/scripts/track_a_correctness.py$SKILL_DIR/scripts/merge_agreement.py$SKILL_DIR/scripts/surfaces_extract.py$SKILL_DIR/scripts/merge_usefulness.py$SKILL_DIR/scripts/slim_fanin.py$SKILL_DIR/scripts/doc_scope.py
如果缺少任何文件,则技能安装已损坏——停止。
步骤 2:清点 + 声明材料
在目标仓库根目录中:
RUN_ID=$(date -u +%Y-%m-%d)-full
python3 "$SKILL_DIR/scripts/inventory_extract.py" --root . --run-id "$RUN_ID"
# Optional scope: AGENTS.md + one-hop related skills only
# python3 "$SKILL_DIR/scripts/inventory_extract.py" --root . --run-id "$RUN_ID" --seed AGENTS.md
预期在 .harness-eval/runs/$RUN_ID/ 下包含:inventory.json、claims.jsonl、claims.md、trap-key.json、optional-docs-candidates.md(以及 .json)。
步骤 2b:可选文档 — Q1(见顶部)
阅读 optional-docs-candidates.md。如果存在可选类型,则运行用户问卷中的 Q1。仅在获得批准后重新运行清点:
python3 "$SKILL_DIR/scripts/inventory_extract.py" --root . --run-id "$RUN_ID" \
--include-doc-type docs # and/or --include-doc path
步骤 2c:跟踪预算 — Q2(见顶部)
在 Track A 之前运行用户问卷中的 Q2。记录答案(A only / B / C / B+C)。除非 B 和/或 C 已获批准,否则不要开始步骤 4 及后续步骤。
步骤 3:Track A(确定性)— 始终运行
python3 "$SKILL_DIR/scripts/track_a_correctness.py" --root . --run-id "$RUN_ID"
预期结果:04-correctness.md(顶部包含术语定义)。抽查 .agents/... 引用是否能正确解析(而不是 agents/...)。
总结 Track A(损坏数量 + 值得注意的集群)。如果 Q2 的答案是 A only,则停止。否则继续执行已获批准的 B 和/或 C 步骤。
步骤 4:Track B — Judge1
阅读 references/judge-prompts.md(Track B Judge1)。启动一个使用允许列表中模型的独立子 Agent,并指定其检查 .harness-eval/runs/$RUN_ID/claims.md。它会写入 05-redundancy-j1.md(包含 model: <id>)。
Judge1 可以读取 inventory.json。不得读取 trap-key.json。
步骤 5:Track B — Judge2(盲评)
阅读 references/judge-prompts.md(Track B Judge2)。启动第二个子 Agent。它会写入 06-blind-scores.md。
Judge2 禁止读取:trap-key.json、05-redundancy-j1.md、07-agreement.md、之前的 agreement 报告。
建议并行执行步骤 4 和 5。
步骤 6:合并 Track B 的一致性结果
python3 "$SKILL_DIR/scripts/merge_agreement.py" --run-dir .harness-eval/runs/$RUN_ID
预期结果:07-agreement.md(Ship/Review/Hold + 这些词的含义)。如果 trap 检查失败:按照 PROTOCOL 修复植入项,为 P00x 重新评分,然后重新合并 — 不要 Ship。
步骤 7:Track C — 表面清单
python3 "$SKILL_DIR/scripts/surfaces_extract.py" --root . --run-id "$RUN_ID"
预期结果:surfaces.md、surfaces.json、usefulness-trap-key.json。
步骤 8:Track C — Usefulness Judge1
阅读 references/judge-prompts.md(Usefulness Judge1)。启动一个使用允许列表中模型的子 Agent(在标题中记录相同的模型 ID)。它会写入 08-usefulness-j1.md。
不得读取 usefulness-trap-key.json。
步骤 9:Track C — Usefulness Judge2(盲评)
阅读 Usefulness Judge2 提示词。为保持一致性稳定,建议使用与步骤 8 相同的模型。它会写入 09-usefulness-j2.md。
禁止读取:usefulness-trap-key.json、08-usefulness-j1.md、10-usefulness-agreement.md,也不得使用 Track B 的 05/06/07 来判断 usefulness 类别。
建议并行执行步骤 8 和 9。
步骤 10:合并 Track C 的一致性结果
python3 "$SKILL_DIR/scripts/merge_usefulness.py" --run-dir .harness-eval/runs/$RUN_ID
预期结果:10-usefulness-agreement.md(Slim/Keep-core/Mixed/Hold + 这些词的含义)、11-mixed-apply.md(每个 Mixed ID 对应的 KEEP/CUT),以及 slim-fanin.json。如果 trap 检查失败:不要 Slim。带有 slim-fanin-blocked 的表面属于 Hold — 不是 Slim apply 候选项。
步骤 11:展示结果
根据 agreement 报告总结(每份报告均以术语定义开头):
- Track A 损坏数量 →
04-correctness.md - Track B trap 检查结果 + Ship/Review/Hold →
07-agreement.md - Track C trap 检查结果 + fan-in + Slim/Keep-core/Mixed/Hold →
10-usefulness-agreement.md - Mixed 数量大于 0 时,指出
11-mixed-apply.md(这是唯一的 Mixed apply 路径) - 指出 Track C 使用的模型 ID,并说明 Slim 对模型敏感
- 指出任何 Slim fan-in 被阻止 的条目(此处可能会出现种子范围以外的消费者)
除非用户要求应用 Ship/Slim/Mixed,否则停止。应用时:
- **Slim:**仅处理 Slim 表格中的路径(fan-in PASS);如果路径被 fan-in 阻止,绝不能先将其设为存根而不先更新引用方。
- **Mixed:**打开
11-mixed-apply.md,并且只根据 ID 执行 KEEP/CUT(规则 12)。绝不能仅根据 Mixed 路径列表重新判断。绝不能用代码树路径指针替代被删除的演示(规则 11)。
示例
示例 1:完整的 harness 评估
用户说:“对这个仓库运行 harness 评估”
操作:清点 → 如有需要则运行 Q1 → Q2(B/C 预算表)→ Track A → 如果获批,则执行步骤 4–11。并行运行 B 的评审,再运行 C 的评审。展示一致性结果(术语见文件)。
示例 2:仅运行 Usefulness(使用已有运行记录)
用户说:“对最近一次 harness-eval 运行记录执行 Track C usefulness”
操作:针对该 RUN_ID 执行步骤 7–11(清点结果必须已存在)。
示例 3:错误的技能
用户说:“setup harness” / “init harness” → harness setup(不是此技能)。用户说:“specify feature” → tlc-spec-driven。
故障排查
陷阱门禁 FAIL(Track B 或 C)
原因:KEEP/KEEP-CORE 植入项是牌组中的重复项,或盲测判定器误判了类别。解决方案:使用技能的固定植入项模板;重新评分植入项;重新合并。
Track A 错误地报告缺少 .agents/...
原因:路径规范化有误。解决方案:技能脚本必须使用 normalize_cite(仅去除 ./)。从 $SKILL_DIR/scripts/ 重新运行 Track A。
子 Agent 受阻
原因:模型缺失/不在允许列表中,或 *-fast 被阻止。解决方案:使用允许列表中的非 fast 模型重新启动。
更改模型后,Track C Slim 看起来不对
预期情况:实用性会受模型影响。在第二个模型上重新运行 C1+C2;Slim 范围的交集是安全的删除集合。
混合应用重写了规范/移除了模块
原因:应用 Agent 根据 Mixed 路径列表重新判断,而没有遵循 KEEP/CUT。解决方案:仅通过 11-mixed-apply.md 应用;如果缺少该文件,重新运行 merge_usefulness.py;如果 Keep-core/Slim 单元格含糊不清,在应用前重新评分这些 ID。
T2 为空 / 技能 references/ 未纳入清单
原因:路径规范化使用了 lstrip("./"),将 .agents/… 转成了 agents/…。解决方案:doc_scope.normalize_rel 必须仅去除 ./ 前缀(与 Track A 的规则相同)。
Track C 中出现了 ADR
原因:旧版清单将所有一跳 docs/** 都视为 T2。解决方案:v1.7+ 不再纳入决策记录目录树;只有用户批准的可选文档类型(绝不包括 ADR/RFC)才能进入 T2。
Slim 存根导致另一个加载该文件的技能出问题
原因:内容存在 OVERLAP/Slim,但未考虑 fan-in——可能是较早的运行,也可能是应用时跳过了门禁。解决方案:恢复清单正文;使用 merge_usefulness.py 重新合并(fan-in 会扫描完整的技能目录树)。使用 slim_fanin.py --path <P> 确认。
缺少脚本
原因:技能文件夹不完整。解决方案:恢复 $SKILL_DIR/scripts/ 和 references/。