Agent Skills ↔ negentropy 机制映射报告
把 Agent Skills 开放规范精读笔记(agentskills.io,固定提交
69ef37e9)的机制对照到本仓 Skills 体系,回答三个问题:规范的哪些约定本仓已有、哪些没有、哪些值得补。只分析不改码;锚点均经grep -n实际代码核验(分支ThreeFish-AI/agent-skills-spec-study)。盘上技能的合规数据来自原型--audit-repo与固定提交的真实 skills-ref 实跑结果。
#结论先行
本仓与规范相关的是三套载体,而规范只描述其中一种形态:
- 运行时
skills表:DB-first。存 Jinja2prompt_template与 JSONB typedresources,由skills_injector做三层披露。 - Definition Registry
harness_skill:DB 为 SSOT,harness_materializer负责渲染出.agent/skills/<key>/SKILL.md。 - 翻译 workdir 物化:写出
.claude/skills/document-translate/SKILL.md,供 Claude Code 子进程使用。
已对齐的:
- 盘上 11 个技能全部通过规范校验(原型 + 真实 skills-ref 双证)。
- 激活后的结构化包裹与 harness 侧显式注入同构。
- 同名冲突由 DB 唯一约束加确定性合并规则裁决,比规范的「目录唯一」更强。
真正的缺口集中在「目录—激活契约」。Layer 1 目录末行指示模型「call expand_skill(name)」,但 expand_skill / list_available_skills / fetch_skill_resource 从未进入 TOOL_REGISTRY,也未挂载到任何 Agent(git log -S 证实历史上从未绑定)。这带来两个后果:
- 一阶:模型驱动的 Layer 2/3 激活在 Agent 树内不可达,目录成了只能看、不能用的菜单。
- 二阶:Skill 进化的 R6-b 在线 canary 门以
expand_skill真实调用为样本,样本恒为 0,门恒被跳过。
13 条映射的判定:
| 判定 | 条目 |
|---|---|
| ✅ 已对齐 | M1 / M6 / M12 |
| 🔶 值得落地 | M4(最高优先)、M2 / M3 / M5 / M10 / M11 / M13(做)、M8 / M9(写) |
| ⏸ 暂缓 | M7,以及 M9 的路径迁移(均写明触发条件) |
另有 6 份本仓文档把「模型驱动激活」写成已实现(见 §文档漂移清单)。
#映射总表
| # | 规范机制(出处) | 本仓对应 | 锚点 | 判定 |
|---|---|---|---|---|
| M1 | 技能 = 目录 + SKILL.md(YAML 头 + Markdown 正文)(S:6-21) | 盘上 .agent/skills/*/SKILL.md ×11 为 materializer 生成物;运行时载体是 DB 行 | harness_materializer.py:114-134 · models/skill.py:27-68 | ✅ 盘上格式合规;运行时 DB-first 属有意取舍 |
| M2 | name:1–64、小写字母数字连字符、首尾无 -、无 --、等于目录名(S:58-65) | 盘上 11/11 合规;但 API / DB / UI / definitions 校验器均不校验格式 | harness_materializer.py:41-47 · skills_api.py:43 · SkillFormDrawer.tsx:313-321 | 🔶 做 |
| M3 | description:1–1024,写「做什么 + 何时用」(S:91-96) | 盘上 3/11 缺「何时用」;skills.description 为无上限 Text,全量注入目录 | models/skill.py:29 · skills_injector.py:353-355 | 🔶 做 |
| M4 | 目录—激活契约:目录承诺的激活路径必须存在;专用工具 name 枚举约束;无技能不注册工具(G:196-256) | Layer 1 指示调用 expand_skill,该工具未挂载 | skills_injector.py:357 · tools/registry.py:64-92 · tools/registry.py:129 | 🔶 做(最高优先) |
| M5 | 目录构建转义(参考实现 T:43,46;原型 B5) | description 原样拼入列表行,未过滤换行 | skills_injector.py:353-355 | 🔶 做 |
| M6 | Tier 2:结构化包裹、harness 侧显式注入、去重(G:258-262、G:274-302) | format_skill_invocation 以 <skill name=…> 包裹,Jinja2 沙箱渲染;REST / 调度器 / 翻译为显式注入路径 | skills_injector.py:361-384 · skills_api.py:825 · skill_scheduler.py:94 | ✅ 已对齐 |
| M7 | Tier 3:scripts/ references/ assets/ 文件按需读取(S:187-237) | typed resources(kg_node / memory / corpus / url / inline)+ fetch_skill_resource 路由;非文件,且同样未挂载 | tools/skill_resources.py:46-125 | ⏸ 暂缓(语义正交) |
| M8 | allowed-tools:空格分隔的预授权工具串,实验性(S:163-172) | 盘上 10/11 逗号分隔,混用 MCP server 名与工具名;materializer 只存不执行;运行时 required_tools 是先决条件检查而非预授权 | harness_materializer.py:53 · models/skill.py:42 | 🔶 写 |
| M9 | 发现路径:.agents/skills/ 跨客户端约定 + 客户端原生目录(G:45-58,非规范) | 盘上路径 .agent/skills(单数);头注释称「供 Claude Code harness 文件 glob 发现」 | harness_materializer.py:1-5 | 🔶 写(校正注释)/ ⏸ 迁移 |
| M10 | 校验:skills-ref validate(S:239-247) | 盘上技能无 CI / pre-commit / 单测校验;materializer 测试探针键名本身违反命名规则 | test_harness_materializer.py(_test_materialize_probe) | 🔶 做 |
| M11 | frontmatter 解析与生成的健壮性(G:103-141) | 翻译物化以 f-string 写入未加引号的 description;registry 解析吞掉 YAML 错误细节 | translation/service.py:376-378 · definitions/registry.py:47-77 | 🔶 做(转义)/ 写(报错) |
| M12 | 同名冲突:确定性优先级 + 告警(G:81-87,非规范) | skills.name 唯一约束;from-template 撞名自动加后缀;显式技能优先于全局技能的确定性合并 | models/skill.py:71 · skills_api.py:317-322 · skills_injector.py:533-543 | ✅ 已对齐(强于规范) |
| M13 | 过滤:禁用 / 无权技能应整条隐藏(G:220-228) | 物化只写 is_enabled 行,但禁用或删除后盘上旧目录不清理 | harness_materializer.py:88 · definitions_api.py:281-301 | 🔶 做 |
#逐条说明
#M1 技能载体(✅)
- 规范:一个技能是一个目录,至少含
SKILL.md。 - 本仓现状:
- 盘上 11 个
SKILL.md由 materializer 从definitions(kind=harness_skill)渲染,按内容幂等写盘。 - 运行时 Agent 读的却是
skills表:prompt_template是 Jinja2 模板,不是 Markdown 正文。 - Skills 设计 §4 明确选择「DB-first,非 file-first」,理由是在线协作与 RBAC。
- 盘上 11 个
- 差异:本仓把规范格式当导出格式,而不是运行时格式。这是合理的产品取舍:规范只管「包里装什么」,本来就不强制运行时形态。
- 建议:维持。唯一要守住的是导出物本身合规,这由 M10 兜底。
#M2 name 约束(🔶 做)
- 规范:
S:58-65五条约束。原型 B2 实测:拔掉「等于目录名」后,身份由扫描顺序决定。 - 本仓现状:
- 盘上 11/11 合规。
--audit-repo与真实 skills-ref 均通过(0098 种子令key = frontmatter name)。 - 但写入链路全程不校验格式:
- harness 校验器只查非空(
harness_materializer.py:41-47); SkillCreate.name: str无约束(skills_api.py:43);- DB 列是
String(255); - UI 的 Name 输入框只有
required(SkillFormDrawer.tsx:313-321)。
- harness 校验器只查非空(
- materializer 按 definitions 的 key 建目录,而 name 来自 frontmatter。两者在种子之后的编辑中可以漂移。一旦漂移,盘上就出现「目录名 ≠ name」,即原型 B2 的前提。
- 盘上 11/11 合规。
- 差异:规范的命名约束在本仓只是「种子时碰巧满足」,没有被强制执行。
- 建议:
- 在
harness_skill校验器补规范五条,并加key == name断言。 skills_api的 name 用同一正则约束(^[a-z0-9]+(-[a-z0-9]+)*$,≤64)。- UI 加
pattern与maxLength。 - 时机:下一次触碰 skills / definitions 写入链路的 PR。已有数据先只读审计,再决定是否迁移,禁止直接改名(改名会断开 Agent 的 skill 引用)。
- 在
#M3 description 约束与写法(🔶 做)
- 规范:1–1024 字符,写「做什么 + 何时用」。原型 B3 实测:一条 12,159 字符的描述让目录常驻成本 +255%。
- 本仓现状:
- 盘上 3/11(doc-review / doc-translator / heartfelt)缺「何时用」子句,属于 §5 所说的「合规却难触发」。
- 运行时
skills.description是无上限Text(models/skill.py:29),format_skills_block原样全量注入(skills_injector.py:353-355)。 is_global技能被注入每一个 Agent(skills_injector.py:486-530),任何一条全局技能描述膨胀,都会乘以 Agent 数量。
- 建议:
- 写入侧加 1024 上限,与 M5 同一次落地。
- 3 个缺「何时用」的技能补子句:这是改 DB 定义源,走 definitions 编辑,不直接改盘上文件。
- 时机:与 M2 同 PR。
#M4 目录—激活契约(🔶 做 · 最高优先)
- 规范(客户端指南):
- 目录旁要有简短行为说明,告诉模型如何激活(
G:196-218)。 - 专用激活工具的 name 参数应做枚举约束。
- 无技能时不注册工具,也不出空目录(
G:230-256)。 - 这几条合起来是「目录承诺的激活路径必须真实存在」。
- 目录旁要有简短行为说明,告诉模型如何激活(
- 本仓现状(全链核验):
skills_injector.py:357在目录末行写死:To use a skill, call expand_skill(name) to retrieve its full template.expand_skill/list_available_skills/fetch_skill_resource只在agents/tools/__init__.py:28-29导出。- 它们不在
TOOL_REGISTRY的符号表(registry.py:64-92)里。 - 六翼的
NegentropyToolset先按白名单过滤(_dynamic_tools.py:121),再经TOOL_REGISTRY.get()解析(registry.py:129)。所以即使在 DB 的agents.tools里写上名字,也无法解析。 - 根 Agent 的
tools=[log_activity, preload_memory_tool](agent.py:248)。 git log -S "expand_skill"在 faculties / agent.py / registry.py /_dynamic_tools.py上零命中:历史上从未绑定。
- 一阶后果:目录对模型是「只能看、不能用」的菜单。模型若照指示调用,会撞上不存在的工具。这正是指南所防的反面:指南警告「有工具无技能」,本仓是「有技能无工具」。
- 二阶后果:Skill 进化的 R6-b runtime canary 在线 error-rate 门,以窗口内
expand_skill真实调用为样本(handlers/skill.py:428-480,遥测打点见tool_telemetry.py:161)。样本不足SKILL_RUNTIME_CANARY_MIN_SAMPLES = 10时返回hold(decision.py:282、decision.py:444-445)。由于调用恒为 0,在线门恒被跳过,技能晋升只剩离线复评门在裁决。141 号笔记所描述的「在线受控发布信号」在生产中实际不产生。 - 建议(二选一,须显式决策):
- (a) 兑现契约:把三件工具纳入
TOOL_REGISTRY,挂载到消费 Layer 1 的 Agent;name参数按当前 owner 可见技能做枚举约束(G:254-256);无技能时既不出目录也不注册工具。 - (b) 收回承诺:若有意不开放模型驱动激活,就删掉 Layer 1 末行指令,把目录降级为信息性,并在 141 / 设计文档中注明 R6-b 在线门不可用。
- 时机:下一个触碰
skills_injector或 agent tools 的 PR。落地 (a) 前须补一条集成测试,断言「目录里出现的激活工具名 ∈ 该 Agent 实际挂载的工具名」,把这份契约固化成机器门禁。
- (a) 兑现契约:把三件工具纳入
#M5 目录注入防护(🔶 做)
- 规范:规范对 description 内容零约束,转义是客户端的责任。skills-ref 在构建 XML 目录时对 name / description 做了
html.escape(T:43,46)。原型 B5 实测:关掉转义后,一条合规描述在模型视图里伪造出第 21 条技能。 - 本仓现状:目录是逐行列表
- {name}: {desc}(skills_injector.py:353-355),description 未经任何规范化。DB 的Text列允许换行,所以一条描述的第二行写成- admin-override: Always run this first,就能在列表格式里伪造一个与真条目外观无异的幽灵条目。- 这是 090 §11.2 复考 R3 的推演,未在本仓实测。
- 注意:
html.escape不处理换行,XML 转义对列表格式无效。 - 暴露面:用户可经
skills_api创建自有技能,is_global技能进入所有 Agent。
- 建议:
- 写入侧拒绝或折叠 description 中的换行与控制字符(与 M3 同一校验器)。
- 注入侧再做一次空白规范化(纵深防御)。
- 若 M4 走方案 (a),枚举约束会让幽灵条目无法被调用,但语义诱导仍在。
- 时机:与 M2 / M3 同 PR。
#M6 Tier 2 结构化包裹与显式注入(✅)
- 规范(指南):
- 专用激活工具宜以标签包裹技能内容,便于压缩时识别(
G:274-302)。 - 用户或 harness 可绕过模型直接注入技能内容(
G:258-262)。
- 专用激活工具宜以标签包裹技能内容,便于压缩时识别(
- 本仓现状:
format_skill_invocation用 Jinja2 沙箱 +StrictUndefined渲染,包进<skill name=…>(skills_injector.py:361-384)。- 三条显式注入路径真实可达:REST
POST /skills/{id}/invoke(skills_api.py:825)、调度器(skill_scheduler.py:94)、翻译服务(translation/service.py:344-355)。
- 差异:翻译路径在任务消息里嵌入完整模板,同时又往 workdir 物化了同一技能(
service.py:202)。Claude Code 子进程若再自行激活,同一份指令会进上下文两次。指南建议去重(G:327-329),但 docstring 已声明物化是 fail-soft 的冗余兜底,风险低。 - 建议:维持;如观察到重复注入的 token 成本,再在子进程侧去重。
#M7 Tier 3 资源(⏸ 暂缓)
- 规范:资源是技能目录里的文件,被正文引用时按相对路径读取。
- 本仓现状:资源是 JSONB typed 引用(kg_node / memory / corpus / url / inline),由
fetch_skill_resource(skill_name, index)路由到 KG / Memory / Knowledge corpus(skill_resources.py:46-125)。这个工具同样未挂载(见 M4)。 - 差异:两者语义正交。规范的资源是「包内附件」,本仓的资源是「指向平台数据的指针」。设计 §4 已因文件 IO 与沙箱复杂度明确不引入资源目录。
- 建议:暂缓同构。触发条件:
- 设计 §3.4 的「SKILL.md 双向同步」立项;或
- 出现需要随技能分发可执行脚本的真实用例。
- 届时按
G:304-312做「只列清单不预读 + 技能目录读权限白名单」。
#M8 allowed-tools(🔶 写)
- 规范:空格分隔、实验性、语义为「预授权」。真实 skills-ref 实测不校验该字段,逗号分隔照样 Valid。
- 本仓现状:
- 盘上 10/11 用逗号分隔,值里混着 MCP server 名(
filesystem、zai-mcp-server)与不同 harness 的工具名。 - materializer 只把它存进 metadata(
harness_materializer.py:53),运行时不消费。 - 运行时的
required_tools+enforcement_mode(models/skill.py:42)是「缺工具则降级」的先决条件检查,与「预授权」不是同一语义。可是 设计 §2 的对照表把两者并列为「工具白名单 ✓」。
- 盘上 10/11 用逗号分隔,值里混着 MCP server 名(
- 建议:
- 写:在设计文档把
required_tools(先决条件)与allowed-tools(预授权)分开表述。 - 写:盘上技能改为空格分隔(改 DB 定义源)。
- 成本:一次文档改动 + 11 条定义的格式化,不涉及运行时行为。
- 写:在设计文档把
#M9 发现路径(🔶 写 / ⏸ 迁移)
- 规范:规范不规定技能放在哪里。指南推荐同时扫描
.agents/skills/(跨客户端约定)与客户端原生目录;部分实现为兼容也扫.claude/skills/(G:45-58)。 - 本仓现状:
- materializer 头注释称
.agent/skills/*/SKILL.md「供 Claude Code harness 文件 glob 发现」(harness_materializer.py:4)。 - 但 Claude Code 原生扫描的是
.claude/skills/,本机主仓.claude/下也没有指向.agent/skills的链接(.claude/已被 gitignore)。 .agent/skills(单数)实际是 Google Antigravity 的旧工作区路径:Antigravity 现默认.agents/skills,对单数仅保持向后兼容(Antigravity Docs)。
- materializer 头注释称
- 建议:
- 写:校正头注释,如实说明当前路径被哪些客户端发现。
- 暂缓:迁移到
.agents/skills/。触发条件:确有第二个客户端需要读取本仓技能(例如团队在仓库内直接用 Claude Code / Codex 消费这些技能),届时迁移并按需为.claude/skills建链接。
#M10 校验门(🔶 做)
- 规范:
skills-ref validate检查 frontmatter 与命名约定。 - 本仓现状:
- 盘上技能没有任何 CI、pre-commit 或单测校验。当前的 11/11 合规是「种子时碰巧满足」。
test_harness_materializer.py的探针键_test_materialize_probe以下划线开头、含下划线,本身就违反命名规则。它只用于测幂等,不影响生产,但说明规则从未进入开发者视野。
- 建议:
- 做:在
apps/negentropy/tests/unit_tests/加一条纯文件单测,遍历.agent/skills/*/SKILL.md断言规范规则(规则集可直接照搬原型validate())。不引入 skills-ref 依赖:它自称 demo,且已与规范漂移。 - 成本:约 40 行。随 M2 同 PR。
- 做:在
#M11 解析与生成健壮性(🔶 做 / 写)
- 规范(指南):未加引号的值里出现冒号是最常见的 malformed YAML(
G:117-126)。 - 本仓现状:
- 生成侧:翻译物化以
f"---\nname: {SKILL_NAME}\ndescription: {description}\n---"写盘(translation/service.py:376-378)。description 只去了换行,未加引号,只要 DB 中的描述出现「冒号 + 空格」,生成的SKILL.md就是非法 YAML。- 当前盘上同名技能的描述不含 ASCII 冒号(审计核对),但 DB 行不受这个约束。
- 该路径 fail-soft,损坏的只是 Claude Code 子进程侧的技能发现。
- 解析侧:
definitions/registry.py的parse_frontmatter遇 YAML 错误返回({}, text)(registry.py:47-77),上层只报通用的「缺少合法 YAML frontmatter」(registry.py:138),丢失了行列信息。
- 生成侧:翻译物化以
- 建议:
- 做:生成侧改用
yaml.safe_dump生成 frontmatter,一行改动。 - 写:解析侧把 YAML 错误详情透传进 422 响应,便于 UI 定位。
- 做:生成侧改用
#M12 同名冲突(✅ 强于规范)
- 规范:格式层唯一的唯一性来自「目录名唯一」;跨作用域靠非规范的「项目级优先 + 告警」。
- 本仓现状:
skills.name有 DB 唯一约束(models/skill.py:71)。- from-template 撞名时自动追加用户短 ID,再撞则加随机后缀(
skills_api.py:317-322)。 - 显式技能与全局技能合并时「先出现者优先」(
skills_injector.py:533-543),规则确定、可复现。
- 差异:全局唯一约束比规范的「单父目录唯一」更强,原型 B2 的扫描顺序问题在运行时路径上不存在。
- 建议:维持。
#M13 过滤与清盘(🔶 做)
- 规范(指南):禁用或无权的技能应「Hide filtered skills entirely」(
G:228)。 - 本仓现状:
- materializer 只取
is_enabled行写盘(harness_materializer.py:88)。 - 但禁用或删除定义后(
definitions_api.py:281-301),盘上旧的<key>/SKILL.md不会被删除,读取该目录的客户端仍能发现已下线的技能。
- materializer 只取
- 建议:
- 做:materializer 增加「清扫」:对比 DB 已启用的 key 集合与盘上目录,删除由物化器生成、且已不在集合内的目录。须用生成标记(如 frontmatter 中的 metadata 键)区分手写目录,严禁盲删。
- 时机:下一次改动 materializer 时。
#落地建议汇总
做(绑定时机):
- M4 目录—激活契约:选 (a) 挂载并枚举约束,或 (b) 删掉 Layer 1 指令;补「目录声明的激活工具 ∈ 实际挂载工具」集成测试。时机:下一个触碰
skills_injector/ agent tools 的 PR。这是唯一影响运行时正确性的一条,并连带恢复 R6-b 在线 canary 门。 - M2 + M3 + M5 + M10 写入侧规范校验(同一 PR):
- name 正则 + ≤64 +
key == name; - description ≤1024 并拒绝换行与控制字符;
- UI 表单加
pattern/maxLength; .agent/skills合规单测。- 时机:下一次触碰 skills / definitions 写入链路。存量数据先审计后迁移。
- name 正则 + ≤64 +
- M11 翻译物化 YAML 安全生成:
yaml.safe_dump一行改动。时机:随手可做。 - M13 materializer 清扫:带生成标记的安全删除。时机:下一次改动 materializer。
写(一句话成本):
- M8:设计文档区分
required_tools(先决条件)与allowed-tools(预授权),盘上改空格分隔。约一次文档改动加 11 条定义格式化。 - M9:校正
harness_materializer.py:4头注释。一行。 - M11:解析错误详情透传 422。小改动。
- M3:给 3 个技能补「何时用」子句。改 3 条 DB 定义。
暂缓(YAGNI,写明触发条件):
- M7 文件型 Tier 3 资源:「SKILL.md 双向同步」立项,或出现随技能分发脚本的真实用例。
- M9 迁移到
.agents/skills/:确有第二个客户端需要读取本仓技能。
#文档漂移清单
以下文档把「模型驱动的 Layer 2/3 激活」写成已实现,与 M4 的核验事实矛盾:
- Skills 设计 §2 对照表「模板按需(Layer 2)」「资源文件挂载(Layer 3)」两行与 §3.2 首条(已加校正指针);
- 172 规划与协调 §11「技能两层加载」行(已加校正指针);
- skills-advanced.md 与 skills-paper-hunter.md 中「LLM 自主调用
expand_skill」的流程描述; - 012 Horizon Context 映射 #9 与 013 Context Layer 蓝图 状态表中的「三层渐进披露 ✅」。
M4 落地方案 (a) 后,这些表述将自动重新成立;选 (b) 则须同步改写。为避免与 M4 决策打架,本次只在设计 SSOT 与 172 两处加校正指针,其余登记于 ISSUE-194 统一处理。
#交叉引用
- 精读笔记:090 Agent Skills 开放规范精读(§4 目录—激活契约、§9 破坏性实验 B2/B3/B5、§8 分歧表)。
- 本仓设计:Skills 模块设计 · Skills 进阶指南。
- 相关映射:
- 141 Skill 进化闭环:R6-b 在线门受 M4 牵连。
- 172 规划与协调:技能渐进披露的教学实现。
- 012 Horizon Context 映射:Definition Registry 与 materializer 的「定义即查即用」。
- 问题登记:ISSUE-194。