Claude Code Skill编写指南:frontmatter字段、四级作用域与避坑要点

Claude Code Skill编写指南:frontmatter字段、四级作用域与避坑要点
张文保 更新 22 分钟阅读 2,198 阅读
本文目录
  1. Skill的定位是什么,与斜杠命令的差别在哪?
  2. 一个最小可用的SKILL.md需要哪些内容?
  3. name必填动名词、description限20字,这两条还成立吗?
  4. frontmatter的进阶字段各自控制什么?
  5. 命令名由什么决定,自定义命令是否已并入Skills?
  6. Skill的四级作用域如何决定可用范围?
  7. 怎样用附属文件让SKILL.md既精简又够用?
  8. 动态上下文注入与context:fork怎么用?
  9. 可复用的Skill设计原则有哪几条?
  10. 写Skill最容易踩的坑有哪些?
  11. 常见问题解答
  12. Skill的name字段必须是动名词形式吗?
  13. description是不是越短越好,最好20字以内?
  14. 自定义命令和Skill是两个不同的东西吗?
  15. 怎么让一个内容很多的Skill不浪费token?
  16. context: fork的作用是什么?
  17. 什么样的任务才值得做成Skill?
  18. 权威参考资料
摘要:不少Skill教程把两条规则讲成定论:name字段必填、还得写成动词加ing的动名词形式,description要压到20字以内。按官方现行规范,这两条都不成立。name是可选字段,不写就用目录名,你敲的命令也来自目录名而非name;description不该越短越好,它和触发说明合起来有1536字符的预算,要诀是把最该命中的使用场景写在最前面。决定一个Skill好不好用的也不止这两个字段,disable-model-invocation、allowed-tools、context:fork、附属文件、动态上下文注入这一整套机制,才是把Skill从能跑写到好用的关键。本文按官方现行规范梳理frontmatter字段、四级作用域、渐进式披露和子代理执行,给出一套经得起用的Skill设计模式。

Skill的定位是什么,与斜杠命令的差别在哪?

Skill是把一套专业知识、工作流程或最佳实践打包成的“能力单元”:你写一个SKILL.md文件,Claude Code就把这项能力收进工具箱。它和手动敲斜杠命令的差别在触发方式上——斜杠命令要你主动点名,Skill则由Claude根据对话上下文自动判断什么时候该用,你在做什么,它就在相关的时候被调起来,不必每次点名。

自动触发之下是一套省token的机制,官方叫渐进式披露。Claude Code官方的Skills文档把规则写得很明确:一个Skill的description会常驻在上下文里,好让Claude知道有这么个能力、什么时候该用,但它的正文只有在真正被调用时才加载进来。所以你可以写一份很长的参考资料型Skill,平时它几乎不占token,用到时才被读进上下文。

这跟CLAUDE.md把每一行都常驻上下文是两种思路。官方也据此建议:CLAUDE.md里某段一旦长成一套流程,就该抽出来做成Skill。两者怎么分工,保哥在CLAUDE.md和README该写什么那篇里写过,这里不重复,记住一句就够:Skill是按需加载的能力,这是它一切设计的出发点。

按需加载这条决定了Skill的写法:description要让Claude准确判断何时触发,正文要在被加载时直奔主题、不啰嗦,重型参考资料要拆到附属文件里,不能一股脑塞进来。后面讲的字段和模式,都围绕同一个目标——让这项能力在对的时机、用最省的代价被准确调起来。

一个最小可用的SKILL.md需要哪些内容?

一个Skill就是一个目录,里面放一个SKILL.md当入口。这个文件分两部分:顶上用---夹起来的YAML frontmatter,告诉Claude什么时候用这个Skill;下面是markdown正文,写Claude被触发后该照着做的指令。最小配置只要一段描述加几句指令就能跑起来:

---
description: 总结未提交的改动并标出风险点。当用户问改了什么、想要提交信息、或要审查diff时使用。
---

## 当前改动

!`git diff HEAD`

## 指令

把上面的改动用两三句话总结,再列出你注意到的风险,
比如缺少错误处理、写死的值、需要更新的测试。若diff为空,就说没有未提交的改动。

把它存成~/.claude/skills/summarize-changes/SKILL.md,重启Claude Code,你问“我改了什么”,它就会自动触发;也可以直接敲/summarize-changes手动调。里头那行!`git diff HEAD`要单独看:Claude Code会在把Skill内容送进去之前先把这条命令跑掉,用真实的diff结果替换掉它,后面专门讲这个机制。让一个Skill跑起来就这点东西,难的是让它在该触发时触发、不该触发时安静,这要回到那些被讲错最多的字段上。

name必填动名词、description限20字,这两条还成立吗?

这两条是流传最广的规则,也是错得最彻底的。不少教程写得斩钉截铁:name字段必填,而且得写成动词加ing的动名词形式,像processing-pdfs;description要言简意赅,最好20字以内。按官方现行规范,这两条都不成立。

先说name。官方的frontmatter参考里,name是可选字段,不是必填;不写它,就默认用Skill所在的目录名。更关键的一点是,触发Skill的那个命令名来自目录名,而不是frontmatter里的name,name只是显示在Skill列表里的一个标签。所以纠结name用不用动名词、要不要动词开头意义不大,决定命令叫什么的是你给目录起的名字。把目录命名得清晰、贴合功能,比抠name字段的词性有用得多。

再说description。它不该被无脑压短。description是Claude判断何时该用这个Skill的唯一依据,写得太短,反而把能帮助命中的关键词砍掉了。官方的规则是:description和可选的when_to_use合起来,在Skill列表里被截断的上限是1536字符,这是个相当宽裕的预算,远不是20字以内。

要诀在于把最该命中的使用场景写在最前面,因为列表空间紧张时是从尾部开始截断。一句话:description要写得具体、带上用户会自然说出口的关键词、把核心用例顶到最前,而不是一味求短。这一条写好了,Skill触发的准头能上一个台阶;写砸了,它要么该出手时哑火,要么动不动乱触发。

frontmatter的进阶字段各自控制什么?

只用name和description,Skill的能力还剩一半没动。官方frontmatter里还有一长串字段,每个对应一种具体的控制需求,先看最常用的几个:

字段作用
descriptionClaude判断何时触发的依据,写具体、关键词靠前(最该写好的一个)
when_to_use补充触发场景和示例请求,接在description后面一起算进1536字符预算
disable-model-invocation设为true则只有你能手动调、Claude不会自动触发,给有副作用的操作用
user-invocable设为false则只有Claude能调、不在斜杠菜单露面,给纯背景知识用
allowed-toolsSkill激活时这些工具免确认直接用,比如放行特定git命令
context设为fork则在隔离的子代理上下文里跑这个Skill
agent配合context:fork,指定用哪种子代理来执行
argument-hint自动补全时提示该传什么参数

其中两个字段最值得先配好。一个是disable-model-invocation: true:凡是带副作用、你想自己攥住触发时机的操作,比如部署、提交、给客户发消息,都该加上它,免得Claude自行判断后就把部署跑了。另一个是user-invocable: false,方向相反:某些纯背景知识型的Skill,比如“某个老系统是怎么运作的”,对人来说/某某并不是一个有意义的动作,但Claude在相关时该知道,这类就藏起来只让Claude用。

两个字段配合起来,你能精确控制每个Skill属于哪一类:只归你调用的命令、只由Claude自动调起的背景能力,或者两者都行。这种控制精度,正是Skill比一根光秃秃的斜杠命令强的地方。

表里没展开的还有几个字段,让控制粒度更细。model能指定这个Skill激活时用哪个模型,比如一个简单的格式化Skill就走便宜的小模型,不必动用最贵的那档,省钱;effort则单独调这个Skill的思考力度。paths用glob模式限定Skill只在你处理匹配的文件时才自动加载,比如一个只管前端规范的Skill,设上paths: "src/web/**",你改后端时它就不会被拉进来,触发更精准。

shell能指定动态注入命令用bash还是PowerShell,Windows用户会用到。这些字段平时未必都用得上,但遇到“想让某个Skill只在特定情况下、用特定代价生效”的需求时,知道它们存在,你就知道该去拧哪个旋钮,不用硬在description里绕。

命令名由什么决定,自定义命令是否已并入Skills?

命令名这件事还牵出另一个大变化,顺着name一起说清。放在~/.claude/skills/或.claude/skills/下的Skill,命令名来自目录名:.claude/skills/deploy-staging/SKILL.md对应的命令就是/deploy-staging。这个规则简单可靠,记住目录名即命令名基本不会错。

那以前在.claude/commands/下写的自定义命令呢?官方已经把自定义命令并入了Skills:一个.claude/commands/deploy.md和一个.claude/skills/deploy/SKILL.md都会生成/deploy命令,行为一致。你原来.claude/commands/里的文件照样能用,不用迁移;Skill则多出三样能力:可以带附属文件、能用frontmatter控制由谁触发、能让Claude在相关时自动加载。新写的优先用Skill的目录形式,能力更全。不少老教程没跟上这条变化,仍把自定义命令和Skill当成两个东西讲,实际上它们早就合流了。

Skill的四级作用域如何决定可用范围?

常见说法只提到个人级和项目级两种,官方现在是四级作用域,放在哪一级决定了谁能用、能用在哪:

层级路径作用范围
企业级由托管设置部署组织内所有用户
个人级~/.claude/skills/你的所有项目
项目级.claude/skills/仅当前项目,可提交共享
插件级插件目录下的skills/启用该插件处

分层逻辑跟CLAUDE.md那套作用域一脉相承:你个人不管在哪个项目都想要的Skill,放个人级;只跟某个项目相关、又想让队友也能用的,放项目级并提交进仓库;要打包分发给一群人的,做成插件。同名时企业级压个人级、个人级压项目级,插件级则用插件名:Skill名的命名空间,不会跟其他层冲突。

一个实用习惯是:先在个人级把一个Skill调顺手,确认好用了,再决定要不要下沉到项目级共享给团队,别一上来就往项目仓库里塞半成品Skill,污染队友的环境。

怎样用附属文件让SKILL.md既精简又够用?

Skill被调用后,它的正文会作为一条消息进入对话,并在整个会话里一直留着,所以正文的每一行都会被反复计入token,写臃肿就是持续消耗预算,还会稀释注意力。但一项能力又常常需要配上大段的参考资料。两头兼顾的办法是附属文件。

一个Skill目录里,SKILL.md是必需的入口,旁边还可以放别的文件:详细的API参考、示例集、能执行的脚本。SKILL.md只保留精炼的概览和导航,重料拆到单独文件里,用到了Claude才去读。官方建议SKILL.md正文控制在500行以内,超了就该往附属文件搬。目录大致长这样:

my-skill/
├── SKILL.md        必需,概览与导航
├── reference.md    详细参考,用到才加载
├── examples.md     示例集,用到才加载
└── scripts/
    └── helper.py   脚本,被执行而非读进上下文

关键动作是在SKILL.md里用一句话点明每个附属文件装了什么、什么时候该看,比如“完整API细节见reference.md”。Claude据此判断,需要时才按图索骥去加载,平时这些重料一个token都不占。把常驻的导航和按需的细节分开,就是渐进式披露的落地写法,也是Skill不发胖的关键一招。再配上正文只说做什么、不解释为什么,Skill就能同时做到轻和够用。

脚本类附属文件还有一个额外好处:它由Claude执行,不读进上下文,所以可以塞进任意复杂的逻辑(生成可视化、跑校验、批处理),脚本干重活,Claude只管编排。

动态上下文注入与context:fork怎么用?

再往上一层,是让Skill接入实时数据,甚至开出独立的工作空间。两个官方机制要单独讲。

第一个是动态上下文注入,就是开头见过的!`命令`语法。Skill正文被送给Claude之前,这些命令先被跑掉,输出替换掉占位符。于是Claude拿到的是已经填好的真实diff内容,而不是一句“去看看diff”。给Skill喂实时数据很顺手,比如总结PR时先把!`gh pr diff`的结果注进来。两点要记牢:这是预处理,Claude不执行命令,只看到最终填好的结果;!要出现在行首或紧跟空白才生效。

第二个分量更重:用context: fork让Skill在一个隔离的子代理里跑。加上这个字段,Skill的正文就变成驱动一个子代理的任务提示,子代理不带你当前的对话历史,自己开一片干净的上下文去干活,干完把结果汇报回来。配合agent字段还能指定用哪种子代理,比如用只读、专为代码探索优化的Explore代理去跑一个研究型Skill:

---
name: deep-research
description: 彻底研究某个主题。当需要在代码库里深入排查、跨多文件梳理时使用。
context: fork
agent: Explore
---

彻底研究 $ARGUMENTS:
1. 用Glob和Grep找到相关文件
2. 读懂并分析代码
3. 给出带具体文件引用的结论

这段里还出现了$ARGUMENTS,它是参数占位符:你敲/deep-research支付回调逻辑,这串就被替换进去。需要按位置取参时还能用$0、$1这种简写。

context: fork的价值是把重型、发散的任务隔离出去跑,不污染你主对话的上下文。它跟MCP、子代理是配套使用的一套机制,保哥在三大扩展机制怎么选里讲过三者各管一段,搭起来用威力才出得来。Agent Skills开放标准本身也是跨工具通用的,Claude Code在它基础上加了触发控制、子代理执行这些扩展,所以你学到的这套设计模式,迁移性也不差。

可复用的Skill设计原则有哪几条?

把前面的字段和机制收拢成四条能直接照着用的设计原则,省得你下次写Skill还得从头琢磨。第一条,description优先:它是触发的命门,永远先把它写具体、把核心用例顶到最前,宁可在它身上多花10分钟,也别让一个好Skill因为描述模糊而总不触发。第二条,正文越精炼越好:只写“做什么”的指令,不写“为什么”的解释,重料一律拆去附属文件,把SKILL.md当导航,不当仓库。

第三条,按副作用决定触发权:纯查询、纯生成的安全操作放手让Claude自动触发,带部署、提交、对外发送这类副作用的,一律加disable-model-invocation攥在自己手里。第四条,按作用域分层:个人习惯放个人级,团队约定放项目级提交共享,这套分层思路和CLAUDE.md的四级作用域是一以贯之的。

用一个真实场景把这套原则走一遍。保哥带的一个做宠物用品独立站的团队,每周要给十几个核心竞品做一轮上新与改价巡检,过去靠人工一个个翻、整理成表,慢且容易漏。后来把它做成了一个Skill:description写得很具体——“巡检竞品上新和价格变动并汇总成表,当用户要做竞品周报、对比竞品价格时使用”,关键词全带上,触发准确也不误伤;正文只留5步精炼指令,详细的竞品清单和字段口径拆进了同目录的reference.md,平时不占token。

这活要跑一堆抓取,属于重型发散任务,就给它加了context:fork扔到子代理里跑,不污染主对话的上下文;它又只查不改、没有副作用,于是放开让Claude在相关时自动触发。配置完成后,运营同事说一句“出本周竞品周报”,成品表就自己生成好了。零散的字段落到一个真实需求上,立刻拼成了一个顺手的工具,设计模式的意义也在这里:不用背字段,而是知道在什么场景该拧哪个旋钮。

写Skill最容易踩的坑有哪些?

下面是高频翻车点,照着自查能少走很多弯路。

第一坑,目录结构写错,Skill直接失效。SKILL.md必须放在一个目录里,比如.claude/skills/my-skill/SKILL.md,不能图省事写成.claude/skills/my-skill.md;文件名也得是大写的SKILL.md,大小写敏感。这个错最隐蔽,因为它不报错,只是单纯不触发,对着一个“怎么调都没反应”的Skill查半天,根子常在路径上。

第二坑,触发不准。该触发时哑火,多半是description没写好,没带上用户会自然说出口的关键词,Claude匹配不上;回去把description写具体、把核心用例顶到最前。反过来,乱触发、该安静时插嘴,是description写得太泛,把它收窄,或者干脆加disable-model-invocation: true改成只手动调。

第三坑,正文写太长。正文常驻上下文、每行都在烧token,长流程和大参考资料该拆去附属文件,SKILL.md只留精炼指令。最后一坑是过度工程化:并非每件小事都值得做成Skill,一句话能交代清楚的事硬包成Skill,纯属给自己添维护负担。判断标准很简单,你是不是反复在把同一套指令、清单或多步流程贴进对话?是,才值得固化成Skill;偶尔用一次的,随手说就好。这几坑避开,写出来的Skill就既好触发、又好维护。

常见问题解答

Skill的name字段必须是动名词形式吗?

不必,name也不是必填字段。按官方现行规范,name可选,不写就默认用Skill所在的目录名;触发Skill的命令名同样来自目录名,而不是frontmatter里的name。所以动词加ing这类词性讲究意义不大,把目录名起得清晰、贴合功能才更实在。那条动名词规则属于过时说法。

description是不是越短越好,最好20字以内?

恰恰相反。description是Claude判断何时触发的唯一依据,压得太短会把能帮助命中的关键词砍掉。官方规则是description和when_to_use合起来上限1536字符,预算相当宽裕。要诀在于写具体、带上用户会自然说出口的关键词、把最该命中的使用场景顶到最前面,因为空间紧张时是从尾部截断。

自定义命令和Skill是两个不同的东西吗?

已经合流了。官方把自定义命令并入了Skills,一个.claude/commands/deploy.md和一个.claude/skills/deploy/SKILL.md都会生成/deploy命令、行为一致。原来commands目录里的文件照样能用,不必迁移;Skill则多了附属文件、触发控制、自动加载这几项能力。新写的优先用Skill的目录形式。不少老教程还把两者当两回事讲,实际上早就是一套了。

怎么让一个内容很多的Skill不浪费token?

用附属文件做渐进式披露。SKILL.md只保留精炼的概览和导航,把详细API参考、示例集、脚本拆到同目录的单独文件里,并在SKILL.md里点明每个文件装了什么、何时该看,Claude用到才加载,平时不占token。官方建议SKILL.md正文控制在500行内。正文本身也只说做什么、不解释为什么,因为它被调用后会一直常驻上下文。

context: fork的作用是什么?

它让Skill在一个隔离的子代理上下文里跑:Skill正文变成驱动子代理的任务提示,子代理不带你的对话历史,自己开一片干净上下文去执行,干完汇报结果。配合agent字段还能指定用哪种子代理,比如用只读的Explore代理跑研究型任务。价值在于把重型、发散的任务隔离出去,不污染你主对话的上下文,适合研究、批量分析这类活。

什么样的任务才值得做成Skill?

判断标准是看你是不是反复在把同一套指令、清单或多步流程贴进对话。是,就值得固化成Skill,省得每次重打;偶尔用一次、一句话能交代清的事,随手说就好,硬包成Skill反而添维护负担。另一个信号来自CLAUDE.md:里面某段一旦从一条事实长成一套流程,就该抽出来做成Skill,让它按需加载而不是常驻。

分享到
标签
版权声明

本文标题:《Claude Code Skill编写指南:frontmatter字段、四级作用域与避坑要点》

本文链接:https://zhangwenbao.com/claude-code-skill-patterns.html

版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交