跳到主要内容

一个 Skill 的解剖

本章讲什么: 把「skill = 文件夹」拆开看——SKILL.md 的 YAML 到底有哪些被代码强制的规则、正文该写什么、scripts//references//assets/ 三者分工,以及一个 skill 怎么被打包成 .skill 分发。读完你能从零写出一个合法的 skill 骨架。

1. 最小可用的 skill(先看终点)

仓库给的模板就是一个合法 skill 的下限:

---
name: template-skill
description: Replace with description of the skill and when Claude should use it.
---

# Insert instructions below

来源:template/SKILL.md(全文 6 行)。也就是说——两个 YAML 字段 + 一个标题,就是一个能跑的 skill。其余一切(脚本、reference、assets)都是可选的「加料」。

2. frontmatter 契约:以代码为准,不以 spec 为准

这一节要点明一个容易踩的坑:仓库里 spec/agent-skills-spec.md 只有一行重定向到线上,正文不在克隆里。所以「frontmatter 到底允许什么」的权威来源是真实执行的校验函数 validate_skill(skills/skill-creator/scripts/quick_validate.py)。

2.1 允许哪些键

校验器写死了允许的键集合:

# skills/skill-creator/scripts/quick_validate.py 内,ALLOWED_PROPERTIES
# 示意,符号名与值取自源码
ALLOWED_PROPERTIES = {'name', 'description', 'license',
'allowed-tools', 'metadata', 'compatibility'}

来源:skills/skill-creator/scripts/quick_validate.py:42(ALLOWED_PROPERTIES)。出现任何其它键,validate_skill 直接判不合格(:44-50)。

一个有意思的事实: 全仓库 17 个 skill + 模板里,实际只用到了 3 个键——namedescriptionlicense。其余允许键(allowed-tools/metadata/compatibility)是「可用但很少用」。这印证了 skill-creator 的说法:compatibility 等字段「optional, rarely needed」(skills/skill-creator/SKILL.md 约 68 行)。

2.2 namedescription 的硬规则

namedescription 是仅有的两个必需键(quick_validate.py:53-56)。它们各自有被代码强制的约束:

字段规则校验位置(符号 / 行)
name必须 kebab-case:^[a-z0-9-]+$quick_validate.py:65
name不能以 - 开头/结尾,不能连续 --quick_validate.py:67
name长度 ≤ 64quick_validate.py:70-71
description不能含尖括号 <>quick_validate.py:80-81
description长度 ≤ 1024quick_validate.py:82-84
compatibility若有:字符串且 ≤ 500quick_validate.py:87-92

为什么 description 禁尖括号?(inferred)很可能因为 skill 元数据会被拼进给模型看的 XML 化列表里,裸 </> 会破坏结构——代码里只看到「禁止」,原因属推断。

2.3 校验入口长什么样

validate_skill(skill_path) 的逻辑很直白,值得记住它的检查顺序(任何一步失败即返回 (False, 原因)):

1. SKILL.md 存在吗? (:16-18)
2. 以 '---' 开头吗? (:23-24)
3. 能正则切出 frontmatter 块吗? (:27-30)
4. 是合法 YAML 且是 dict 吗? (:34-39)
5. 有没有不在白名单里的键? (:44-50)
6. name / description 在不在? (:53-56)
7. name 命名规范 + 长度 (:64-71)
8. description 无尖括号 + 长度 (:78-84)

来源:skills/skill-creator/scripts/quick_validate.pyvalidate_skill(:12-94)。这是「合法 skill」的可执行定义——比线上 spec 文字更可靠,因为打包时真的会跑它(见 §5)。

3. 正文(L2):写「总纲 + 指针」,不写「全部细节」

SKILL.md 的 markdown 主体是 L2:只要 skill 被触发就整份进上下文。所以它要短而像总纲,把又长又专的内容推到 L3。

两条来自 skill-creator 的硬建议:

  • 正文控制在 500 行以内;接近上限就「加一层层级 + 明确指针,告诉模型下一步该去读哪个文件」。来源:skills/skill-creator/SKILL.md 约 96 行。
  • 大 reference 文件(>300 行)要带目录,方便按需跳读。来源:同上,约 98 行。

正文里最该出现的东西是『指针』——「需要 X 时去读 references/x.md」「重复活儿跑 scripts/y.py」。mcp-builder 是教科书级示例:正文是四阶段工作流骨架,真正的语言细节全在 reference/python_mcp_server.md / node_mcp_server.md,正文只用一行链接把它们挂出来(skills/mcp-builder/SKILL.md:60-66)。

4. 三级加载里的 L3:scripts vs references vs assets

三个可选目录职责不同,别混:

目录装什么进不进上下文典型例子
scripts/确定性/重复活儿的可执行代码可以只执行、不读入(省上下文)skills/skill-creator/scripts/package_skill.py
references/按需读进上下文的细节文档读入(用到才读)skills/mcp-builder/reference/evaluation.md
assets/产出里要用的素材通常不读、被引用/拷贝进结果模板、图标、字体

来源:skills/skill-creator/SKILL.md「Anatomy of a Skill」+「Progressive Disclosure → Bundled resources」(约 75-91 行)。

「脚本当黑盒」是一条明确纪律。 webapp-testing 把这点写死:「先跑 --help,别读源码;这些脚本可能很大,读进来会污染上下文窗口。它们就是要被当黑盒直接调用,而不是被吃进上下文。」来源:skills/webapp-testing/SKILL.md:11-14 与「Best Practices」(约 85 行)。这正是 L3「脚本可只执行不读入」的现实体现——详见 03 章

按域组织 references。 当一个 skill 跨多个框架/方言时,按变体拆 reference,让模型只读相关那份:

cloud-deploy/
├── SKILL.md ← 工作流 + 选哪个的判断
└── references/
├── aws.md
├── gcp.md
└── azure.md ← Claude 只读相关那一份

来源:skills/skill-creator/SKILL.md「Domain organization」(约 100-109 行)。mcp-builder(python/node 两份)和 claude-api(按语言分目录:python/ typescript/ go/ java/ …)都是这套(skills/claude-api/ 目录布局)。

5. 打包成 .skill:把校验焊进流程

一个 skill 文件夹通过 package_skill.py 变成可分发的单文件 .skill(本质是个 zip)。最妙的设计是:打包前强制先校验,校验不过就拒绝打包。

# skills/skill-creator/scripts/package_skill.py 内,package_skill()
# 示意,逻辑取自源码
valid, message = validate_skill(skill_path) # 复用 §2 的校验器
if not valid:
print(f"Validation failed: {message}")
return None # 不合格 → 不打包
# ……随后把文件夹 rglob 进 zip,命名 <skill_name>.skill

来源:skills/skill-creator/scripts/package_skill.pypackage_skill(:42-104),校验调用在 :71-77,zip 写入在 :90-101

打包时会排除的东西(避免把构建垃圾/评测数据塞进分发包):

排除项范围符号
__pycache__node_modules任意层EXCLUDE_DIRS(:20)
*.pyc任意层EXCLUDE_GLOBS(:21)
.DS_Store任意层EXCLUDE_FILES(:22)
evals/仅 skill 根目录ROOT_EXCLUDE_DIRS(:24) + should_exclude(:27-39)

注意 evals/ 只在根层被排除(should_excludeparts[1] 的判断,:33-35)——因为评测集是开发期产物,不该跟着分发,但更深层若恰好叫 evals 则不误伤。

6. 巧妙之处

  • 「合法」有可执行定义。 frontmatter 规则不是散落在文档里的口头约定,而是一个会在打包时真跑的函数 validate_skill。这让「写错 frontmatter」在分发前就被拦下(package_skill.py:71-77)。
  • 校验器自带『修正建议』。 报错信息会把允许键列出来给你看(quick_validate.py:46-50),而不是只说「键非法」。
  • 三级模型把『成本』显式化。 L1 永远在(所以要极省、要准)、L2 触发才进(所以 <500 行)、L3 用到才取(所以脚本能只跑不读)——整套设计就是在管理「上下文这件最贵的资源」。

7. 代码地图

主题文件路径符号 / 锚点
frontmatter 校验全流程skills/skill-creator/scripts/quick_validate.pyvalidate_skill
允许键集合skills/skill-creator/scripts/quick_validate.pyALLOWED_PROPERTIES
打包 + 强制校验skills/skill-creator/scripts/package_skill.pypackage_skill
打包排除规则skills/skill-creator/scripts/package_skill.pyshould_exclude, ROOT_EXCLUDE_DIRS
三级加载 / 目录分工skills/skill-creator/SKILL.md「Anatomy of a Skill」「Progressive Disclosure」
脚本黑盒纪律skills/webapp-testing/SKILL.md「Best Practices」
最小模板template/SKILL.mdfrontmatter