--- name: skill-creator description: 引导用户创建 / 改造自己的 skill(存进用户私有 `.skills/`,只对自己生效)。当用户说"我想做个自己的 skill / 把某个能力固化下来 / 把 zcbot 的某 skill 改成我要的样子 / 每次都要重复交代同一套规矩"时使用。本 skill 教怎么写 SKILL.md、怎么 fork 内置 skill 再改、怎么写好路由用的 description。用户只是要完成一个具体任务(写本子 / 画图 / 查文献)时不用 —— 那直接走对应 skill。 --- # Skill Creator - 造你自己的 skill 帮用户把"反复要交代的一套做法"沉淀成一个**私有 skill**,存在他自己的 `.skills/` 下,只对他生效,不影响别人也不动内置 skill。 两种来源: - **从零写**:全新能力,用 `save_skill` 写一份 SKILL.md。 - **fork 内置再改**(最常见):看中某个内置 skill(如 ppt / proposal)但想调规矩,用 `fork_skill` 整目录拷过来(**带它的脚本**),再编辑 SKILL.md。 ## 何时用 - 用户说"我想要个自己的 skill / 自定义 skill / 把这套流程固定下来" - 用户说"zcbot 的 X skill 挺好但我想改成 Y" → fork 再改 - 用户每次任务都要重复交代同一套约束(术语表 / 模板 / 禁忌) → 建议固化成 skill - 用户问"skill 怎么写 / SKILL.md 什么格式" ## 何时不用 - 用户只是要完成一个具体任务 → 走对应内置 skill,别绕到造 skill - 用户要改的是**全局行为**(所有任务都该这样) → 那是 system prompt / 偏好,不是 skill - 一次性的事 → 直接做,不值得固化 ## 关键机制(先讲清楚再动手) **存哪**:用户 skill 在私有 `.skills//SKILL.md`(与 `.memory/` 同级,文件面板里隐藏)。**你不用、也不该用 write/shell 去手写这个目录** —— 沙箱 fs 的根不指向那里,跨 host/docker 不可靠。一律用下面两个工具,它们 host 侧直接落到正确位置。 **两个工具**: - `save_skill(name, content)` — 新建 / 覆盖 `.skills//SKILL.md`。`content` 是完整 SKILL.md(含 frontmatter)。写时校验 frontmatter 合法且有 description,不合格直接拒。 - `fork_skill(src, new_name)` — 把内置(或用户已有)skill **整目录**拷到 `.skills//`,脚本 / references 一起带过来,frontmatter 的 name 自动改成 `new_name`。 **生效时机**:造好 / 改好后,**下一条消息**才生效(registry 每轮重建)。告诉用户造完这条结束,下次发消息就能用了。 **覆盖语义(user wins)**:用户 skill 与内置**同名 → 覆盖内置**(只对该用户)。想替换内置就用同名,想**两个都留**就改名(如 `ppt-mine`)。覆盖会在 skill 列表里显式标 `[你的·已覆盖内置]`,不静默。 ## 工作流 ### 1. 先问清楚要造什么(BLOCKING) - 是**从零**还是**基于某内置 skill 改**?基于改 → 是哪个、想改什么? - 这个 skill 解决什么任务?**什么时候该触发、什么时候不该**?(这决定 description,见下) - 要不要带脚本 / 模板? ### 2a. fork 路径(基于内置改) 1. `fork_skill(src=<内置名>, new_name=<用户起的名>)` —— 默认建议改名(如 `ppt` → `ppt-mine`),除非用户明确要覆盖内置。 2. fork 回包会给出 `.skills//` 路径。用 `read` 看 SKILL.md,用 `edit` 改用户想改的部分(规矩 / 模板 / 默认值)。 3. 改完告诉用户:下条消息起,`` 就在 skill 列表里了。 ### 2b. 从零路径 1. 跟用户敲定 name + description + 正文骨架。 2. `save_skill(name, content)`,`content` 是完整 SKILL.md。 3. 若校验报错(缺 description / YAML 坏),按提示修了重存。 ### 3. 写好 description —— 这是最关键的一环 description 是**唯一进每轮 skill 列表、决定路由**的字段。写糊了的代价不是"skill 不好用",而是**误触发 + 稀释列表**。规则: - 一句话讲清**做什么** + **何时用** + **何时别用** - 给**触发词**(用户会怎么开口),必要时给**反例**(像不该触发的近义场景) - 别写成功能罗列,要写成"路由信号" 照抄内置的结构,比如: > `description: 生成 PowerPoint(.pptx)。✅ 触发:PPT / 幻灯片 / slide / deck / .pptx。⛔ 不触发:报告 / 文档 / 纪要(走 documents/proposal)。...` ### 4. SKILL.md 正文骨架(从零时给用户的模板) ```markdown --- name: <小写、[a-z0-9_-]、≤64> description: <路由说明:做什么 + 何时用 + 何时别用 + 触发词> --- # <标题> <一句话定位:这个 skill 帮用户做什么> ## 何时用 / 何时不用 - ... ## 工作流 1. ... ## 反模式 - ... ``` 正文要不要分阶段 / 卡 BLOCKING / 带 quality_check,看任务复杂度 —— 简单 skill 几行就够,别硬套。带脚本的:脚本放 `.skills//scripts/`,SKILL.md 里用 `/scripts/xxx.py` 引(`` 是 `load_skill` 返回头给的路径,host/docker 都对)。 ## 反模式 - 用 `write` / `shell` 手动往 `.skills` 写 —— 用 `save_skill` / `fork_skill`(沙箱 fs 根够不到 `.skills`,会写错地方) - fork 带脚本的内置 skill(ppt/proposal)却只 `save_skill` 拷了 SKILL.md —— 脚本没带过来,`import` 必崩;带脚本一律 `fork_skill` - description 写成"很厉害的 PPT skill" —— 没有触发信号,路由抓瞎 - 默认就覆盖同名内置 —— 除非用户明说要替换,否则改名并存,别悄悄遮掉内置 - 造完不告诉用户"下条消息才生效",用户当场没看到以为失败 - 把"所有任务都该遵守的全局规矩"做成 skill —— 那该进偏好 / system prompt ## 输出 完成后给用户: - skill 名 + 路径(`.skills//`) - 是覆盖内置还是新增 / 并存 - 一句话:下条消息发什么就能触发它(或让 LLM 自动按 description 路由)