Claude Code 技能:结构、触发与最小可用示例

Claude Code 技能是什么?
目录里放一份 SKILL.md,就是一个 Claude Code 技能(Claude Code Skills)。SKILL.md 开头是 YAML frontmatter,name 和 description 两个字段不能少;Claude 该不该在这个时机调用它,判断依据就是 description 的内容。它要解决的问题很具体:每开一个新会话,同一套提交规范得再粘一遍,同事之间各粘各的,仓库里最后长出三种 commit 风格。推出时间是 2025 年 10 月,2025 年 12 月 18 日 Agent Skills 被发布为开放标准,规格站是 agentskills.io。起步只有两件事:建目录,把 name 和 description 写好。

最小形态不需要打包,也不必注册命令:一个目录,一份 SKILL.md,正文把步骤写明白。您敲出来的命令名一般跟目录名一致,所以名字先和用途对齐,叫 commit-check 的,该出现的时机就是您准备提交代码的时候。
跨工具迁移这件事现在不用先做规划。Agent Skills 的规格出自 agentskills.io,哪些工具已经支持、支持到哪一步,规格站的清单里有。您在 Claude Code 里搭的目录结构本来就照这份规格写,把手上这一个技能先跑通,比先操心生态更实际。
技能、提示词、插件和 MCP 工具,各自解决什么问题?
提示词是您这一次打出去的那段话;技能是把做法写进文件、按需加载;插件是打包用的容器;MCP 工具负责把外部系统接进来。
两者最实际的差别在寿命。对话一结束,提示词就没了;技能躺在目录里,换个会话照样在。往上还有两层容器。技能装进插件之后,命令名会多一个插件名前缀,例如 /my-plugin:review。MCP 服务器属于另一类接入面,文档把它和 hook 并列,两者都会收到 CLAUDE_PROJECT_DIR 这个项目根目录路径。

| 东西 | 解决什么 | 怎么出现 |
|---|---|---|
| 提示词 | 这一次任务的具体要求 | 您直接打在对话框里,只在当前这一轮生效 |
| 技能 | 可以反复使用的步骤和知识 | 放在技能目录,用 /技能名 调用,或由 Claude 按 description 自己取用 |
| 插件 | 一次装进一批能力 | 技能文件夹里加上 .claude-plugin/plugin.json 就作为插件加载,能捆 agent、hook 与 MCP 服务器 |
| MCP 工具 | 把外部系统接进来 | MCP 服务器和 hook 一样接收 CLAUDE_PROJECT_DIR 路径 |
旧格式还有一层容易混。.claude/commands/ 里的 Markdown 文件照样有效,frontmatter 支持的和技能一样,差在没有 name 和 paths 两个字段。新的工作直接做成技能更合适,原因是技能能带支持文件,命令文件带不了。
最小可用技能长什么样?
目录加一份 SKILL.md 就是最小形态。frontmatter 里 name 和 description 至少要有;正文写清分几步走、每一步看什么、遇到什么情况要停下来问您。只让 Claude 按固定格式写提交信息的话,一个文件足够;内容长起来再加支持文件,要执行命令才建 scripts/。

最小目录
my-skill/
├── SKILL.md
├── reference.md
├── examples.md
└── scripts/
└── helper.py
name 有硬性限制。按 Agent Skills 规格,字符只允许小写字母、数字和连字符,长度 1 到 64 个字符,连字符不能出现在开头或结尾,也不能连着出现两个,而且必须和目录名一致。

---
name: commit-check
description: "按 type(scope): subject 的格式校验提交信息,并给出修改建议。当用户准备提交代码、写 commit message 或者询问提交规范时使用。"
---
frontmatter 负责交代触发条件和能力范围这两件事。它们常驻在上下文里,正文要等技能被选中才整份加载,所以 description 写得清楚,对体验的影响比正文写得漂亮更大。值里面出现英文冒号加空格、或者以引号开头时,整段用双引号包起来,YAML 才读得对。

什么时候该拆支持文件
判断标准是它要不要进上下文。官方示例把 SKILL.md 标成 required,其他文件按需加载,第一版只有一个文件完全够。
| 文件 | 作用 | 加载方式 |
|---|---|---|
| SKILL.md | 必需的概览与导航,写清步骤 | 技能被选中时整份加载 |
| reference.md | 详细的接口或规则 | 需要时加载 |
| examples.md | 输入与输出的样例 | 需要时加载 |
| scripts/helper.py | 实际执行的小工具 | 被执行,不进上下文 |
主文件也有个大致的行数上限,常见建议是把 SKILL.md 压在 500 行以内。清单、样式指南这类细节挪进支持文件,正文留一句指向它的说明就行,技能再好用也不会一次把上下文塞满。
把文件丢进 scripts/ 还不算完,SKILL.md 里要写明它存在、怎么用,Claude 才知道有这个工具。引用脚本时路径用 ${CLAUDE_SKILL_DIR} 拼,别靠当前工作目录,不然换个人或换个目录跑,脚本就找不着了。
怎么让技能被触发、被调用?
能不能被触发,取决于 description 有没有把场景写清。调用方式有两种:/技能名 出现在消息开头,Claude Code 直接把它跑起来;出现在普通文本中间、单独成词的时候,它算您给这次回复的授权,跑不跑由 Claude 判断。传参可以走 $ARGUMENTS、$0、$1,也可以用 arguments 列表里声明过的 $name;谁有权调用,由 frontmatter 上两个开关决定。
description 决定技能会不会被触发
技能做好了却总也不生效,多数时候问题就在 description。范围只写到「帮忙处理文档」,Claude 判断不出眼前的对话和它有没有关系;把能做的事、该启用的场景写具体,命中的情况会明显不同。
测试不必另外搭环境,编两句提示各跑一次就够了:一句明显该用这个技能,一句明显不该用。不少人技能装好了却从没验证过触发范围,这两句正好补上。该用的时候没启用,或者不相关的请求它也冒出来,就回去改触发条件的描述,一般比改正文见效。
调用语法与参数替换
参数是在调用那一刻替换进去的,玩法分三类:全部收下、按下标取、按名字取。下面这些变量都能直接写在 SKILL.md 里。
| 写法 | 替换成什么 |
|---|---|
| $ARGUMENTS | 调用时传入的全部参数;没有占位符接收时,以 ARGUMENTS: <value> 的形式追加 |
| $ARGUMENTS[N]、$N | 按从 0 开始的下标取某个参数,$0 是第一个,$1 是第二个 |
| $name | arguments frontmatter 列表里声明的命名参数,按顺序映射到位置 |
| ${CLAUDE_SESSION_ID} | 当前会话 ID,用来把技能输出和这次会话关联起来 |
| ${CLAUDE_EFFORT} | 当前 effort 级别,取值 low、medium、high、xhigh 或 max |
| ${CLAUDE_SKILL_DIR} | 包含该 SKILL.md 的目录 |
| ${CLAUDE_PROJECT_DIR} | 项目根目录,和 hook、MCP 服务器收到的是同一个路径 |
| ${CLAUDE_PLUGIN_ROOT}、${CLAUDE_PLUGIN_DATA} | 插件的安装目录与持久数据目录,只在插件技能里替换 |
一个短例子:敲 /preview-changelog 2.1.0,正文写 $ARGUMENTS 就拿到 2.1.0;正文写「把 $0 从 $1 迁到 $2」,第一个参数落进 $0。没人接这些参数时,Claude Code 会以 ARGUMENTS: <value> 的形式把它们附在技能内容后面。
谁可以调用
提交、部署、发消息这类带副作用的流程,您不会想让 Claude 看见代码像是准备好了就自己动手。frontmatter 上那两个开关管的就是这件事。
| Frontmatter | 您可以调用 | Claude 可以调用 | 何时加载到上下文 |
|---|---|---|---|
| 默认,什么都不写 | 是 | 是 | description 常驻上下文,调用时加载完整技能 |
| disable-model-invocation: true | 是 | 不能自行调用 | description 不进上下文,调用时加载完整技能 |
| user-invocable: false | 否 | 是 | description 常驻上下文,调用时加载完整技能 |
长流程交给子代理
技能本身就是一段完整流程的时候,比如要跨多个文件调查再汇总,加 context: fork 就能让它在一个隔离子代理里跑。技能内容变成子代理的提示,用什么模型、工具和权限由 agent 字段决定;结果送回来给主对话,中间过程不占主对话的上下文。
---
name: repo-survey
description: 跨多个文件调查一个模块的实现并汇总发现。当需要理解陌生代码时使用。
context: fork
agent: Explore
---装好技能只是第一步,开发会话还是靠自然语言一步步推;怎么用自然语言和 Claude 一起把代码写出来里有完整做法。
技能里的脚本要调模型,接口怎么接?
脚本的 base URL 指向 MixRoute 之后,同一把 key 能覆盖 250+ 个模型。OpenAI SDK 只改 base URL,换成 https://api.mixroute.ai/v1,模型名原样不动。Anthropic SDK 写成 Anthropic(api_key=<MixRoute key>, base_url="https://api.mixroute.ai"),client 和 client.messages.create 照旧用。两条路改的都只是 key 和 base URL。
这条兼容 Anthropic 的 Messages API 端点在 POST https://api.mixroute.ai/v1/messages。请求和响应用原生 Anthropic 格式,请求头是 Authorization: Bearer <MixRoute key> 和 anthropic-version: 2023-06-01;model、messages、max_tokens 三个字段不能省。
# OpenAI SDK
client = OpenAI(api_key="<MixRoute key>", base_url="https://api.mixroute.ai/v1")
# Anthropic SDK
client = Anthropic(api_key="<MixRoute key>", base_url="https://api.mixroute.ai")
团队脚本要调模型的话,接口层只改脚本开头那几行初始化,SKILL.md 的步骤一字不动。费用先看一眼:MixRoute 定价页写的是 0% platform fee、no markup,按用量结算,没有平台加价这一层,脚本这批调用按用量算下来要花多少。key 从环境变量读取,SKILL.md 里写明脚本读的是哪个变量。权限上可以用 allowed-tools 预批准具体命令,比如只放行跑这个脚本的那一条。这个预批准走正常权限流;组织如果设了 allowManagedPermissionRulesOnly 就不适用,那种环境按管理员下发的规则走。
做完怎么验证技能真的生效?
装好技能和它能用是两回事。要验证五块:目录与文件名、触发、参数、脚本与环境、权限和可见性。
上线前的核对清单
- 结构:技能目录里放着 SKILL.md,frontmatter 的 name 与目录名一致,敲 / 能看见它。
- 触发:编两句提示,一句该启用、一句不该启用,各跑一遍;结果不对就回去改 description。
- 参数:故意多塞一个参数进去,检查 $0、$1 和 $ARGUMENTS 展开得对不对。
- 脚本:手动跑一遍 scripts/ 里的命令,确认依赖都装好,路径用
${CLAUDE_SKILL_DIR}拼。 - 权限与可见性:allowed-tools 放行的命令范围刚好够用就好,不要多开;需要在 skillOverrides 里设 on、name-only、user-invocable-only 或 off,决定它在 Claude 和 / 菜单里的出现方式。
命令跑不动,先查两件事。默认 bash shell 下,每个注入命令受 Bash 工具默认的 2 分钟超时限制;被超时杀掉的命令会中止这次调用,不在自动后台名单里的不会自己转到后台。转到后台的那种,技能照常呈现,注入的文本会说明它已被移到后台,并给出后台任务名和收输出的文件。另一件是 shell 和系统不匹配:写了 shell: bash 而机器上没有 Git Bash,调用在任何命令执行之前就失败,提示会点名是哪个技能缺 Git Bash。
装别人做的技能,执行这一层得自己把关。scripts/ 里的文件是真会被执行的,下载后一个一个看:有没有往外部地址发请求,有没有动系统文件,有没有读敏感数据。SKILL.md 也要扫一眼,恶意技能会在指令里塞一句,让 Claude 把 .env 的内容发到某个网址去。用得上就留,用不上别放进技能目录。
装在哪里,怎么和同事共享?
~/.claude/skills/ 属于个人层,任何一个项目里都能用;项目的 .claude/skills/ 跟着仓库走,同事拉下来就有。两边撞名的时候,个人层盖过项目层。同一个技能您自己跨好几个项目都要用,就放个人目录;team 里每个人都该有的,跟着仓库走。
| 放法 | 谁能用 | 怎么共享给同事 |
|---|---|---|
| ~/.claude/skills/ | 您自己,跨所有项目 | 不跟着仓库走,需要各自安装 |
| 项目的 .claude/skills/ | 这个项目,包括拿到仓库的同事 | 提交进版本控制 |
| 插件的 skills/ 目录 | 安装了该插件的人 | 随插件一起分发 |
| 托管设置 | 整个组织 | 由管理员统一部署 |
共享出去之后,暴露面还得收住。Claude 能调用哪些技能,由 Skill(...) 的 allow 与 deny 规则决定;deny 里写 Skill(deploy *),名叫 deploy 的技能带任意参数都进不来。规则按名字匹配时,别名也一起挡:挡住 Skill(review),通过 /review 别名调用的捆绑技能同样进不来。团队里技能越攒越多,规则先定好再发出去,比事后一个个回收省事;升级之后也要回头核对 allow、deny 和别名,别让旧权限跟着文件一起放宽。
把技能当可维护的项目文件来管,比当成一段神奇提示稳得多。每个技能划一条清楚的责任边界,比如只整理变更记录,或者只检查提交信息;触发条件、输入格式、完成标准都写进 SKILL.md,请求超出范围就停下来交回主会话。脚本要的环境变量、能接受的文件类型、失败时留下的退出码,也写进正文;完整日志不必塞进主上下文,返回摘要和日志文件路径就够,要不要继续交给主会话决定。
提交代码、改文件、部署、发消息之前,先把要执行的命令和目标显示出来,让操作者确认范围;只读检查可以放进允许工具,少几次重复确认。
技能目录跟一组最小测试提示一起进版本控制。测试至少要有四类例子:一个该触发的、一个不该触发的、一个带参数的、一个会碰到权限边界的。改过 description、参数占位符或脚本路径之后,把这四类重跑一遍,才分得清是能力变强了,还是误触发多了。同事要接手,就把安装位置、需要的环境变量和撤销方法写进 README;新成员先在临时项目里验证,再把项目级技能提交到仓库。
FAQ
技能和提示词有什么不一样?
差别在寿命。提示词就是您这一轮打在对话框里的那段话,会话一结束就散了;技能是写在文件里的指令包,换个项目、换个人都还在。代价是改技能要动文件,提示词随手就能改。同一段流程已经贴到第三次,就值得做成技能;只用一次的临时要求,直接打字更快。
只放一个 SKILL.md,不写脚本,能用吗?
能。目录加一个 SKILL.md 就是最小形态,scripts/ 只在技能需要执行命令时才有意义。纯知识型的技能,比如解释旧系统怎么运作,设成 user-invocable: false 更合适,让 Claude 在相关的时候自己读,不用等您敲一条本身没有操作意义的命令。正文长到不好维护了,再拆出 reference.md 和 examples.md。
为什么我装好的技能 Claude 一直不用?
先查 description,多数问题都出在这。范围只写「帮忙处理文档」,Claude 判断不出这次任务用不用得上它;把能做的事和该启用的场景写具体,命中情况就不一样。另一种可能也要排除:技能带了 disable-model-invocation: true,描述不进上下文,Claude 不会自己想起来。描述改完,拿一句明显该用的提示试一次,差别通常当场就看得出。
Windows 上技能里的命令为什么直接报错?
原因在 shell 设置跟机器对不上:写着 shell: bash,机器上却没有 Git Bash,调用会在任何命令运行之前就失败,提示里会点名是哪个技能缺 Git Bash。照提示装上 Git Bash,或者把 frontmatter 改成这台机器上有的 shell,都能解开。另外注入命令默认 2 分钟超时,被超时杀掉一样会中止这次调用,长任务要在 SKILL.md 里说明它可能被移到后台。
技能里能跑一整段独立流程吗?
可以。加一行 context: fork,技能就在隔离子代理里跑,模型、工具和权限由 agent 字段决定。子代理加载的是 SKILL.md 的内容加上它自己的启动上下文,跑完把结果带回主对话,中间过程不占主对话。适合要翻好几个文件才汇总得出来的长流程;需要边做边问您的步骤,留在主会话更顺。
从网上下载的技能可以直接用吗?
先看过内容再装。scripts/ 里的文件会被真的执行,等于让对方在您的机器上跑脚本。三处要重点扫:脚本有没有往外部地址发请求,有没有改系统文件或者读敏感数据,SKILL.md 里有没有引导 Claude 把 .env 这类内容发出去。用得到的才留,用不上的没必要放在技能目录里。
技能放个人目录还是项目目录?
要看技能给谁用。只在您手上、跨好几个项目都会碰到的,放 ~/.claude/skills/;team 里每人都该有的,放进项目的 .claude/skills/ 并提交到版本控制,同事拉下来就有。两边同名时个人层盖过项目层,排查「为什么同事那边跑的不一样」先看这里。要一次发给很多人,放进插件的 skills/ 目录或托管设置更省事。
可以让 Claude 不自己调用某个技能吗?
可以。frontmatter 写 disable-model-invocation: true,技能就只在您主动敲命令的时候跑。提交、部署、发消息这类有副作用的流程适合这样管住,免得 Claude 看到代码像是准备好了就自己动手。反过来,只想让 Claude 在相关时自己取用、不希望它变成一条命令的背景知识,写 user-invocable: false。