Claude Code 学习站
Mingyu's Library

学习站 / 系统课程 / D7

D7 · Skills

把反复粘贴的流程和参考资料沉淀成 SKILL.md,让 Claude 按需加载:学会写结构、写描述、选位置,并做出第一个能自动触发的 skill。

一个 skill 就是一个带说明书的文件夹:说明书(description)常驻上下文供 Claude「认路」,正文只在被调用时加载。本课基于 2026-08-05 抓取的官方文档(Claude Code 2.1.222 水位)。

为什么这天学这个

D4 讲过 CLAUDE.md:全文常驻,每一轮请求都占着上下文,所以只放「永远要遵守」的短规则。但真实工作里还有另一类内容——部署清单、API 风格指南、调试手册——不是每轮都要,但要用时得完整。这正是 Skills 的位置:官方官方文档明确建议,当你反复往对话里粘贴同一套指令,或 CLAUDE.md 里某一节已经从「事实」长成「流程」,就该把它抽成 skill;skill 的正文只在用到时加载,长篇参考资料闲置时几乎不占上下文。

本课也是后半程的地基:D8 Hooks 会和 skill 对比「确定性执行 vs 模型理解执行」;D10 Subagents 会用到本课提到的 context: fork;D14 Plugins 讲的打包分发,装的主要货物就是 skill。跳过这课,后面三课都会缺一块拼图。

概念讲清楚

SKILL.md:frontmatter + 正文

官方每个 skill 是一个目录,入口文件固定叫 SKILL.md,分两部分:--- 包起来的 YAML frontmatter 告诉 Claude「什么时候用我」,后面的 markdown 正文是被调用时 Claude 执行的指令。目录名就是你输入的命令名(.claude/skills/deploy-staging//deploy-staging)。所有 frontmatter 字段都可选,官方只推荐必写 description:

常用字段作用
descriptionskill 做什么、什么时候用。Claude 靠它决定是否自动加载;省略时用正文第一段代替
when_to_use补充触发场景(触发短语、示例请求),追加在 description 之后;两者合计在列表里截断于 1,536 字符
disable-model-invocationtrue 后只有你能触发(适合 deploy、commit 这类有副作用的动作)
user-invocablefalse 后从 / 菜单隐藏,只有 Claude 能用(适合纯背景知识)
allowed-tools调用该 skill 的那一轮里免审批可用的工具;你发下一条消息时授权即清除
context: fork + agent在隔离的 subagent 里跑这个 skill(详见 D10)
pathsglob 模式,只在操作匹配文件时才自动激活

官方正文里可以用 $ARGUMENTS / $0 接收参数,用 ${CLAUDE_SKILL_DIR} 引用 skill 自带的脚本;还有一种「动态上下文注入」:!`命令` 会在 Claude 看到内容之前先执行,输出直接替换占位符——所以 Claude 拿到的是真实数据,不是命令本身。官方建议 SKILL.md 保持在 500 行以内,细节资料拆成目录里的附属文件,让 Claude 需要时再读。

触发:description 是唯一的「广告位」

官方会话开始时,所有可被模型调用的 skill 只有名字和 description 进入上下文;Claude 拿你的请求和这些描述做匹配,命中才加载全文。你也可以直接输入 /skill-name 跳过匹配强制加载。这意味着:描述写得好不好,直接决定 skill 会不会被想起来

你输入一条消息 描述匹配 命中 加载 SKILL.md 全文 按指令执行 未命中:只保留描述,不加载全文 /skill-name 直接调用 跳过匹配,直接加载
skill 的两条触发路径:Claude 按描述匹配自动加载,或你用 /skill-name 手动加载。

描述怎么写才容易命中?官方排错指南给的方向:官方描述里要包含用户会自然说出的关键词,把最核心的使用场景写在最前面(超长会被截断);skill 不触发时,先确认它出现在「What skills are available?」的回答里,再换个更贴近描述的问法,或直接 /skill-name 调用。本站观点如果你平时用中文和 Claude Code 对话,就把中文触发词也写进 description——匹配是按语义做的,但把你真实会说的话原样放进去,命中率最稳。

一个隐蔽的坑:官方frontmatter 的 YAML 写坏时,Claude Code 会带着「空元数据」加载正文——/skill-name 手动调用照常能用,但 Claude 没有 description 可匹配,自动触发彻底失效。用 --debug 启动能看到解析报错。所以「手动能跑、从不自动触发」十有八九是描述缺关键词或 YAML 坏了。

放哪:三级位置与重名规则

官方skill 放在哪,决定谁能用:

级别路径生效范围
个人级~/.claude/skills/<skill-name>/SKILL.md你的所有项目
项目级.claude/skills/<skill-name>/SKILL.md仅当前项目(可随仓库提交共享给团队)
插件级<plugin>/skills/<skill-name>/SKILL.md启用了该插件的地方
企业级managed settings 下发组织内所有用户

官方重名时按级别覆盖:企业级 > 个人级 > 项目级,且任何一级的同名 skill 会覆盖内置的 bundled skill(比如项目里放一个 code-review 就替换掉自带的 /code-review)。插件 skill 用 plugin-name:skill-name 命名空间,天然不冲突。skill 目录是被实时监听的:改动 SKILL.md 当场生效,不用重启会话(新建顶层 skills 目录除外)。这套「项目级随仓库提交、插件级打包分发」的路径,就是 D14 Plugins 的入口。

对比 CLAUDE.md:常驻 vs 按需(承接 D4)

会话开始 你或 Claude 调用 skill CLAUDE.md 全文常驻:每次请求都计入上下文 Skill 只有名字+描述(很轻) 调用时才加载全文
同样一份内容,放 CLAUDE.md 是每轮固定开销,做成 skill 则闲时只花一条描述的钱。

官方官方给的分工原则:「每个会话都必须知道」的短规则(构建命令、编码约定、never-do 规则)放 CLAUDE.md,并保持在 200 行以内;偶尔才需要的参考材料和可触发的工作流做成 skill。两个细节值得记住:一是 skill 全文一旦被调用,会作为一条消息留在会话里直到结束,所以正文也要克制,别当垃圾场;二是给 skill 设 disable-model-invocation: true 后连描述都不进上下文,对只手动触发的 skill 是零闲置成本。本站观点判断口诀:内容是「事实和规矩」进 CLAUDE.md,是「流程和资料」进 skill;CLAUDE.md 里哪一节开始出现第 1、2、3 步了,就是它该搬家的信号。

slash command 就是 skill

官方自定义命令已并入 skill 体系:.claude/commands/deploy.md.claude/skills/deploy/SKILL.md 都会创建 /deploy,行为一致;旧的 commands 文件继续有效。skill 是超集,多出三样:整目录附属文件、控制「谁能调用」的 frontmatter、以及被 Claude 按描述自动加载的能力。内置的 bundled skills(/code-review/debug/loop 等)也是同一套机制。默认你和 Claude 都能调用任何 skill;两个开关把它变成「只许你」(disable-model-invocation: true,适合 deploy 这种你要掌握时机的动作)或「只许 Claude」(user-invocable: false,适合没有动作意义的背景知识)。

选型延伸skill、hook、MCP、subagent、plugin 五件套怎么选,本站有专门一篇对照:Tip E1 · skill / hook / MCP / subagent / plugin 怎么选。本课先记住一句:「要 Claude 理解着做」用 skill,「必须每次不走样」用 hook(D8 展开)。

当天能做完的实操

目标:做一个「总结未提交改动」的最小 skill,验证自动触发、手动调用、按需加载三件事。全程约 20 分钟,需要一个 git 项目。

  1. 创建 skill 目录(个人级,所有项目可用):
    mkdir -p ~/.claude/skills/summarize-changes
    预期:目录创建成功。注意:如果 ~/.claude/skills/ 是本次新建的,而 Claude Code 会话已开着,先重启会话让它监听新目录;之后再改文件就都是当场生效了。
  2. 把下面内容存为 ~/.claude/skills/summarize-changes/SKILL.md(结构来自官方入门示例,描述做了中文化以贴合你的真实问法):
    ---
    name: summarize-changes
    description: 总结当前未提交的 git 改动并标出风险点。当用户问「我改了什么」「帮我看看这次改动」、想要 commit message 或让你 review diff 时使用。Summarizes uncommitted changes and flags anything risky.
    ---
    
    ## 当前改动
    
    !`git diff HEAD`
    
    ## 指令
    
    用两三条要点总结上面的改动,然后列出你注意到的风险,
    例如缺少错误处理、写死的值、需要同步更新的测试。
    如果 diff 为空,直接说没有未提交的改动。
    其中 !`git diff HEAD` 是动态上下文注入:skill 被调用时先跑这条命令,把真实 diff 塞进指令再交给 Claude。
  3. 在任一 git 项目里随手改一个文件,启动 claude,先测自动触发——用贴近描述的自然问法:
    我刚才改了哪些东西?帮我总结一下这次改动,并指出有没有风险。
    预期:界面显示 skill 被加载,Claude 给出基于真实 diff 的两三条总结加风险清单——而不是靠猜。
  4. 再测手动调用:输入 /summarize-changes。预期:跳过描述匹配,直接得到同样结构的输出。
  5. 验证按需加载:问 Claude「What skills are available?」确认 skill 已注册;再回想 D1 学过的 /context,Skills 一行显示的只是描述列表的开销——全文是刚才被调用后才进的上下文。
  6. 进阶一步:在 frontmatter 里加一行 disable-model-invocation: true,保存(不用重启),再问一遍第 3 步的问题。预期:不再自动触发(描述已从上下文移除),但 /summarize-changes 依然能用。体会完删掉这行恢复。

最后,把这套能力用到真实工作上——让 Claude Code 帮你把一个常用流程沉淀成项目级 skill:

帮我把「发布前检查」流程沉淀成一个项目级 skill:
- 创建 .claude/skills/release-check/SKILL.md
- description 写清触发场景,包含我平时会说的关键词(发布、上线、release)
- 正文列出检查步骤,每步可验证
- 设 disable-model-invocation: true,只允许我手动 /release-check 触发
写完后展示文件内容,并逐个解释 frontmatter 字段的作用。

验收标准

  • 能不看笔记说清 SKILL.md 的两段结构,以及 description 在「会话开始时」和「触发时」分别扮演什么角色。
  • 能画出(或口述)本课第一张图:自动匹配和 /skill-name 两条触发路径的区别。
  • 能解释同一份内容放 CLAUDE.md 和做成 skill 的上下文成本差异,并说出各自适合装什么。
  • 实操 6 步全部跑通:自动触发、手动调用、disable-model-invocation 的效果都亲眼见过。
  • 自测题:一个 skill 用 /name 能正常跑,但 Claude 从不自动使用它。说出两个最可能的原因和对应修法。(提示:一个在 description 的内容上,一个在 frontmatter 的语法或开关上。)