DeepDojo.AI发布 2026-11-12English
自定义 Skill 不显示或调到旧版的排查方法
同事昨晚更新了项目里的 /review:现在它应该输出一张带风险等级的审查表。你新开会话一调用,输出的还是一段自由文字,和改之前一模一样。你重开了两次会话,结果不变。
这类问题有两种表现,排查方向完全不同:
- 菜单里根本没有:Skill 没被发现,要查目录、文件名、frontmatter 和可见性设置;
- 菜单里有,但行为不对:调到的可能是另一份同名 Skill,要查项目、个人和更高优先级的来源。
开头这个例子属于第二种。你个人目录里恰好有一个上周建的同名 review Skill,而个人 Skill 的优先级高于项目 Skill。文件同时存在,和这次确实加载了旧版,是两件事,要用 /skills 看实际来源才能确认。
下面先讲同名时谁优先,再分两种症状给出排查清单,最后说明一个 Skill 写完后怎样才算验收通过:成功的样本要试,缺参数、依赖缺失这些失败路径也要试。
01 同名时谁优先
项目 Skill 位于 .claude/skills/<skill-name>/SKILL.md,个人 Skill 位于 ~/.claude/skills/<skill-name>/SKILL.md。完整的范围如下:
| 范围 | 位置 | 用途 |
|---|---|---|
| 企业 | 管理员部署位置 | 组织统一能力和政策 |
| 个人 | ~/.claude/skills/ | 跨项目复用的个人方法 |
| 项目 | .claude/skills/ | 当前仓库特有、需要团队共享 |
| 插件 | 插件 skills/ | 随插件分发的成套能力 |
同名时,企业定义优先于个人,个人优先于项目;插件用命名空间区分。Claude Code 的 Skills 文档给的例子正好对应开头的情况:deploy 同时出现在 ~/.claude/skills/ 和项目的 .claude/skills/ 里,/deploy 运行的是个人那份。插件 Skill 以 /插件名:skill名 的形式出现,所以不会和它们撞名。
旧式命令也在这张优先级里。.claude/commands/deploy.md 仍能提供 /deploy,但同名 Skill 一旦存在,就会优先。迁移旧入口时,先建并验证新 Skill,再清理旧文件,避免有人在过渡期间用到不同的方法,具体做法见把常用流程做成 Claude Code 斜杠命令。
命令名有两个来源:目录名可以调用它;frontmatter 里写了 name 时,官方说明菜单显示的、你输入的命令就以 name 为准,前提是这个名字没被别的命令占用。
02 菜单里没有:查发现条件
创建后先用 /skills 检查发现状态,再查看斜杠菜单。命令没有出现时依次确认:
- 目录是否真的是
.claude/skills/<name>/SKILL.md,文件名大小写是否正确。 - YAML frontmatter 是否由成对的
---包围,字段和缩进是否有效。 user-invocable是否被设成false,或 Settings 中的skillOverrides是否把它关闭。- 是否刚创建了一个会话启动时还不存在的顶层 Skills 目录。
- 是否存在同名的个人、企业或旧式 Command,导致当前加载版本与预期不符。
第 4 条的处理方式按官方文档写:Claude Code 会监视已有的 Skill 目录,增删改都能在当前会话生效;如果你新建了一个启动时不存在的顶层 Skills 目录,它还没在监视,需要运行 /reload-skills,之后在那个目录里的每次修改也要再运行一次。
第 2 条有两个细节。官方说明,只有开头的 --- 是文件第一行时,Claude Code 才会把它当作 frontmatter;YAML 写坏时,Skill 正文仍会加载,但元数据全是空的,所以 /skill-name 能用,Claude 却没法按描述自动匹配。要批量找出解析失败的文件,可以运行 claude plugin validate .claude/skills。
第 3 条里的 skillOverrides 是一个可以不改 SKILL.md 就隐藏或折叠 Skill 的设置。按设置字段参考的说明,在 /skills 菜单里切换可见性,会写进 .claude/settings.local.json。自己哪天随手关掉过,就会在这里找到。
03 菜单里有,但版本不对:查实际来源
命令或 Skill 没出现,就用 /skills 查。下一步取决于看到的结果:
列表里没有 → 查目录、SKILL.md、frontmatter 和可见性
列表里有,但行为不对 → 核对项目、个人及更高优先级的同名版本回到 /review 的例子。先把现象写成一份简短的记录:
- 现象:昨晚 22 点起,本仓库执行
/review后输出自由段落,未按预期生成带风险等级的审查表。 - 复现:新开会话,输入
/review,每次出现同样结果。 - 环境:版本 2.x,模型未变;期间同事在项目
.claude/skills/中更新了文件,个人目录中也有一个上周创建的同名 Skill。
有了时间、输入和两处同名文件,“同名覆盖”就成了值得先查的假设。接下来仍要看实际来源。项目模板明明改过了,/skills 却显示来自个人目录,这时才有依据优先排查同名旧版:给项目 Skill 一个不冲突的目录名,仍用同一份 diff 调用。
来源、输出一起符合预期,才支持修正有效。如果来源本来就对,就继续检查正文或输入,继续改名会失去方向。故障记录该写哪些内容、怎样按层定位,见Claude Code 出问题时的分层排查方法。
04 写完的 Skill 怎样算验收通过
菜单出现后,再用真实输入查三件事:读的范围对吗,该停时停了吗,返回结果符合约定吗?按调用顺序检查:
- 用
/skills或斜杠菜单确认名称、范围和来源; - 用用户真实会说的话测试自动触发,或直接调用手动 Skill;
- 确认授权工具无需重复询问,移除的工具确实不可用;
- 用一个低风险真实样本检查结果质量;
- 测试缺少参数、目标不存在、依赖缺失和动态命令失败。
没触发,就先看 description 有没有说明这类请求,再查调用限制和 frontmatter。触发太多,就收窄描述或改成手动调用。配置和上下文预算问题用 /doctor 查,YAML 解析错误再用 claude --debug 启动看调试日志。
以提交准备命令为例,分别测试有暂存改动和没有暂存改动的情况:前者返回相符草稿,后者说明原因后停止。两者都符合契约;没有输入时编造总结则不符合。
成功样本和失败路径都要验收。缺少输入或环境不符时,明确说明并停止,也是结果质量的一部分。开头那个 /review 改名以后能调到新版,只是第一步;用同一份 diff 跑出新格式,再试一次没给基线的调用,看它会不会停下,这个 Skill 才算可以交给团队用。