---
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/<name>/SKILL.md`(与 `.memory/` 同级,文件面板里隐藏)。**你不用、也不该用 write/shell 去手写这个目录** —— 沙箱 fs 的根不指向那里,跨 host/docker 不可靠。一律用下面两个工具,它们 host 侧直接落到正确位置。

**两个工具**:
- `save_skill(name, content)` — 新建 / 覆盖 `.skills/<name>/SKILL.md`。`content` 是完整 SKILL.md(含 frontmatter)。写时校验 frontmatter 合法且有 description,不合格直接拒。
- `fork_skill(src, new_name)` — 把内置(或用户已有)skill **整目录**拷到 `.skills/<new_name>/`,脚本 / 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/<new_name>/` 路径。用 `read` 看 SKILL.md,用 `edit` 改用户想改的部分(规矩 / 模板 / 默认值)。
3. 改完告诉用户:下条消息起,`<new_name>` 就在 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/<name>/scripts/`,SKILL.md 里用 `<skill_dir>/scripts/xxx.py` 引(`<skill_dir>` 是 `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/<name>/`)
- 是覆盖内置还是新增 / 并存
- 一句话:下条消息发什么就能触发它(或让 LLM 自动按 description 路由)
