验证流程指南
这份文档假设你没有读过本项目的其它任何文档。它讲的是:怎么在任意宿主的机器上 装配并运行这条技能验证流水线。
配套:技能本身怎么写 → 《技能编写指南.md》;新手照着做 → 《操作手册.md》; 换机器 / 搬到别的宿主 → 《迁移与部署指南.md》;想弄清代码结构 → 《仓库结构说明.md》。 适用前提:个人小团队(≤2 人);不需要联网(除官方校验器对账外);不需要安装任何第三方 Python 包。
一、它是什么,解决什么问题
skillverify 是一条覆盖 Agent Skill 从设计到运行的验证流水线,分五层:
| 层 | 命令 | 查什么 | 为什么需要它 |
|---|---|---|---|
| 官方规范 | spec |
frontmatter 6 字段与命名约定 | 官方校验器只查这些 |
| 机械补检 | lint |
引用、上下文预算、目录卫生、脚本契约、依赖、安全、编码 | 官方完全不查这些 |
| 评测资产 | evals |
官方 evals/evals.json 与工作区产物(输出质量)+ evals/trigger-queryset.json 与运行记录(会不会被触发) |
官方给了硬约定但没有工具;触发这一层官方根本不覆盖 |
| 语义评审 | review |
30 条提示词的判断(描述质量、可验证性、安全性…) | 机械层查不了"写得对不对" |
| 交付门禁 | deliver |
汇总上面的结论,决定能不能交付 | 防止"带着没查的项交付" |
设计前提:宿主无关(不假设特定宿主的目录、不硬编码宿主名)、纯标准库、 强制 UTF-8(Windows 上的 GBK 曾把旧工具链直接打崩)。
退出码(全族统一,便于任何 CI 消费):
| 码 | 含义 |
|---|---|
0 |
全 PASS(含"不适用") |
1 |
有 FAIL(阻断项) |
2 |
无 FAIL,但有 WARN(需人工判断)或 SKIP(本项未执行) |
报告里的判定只有五种:FAIL(阻断)、WARN(人工甄别)、SKIP(本项未执行,不许当成通过)、
INFO(不适用)、PASS。
二、跑起来
不需要 pip 安装也能用(免安装直接跑 repo):
cd <本仓库>
python -m skillverify.cli --help
安装后(可选,见本仓库的打包配置)命令名就是 skillverify:
skillverify --help
Python 版本:
discover/check/watch/deliver/hook需要 ≥3.11 (用标准库tomllib解析配置文件);spec/lint/evals/review在更早版本也能用。
三、技能放在哪里:声明式宿主适配
技能存放位置不写死在代码里,而是读一份声明文件 hosts.toml:
skillverify discover --show-config # 看当前生效的配置(含来源顺序)
skillverify discover # 看发现了哪些技能、每个根命中几个
内置配置(随包分发)里的默认档就是官方跨宿主约定:项目级 <项目>/.agents/skills/、
用户级 ~/.agents/skills/。另外预置了几个兼容档(workbuddy、project-local、
nested-by-category)供参考。
配置覆盖顺序(后者覆盖前者,列表是整体替换而不是拼接):
内置 < ~/.agents/skillverify/hosts.toml < <项目>/.agents/skillverify/hosts.toml < --config <文件>
接入一个新宿主:只改配置,不改代码
假设某宿主把技能放在 .acme-corp/skills/:
# acme.toml
[hosts.acme-corp]
description = "Acme 布局"
project_roots = [".acme-corp/skills", ".agents/skills"]
user_roots = ["~/.acme-corp/skills", "~/.agents/skills"]
trace_dir = ".agents/skillverify"
max_depth = 1
skillverify discover --config acme.toml --host acme-corp
skillverify check --config acme.toml --host acme-corp
字段含义:project_roots(相对项目目录;绝对路径原样使用)、user_roots(~ 按当前用户主目录展开)、
trace_dir(中央留痕目录)、max_depth(技能根下最多下钻几层找 SKILL.md)。
未知键会直接报错(把 project_roots 拼成单数而静默发现 0 个技能,是这类工具最坏的失败模式)。
不想动配置文件时,用 --root 直接指定技能根(给出后完全替换配置里的根列表):
skillverify discover --root <技能根>
同名技能出现在多个根时,会记 DISC-001 并保留两者(不静默覆盖)——两处并存说明不同宿主
可能加载到不同版本,这是要解决的问题,不是要掩盖的问题。
四、逐层跑
4.1 单个技能
skillverify spec <技能目录> # 官方规范(可加 --official 与官方 CLI 对账)
skillverify lint <技能目录> # 机械补检
skillverify lint <技能目录> --scripts # 额外实测脚本契约(会执行脚本,须显式开启)
skillverify evals <技能目录> # 两类评测资产:官方 evals.json + 触发查询集
执行层委托官方工具:评测的执行(跑 with/without、算 benchmark、A/B、按结果改进)
由官方 skill-creator(或你的宿主)提供,本项目不自研执行器——只校验它产出的产物形状与口径
(grading.json / timing.json / benchmark.json 的字段、阈值、对账关系)。理由很直接:
官方已有执行层,重复造一个只会与它的产物格式漂移。
要真跑评测:本工具不执行评测。用官方 skill-creator 或你的宿主跑,再把它的入口命令交给
evals --run-with "<命令>" 委托执行(本工具负责限时、报退出码,并在跑完后重新校验产物;
命令失败记 RUN-101 FAIL,绝不写成"不适用")。
evals 同时校验两类资产:官方输出质量评测(evals/evals.json,形状由官方固定)与
触发评测(evals/trigger-queryset.json + evals/trigger-runs.json,本项目约定)。
两类都没有时都会给出 WARN 而不是静默通过——「没有证据」与「证据全绿」必须能区分开。
若技能里还留着旧落点(.verification/trigger-eval/queryset.json),报告会直接给出迁移指引。
4.2 整库批量
4.1b 机械层还会查什么(加固轮新增)
| 规则 | 查什么 | 判定 |
|---|---|---|
HYG-006 |
license 字段是否过长(完整条款该放随包文件) |
WARN |
HYG-007 |
声明了 license 就该有随包许可文件 |
WARN |
SEC-008 |
隐藏字符:双向控制符(Trojan Source)/ 零宽字符 | 代码里双向控制符 FAIL;其余 WARN |
SCRIPT-009 |
声明了 --dry-run 的脚本试跑后不得改动技能目录 |
改动 → FAIL(在临时副本里验证) |
SCRIPT-005 |
破坏性/有状态操作须有防护旗标(扫全包代码文件);证据给出 file:行(类别):原文 的定位段落 |
无旗标 → WARN |
EVAL-010 |
断言区分度:跨轮次恒真/恒假的断言 | WARN(观测不足 3 次记 INFO) |
REV-012 |
评委校准:判错校准样本 | 判错 → FAIL(结论不可用);没做 → INFO |
skillverify check --root <技能根> --stages all
--stages 可选 all(spec+lint+evals+review)/ both(spec+lint)/ 单阶段。
check 默认 both(日常快查)。未发现任何技能时返回 1——"什么都没检查"不允许看起来像通过。
4.3 挂载前置检查(上宿主之前)
skillverify mount --project <项目> --user-home <用户主目录> # 查当前生效的宿主档
skillverify mount --project <项目> --skill <技能名> # 只查这个技能
skillverify mount --project <项目> --all-hosts # 逐个宿主档都查(新接宿主时用)
它在仓库侧能确定的范围里回答「这个技能放到宿主上会不会有问题」:
| 检查 | 问的是 |
|---|---|
MOUNT-001 |
技能真的落在该宿主档声明的目录里吗(不是「我以为我放进去了」) |
MOUNT-002 |
SKILL.md 可解析、name/description 都读得出来且非空吗(描述为空的技能宿主会跳过) |
MOUNT-003 |
同一宿主档里有没有同名技能(宿主加载哪一份是不确定的) |
MOUNT-004 |
把三种结构损坏的 frontmatter 注入临时副本后,解析器会 fail-loud 吗(不触碰原目录) |
它不验证宿主注册表与真实触发匹配——本工具没有宿主 API、也没有宿主运行时,那两件事请在目标
宿主里人工确认。默认只查当前生效的宿主档;配置里的兼容档并不是你在用的布局,拿它们报
「技能不在声明目录里」只会是噪声,所以逐个档验收时要显式 --all-hosts。
4.4 库级检查(把技能集合当整体看)
单技能检查看不见两类问题,它们只在技能一多时才出现:
skillverify discover --project <项目> # 顺带打印库级结论
skillverify check --project <项目> --metadata-budget 8000 # 也可以收紧预算
| 检查 | 问的是 |
|---|---|
LIB-001 |
全部技能的 name+description 加起来多少字符?超过预算没有?宿主启动时会把它们一起读进上下文,超了就会静默丢弃某些技能(不报错、不生效) |
LIB-002 |
有没有两个技能的描述用词高度重合?(触发时互相抢)会点名是哪两个、并列出共同词元 |
口径写在报告里,别当成官方硬线:预算默认 8000 字符(本项目约定,可用 --metadata-budget 覆盖,
真实上限由你的宿主决定);只计 name+description,不含宿主自身的包装开销;
LIB-002 是词面重叠(字符 bigram + 词元,纯离线),不是语义相似度——它只把
"最该人工看一遍的那几对"挑出来,词元太少的描述会被明确排除在比对之外。
4.5 外来技能审计(从别处拿来的技能,用之前)
skillverify audit <技能目录或技能名> --record # 出审计单并留痕(下次可比对)
它把各阶段的结论组合成一张"要不要用它"的单子:来源(git 远端/提交,能查到就记)、 能力清单(脚本、网络端点、破坏性/有状态操作、疑似硬编码密钥、外部依赖)、 判定明细(spec/lint 的 FAIL/WARN 原样带进来)、内容指纹,以及库内名字近似提示。
退出码:audit 会把 lint 的结论一并带进来,所以默认(不执行脚本)返回 2——
那表示"脚本契约四项没执行",与 lint 的口径一致;不是审计失败。要连脚本一起实测再加 --scripts
(审计外来技能时请先想清楚:那会真的执行对方的脚本)。
能力清单不是从报告文字里猜的:它来自机械层的结构化扫描(security.facts()、
scripts.facts()、deps.facts()),所以 lint 的措辞改了也不会影响审计单。口径写在单子上:
网络端点 = 代码文件里出现且未在 frontmatter 声明的主机;破坏性/有状态操作 = 脚本里的删除/覆盖/
移动等形态;疑似密钥 = 高置信度特征命中;外部依赖 = Python 脚本导入的第三方模块。
AUDIT-005 有三种判定,别混淆:PASS 表示清单里有内容(值得看);INFO 表示这是纯文档技能、
清单为空(不适用,不影响退出码);SKIP 表示 lint 前置检查失败、清单没生成(未覆盖项)。
再审计同名的技能时,会比对指纹并明确告诉你"内容与上次不同"——别人可以在你审计之后替换内容, 这是审计留痕唯一的意义。审计单里留了一栏「来源与信任级别」由人填写: 工具只保证"同一份内容"与"内容变了"能被认出来,不做行为审计、不做信任分级。
4.6 开发期即时反馈
skillverify watch --root <技能根> # 轮询(默认 1 秒),变化即复跑
skillverify watch --root <技能根> --once # 跑一轮就退出(CI 用)
skillverify watch --root <技能根> --json # 每轮一行 JSON,便于管道消费
只复跑内容指纹变化的技能(指纹取 stat,不读文件内容);刻意不执行脚本 (高频复跑下反复执行脚本既慢又有副作用)。
五、语义评审:三档执行器,一个 schema
30 条提示词(旧体系 29 + 新增 W-17)(D 设计期 / W 编写期 / E 测试期 / R 运行期),每条带 PASS/FAIL 判据与证据要求:
skillverify review prompts # 全部 29 条(含判据)
skillverify review prompts --family W # 只看编写期那 16 条
档 2 · 会话任务包(推荐默认):
skillverify review pack <技能目录> # 生成任务包(默认 29 条)
skillverify review pack <技能目录> --prompts W-01,W-02 # 只评指定几条
skillverify review pack <技能目录> --split # 每条提示词一个 Markdown(便于一条一个调用)
产出三件:<技能名>-review-pack.md(任务书)、<技能名>-review-template.json
(预填好 prompt_id 的回写模板,评审者只填结论)、<技能名>-review-manifest.json
(记录本轮范围与技能内容指纹)。
把任务书交给任意 LLM 或人——这一步不依赖任何宿主,因为任务包就是 Markdown + JSON。 填好的模板就是回写:
skillverify review collect <填好的 JSON> --skill-dir <技能目录>
skillverify review collect --dir <回写目录> --skill-dir <技能目录> # 汇总一批
skillverify review status # 看各技能的评审状态与新鲜度
回写 schema(三档共用):
{
"schema": "skillverify.review/1",
"skill": "my-skill",
"reviewer": "你的人名或模型标识",
"tier": "pack",
"generated_at": "2026-10-04T10:00:00+08:00",
"prompt_ids": ["W-01", "W-02"],
"results": [
{"prompt_id": "W-01", "verdict": "PASS",
"evidence": "见 SKILL.md:12 的 description 字段,含 PDF/表单/提取三个关键词",
"finding": "", "suggestion": ""}
]
}
档 1 · 任意 CLI 自动:
skillverify review run <技能目录> --runner "你的评审命令"
skillverify review run <技能目录> --runner "你的评审命令" --prompts W-01,W-13 # 只跑几条
skillverify review run <技能目录> --runner "你的评审命令" --out <回写目录> # 落盘便于复核
skillverify review run <技能目录> --runner "你的评审命令" --collect # 顺带写中央记录
它逐条把提示词送上 runner 的 stdin,从 stdout 取回一个 JSON 结论
(围栏或寒暄都能容忍,取不到就报错),组装成与档 2/档 3 完全相同的
skillverify.review/1 回写,再走同一条校验与汇总。
- 工具不内置 LLM 客户端:一旦内置就得维护各家 API、密钥与重试,而"用哪个模型、怎么提示" 是使用者的事。这里只做机械部分。
- runner 失败(非零退出 / 超时 / 输出不可解析)不会被写成 NA——那会把"工具坏了"伪装成
"本项不适用"。失败条目直接不产出,并以非零退出码报出来(
--allow-partial可只记 WARN)。 - 回写的
reviewer写的就是实际跑的命令:评审必须有签署;中央记录里还会记tiers(这批结论出自哪一档)。 - 命令由你提供、以你的权限执行,与
lint --scripts同类,均需显式开启。--runner收的是一个命令字符串:整串用引号包住(--runner "my-llm -m gpt-4");若命令内部还需要引用(例如解释器路径含空格),改用单引号包外层或写一个包装脚本。
档 3 · 人工兜底:手写同一个 JSON 即可,collect 的校验一模一样。
collect 会拦下这些(这就是"评审切实有效"的机械保障):
| 会被拦下的 | 判定 |
|---|---|
reviewer 为空 |
FAIL(无签署的评审等于没有评审) |
| 证据过短、或没有文件/行号/引用/计数 | FAIL(不可定位 = 无法复核) |
| 证据与判据文本高度重合 | WARN(复述判据不算证据) |
FAIL 没写 finding / NA 没写理由 |
FAIL |
| 同一提示词出现两条互相冲突的结论 | WARN(双评场景,须人工裁决) |
| 声明的提示词有没有结论的 | WARN(未覆盖项) |
让语义评审独立成一个技能包(可选)
skillverify review skill --out <输出目录>
生成 skillverify-review/ 技能包(SKILL.md + references/ + assets/),
把它放进任意宿主的技能目录即可加载使用——语义评审因此不绑定任何宿主。
执行轮次自证(WS-008,双跑对照必做)
执行层不自研,但**「这轮到底怎么跑的」必须留痕**:在每个 iteration-N/ 下放一份
run-inputs.json(模板见 examples/run-inputs.json),写清四件事:
| 字段 | 写什么 |
|---|---|
isolation |
隔离 / 降级 / 未执行——做不到就如实写降级,不许留空 |
executor |
两臂用的命令行(例如各起独立进程、禁用 Skill 工具与 resume) |
input_hash |
技能目录 + 靶子任务输入的联合哈希(证明输入冻结) |
prompt_hashes |
两臂提示词哈希(应仅差技能约束行) |
另外两个可选字段,登记「断言是什么时候写的」(EVAL-011):
| 字段 | 写什么 |
|---|---|
assertions_added_at |
断言写下的时间(ISO 8601,如 2026-10-05T11:00:00+08:00) |
outputs_produced_at |
本轮产出输出的时间(可选);写了它,报告会给出两者的先后关系 |
-
只认这两个显式字段:旧实现靠文件 mtime 猜「断言何时补的」,复制/克隆/重写都会变, 本项目不猜时间——不写就记 INFO(不适用),不报错也不推断;
-
写了但解析不出 ISO 8601 →
EVAL-011WARN(无法解析的声明等于没声明); -
先后关系只登记、不判缺陷:官方明确允许"先跑一轮再补断言",「先写断言再跑」也自有道理, 工具不替使用者选一种流程。
-
完全没提供 →
WS-008INFO(增强项,不阻断);同一工作区里只提供了一部分 或写了降级/未执行→ WARN; -
标成
降级/未执行→ WARN:该轮只能算参考级证据,其 delta 不得当作技能带来的增益。
运行台账(AUDIT-006,可选)
运行期观测没法自动化,但别让台账变成摆设:把 run-log.md(模板 examples/run-log.md)
放进中央留痕目录,audit 会检查两件事——异常观察写了却没写处置、超过 30 天没更新。
有台账才检查;没有记 INFO(不阻断)。
日期请按 YYYY-MM-DD 写(2026-9-5 这种非补零写法也认):一条日期都认不出来时,
audit 会记 WARN「陈旧检查未执行」——"没算出来"不等于"很新鲜"。
评委校准(第 0 步,可选但推荐)
任务包里带 4 个答案明确的校准样本(2 应过 / 2 应挂)。先判它们并把结果填进回写的 calibration:
判错 → REV-012 FAIL,本轮结论不可用(评委分不稳);判对 → PASS;判了一部分 → WARN;没做 → INFO。
几条提示词需要的流程材料:review material
有几条提示词评的不是技能文件本身,而是流程产物或技能集合。先让工具把它们摘成材料文件:
skillverify review material <技能目录> # 生成到 <技能名>-review-material/
skillverify review material <技能目录> --workspace <工作区目录> # 显式指定评测工作区
skillverify review material <技能目录> --diff-base HEAD~1 # 指定 description diff 的基线
skillverify review material <技能目录> --blind <旧版> <新版> # 盲评:两版产物随机落到 A/B
| 材料 | 服务的提示词 | 来源 |
|---|---|---|
description-diff.md |
E-02 |
git diff <基线> -- SKILL.md(非 git 仓库会说明无法取 diff) |
revision-signals.md |
E-03 |
工作区里的失败断言 + 人工反馈 + benchmark delta |
blind/(blind-A/、blind-B/、mapping.json) |
E-06 |
你给的两版产物,随机分配;评审结束前不要看 mapping.json |
workspace-digest.md |
E-07、E-08 |
工作区各 iteration 的逐次产物与聚合值,摘成一屏数字 |
adjacency.md |
W-11 |
同级技能目录里各邻居的 description 与词面重叠系数(与 LIB-002 同一套口径),并留一栏「边界裁决」给人填 |
生成不了的项目记 SKIP 并逐条说明缺什么(缺工作区?不是 git 仓库?没给两版产物?同级目录列不出来?)——
所以退出码常是 2:那是「有材料没生成」的正常信号,不是失败。
唯一的例外是 adjacency.md:同级根本没有别的技能时记 INFO(不适用),因为那时确实没有可比的对象。
adjacency.md 的局限写在材料里:只在同级找邻居,分类嵌套(<root>/<类别>/<技能>/)布局会漏,
那种布局请手工补一份相邻技能清单;词面重叠不是语义相似度,串扰与否仍由 W-11 判。
其余条目只读技能目录本身(SKILL.md、references/、scripts/、evals/),不需要额外准备。
材料不齐时在回写里记 NA 并写明缺什么,不要凭印象给结论。
六、交付门禁
check 是日常检查;deliver 是交付门禁——没有 FAIL 且没有未覆盖项才算通过:
skillverify deliver --root <技能根> # 全库
skillverify deliver --root <技能根> --strict # 连"未覆盖项"也阻断(发行前跑一次)
skillverify deliver --root <技能根> --verbose # 把未覆盖/待甄别项也逐条打出来
- FAIL 阻断;
- WARN 不阻断,但逐条写进交付记录(这就是"需人工书面甄别"的书面痕迹);
- SKIP 分两类:属"未开启的可选批次/环境能力不足"的记未覆盖项(默认不阻断,
--strict时阻断);其余 SKIP(本项确实没执行,例如前置失败)一律阻断; - 语义评审默认参与(含在
--stages all里);--skip-review可一键跳过,且留痕为未覆盖项。
交付记录写到中央留痕目录(默认 <项目>/.agents/skillverify/deliver/):
latest.json—— 含rules_hash(证明是哪套规则判的)、git commit/branch/dirty、逐技能结论、 门禁结论(阻断项 / 未覆盖项 / 待甄别项);latest.md—— 人读报告;history.jsonl—— 每次交付追加一行,便于 grep 趋势。
--json 输出的是交付记录本身(含门禁结论),便于 CI 直接消费。
执行器样例(examples/)
执行层不自研,但怎么委托有可以照抄改的模板(纯标准库、支持 --dry-run):
| 模板 | 干什么 | 典型用法 |
|---|---|---|
examples/run_evals.py |
双臂(with/without skill)各跑一遍、按官方布局建工作区、记实测耗时与 token | python examples/run_evals.py --skill <技能> --cmd "claude -p {prompt}" |
examples/run_triggers.py |
把触发查询集真跑一遍并写 trigger-runs.json |
python examples/run_triggers.py --skill <技能> --cmd "<判定命令>" |
examples/badcase_to_evals.py |
把线上坏例子回流成一条 evals.json 用例 |
python examples/badcase_to_evals.py --skill <技能> --prompt … --expected … |
三个都不替你打分——评分与断言是人的判断(见 E-04)。
⚑ 逐条双评(REV-013)
目录里 8 项标 ⚑(W-02/04/05/08/15、E-04/06、R-02):要求两条各自署名的独立结论
(回写里写 by + at;同一人跑两遍不算)。署名缺失记 INFO(未启用),独立署名不足 2 条记 WARN,
两人结论不一致升级为待人工裁决。
注意:本工具不生成"看起来独立"的 A/B 任务包——旧体系那套 A/B 包实测逐字相同、仅包号不同, 独立性全靠人工开两个会话。这里改成机械判定署名,宁可让人真去开第二个会话。
WARN 的裁决留痕(WARN = 人工甄别,不是"记一下就算了")
deliver 记录里的 adjudications 会给出三份清单:pending(没人认领的 WARN)、
void(裁决已失效:证据变了或缺字段)、resolved(已拍板且证据一致)。
裁决写在 <留痕目录>/adjudications.json(模板 examples/adjudications.json),
每条必须带 decision(accept/fix)、reason、by、at 与 evidence_hash。
证据一变,裁决自动回到待裁决——签认只覆盖它当时看过的那一份证据。
误报的出口:豁免通道
skillverify deliver --accept <规则ID> --because "<理由>"
把该规则的阻断项记为「已豁免」(落盘在 gate.waivers),门禁随即放行;缺理由直接拒绝。
这是方案 §6.1「[S] 级书面说明后放行」的落地——显式、有理由、可追溯,不是静默放过。
接到提交上(git hook)
skillverify hook install --project <仓库目录>
skillverify hook status --project <仓库目录>
装好后每次提交自动执行 deliver --staged(只查本次提交涉及的技能,按目录前缀归属):
- 存在他人 hook 时拒绝改动,
--force会先备份成pre-commit.bak再覆盖; - 找不到可执行的 skillverify 时只告警不阻断(
SKILLVERIFY_HOOK_STRICT=1改为故障关闭)—— 一个会把你锁死在"改不动也提交不了"状态的门禁,对两人团队比漏检更糟; - 逃生阀:
git commit --no-verify、SKILLVERIFY_SKIP=1。
只改非技能文件(例如 README)时不会阻断(本次没有需要检查的技能)。
七、全程演练(照着敲一遍)
下面 18 步用一份本机技能目录把整条流水线走一遍。把 <> 里的占位符换成你自己的路径,
行尾的 # N 是期望退出码,命令上方的整行注释是这一步在干什么。
这一段不是"示意":
tests/test_docs.py会把这块里<!-- runnable -->标记的每条命令真跑一遍, 并核对实际退出码与标注一致。所以它既是你照着敲的脚本,也是文档不失效的保证—— 改了命令就必须同步改期望退出码,改不对测试就红。
# 1) 官方规范(离线、不联网):frontmatter 六个字段白名单、name 与父目录名一致、description 非空
skillverify spec "<技能目录>" # 0
# 2) 机械补检:引用、上下文预算、目录卫生、编码、依赖、安全。默认**不执行**脚本,
# 所以脚本契约四项没跑 → 记 SKIP,退出码为 2(未覆盖项,不是失败)
skillverify lint "<技能目录>" # 2
# 3) 同一套补检,并**实测脚本契约**:--help 可用、非法参数非零退出且错误走 stderr、重复调用一致
skillverify lint "<技能目录>" --scripts # 0
# 4) 两类评测资产:官方 evals.json(输出质量)+ 触发查询集与运行记录(会不会被触发)
skillverify evals "<技能目录>" # 0
# 5) 整库发现:按生效配置找出所有技能,看每个技能根命中几个、有没有同名冲突
skillverify discover --project "<项目>" --user-home "<用户主目录>" --root "<技能根>" # 0
# 6) 打印**生效配置**(内置 < 用户级 < 项目级 < --config 的覆盖顺序)——接入新宿主先看它
skillverify discover --show-config # 0
# 上宿主之前:技能是不是真的落在该宿主档声明的目录里、能不能被读出来、有没有同名冲突
skillverify mount --project "<项目>" --user-home "<用户主目录>" --skill "<技能名>" # 0
# 7) 外来技能审计:组合各阶段结论 + 来源 + 能力清单 + 内容指纹,出一张决策单(--record 留痕)。
# 再审计时会比对指纹,提示「内容被换过」;明确不做行为审计与信任分级。
# 这里的 2 与第 2 步同源:默认不执行技能自带脚本,脚本契约四项记 SKIP(未覆盖项,不是失败)
skillverify audit "<技能目录>" --project "<项目>" --user-home "<用户主目录>" --record # 2
# 8) 开发期即时反馈:只有内容指纹变化的技能才复跑;--once 跑一轮就退出(CI 用)。
# 它刻意不执行脚本(高频复跑下反复执行脚本既慢又有副作用)→ 同样记 SKIP,退出码 2
skillverify watch --project "<项目>" --user-home "<用户主目录>" --root "<技能根>" --once # 2
# 8) 查看语义评审提示词目录(29 条,每条带 PASS/FAIL 判据与证据要求);--family W 只看编写期 16 条
skillverify review prompts --family W # 0
# 9) 档 1 执行器:把提示词逐条喂给你指定的命令,收回与档 2/档 3 同 schema 的回写(这里示范跑 1 条)
skillverify review run "<技能目录>" --runner "<评审命令>" --prompts W-01 --out "<回写目录>" # 0
# 10) 生成几条提示词需要的**流程材料**:描述修订 diff、修订信号、盲评 A/B、工作区数字摘要
skillverify review material "<技能目录>" --out "<材料目录>" --blind "<盲评旧版>" "<盲评新版>" # 0
# 11) 档 2 任务包:Markdown 任务书 + **预填好的回写模板** + manifest(含技能内容指纹)
skillverify review pack "<技能目录>" --prompts W-01,W-13 --out "<任务包目录>" # 0
# ↓ 这一步由人或任意 LLM 完成:把 <任务包目录>/<技能名>-review-template.json 填好
# 12) 校验回写(签署、证据是否可定位、FAIL 有没有写问题…)并汇总进中央记录
skillverify review collect "<回写文件>" --skill-dir "<技能目录>" --project "<项目>" --user-home "<用户主目录>" --root "<技能根>" # 0
# 13) 看各技能的评审状态与新鲜度:技能在评审后被改过,会提示"需重评"
skillverify review status --project "<项目>" --user-home "<用户主目录>" --root "<技能根>" # 0
# 14) 整库总检:spec + lint + evals + review 一网打尽(all 含语义评审;--scripts 打开脚本实测)
skillverify check --project "<项目>" --user-home "<用户主目录>" --root "<技能根>" --stages all --scripts # 0
# 15) 交付门禁:FAIL 阻断交付、WARN 逐条记账、未覆盖项列出来;并写出 latest.json/md 与 history.jsonl
skillverify deliver --project "<项目>" --user-home "<用户主目录>" --root "<技能根>" # 0
# 16) 把"语义评审"导成一个独立技能包(SKILL.md + references/ + assets/),可放进任意宿主
skillverify review skill --out "<独立技能目录>" # 0
# 17) 装 git hook:提交时只查本次改动涉及的技能,坏技能直接拦住提交
skillverify hook install --project "<项目>" # 0
# 18) 看 hook 装没装、技能包版本对不对
skillverify hook status --project "<项目>" # 0
分五段看:1–4 单技能逐层检查 | 5–7 整库与开发期反馈 | 8–13 语义评审(含三档执行器)| 14–15 交付门禁 | 16–18 分发与自动化。
退出码里那几个 2,含义都是"有项没跑",不是失败:
- 第 2 步是
2:没加--scripts时脚本契约实测没执行,记 SKIP(未覆盖项)。加上--scripts(第 3 步)就变成0。 - 第 7 步也是
2:watch刻意不执行脚本,只做静态检查。 - 若技能没有评测资产,第 4 步会返回
2(EVAL-000提示"没有任何质量证据")—— "没有 evals"和"evals 全绿"必须能区分开,所以这里不是0。 - 第 10 步本次是
0:给了工作区与两版盲评产物,四项材料都产出了。若没给(没跑过评测、不是 git 仓库), 它会记 SKIP 并返回2——那是「有材料没生成」的正常信号,逐条原因写在报告里。
三条容易踩的:
- 第 12 步的
--skill-dir不能省:它把技能目录的内容指纹写进评审记录,技能之后改过就会被判 "记录过期,需重评"(按内容比对,不看文件时间)。第 13 步就是查这个状态。 - 第 15 步默认把语义评审算进来;只想跳过就加
--skip-review(会留痕为未覆盖项)。 - 第 16 步产出的技能包可以放进任意宿主的技能目录,语义评审因此不绑定宿主。
八、它不做什么(先说清楚)
- 不承诺在宿主内自动触发技能激活——跨宿主没有统一机制;本项目给的是
watch(改文件即时复跑)+ git hook(拦提交)+ 技能里的触发词。 - 不验证宿主注册表:
mount只做仓库侧的挂载前置检查;「宿主技能列表里看不看得见」、「真实触发会不会串扰」要在目标宿主里人工确认。 - 不内置任何 LLM:语义评审只负责生成任务包、把提示词喂给你指定的命令(档 1)、校验回写、汇总结论。用哪个模型、怎么提示,由你决定。
- 不做 46 个宿主的路径映射表:官方 clients 页根本没有路径信息;接入宿主请用
hosts.toml声明。 - 不引入独立依赖清单:脚本依赖写在脚本里(Python 用 PEP 723;Deno 写
npm:pkg@1.2.3、 带版本的 import 说明符、Rubybundler/inline的gem "x", "1.2.3"——DEP-005只认这些明确形态)。 - 不自研评测执行层:
evals只校验资产与产物形状,不执行、不联网。真要跑就把执行委托出去 (evals --run-with <命令>),比如 AgentV——它原生识别官方evals.json;样例与配合契约见examples/agentv/README.md与《操作手册》A4b。代价与密钥由使用者承担,我们只做"起进程 + 限时 + 跑完复校"。 - 不做密钥评分、域名信誉、混淆对抗这类判据——它们"命中不等于恶意", 本项目只把它们记 WARN,终判交给语义评审。
- 不用自建哈希清单做历史留痕:改用 git 做单一真源。
九、开发者:跑回归
改了这个工具本身之后,跑回归套件(纯标准库、离线;断言数看输出,本文件不写死):
python -m tests.run_all # 全部套件
python -m tests.run_all --dogfood # 额外把仓库里归档的旧技能拉进来跑 dogfood 项
python -m tests.run_all --install # 连打包的真装检查一起跑(需要网络,约 1 分钟)
python -m tests.test_lint # 也可以单独跑某一套
套件共 12 个(默认跑 13,--install 加跑打包):spec / lint / discover / automation / evalx / trigger / review / docs / injection / selfcheck(另有 packaging,默认不跑;全套约 1.5 分钟)。
其中 injection 是注入自测:先造一份 spec + lint + 评测 + 触发资产全绿的技能,再对它的独立副本逐个注入 38 处缺陷(含两处库级:评审记录过期、同名技能跨根),要求「期望的规则里至少一条必须报错」且「不许牵连无关规则」。
它证明的是校验器不是瞎的——方向与其它套件相反:那些查「给定坏输入会不会报错」,这个查「本来全绿的技能被动过手脚后一定会被抓住」。
打包相关的两档:默认只做 pyproject.toml 的静态检查(入口点/包列表/package-data glob
是否真的匹配到 data/ 下的运行时数据);加 --install 才真的建 venv、pip install -e .、
在仓库之外的任意目录执行命令,并构建 wheel 检查 data/ 确实进了发布物。
改动交付文档里的命令时,
tests.test_docs会执行《验证流程指南.md》里<!-- runnable -->标记的那段演练并要求退出码与标注一致——文档承诺的东西必须真能跑。
十、排障
| 现象 | 原因与处置 |
|---|---|
check 说"未发现任何技能"并返回 1 |
根列表不对。discover --show-config 看生效配置;或用 --root <技能根> 直接指定 |
| 配置报"未知键" | 键名拼错了,报错信息里列了允许的键 |
退出码恒为 2 |
通常是 SKIP(未执行项):看报告里 [可选批次·未覆盖] 标记与 SKIP 行的说明 |
报告里出现 DISC-001 |
同名技能出现在多个根,需你决定哪个是真源 |
报告里出现 LIB-001(WARN) |
库内元数据总量超出预算:宿主可能静默丢弃排在后面的技能。精简描述、合并同类技能,或用 --metadata-budget 按宿主实测值调整 |
报告里出现 LIB-002(WARN) |
两个技能的描述高度重叠,触发时可能互相抢。让每个描述点明本技能独有的能力与边界;确实同类就合并 |
| 审计单说「内容与上次审计不同」 | 技能内容在你审计之后变过。重新过一遍;若你没换过它,就要查是谁换的 |
报告里出现 DISC-004 |
技能主文件名大小写不对(写成了 Skill.md 之类)。大小写敏感的系统上它等于不存在:宿主不加载、报错也很难懂。重命名为 SKILL.md |
| 工具说「未发现技能」,但我明明放进去了 | 先看 SKILL.md 的文件名与位置:名字必须精确是 SKILL.md(或 skill.md),且直接位于技能根下的 <技能名>/ 里 |
deliver 说"评审记录已过期" |
技能在评审后改过;重跑 review pack → 评审 → collect |
| Windows 终端乱码/崩溃 | 本项目强制 UTF-8;命令行入口已把 stdout/stderr 切到 UTF-8,无需额外设置 |
hook 装不上 |
--project 必须指向 git 仓库;hook status 可先看现状 |
mount --host 敲错档名 |
应报「未知宿主档 'x';可用: …」并退出 1。若看到的是 traceback,那是 mount.py 漏导入 ConfigError 的老缺陷(已修;防复发由 test_selfcheck 的「未定义名」守卫看着) |
| 报告说「检测到旧落点」 | 旧体系把触发查询集放在 .verification/trigger-eval/queryset.json;迁到 evals/trigger-queryset.json(本项目只认单一来源,不回退读旧路径) |
evals 返回 2 但官方资产全绿 |
是 TRIG-000 在提示「没有触发评测证据」;补 evals/trigger-queryset.json + trigger-runs.json 即可 |
十一、命令与旗标速查(改结果的开关,一个都不藏)
skillverify <命令> --help 永远是权威。下表收的是正文没有逐条讲、但会改变结果的开关——
放在这里,免得出现"实现了却没人知道"。tests/test_consistency.py 会核对:
每个子命令、每个旗标至少在某份根文档里出现过一次(含本表)。
| 旗标 | 属于 | 作用 |
|---|---|---|
--iteration N |
evals / check / deliver |
只看指定那一轮 iteration-N(工作区有多轮时用);指定的号不存在记 WARN,不静默跳过 |
--workspace 目录 |
evals / review material |
显式指定评测工作区(默认找并列的 <技能名>-workspace/) |
--scripts |
lint / audit / check / deliver |
开启脚本契约实测(--help 可用性、非法参数退出码、幂等、输出量)。默认不开:执行技能自带脚本有风险,由你显式打开;deliver --strict 要过含脚本的技能必须带上它(此前 deliver 漏定义这个旗标,"严格模式"对含脚本技能永不可能通过) |
--script-timeout 秒 |
lint / check / watch / deliver |
单个脚本实测的超时(默认 10s;另有 120s 全局预算,用尽即记 SKIP) |
--run-timeout 秒 |
evals --run-with |
委托执行的那条命令的整体超时(默认 1800s) |
--timeout 秒 |
review run --runner |
每条提示词喂给执行器命令的超时(默认 180s) |
--desc-overlap 比例 |
discover / check |
库级「描述词面重叠」的提示阈值(默认 0.5);与 --metadata-budget 同属库级口径 |
--trace |
check |
把这次的 check.md + check.json 落到中央留痕目录(默认只打印) |
--no-record |
deliver |
只判定、不写交付记录(CI 里只想拿退出码时用) |
--no-store |
review collect |
只校验回写、不写中央评审记录 |
--no-config |
audit / mount |
忽略用户级/项目级 hosts.toml,只用内置档(排查"是不是我的配置在捣乱") |
--fail-closed |
hook install |
找不到可执行的 skillverify 时阻断提交(默认故障开放,等价环境变量 SKILLVERIFY_HOOK_STRICT=1) |
--interval 秒 |
watch |
轮询间隔(默认 1s) |
--cycles N / --once |
watch |
跑 N 轮后退出;--once 等价 --cycles 1(CI 与测试用) |
--blind-seed N |
review material --blind |
固定盲评 A/B 的随机分配(同一份盲评包可复现) |
--name 名 |
review skill |
生成"语义评审"独立技能包时的技能名(默认 skillverify-review) |
--quiet |
多数命令 | 不打印报告正文。机读场景不要加:它会把 --json 一起静音 |
--json / --out 文件 |
多数命令 | 机读输出 / 报告落盘;两者可同时用(stdout 仍只有 JSON,进度提示一律走 stderr) |
Metadata
Release files for skillverify 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| skillverify-0.1.0.tar.gz | 365.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| skillverify-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 600.0 kB
Release files / skillverify-0.1.0.tar.gz
| Download URL | skillverify-0.1.0.tar.gz |
|---|---|
| Size | 365.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
168e7c75221e40645a7a8beca4711404ef2b60a4a1bf31047d0734325d87a5ad
|
|
BLAKE2b-256 checksum How to use checksums |
81a6f352572d999b0953641245af081951034f1974c6ae0c0590752dc88f4e47
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / skillverify-0.1.0-py3-none-any.whl
| Download URL | skillverify-0.1.0-py3-none-any.whl |
|---|---|
| Size | 235.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
549044e76860c6927ca6fbefd7c195bec5028e20dffc29a4d1f7a9ad9b4854b8
|
|
BLAKE2b-256 checksum How to use checksums |
25ca76b745150cd114de9c7f8a5a843b0c41941f77a963b35cfb4b14aa07e031
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|