Skill 封装与发布
> 一句话:把已经跑通的工作流,变成别人(和三个月后的你)能一条命令复用的 skill。
交付物(铁律:两件缺一不可)
| # | 文件 | 内容 |
|---|---|---|
| ① | dist/<slug>.zip |
上传包,顶层目录必须是 <slug>/,内含 SKILL.md |
| ② | dist/_skillhub_submit_readme.txt |
《SkillHub 发布新技能 - 表单填写内容》,字段顺序固定 |
这两条不可协商:
- 包内只放
.md和.py。 出现.bat/.cmd/.ps1/.vbs/.exe,
平台会逐个校验扩展名并直接拒收(实测报错:提交失败 / 不允许的文件类型: scripts/_runner.bat)。<!-- audit:allow-ref -->
需要启动器/快捷方式时,把内容写成.py里的字符串常量,加一条
--make-shortcuts之类的命令在本地生成 —— 而不是随包分发。 - 打包必须本地实测。 解压到空目录,只按 SKILL.md 里的文档步骤跑一遍。
本地目录里早有一份能跑的文件,漏掉的步骤在那里完全看不出来。
何时使用
- 用户说「把 XX 封装成 skill」「这套流程整理成 skill」「打包发布到 SkillHub」
- 一个工作流已经跑通 ≥2 次,且下次还会用到
- 需要给已有 skill 升版本并重新发布
不适用:一次性脚本(不值得封装);只是问「skill 怎么写」的概念问题(直接答)。
五步流水线
| 步 | 做什么 | 工具 |
|---|---|---|
| 0 | 准入判定:值不值得封装 | 下面四个问题 |
| 1 | 建骨架 | scripts/new_skill.py |
| 2 | 写 SKILL.md | 规范见 references/skill-md-authoring.md |
| 3 | 搬实现、写脚本 | 三条铁律见下 |
| 4 | 审计 + 从零解压演练 | scripts/audit_skill.py |
| 5 | 打包出两件套 | scripts/pack_skill.py |
后续命令里的 $SKILL_DIR 指本 skill(skill-packaging)自身的目录,
用绝对路径替换即可跨机器通用。
Step 0 · 准入判定
四个问题,全过才值得封装:
- 跑通过吗? 没跑通就封装 = 把不确定性固化下来,以后每次用都要重新排障。
- 会重复吗? 用过 ≥2 次,或明显会周期性使用。
- 步骤 ≥3 且需要判断吗? 纯一条命令能解决的不值得(写进 memory 就够了)。
- 边界说得清吗? 说不清「什么时候别用它」,description 也一定写不好。
反向信号同样重要:踩过坑的流程最值得封装 —— 坑本身就是最有价值的交付物,
不封装就等于下次再踩一遍。
Step 1 · 建骨架
python "$SKILL_DIR/scripts/new_skill.py" <slug> \
--display-name "中文显示名" \
--description "一句话说清解决什么问题。触发词:……" \
--with-scripts --with-references
产出 <skills_root>/<slug>/:SKILL.md(frontmatter 字段已填全)+ 按需的
scripts/<模块名>.py(自定位 + argparse + ASCII 输出标记)+ references/notes.md(占位参考文档)。<!-- audit:allow-ref -->
--dry-run 可先看会写哪些文件。
Step 2 · 写 SKILL.md
description 是检索键,不是简介。 模型决定是否加载本 skill 时只能看到
description —— 所以它要回答「用户说了什么话 → 该用我」,并显式列出用户的原话
作为触发词。详细规范(含好/坏描述对照、正文骨架、写什么不写什么)见
references/skill-md-authoring.md。
frontmatter 硬性要求:name(kebab-case ASCII,与目录名一致)、description、
agent_created: true(缺了它,后续无法用 SkillManage 修改本 skill)。
Step 3 · 搬实现、写脚本
| 铁律 | 做法 | 为什么 |
|---|---|---|
| 自定位 | HERE = os.path.dirname(os.path.abspath(__file__)) |
写死用户名/盘符/$HOME 换台机器必挂 |
| 控制台安全 | 入口加 sys.stdout.reconfigure(errors="replace"),输出标记用纯 ASCII([OK]/[WARN]/[ERROR]) |
中文 Windows 控制台是 cp936,print emoji 会让进程以退出码 1 结束、输出停在符号前一行、stderr 还是空的 —— 极难排查 |
| 不重写逻辑 | 搬已经跑通的代码,只补 argparse 外壳 | 看着代码重写一遍 = 重造 bug |
外加:提供 --help,并给一个能被脚本打印的版本号常量。
Step 4 · 审计与从零演练
# ① 源码审计
python "$SKILL_DIR/scripts/audit_skill.py" <skill_dir>
# ② 从零演练:把 zip 解压到临时目录再查一遍
python "$SKILL_DIR/scripts/audit_skill.py" --package dist/<slug>.zip
检查项(全部来自真实踩过的坑):
| 前缀 | 检查 | 对应教训 |
|---|---|---|
S |
SKILL.md 存在、frontmatter 合法、必填字段齐全 | 模型靠 description 唤起,缺了就是隐身 skill |
F |
禁止的文件类型、文件数 ≤200、体积 ≤10 MB、本地残留 | .bat 被平台拒收 |
P |
.py 语法可编译、SKILL.md 引用的包内文件真实存在 |
文档与实物对不上,用户按文档跑直接失败 |
X |
脚本里是否写死了用户名/盘符 | 跨机器必挂 |
D |
目录构成提示 | — |
--strict 让 WARN 也算失败;--json 给机器读。
文档里纯粹举例用的路径(贴平台报错原文、说别的 skill 生成了什么文件)会被 P004 误报 ——
在那一行加一个 <!-- audit:allow-ref --> 豁免即可(注释渲染时不可见)。
检查器故意默认「凡是写成 scripts/…、references/… 的相对路径,都假定属于本包」,
因为漏报(文档引用了不存在的文件)比误报更糟。
审计通过 ≠ 交付完成,下面这步脚本替代不了:
> 手工从零演练:把 zip 解压到一个空目录,只按文档里写的步骤操作,
> 记录「文档没写到但实际必须做」的每一步。文档缺步骤只有空目录才暴露。
> (实例:某次发布包里 --shortcut-dir 参数被漏掉,本地因早有旧文件完全看不出来。)
Step 5 · 打包出两件套
python "$SKILL_DIR/scripts/pack_skill.py" <skill_dir> -o dist \
--slug <slug> --name "中文显示名" \
--cat1 效率工具 --cat2 自动化 \
--version 1.0.0 \
--description "……" \
--changelog "首次发布。……"
一次调用同时产出 zip 与 _skillhub_submit_readme.txt。
描述很长时用 --desc-file 从文件读,避开命令行转义。
要点:
- 打包前会预检禁止的文件类型并直接拒绝 —— 把失败挡在本地,
而不是等上传时被平台回一句「不允许的文件类型」。确需绕过加--allow-forbidden。 --cat1/--cat2没有官方清单,按平台实际 taxonomy 选。
已知可用组合、表单 8 个字段的填法、变更说明的写法见references/skillhub-rules.md。
拿不准就留(待选择)并在交付时提醒用户去界面挑,不要猜一个填上去。- 本 skill 自带的
scripts/pack_skill.py是权威版本。
全局那份旧拷贝~/.workbuddy/templates/pack_skill.py可能与之漂移,
一律优先走本 skill 内的(模板查找顺序也已把本 skill 的templates/排在全局目录之前)。
完成前自检清单
- [ ] SKILL.md 里没有残留的「待补充」「TODO」
- [ ] 源码审计:0 ERROR / 0 WARN
- [ ]
--package审计:0 ERROR - [ ] 空目录解压演练跑通,且文档步骤完整(有没有哪步是「我本来就知道才做的」?)
- [ ]
dist/下 zip 与_skillhub_submit_readme.txt都在,readme 里没有(待选择) - [ ] 版本号、显示名称、描述在 SKILL.md / zip / readme 三处一致
- [ ] 已把 zip 与 readme 一起交付给用户(两件都要给)
常见失败
| 现象 | 根因 | 处理 |
|---|---|---|
| 上传报「不允许的文件类型」 | 包内有 .bat/.cmd/.ps1 等 |
改成运行时本地生成;见 references/pitfalls.md 第 1 条 |
| 模型从来不自动唤起这个 skill | description 没写触发词,写的是简介 | 按 references/skill-md-authoring.md 重写 |
| 用户照文档跑不起来 | 文档引用了不存在的文件,或漏了必需步骤 | 审计 P 类检查 + 空目录手工演练 |
| 审计报 X001 硬编码路径 | 脚本里写死了用户名/盘符 | 改自定位,见 Step 3 |
| 改了一处、另一处没生效 | 同一个文件一轮里发了多个并行编辑,互相覆盖(两边都报「成功」) | 同文件改动必须串行,改完用断言列表全量审计收口 |
| 打包用的规则和预期不符 | 用的全局旧版 pack_skill.py |
改用本 skill 内的 scripts/pack_skill.py |
相关文档
references/skillhub-rules.md— 平台硬约束、表单 8 个字段、已知分类标签、变更说明写法references/skill-md-authoring.md— SKILL.md 写作范式(description 写法、正文骨架)references/pitfalls.md— 实测踩坑档案(拒收清单、并行编辑覆盖、Windows 脚本铁律)templates/skillhub_submit_readme.template.md— 提交说明模板,被scripts/pack_skill.py自动读取