你在 ~/.claude/skills/my-skill/ 下放了一个 SKILL.md,输入 /my-skill 却报「skill not found」。或者它在 / 菜单里能看到,但你用自然语言描述同样的任务时它从来不自动触发。
最快的修法:在会话里跑 /skills。如果你的 skill 不在这个列表里,那就是路径或 frontmatter 的问题(跳到原因 1-2)。如果它在列表里、但标了「user-only」,说明它设了 disable-model-invocation: true,只能靠 slash 调用。如果它在列表里、也允许自动调用、但 Claude 还是不理它,那就是 description 太泛、或者被 skill 预算挤掉了(原因 4 和 7)。每一种都是改一行就能修好。
有几个 2026 年变了、最容易把人绕进去的点:你输入的命令名来自文件夹名,不是 frontmatter 里的 name 字段;而且改已有的 SKILL.md 现在在运行中的会话里实时生效——不用重启(截至 2026 年 6 月,Claude Code v2.1.x)。老的「重启然后 grep claude --debug」的建议已经过时了。
你属于哪一类
先跑 /skills,再对照下表:
/skills 里的表现 | 大概率原因 | 看哪一节 |
|---|---|---|
| skill 完全不出现 | 路径错,或 frontmatter 被解析器拒了 | 原因 1-2 |
| 列出了,标签是「user-only」 | 设了 disable-model-invocation: true | 原因 3 |
列出了、可调用、/name 能跑但不自动触发 | description 太泛 | 原因 4 |
| 列出了,但你看到「skill descriptions dropped」警告 | skill listing 预算溢出 | 原因 7 |
| 两个同名 skill | 一个把另一个盖住了 | 原因 6 |
常见原因
按命中率从高到低。
1. Skill 文件没放在期望的路径
Claude Code 扫一组固定位置:~/.claude/skills/<skill-name>/SKILL.md(用户全局)、项目本地的 .claude/skills/<skill-name>/SKILL.md(以及从当前目录到仓库根的每一层父目录里同名路径)、还有插件提供的 <plugin>/skills/<skill-name>/SKILL.md。如果你存成了扁平文件 ~/.claude/skills/my-skill.md(没有文件夹)或者放进了 ~/.claude/skill/(单数、目录名错),它永远不会被加载。这是最常见的一种——官方文档也把它排在第一位。
怎么判断:跑 ls ~/.claude/skills/,确认每一项都是文件夹、里面有一个名字正好是 SKILL.md 的文件。直接丢在 skills/ 里的裸 .md 文件不会被加载。
2. Frontmatter 缺失或格式坏了
SKILL.md 应该以 --- 包起来的 YAML frontmatter 开头。严格说每个字段都是可选的,Claude 会回退到用文件夹名和 body 第一段;但坏掉的块——少了收尾的 ---、从文档里粘了智能引号、用了 tab 而不是空格——会让解析器直接拒了这个文件,于是它根本不出现在 /skills 里。
怎么判断:打开 SKILL.md。确认第一行是 ---、body 前面有配对的收尾 ---、引号只用直引号 " 不用弯引号。再跑 /doctor——它会标出配置里的 schema 错误和非法 key。
3. Skill 被设成了只能手动调用(或被隐藏)
如果 skill 在 /skills 里、但从不自动触发,看一下它的标签。frontmatter 里的 disable-model-invocation: true 意味着只有你能用 /name 调它;Claude 不会自己触发,而且它的 description 会被整个从上下文里去掉。反过来,user-invocable: false 会把它从 / 菜单里隐藏(Claude 仍能调用)。
怎么判断:/skills 里出现「user-only」标签就说明模型没法触发它。打开 frontmatter 找 disable-model-invocation: true,想要自动触发就删掉它。
4. description 太泛、自动触发不了
要让模型自动调用,Claude 是拿你的请求去 match 每个 skill 的 description(再加上可选的 when_to_use)。如果你写了「helper」这种一个词的描述,模型完全没东西可匹配,只能靠 slash 调用才跑。把关键用途写在最前面:listing 里 description + when_to_use 合起来在 1,536 个字符处截断(可用 maxSkillDescriptionChars 调整)。
怎么判断:把 description 读出来。如果没有点出具体触发场景(「用户要求部署时」、「SQL migration 的时候」),就是太泛了。测的时候把请求写得尽量贴近 description。
5. allowed-tools 的误解(现在通常不是问题)
allowed-tools 不限制 skill 能用哪些工具——它是把列出的工具预先批准,让 skill 激活期间 Claude 不用每次弹权限确认就能用。其他工具照样都能用,只是会弹确认。所以 allowed-tools 和 body 里用到的工具对不上,不会导致 skill 加载不了。如果跑到一半还是要确认权限,把那些工具加进 allowed-tools(比如 allowed-tools: Bash(git commit *) Read)。
怎么判断:如果 skill 加载了、但跑某个工具时停下来要权限,那是这个工具没在 allowed-tools 里,不是被禁了。
6. 重名 skill 把你的覆盖了
同名 skill 跨层级时,优先级是:enterprise > personal > project。插件 skill 带命名空间(plugin-name:skill-name),所以不会和你自己的撞。如果 ~/.claude/skills/foo/ 和 .claude/skills/foo/ 都存在,用户全局那个赢、项目那个被藏起来。
怎么判断:在 /skills 里看是不是有两条都解析到同一个 /foo。给其中一个改名(加前缀,比如 my-foo),两个就都能用了。
7. description 被 listing 预算挤掉了
2026 年新增的机制:Claude 会加载每个 skill 的名字,但description 共享一份上下文预算,默认是模型上下文窗口的 1%(对应 skillListingBudgetFraction 设置)。如果你 skill 很多、预算溢出了,用得最少的那些会丢掉 description,于是模型没法再自动匹配它们——你会在启动时看到「skill descriptions dropped」警告。这个 skill 用 slash 调用照样能跑。
怎么判断:跑 /doctor,它会报告预算是不是溢出了、哪些 skill 受影响。在 ~/.claude/settings.json 里用 "skillListingBudgetFraction": 0.02 调高(2% 大约每个会话多花 2,000 个 token),或者在 skillOverrides 里把低优先级 skill 设成 "name-only"。
开始前
- 确认你用的是 Claude Code CLI,不是 Claude.ai web(那边 Skill 加载机制不一样)。
- 改已有的
SKILL.md不用重启——live change detection 会在会话里实时生效。只有当你刚创建了一个会话启动时还不存在的顶层 skills 目录,才需要重启。 - 想清楚你是要 slash 调用、自动触发、还是两个都要——它们失败的原因不一样。
需要收集的信息
- Claude Code 版本:
claude --version(实时重载和/skills需要较新的 2.1.x)。 - 系统和 shell:
uname -a加echo $SHELL。 ls -la ~/.claude/skills/和项目根目录下ls -la .claude/skills/的输出。SKILL.md的完整内容,特别是 frontmatter 部分。- 会话里:
/skills(加载了什么)和/context(description 在不在上下文里)。 - 输入
/your-skill-name时打印的任何报错。
一步一步修复
Step 1:核对磁盘上的目录结构
ls -la ~/.claude/skills/
ls -la ~/.claude/skills/my-skill/
应该看到一个 my-skill/ 文件夹、里面装着 SKILL.md。如果看到的是扁平的 my-skill.md,把它挪进文件夹——文件夹名会成为你的 /command:
mkdir -p ~/.claude/skills/my-skill
mv ~/.claude/skills/my-skill.md ~/.claude/skills/my-skill/SKILL.md
Step 2:列出实际加载了什么
在会话里跑:
/skills
这是权威的「已加载 skill」列表(项目、用户、插件三个来源),每条都带一个标签标明能不能被模型自动调用。如果你的 skill 不在这里,说明 loader 拒了它——继续 Step 3。如果它在、但标了「user-only」,跳到 Step 5。
Step 3:校验 frontmatter
打开 SKILL.md,看最上面这一块:
---
name: my-skill
description: Summarize uncommitted changes and flag risky edits. Use when the user asks what changed, wants a commit message, or asks to review their diff.
---
开头和结尾的 --- 必须配对,frontmatter 块才能解析。别用 tab、别用智能引号。然后跑 /doctor——它校验配置文件、报告 schema 错误和非法 key;按 f 可以把报告发给 Claude,让它带你修。
Step 4:确认模型看得到这个 skill
用自然语言问一句:
What skills are available?
如果回答里点了你的 skill,说明 Claude 能看到、也能自动调用它。如果 /skills 里列了它、但这个回答里没有,多半是 description 被 listing 预算挤掉了——去 Step 7。
Step 5:把 description 改得更适合自动触发
重写 description,加上具体的触发短语,关键用途放最前:
description: |
Deploy a service, run database migrations, or invalidate the CDN
cache. Use when the user says "deploy api to staging" or
"run migration 0042".
具体的触发场景能显著提高自动命中率。如果你之前为了保险设了 disable-model-invocation: true,记住那是故意挡掉所有自动触发的——想让模型自己触发就把它删掉。
Step 6:检查 allowed-tools 覆盖(只在它停下来要权限时才需要)
allowed-tools 不管加载,只是预批工具。如果 skill 跑起来了、但跑到比如 git commit 时停下来要确认,把那个工具列上:
allowed-tools: Bash(git add *) Bash(git commit *) Read
干脆不写 allowed-tools,就回退到你平时的权限弹窗。
Step 7:解决被挤掉或被覆盖的 skill
/doctor
如果 /doctor 报「skill descriptions dropped」,说明你的 listing 预算溢出了。要么调高、要么把不常用的降级:
{
"skillListingBudgetFraction": 0.02,
"skillOverrides": { "legacy-context": "name-only" }
}
如果是真的重名冲突(两个 skill 解析到同一个 /command),把其中一个文件夹加个人前缀改名,比如 my-deploy 而不是 deploy。
Step 8:实在不行,用 safe mode 隔离
如果一个看起来没问题的 skill 还是加载不了,开一个干净会话,排除掉某个冲突的 hook、插件或设置:
claude --safe-mode
Safe mode(v2.1.169+)会禁用所有自定义——CLAUDE.md、skills、插件、hooks、MCP。如果你只重新启用它之后就能用了,说明是配置里别的东西在捣乱。更深一层的测法:把 Claude 指向一个空配置目录:cd /tmp && CLAUDE_CONFIG_DIR=/tmp/claude-clean claude。
怎么确认修好了
/skills里列出了这个 skill、没有「user-only」标签(除非你本来就要只手动调用)。/my-skill能跑、也输出预期内容。- 问「What skills are available?」时点到了你的 skill,而且用一句匹配 description 的自然语言,一两轮内能自动触发。
/doctor里没有 schema 错误、也没有这个 skill 的「descriptions dropped」警告。- 在一个全新会话里也能用,不是只在你改完那一次的会话里能用。
长期预防
- dotfiles 里维护一个
skills/README.md,列出每个 skill 和它的触发短语。 - 定期跑
/doctor;它能在 frontmatter schema 错误和预算溢出发作前就抓出来。 - 只对有副作用、想手动触发的 skill(deploy、commit)用
disable-model-invocation: true。 - 把不常用的 skill 在
skillOverrides里降级成"name-only",把预算留给真正依赖的那些。 - 把
~/.claude/skills/目录纳入版本控制。
容易踩的坑
- 以为改完必须重启。不用——改已有的
SKILL.md会实时重载。只有全新的顶层 skills 目录才需要重启。 - 以为 frontmatter 的
name决定斜杠命令。它决定的是显示标签;/command由文件夹名决定(plugin-root 的SKILL.md除外)。 - 从博客复制 frontmatter,把智能引号或 tab 一起带进来。
- 设了
disable-model-invocation: true,然后纳闷为什么从不自动触发。 - description 写 300 字;超过 1,536 字符会被截断,预算紧张时还可能被整条丢掉。写得紧凑、触发条件放最前。
- 把 skill 放进
~/.claude/skill/(单数)这种 typo 目录。
常见问答
- Claude Code 去哪里找 skill? 用户全局
~/.claude/skills/<name>/SKILL.md、项目里及其父目录的.claude/skills/<name>/SKILL.md、以及插件的<plugin>/skills/<name>/SKILL.md。同名冲突时优先级:enterprise > personal > project。 - 加了 skill 要重启吗? 改已有的
SKILL.md不用——live change detection 会在运行中的会话里应用。只有当你创建了一个会话启动时还不存在的顶层 skills 目录,才需要重启。 - 斜杠命令名由什么决定? skill 的文件夹名,不是 frontmatter 的
name字段。.claude/skills/deploy-staging/SKILL.md不管name:写什么,命令都是/deploy-staging。 - 我的 skill 在
/skills里能看到,但永远不自动触发? 要么设了disable-model-invocation: true(只能手动),要么 description 太泛、或者被 listing 预算挤掉了。跑/doctor看预算,否则就把 description 写具体。 - 怎么列出所有加载的 skill? 在会话里跑
/skills,或者问「What skills are available?」看模型能自动调用哪些。/context能看 description 占不占上下文。 - 「skill descriptions dropped」警告是什么? skill 的 description 共享一份预算,默认是上下文窗口的 1%。skill 多了就溢出,用得最少的会丢掉 description。调高
skillListingBudgetFraction(比如0.02),或者把低优先级 skill 设成"name-only"。 - 两个 skill 能同名吗? 跨层级时优先级高的赢、盖掉另一个。插件 skill 带命名空间(
plugin:name),所以从不冲突。把你自己的其中一个改名,避免被覆盖。
相关
- Claude Code settings.json 不生效
- Claude Code subagent 结果回传不到主会话
- Claude Code hook 莫名其妙拦下 Edit
- Claude Code permissions 弹窗循环
- Claude Code 工具执行卡住
外部参考:Extend Claude with skills 和 Debug your configuration(Claude Code 官方文档)。
标签: #Claude Code #Skills #排查 #CLI