目标:讲清 Claude Code 的 Skills 系统——三种来源、渐进式加载(三级)、触发机制(自动/
//Skill 工具)、inline 与 fork 两种执行模式、写作规范、ProposeSkills 反向提议、安全与用量追踪。这是插件体系中最核心的扩展机制。 受众:专业程序员。本机版本2.1.220。
10.1 Skills 不是什么
在讲 Skills 是什么之前,先排除三个容易混淆的概念:
| 概念 | 是什么 | Skills 不是它 |
|---|---|---|
| Slash Command | 用户手动敲 /xxx 触发的指令 | Skill 可以被模型自动触发,不需要你敲 / |
| Subagent | 独立上下文、独立运行的后台 agent | Skill 可以inline 执行,不一定要 fork |
| CLAUDE.md | 启动时全量注入的静态指令 | Skill 是按需加载的——正文只在触发时才进上下文 |
心智模型:
Skill = 给 Claude 的"入职指南"。 它把一个通用 agent 变成某个领域的专家,装上它自身不具备的程序性知识。
从二进制看 Skill 如何被调用:
model-invoked skills are `"name":"Skill"` with the skill name in `input.skill`
Skill(大写 S)是和 Bash、Read、Write 并列的内置工具。模型在 Agent 循环中判断"这个任务需要某个 skill",就调 Skill 工具加载。
10.2 三种来源
Skills 按存放位置分三种作用域:
Personal: ~/.claude/skills/<name>/SKILL.md ← 跟你走,所有项目通用
Project: ./.claude/skills/<name>/SKILL.md ← 跟项目走,可提交 git
Plugin: plugin-name/skills/<name>/SKILL.md ← 跟插件走,安装即生效
二进制确认:
- **Personal** (`~/.claude/skills/<name>/SKILL.md`) — follows you across all repos
- **This repo** (`.claude/skills/<name>/SKILL.md`) — for workflows specific to this project
自动发现:runtime 扫描这些目录,找到含 SKILL.md 的子目录就注册。和 CLAUDE.md 一样——路径即契约,不需要配置文件声明。
/skills 命令列出所有可用 skill。已注册但从未被调用的 skill 会有提示:
loaded but never invoked. Each one adds to the system prompt every turn. Disable in /skills, or remove from .claude/skills.
10.3 解剖一个 Skill
skill-name/
├── SKILL.md ← 必需。YAML frontmatter + Markdown 正文
├── scripts/ ← 可执行代码(Python/Bash),可直接运行而不进上下文
├── references/ ← 参考文档,Claude 按需用 Read 读取
├── assets/ ← 产出物模板(HTML、图片、字体),不进上下文,被复制使用
└── examples/ ← 可运行的完整示例,供用户复制改编
SKILL.md 的 frontmatter
只有两个必填字段:
---
name: frontend-design
description: Guidance for distinctive, intentional visual design when building new UI...
---
没有 allowed-tools、没有 model——这些是 slash command 的前置 matter,Skill 不需要。
四个可选子目录的语义
| 目录 | 内容 | 何时用 | 是否进上下文 |
|---|---|---|---|
scripts/ | 可执行代码 | 同一段逻辑被反复重写,或需要确定性可靠执行 | 否(可直接执行) |
references/ | 参考文档 | SKILL.md 放不下的详细内容(schema、API 文档、策略) | 是(按需用 Read 读) |
assets/ | 模板、图片、字体 | 产出物需要的模板文件和静态资源 | 否(被复制使用) |
examples/ | 可运行示例 | 完整的、可复制改编的示例 | 是(按需读) |
10.4 渐进式加载——Skills 设计的核心
这是 Skills 最重要的设计原则。三级加载,按需升级:
Level 1: Metadata(name + description)
├─ 始终在 context 中(~100 词/个)
├─ 每个已注册 skill 一行,列在 system prompt 里
└─ 开销极低——注册 20 个也才 ~2,000 词
Level 2: SKILL.md 正文
├─ 触发时才加载(推荐 1,500~2,000 词,上限 < 5,000 词)
└─ 注入当前轮次的 context
Level 3: Bundled resources(references/、examples/)
├─ Claude 自己判断何时需要,用 Read 工具读
└─ scripts/ 甚至可以不进上下文,直接用 Bash 执行
二进制中一句话点睛:
(dash = not in the current listing, costs nothing; full SKILL.md loads only when it runs)
dash = 没加载,不花钱。 对比 CLAUDE.md:一个 500 行的 CLAUDE.md 每次对话都全量占着上下文。Skill 把元数据和正文分离,信息密度高但常驻开销低。
什么放在 SKILL.md vs references/
| 放 SKILL.md(正文) | 放 references/(按需加载) |
|---|---|
| 核心概念和概述 | 详细模式和实践 |
| 基本流程和工作流 | 完整 API 文档 |
| 快速参考表 | 迁移指南 |
| 指向 references/examples/scripts 的指针 | 边缘情况和故障排除 |
| 最常见的用例 | 大量示例和走查 |
原则:如果信息 > 10,000 词,在 SKILL.md 里写 grep 搜索模式,让 Claude 知道如何在 references/ 中找到具体内容。
10.5 触发机制
三种触发路径:
路径一:自动触发(description 匹配)
模型读 system prompt 中每个 skill 的 description,自己判断当前任务是否匹配。Description 的质量直接决定 skill 能否被正确触发。
# ✅ 正确:第三人称 + 引号触发短语
description: This skill should be used when the user asks to "create a hook",
"add a PreToolUse hook", "validate tool use", or mentions hook events.
# ❌ 错误
description: Use this skill when working with hooks. # 不是第三人称
description: Load when user needs hook help. # 没有触发短语
description: Provides hook guidance. # 太模糊
路径二:Slash 命令
/frontend-design
/ 加 skill name,和 slash command 完全一样的调用体验。
二进制描述:
Packaged instructions Claude invokes automatically when a task matches, or that you trigger with a slash command (e.g.
/frontend-design,/commit-push-pr).
路径三:Skill 工具显式调用
模型在 Agent 循环中主动调 Skill 工具:
{"type": "tool_use", "name": "Skill", "input": {"skill": "hook-development", "args": "[hooks-only] Constructing a PostToolUse hook..."}}
Skill 工具的 input schema(从二进制还原):
skill: string ← skill name,来自 available-skills 列表。不要猜名字。
args: string ← 可选参数,传递给 skill
10.6 两种执行模式:Inline vs Fork
Skill 工具内部有两条完全不同的执行路径(从二进制混淆代码还原):
Inline(内联执行)
- Skill 正文直接注入当前对话的 messages
- 后续指令在当前上下文执行
- 适合:需要用户中途介入、和用户交互的任务
- 工具返回
{status: "inline", success: true}
Fork(分支执行)
- 启动一个 subagent,给它独立的上下文
- Skill 正文注入子 agent 的 system prompt
- 主会话收到通知:
Running in the background as @agent-name - 适合:自包含、不需要中途介入的任务
- 工具返回
{status: "forked", agentId: "...", background: true}
二进制中的 fork 启动日志:
SkillTool executing forked skill {name} with agent {agentType}
防递归
如果一个 skill 已经在 fork 上下文里执行,模型不能再调 Skill 工具去 fork 同一个 skill:
Skill {name} is already executing in this forked context — you are the subagent
running it. Execute the instructions in the skill body directly instead of
re-invoking the Skill tool.
Re-invocation 去重
如果同一个 skill 已经被加载且指令未变,再次调用不会重复注入:
Skill /{name} is already loaded above; instructions unchanged.
SkillTool eliding byte-identical re-invocation of skill {name}
10.7 Fork 的来源追踪(Provenance)
Fork 出来的子 agent 携带来源标记,用于安全追踪:
.forked-skill.json ← skill 的 fork 作用域记录
.forked-skill.marker.json ← 来源标记见证
恢复会话时的安全校验(二进制中多条拒绝逻辑):
"carries a forked-skill provenance marker but its scoping record is missing; refusing to resume it without the skill's permission scoping.""declares forked-skill scoping record that does not match its task record; refusing to resume it.""has a forked-skill scoping record with no matching provenance-marker witness; refusing to resume it on a cold path without a corroborated fork identity.""has a malformed forked-skill scoping record; refusing to resume it without the skill's permission scoping."
这些保护确保 fork 链的完整性——你不会在不知情的情况下恢复一个来源不明的子 agent。
10.8 消息归属
Skill 产生的每条消息都标记来源。二进制中消息结构携带:
attributionSkill ← 哪条消息是哪个 skill 产生的
attributionAgent ← 哪个 agent
attributionPlugin ← 哪个插件
attributionMcpServer ← 哪个 MCP 服务器
attributionMcpTool ← 哪个 MCP 工具
这让用量统计和调试都能追溯到具体 skill。
10.9 写作规范
从 skill-development/SKILL.md 中提炼的六条核心规则:
1. Description:第三人称 + 触发短语
# ✅
description: This skill should be used when the user asks to "create a hook", ...
# ❌
description: Use this skill when you want to create a hook...
description: Load this skill when user asks...
description: Provides hook guidance.
2. 正文:祈使/不定式(不是第二人称)
# ✅
Parse the frontmatter using sed.
Validate values before use.
To create a hook, define the event type.
# ❌
You should parse the frontmatter...
You can use grep to search...
Claude should extract fields...
原因:SKILL.md 是给 Claude 的指令,不是给用户看的。第二人称增加理解开销。
3. 正文长度:严格控制
推荐:1,500~2,000 词
上限:< 5,000 词
超过 → 拆到 references/
插件开发 skill 自身的 SKILL.md 是 1,651 词,agent-development 是 1,438 词——典范。
4. 指向 references/ 的指针
正文中显式声明 references 的存在:
## Additional Resources
### Reference Files
- **`references/patterns.md`** — Detailed patterns
- **`references/advanced.md`** — Advanced techniques
### Examples
- **`examples/script.sh`** — Working example
不声明 = Claude 不知道 references/ 存在 = 永远不会被读。
5. 信息不重复
同一信息不应该同时出现在 SKILL.md 和 references/ 中。详细内容优先放 references/,正文只保留核心流程。这避免了"正文已经够用,references/ 永远不会被读"的问题。
6. 验证清单
skill-development/SKILL.md 的完整 checklist:
- 目录结构正确(SKILL.md 在
skills/<name>/下) - Frontmatter 含
name和description - Description 第三人称 + 引号触发短语
- 正文祈使语气,非第二人称
- 正文控制在 1,500~2,000 词
- 详细内容在 references/ 中
- 正文声明了 references/ 的路径
- 示例完整且可运行
- 脚本可执行且有文档
10.10 ProposeSkills:agent 反向提议创建 Skill
这是 Skills 体系最巧妙的设计——Claude 在工作中发现值得封装成 skill 的重复模式,主动向用户提议创建。
sdk-tools.d.ts 中的类型定义:
interface ProposeSkillsInput {
proposals: [{
name: string; // kebab-case skill slug
kind: "new" | "improvement";
target?: string; // 改进已有 skill 时指定
description: string; // 一行摘要,显示在提议卡片上
evidence?: string[]; // memory 文件路径,记录观察来源
skillMd: string; // 完整的 SKILL.md 草稿(frontmatter + 正文)
}];
// 一次最多 3 个提案
}
这和 memory 系统的 push 模式一脉相承(第 7 章):agent 不被动等指令,还主动观察工作模式,把值得封装的流程提请用户确认。
10.11 安全与用量
安全模式
(custom skills are disabled in safe mode)
--safe-mode 下所有自定义 skill 不可用。
Fork 来源链
10.7 节详述的 provenance marker 机制——子 agent 的完整 fork 链必须可验证,否则拒绝恢复。
用量追踪
skillUsage: {
name → { usageCount, lastUsedAt }
}
usageCount = LIFETIME total since install(永不清零)
lastUsedAt = 只在实际 dispatch 时写入
7d tokens = skill 在过去 7 天的 token 消耗
遥测事件:tengu_skill_tool_invocation,携带 command_name、execution_context(inline/fork)、invocation_trigger、query_depth 等字段。
/plugin stats 显示 skill 使用数据和上下文成本。
10.12 Skills vs Commands vs Agents 对比
| 维度 | Skill | Slash Command | Subagent |
|---|---|---|---|
| 触发方式 | 自动 / / / Skill 工具 | 用户手动 / | Task 工具 |
| 加载方式 | 渐进式(三级) | 调用时一次性注入 | 独立上下文 |
| 文件结构 | 目录 + SKILL.md | 单个 .md 文件 | 单个 .md 文件 |
| 可附带资源 | scripts/references/assets/examples | 无 | 无 |
| 谁写 | 人 / agent(ProposeSkills) | 人 | 人 |
| 核心 frontmatter | name + description | description + allowed-tools + model + argument-hint | description + capabilities |
| 执行模式 | inline 或 fork | inline | 独立进程 |
| 是否可自动触发 | 是 | 否 | 部分(agent 匹配 task) |
什么时候用哪个
用户需要手动触发、传参数 → Slash Command
需要模型自动识别场景并介入 → Skill
需要独立上下文、后台执行 → Subagent
需要在 Skill 运行前让用户确认参数 → Slash Command 包裹 Skill
10.13 本章核心带走
-
Skill 是渐进式加载的领域工作流。 不是 command(无法自动触发),不是 subagent(独立上下文),不是 CLAUDE.md(全量注入)。metadata 常驻、正文按需、资源可选。
-
三级渐进加载:Level 1 metadata 常驻(~100 词),Level 2 SKILL.md 触发时加载(<5k 词),Level 3 resources 按需读取。信息密度高但上下文开销低。dash = 不花钱。
-
三种来源 + 自动发现:Personal (
~/.claude/skills/)、Project (.claude/skills/)、Plugin (skills/)。路径即契约——放对位置就自动注册。 -
两种执行模式:inline(注入当前会话,适合需用户交互的任务)和 fork(独立 subagent + provenance 追踪,适合自包含任务)。
-
Description 是 Skill 的接口。 第三人称 + 引号触发短语 = 决定模型何时识别并加载。写得不好 Skill 永远不会被触发。
-
正文写作规范严格:祈使语气(非第二人称)、1,500~2,000 词、超量内容拆到 references/、显式声明 references 路径。
-
ProposeSkills 让 agent 反向提议创建 skill——和 memory 系统一样,agent 在工作中主动观察、主动建议。
-
Fork 安全链完整:provenance marker → scoping record → 恢复时验证完整性,缺一环就拒绝。