第7章:技能系统
本章深入分析 Claude Code 的技能系统实现,包括 Skill 目录结构、加载机制、内置 Skills 详解和自定义 Skill 开发指南。
7.1 skills/ 目录结构
目录概览
src/skills/
├── bundled/ # 内置 Skills 目录
│ ├── index.ts # 入口索引
│ ├── batch.ts # 批量处理 Skill
│ ├── claudeApi.ts # Claude API Skill
│ ├── claudeApiContent.ts # API 内容处理
│ ├── debug.ts # 调试 Skill
│ ├── keybindings.ts # 键绑定 Skill
│ ├── loop.ts # 循环执行 Skill
│ ├── loremIpsum.ts # 测试文本 Skill
│ ├── remember.ts # 记忆 Skill
│ ├── simplify.ts # 代码简化 Skill
│ ├── skillify.ts # Skill 创建 Skill
│ ├── stuck.ts # 卡住处理 Skill
│ ├── updateConfig.ts # 配置更新 Skill
│ ├── verify/ # 验证 Skills 子目录
│ │ ├── index.ts
│ │ └── ...
│ └── scheduleRemoteAgents.ts # 远程 Agent 调度
│
├── bundledSkills.ts # 内置 Skill 注册机制
├── loadSkillsDir.ts # Skill 目录加载逻辑
└── mcpSkillBuilders.ts # MCP Skill 构建器
Skill 文件组织结构
graph TD
subgraph "Skill 来源"
BUNDLED[bundled/ 目录<br/>内置 Skills]
USER[userSettings<br/>~/.claude/skills/]
PROJECT[projectSettings<br/>.claude/skills/]
PLUGIN[Plugin Skills<br/>外部插件]
MCP[MCP Skills<br/>MCP Server 提供]
end
subgraph "加载器"
LOADER[loadSkillsDir.ts]
REGISTER[bundledSkills.ts]
PLUGIN_LOADER[loadPluginCommands.ts]
MCP_BUILDER[mcpSkillBuilders.ts]
end
subgraph "注册"
REGISTRY[Command Registry]
SKILL_TOOL[SkillTool]
end
BUNDLED --> REGISTER --> REGISTRY
USER --> LOADER --> REGISTRY
PROJECT --> LOADER --> REGISTRY
PLUGIN --> PLUGIN_LOADER --> REGISTRY
MCP --> MCP_BUILDER --> REGISTRY
REGISTRY --> SKILL_TOOL
7.2 Skill 加载机制
Skill 文件格式(.md 文件)
Skill 文件采用 Markdown 格式,支持 YAML frontmatter 定义元数据:
---
name: my-skill
description: My custom skill for specific tasks
aliases: [my-skill-alias]
whenToUse: Use this skill when you need to perform X
argumentHint: [target_file]
allowedTools: [Read, Edit, Bash]
model: claude-sonnet-4-20250514
disableModelInvocation: false
userInvocable: true
---
# My Skill
This skill helps you perform specific tasks.
## Instructions
1. First, read the target file
2. Analyze the content
3. Make necessary modifications
## Example
When you run `/my-skill src/main.ts`:
- The skill will read the file
- Analyze its structure
- Suggest improvements
Frontmatter 字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
name | string | Skill 名称(唯一标识) |
description | string | 功能描述 |
aliases | string[] | 别名列表 |
whenToUse | string | 使用场景说明 |
argumentHint | string | 参数提示 |
allowedTools | string[] | 可用工具列表 |
model | string | 指定使用的模型 |
disableModelInvocation | boolean | 是否禁用模型调用 |
userInvocable | boolean | 是否用户可调用 |
hooks | HooksSettings | Hook 配置 |
BundledSkill 注册机制
// bundledSkills.ts 核心实现
export type BundledSkillDefinition = {
name: string
description: string
aliases?: string[]
whenToUse?: string
argumentHint?: string
allowedTools?: string[]
model?: string
disableModelInvocation?: boolean
userInvocable?: boolean
isEnabled?: () => boolean
hooks?: HooksSettings
context?: 'inline' | 'fork'
agent?: string
files?: Record<string, string> // 附加文件
getPromptForCommand: (args: string, context: ToolUseContext) => Promise<ContentBlockParam[]>
}
const bundledSkills: Command[] = []
export function registerBundledSkill(definition: BundledSkillDefinition): void {
const { files } = definition
// 如果有附加文件,延迟提取到磁盘
let skillRoot: string | undefined
let getPromptForCommand = definition.getPromptForCommand
if (files && Object.keys(files).length > 0) {
skillRoot = getBundledSkillExtractDir(definition.name)
// 闭包本地缓存:每个进程只提取一次
let extractionPromise: Promise<string | null> | undefined
const inner = definition.getPromptForCommand
getPromptForCommand = async (args, ctx) => {
extractionPromise ??= extractBundledSkillFiles(definition.name, files)
const extractedDir = await extractionPromise
const blocks = await inner(args, ctx)
if (extractedDir === null) return blocks
return prependBaseDir(blocks, extractedDir)
}
}
const command: Command = {
type: 'prompt',
name: definition.name,
description: definition.description,
aliases: definition.aliases,
hasUserSpecifiedDescription: true,
allowedTools: definition.allowedTools ?? [],
// ... 其他属性
source: 'bundled',
loadedFrom: 'bundled',
getPromptForCommand,
}
bundledSkills.push(command)
}
export function getBundledSkills(): Command[] {
return [...bundledSkills]
}
loadSkillsDir.ts 加载逻辑
// 从目录加载 Skills
export async function getSkillDirCommands(cwd: string): Promise<Command[]> {
const skillsDirs = [
// 用户配置目录
join(getClaudeConfigHomeDir(), 'skills'),
// 项目配置目录
join(cwd, '.claude', 'skills'),
// 其他配置目录
...getAdditionalDirectoriesForClaudeMd().map(d => join(d, 'skills')),
]
const commands: Command[] = []
for (const dir of skillsDirs) {
if (!fs.existsSync(dir)) continue
const files = await loadMarkdownFilesForSubdir(dir)
for (const file of files) {
const command = await parseSkillFile(file, dir)
if (command) commands.push(command)
}
}
return commands
}
// 解析 Skill 文件
async function parseSkillFile(file: MarkdownFile, baseDir: string): Promise<Command | null> {
const { frontmatter, content } = parseFrontmatter(file.content)
// 验证必要字段
if (!frontmatter.name) return null
return {
type: 'prompt',
name: frontmatter.name,
description: coerceDescriptionToString(frontmatter.description)
?? extractDescriptionFromMarkdown(content),
aliases: frontmatter.aliases,
whenToUse: frontmatter.whenToUse,
allowedTools: frontmatter.allowedTools ?? [],
model: frontmatter.model,
contentLength: content.length,
source: getSettingSource(baseDir),
loadedFrom: 'skills',
userInvocable: frontmatter.userInvocable ?? true,
getPromptForCommand: async (args, context) => {
// 参数替换
const processedContent = substituteArguments(content, args)
return [{ type: 'text', text: processedContent }]
},
}
}
Skill 加载流程图
sequenceDiagram
participant Init as 启动初始化
participant Bundled as bundledSkills.ts
participant Loader as loadSkillsDir.ts
participant Parser as Frontmatter Parser
participant Registry as Command Registry
Init->>Bundled: registerBundledSkill()
Bundled->>Registry: 注册内置 Skills
Init->>Loader: getSkillDirCommands(cwd)
Loader->>Loader: 遍历 skills 目录
Loader->>Parser: 解析 .md 文件
Parser->>Parser: parseFrontmatter()
Parser->>Parser: 验证字段
Parser-->>Loader: Command 对象
Loader-->>Registry: 注册 Skills
Registry->>Registry: getCommands()
Registry-->>Init: 合并所有 Skills
7.3 内置 Skills 详解
核心 Skills 分类
graph TD
subgraph "开发辅助"
INIT[init<br/>初始化项目]
REVIEW[review<br/>代码审查]
SECURITY[security-review<br/>安全审查]
DEBUG[debug<br/>调试辅助]
SIMPLIFY[simplify<br/>代码简化]
end
subgraph "配置管理"
CONFIG[updateConfig<br/>配置更新]
KEYBIND[keybindings-help<br/>键绑定]
PERMISSION[fewer-permission-prompts<br/>权限优化]
end
subgraph "API 相关"
API[claude-api<br/>API 开发]
API_CONTENT[claudeApiContent<br/>API 内容]
end
subgraph "流程控制"
LOOP[loop<br/>循环执行]
BATCH[batch<br/>批量处理]
STUCK[stuck<br/>卡住处理]
end
subgraph "记忆系统"
REMEMBER[remember<br/>记忆存储]
VERIFY[verify<br/>验证检查]
end
init Skill
// init Skill 定义
registerBundledSkill({
name: 'init',
description: 'Initialize a new CLAUDE.md file with codebase documentation',
aliases: ['initialize'],
whenToUse: 'Use when starting work on a new project to create documentation',
argumentHint: '[project_path]',
getPromptForCommand: async (args, context) => {
return [
{ type: 'text', text: `
# Project Initialization
Analyze the codebase at ${args || 'current directory'} and create:
1. CLAUDE.md file with:
- Project overview
- Key files and their purposes
- Build/test commands
- Architecture summary
2. Recommended configurations:
- .claude/settings.json if needed
- MCP server recommendations
Use Glob to discover files, Read to analyze key files, and Write to create CLAUDE.md.
` }
]
},
})
review Skill
registerBundledSkill({
name: 'review',
description: 'Review a pull request',
aliases: ['pr-review'],
whenToUse: 'Use when you need to review code changes in a PR',
argumentHint: '[pr_url_or_number]',
allowedTools: ['Bash', 'Read', 'Grep', 'Glob'],
getPromptForCommand: async (args, context) => {
// 解析 PR 信息
const prInfo = await parsePRArg(args)
return [
{ type: 'text', text: `
# Pull Request Review
Review PR ${prInfo.number}: ${prInfo.title}
## Tasks
1. Fetch the PR diff using \`gh pr diff ${prInfo.number}\`
2. Analyze the changes for:
- Code quality issues
- Potential bugs
- Security concerns
- Performance implications
3. Check if tests cover the changes
4. Provide actionable feedback
## Output Format
- Summary of changes
- Critical issues (if any)
- Suggestions for improvement
- Overall assessment
` }
]
},
})
security-review Skill
registerBundledSkill({
name: 'security-review',
description: 'Complete a security review of pending changes',
whenToUse: 'Use before merging sensitive changes or deploying to production',
getPromptForCommand: async (args, context) => {
return [
{ type: 'text', text: `
# Security Review
Perform a comprehensive security review of the current branch changes.
## Checklist
1. **Authentication & Authorization**
- Check for proper auth checks
- Verify permission boundaries
2. **Data Protection**
- Sensitive data handling
- Encryption requirements
- Data validation
3. **Injection Prevention**
- SQL injection
- XSS vulnerabilities
- Command injection
4. **API Security**
- Input validation
- Rate limiting
- Error handling
5. **Dependency Security**
- Known vulnerabilities
- License compliance
Provide a detailed report with severity ratings and remediation steps.
` }
]
},
})
claude-api Skill
registerBundledSkill({
name: 'claude-api',
description: 'Build, debug, and optimize Claude API / Anthropic SDK apps',
whenToUse: 'TRIGGER when code imports anthropic/@anthropic-ai/sdk',
allowedTools: ['Read', 'Edit', 'Write', 'Bash', 'Grep', 'Glob'],
getPromptForCommand: async (args, context) => {
return [
{ type: 'text', text: `
# Claude API Development
Assist with Claude API / Anthropic SDK development.
## Focus Areas
- Prompt caching optimization
- Model version migration (4.5 → 4.6 → 4.7)
- Tool use implementation
- Streaming response handling
- Batch processing
- Error handling and retries
## Best Practices
1. Always include prompt caching where applicable
2. Use proper error handling for API errors
3. Implement retry logic for transient failures
4. Track token usage for cost optimization
## Code Patterns
- Show proper SDK initialization
- Demonstrate tool definition patterns
- Provide streaming examples
` }
]
},
})
部分 Skill(如 claude-api)使用 whenToUse 字段定义触发条件。当代码匹配导入语句(如 import anthropic)时,Skill 会自动被建议使用。
7.4 自定义 Skill 开发
创建文件型 Skill
- 创建
.md文件:
---
name: my-custom-skill
description: My custom skill description
aliases: [my-skill]
whenToUse: Use this when...
argumentHint: [arg1] [arg2]
allowedTools: [Read, Edit, Bash]
---
# My Custom Skill
Detailed instructions for the skill.
## Arguments
- `arg1`: First argument description
- `arg2`: Second argument description
## Steps
1. First step instruction
2. Second step instruction
3. ...
## Output
Expected output format.
- 放置到正确目录:
# 用户级 Skill
~/.claude/skills/my-custom-skill.md
# 项目级 Skill
.claude/skills/my-custom-skill.md
创建 Bundled Skill
// 在 bundled/index.ts 中注册
import { registerBundledSkill } from '../bundledSkills.js'
registerBundledSkill({
name: 'my-bundled-skill',
description: 'A bundled skill that ships with the CLI',
whenToUse: 'Use when condition X is met',
argumentHint: '[target]',
allowedTools: ['Read', 'Write', 'Bash'],
// 附加参考文件(可选)
files: {
'templates/default.md': '# Template content...',
'schemas/config.json': '{"type": "object", ...}',
},
getPromptForCommand: async (args, context) => {
const target = args || 'default'
return [
{ type: 'text', text: `
# My Bundled Skill
Target: ${target}
## Instructions
Detailed instructions here...
## Available Resources
- templates/default.md (if needed)
- schemas/config.json (for validation)
` }
]
},
})
Skill 开发最佳实践
flowchart TB
subgraph "Skill 设计原则"
P1[明确单一职责]
P2[提供清晰指令]
P3[限制工具范围]
P4[使用 whenToUse]
P5[处理参数错误]
end
subgraph "Skill 内容结构"
S1[标题和概述]
S2[参数说明]
S3[执行步骤]
S4[输出格式]
S5[错误处理]
end
subgraph "测试验证"
T1[测试边界情况]
T2[验证工具权限]
T3[检查输出格式]
end
P1 --> S1
P2 --> S3
P3 --> T2
P4 --> S1
P5 --> S5
S1 --> T1
S3 --> T3
S4 --> T3
Skill 调用流程
sequenceDiagram
participant User as 用户
participant REPL as REPL
participant Parser as 命令解析
participant SkillTool as SkillTool
participant Skill as Skill Instance
participant Model as Claude Model
User->>REPL: /my-skill arg1 arg2
REPL->>Parser: 解析斜杠命令
Parser->>Parser: findCommand('my-skill')
Parser-->>REPL: Command 对象
REPL->>SkillTool: 调用 Skill
SkillTool->>Skill: getPromptForCommand('arg1 arg2')
Skill-->>SkillTool: ContentBlockParam[]
SkillTool->>Model: 发送 Skill 内容
Model->>Model: 执行 Skill 指令
Model->>SkillTool: 工具调用请求
SkillTool->>SkillTool: 检查 allowedTools
SkillTool->>SkillTool: 执行工具
SkillTool-->>Model: tool_result
Model-->>SkillTool: 最终响应
SkillTool-->>REPL: Skill 结果
REPL->>User: 显示结果
下一章将分析 命令系统 的实现细节。