最近在 VSCode 里用 RooCode 插件,往 ~/.roo/skills/ 丢了几个自定义 skill,结果发现只有原来装的四个(docxpdfpptxskill-creator)能在全局技能区看到,我自己加的几个死活不出来。重启 VSCode、重载窗口,还是没有。

折腾了一番,最后翻了插件源码才搞清楚怎么回事。记录一下排查过程,以后要是再碰到,或者你也遇到类似问题,希望能省点时间。


先说结论

RooCode 识别 skill 的逻辑比想象中严格,SKILL.md 的 frontmatter 有几个硬性条件,只要有一条不满足,这个 skill 就会被静默丢弃——不报错、不警告,就是不出现在列表里。


RooCode 怎么扫描 skill

插件会扫描这几个路径:

~/.roo/skills/             # 全局,所有工作区都能用
~/.agents/skills/          # 全局备用路径
<workspace>/.roo/skills/   # 工作区级别
<workspace>/.agents/skills/

对每个路径,插件会列出子目录,然后找每个子目录里的 SKILL.md,用 gray-matter 解析 frontmatter,再做一堆校验。任何一步出错都会直接 return,没有任何提示。

核心校验逻辑大概长这样(从 extension.js 里扒出来的):

// name 必须存在
if (!u.name || typeof u.name !== 'string') return;

// description 必须存在
if (!u.description || typeof u.description !== 'string') return;

// name 必须和目录名一致
if (u.name !== directoryName) return;

// name 格式:只能小写字母、数字、连字符,最长 64
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) return;

// description 长度 1–1024
if (description.length < 1 || description.length > 1024) return;

我碰到的四个坑

坑 1:description 里有单引号,没加引号

某个 skill 的 SKILL.md frontmatter 长这样:

---
name: my-skill
description: Triggered by phrases like 'do this thing,' 'help me with that,' ...
---

乍一看没问题,但 YAML 里裸字符串包含单引号,gray-matter 解析会出问题,导致 description 字段拿不到正确的值,进而被过滤掉。

修法很简单,把 description 的值用双引号包起来:

description: \"Triggered by phrases like 'do this thing,' 'help me with that,' ...\"

坑 2:description 太长

有个 skill 的描述写了 1050 个字符,超过了 1024 的上限。这个限制藏得比较深,文档里没有明确说,是看源码才发现的。

把描述末尾几句砍掉,控制在 1024 以内就好了。写描述的时候尽量精炼,说清楚触发条件和能做什么,不需要把所有细节都塞进 frontmatter。

坑 3:name 和目录名对不上

有个 skill 的目录名是 my-skill-folder,但 SKILL.md 里写的是:

name: my-skill

两者不一致,直接被跳过。RooCode 用目录名作为 key,name 字段必须和目录名完全一致

改成一样就行:

name: my-skill-folder

或者把目录重命名成和 name 一致的——改哪边都行,保持一致才是关键。

坑 4:目录名含大写字母

这个最坑。有个 skill 目录叫 my-Skill-Main,里面的 SKILL.md 写的是 name: my-skill-main(小写)。看起来很合理——name 本身格式没问题——但:

RooCode 要求 name 和目录名完全一致,而目录名本身也必须满足格式规则(只能小写+数字+连字符)。my-Skill-Main 里有大写字母,目录名不合法,校验在目录名这一关就失败了。

Windows 上把目录名改成大小写不同但字母相同的形式会报"文件已存在"的错误,需要绕一步:

# 先改成一个中间名
Rename-Item 'my-Skill-Main' 'my-skill-main-tmp'
# 再改成目标名
Rename-Item 'my-skill-main-tmp' 'my-skill-main'

重命名之后,如果 ~/.roo/skills/ 里有对应的 junction/symlink 指向旧名字,也要一并更新:

rmdir "C:\Users\<你的用户名>\.roo\skills\my-Skill-Main"
mklink /J "C:\Users\<你的用户名>\.roo\skills\my-skill-main" "<技能实际所在目录>\my-skill-main"

正确的 SKILL.md 长什么样

对照官方已识别的技能(如 docx),frontmatter 应该长这样:

---
name: my-skill-name
description: "一句话说清楚这个 skill 做什么、什么时候触发。如果描述里有单引号就用双引号包住。长度控制在 1024 字符以内。"
license: Proprietary. LICENSE.txt has complete terms
---

几条硬规则:

  • name 只能含小写字母、数字、连字符(-),长度 ≤64
  • name 必须和技能目录名完全一致,一个字母都不能差
  • description 长度 1–1024 字符
  • 描述里有单引号,记得用双引号包裹整个值

排查的时候怎么看哪个 skill 出了问题

RooCode 把错误信息打到了 console.error,在 VSCode 里可以这样看:

  1. 帮助 → 切换开发者工具(Help → Toggle Developer Tools)
  2. 切到 Console 标签
  3. 搜索 Skill

能看到类似这样的信息:

Skill name "my-skill" doesn't match directory "my-skill-folder"
Skill "another-skill" has an invalid description length: must be 1-1024 characters (got 1050)

这比盲目猜要高效得多,建议排查时先看这里。


快速 Checklist

遇到 skill 不出现,按顺序查:

  • skill 目录是否在 ~/.roo/skills/<workspace>/.roo/skills/
  • 目录下是否有 SKILL.md
  • frontmatter 里是否有 namedescription
  • name 是否和目录名一模一样(含大小写)
  • name 是否只含小写字母、数字、连字符,且 ≤64 字符
  • description 是否 ≤1024 字符
  • description 含单引号时是否用双引号包裹
  • YAML 是否能正常解析(贴到 yaml.org/parser 验一下)
  • 打开开发者工具看 console 里有没有相关报错
Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐