Skip to content

来源:Claude Code 技术文档 - v2.1.88 源码分析

插件与技能系统

10.1 概述

Claude Code 的扩展系统分为四个层次:

┌────────────────────────────────────────────────┐
│              扩展系统层次                        │
│                                                │
│  1. 内置插件 (Builtin Plugins)                  │
│     └─ 代码内注册,始终可用                      │
│                                                │
│  2. 打包技能 (Bundled Skills)                   │
│     └─ 随安装包分发,按需提取                    │
│                                                │
│  3. 技能目录 (Skill Directories)                │
│     └─ .claude/skills/ 中的自定义技能            │
│                                                │
│  4. MCP 技能 (MCP Skills)                      │
│     └─ 通过 MCP 协议加载的外部技能               │
│                                                │
│  5. 外部插件 (Plugins)                          │
│     └─ 第三方插件仓库                            │
│                                                │
└────────────────────────────────────────────────┘

10.2 内置插件 (builtinPlugins.ts)

10.2.1 API

// 注册内置插件
function registerBuiltinPlugin(plugin: BuiltinPlugin): void

// 获取所有内置插件
function getBuiltinPlugins(): BuiltinPlugin[]

// 获取内置插件提供的技能命令
function getBuiltinPluginSkillCommands(): Command[]

10.2.2 特点

  • 在代码中直接注册
  • 始终可用,不需要外部加载
  • 提供技能命令 (skill commands)
  • 与其他命令通过统一接口集成

10.3 打包技能 (bundledSkills.ts)

10.3.1 API

// 注册打包技能
function registerBundledSkill(skill: BundledSkill): void

// 获取所有打包技能
function getBundledSkills(): BundledSkill[]

// 获取打包技能的提取目录
function getBundledSkillExtractDir(): string

10.3.2 懒加载文件提取

打包技能的内容在首次使用时从安装包中提取:

首次调用打包技能

  ├─ 检查提取目录是否存在

  ├─ 不存在?
  │   ├─ 创建提取目录
  │   ├─ 从捆绑数据提取文件
  │   │   ├─ 使用 O_NOFOLLOW (不跟随符号链接)
  │   │   └─ 使用 O_EXCL (确保文件不存在)
  │   └─ 设置文件权限

  └─ 已存在?
      └─ 直接使用缓存的文件

10.3.3 安全提取

// 安全标志确保:
// O_NOFOLLOW — 防止符号链接注入攻击
// O_EXCL — 防止 TOCTOU (Time-of-check-to-time-of-use) 竞争

10.4 技能目录 (loadSkillsDir.ts)

10.4.1 API

// 加载技能目录中的命令 (memoized)
function getSkillDirCommands(cwd: string): Promise<Command[]>

// 发现项目中的技能目录
function discoverSkillDirsForPaths(paths: string[]): Promise<SkillDir[]>

// 条件激活 — 基于项目配置决定是否加载
// 某些技能只在特定项目类型中激活

10.4.2 技能目录结构

.claude/
  └─ skills/
      ├─ my-skill/
      │   ├─ skill.json          # 技能配置
      │   ├─ prompt.md           # 提示词内容
      │   └─ tools/              # 工具定义(可选)

      └─ another-skill/
          ├─ skill.json
          └─ prompt.md

10.4.3 skill.json 配置

{
  "name": "my-skill",
  "description": "技能描述",
  "version": "1.0.0",
  "allowedTools": ["BashTool", "FileReadTool"],
  "model": "claude-sonnet-4-20250514",
  "context": "inline",
  "argNames": ["arg1", "arg2"],
  "paths": ["src/**"],
  "whenToUse": "当需要 X 时使用此技能"
}

10.4.4 Memoization

// getSkillDirCommands 使用 memoize 缓存
// 按 cwd 参数缓存结果
// 清除: clearCommandMemoizationCaches()

10.5 MCP 技能构建器 (mcpSkillBuilders.ts)

10.5.1 API

// 注册 MCP 技能构建器
function registerMCPSkillBuilders(builders: MCPSkillBuilder[]): void

// 获取 MCP 技能构建器
function getMCPSkillBuilders(): MCPSkillBuilder[]

10.5.2 循环依赖解决

mcpSkillBuilders.ts 的存在是为了解决循环依赖问题:

MCP Client → 需要构建技能命令
技能命令 → 需要 MCP Client 连接
         ↺ 循环依赖

解决方案:
MCP Client → registerMCPSkillBuilders() (注册构建器)
技能系统 → getMCPSkillBuilders() (获取构建器)
         → 延迟构造技能命令(避免初始化时循环)

10.6 命令系统中的技能集成

10.6.1 统一加载

所有技能通过 getSkills() 统一加载:

async function getSkills(cwd: string): Promise<{
  skillDirCommands: Command[]      // 技能目录命令
  pluginSkills: Command[]          // 插件技能
  bundledSkills: Command[]         // 打包技能
  builtinPluginSkills: Command[]   // 内置插件技能
}>

错误处理:每个来源的加载独立捕获错误,不影响其他来源。

10.6.2 命令源优先级

bundled-skills       (最高)

builtin-plugin-skills

skill-dir-commands

workflow-commands

plugin-commands

built-in-commands    (最低)

10.6.3 技能作为命令

技能命令是 PromptCommand 类型:

const skillCommand: PromptCommand = {
  type: 'prompt',
  name: 'my-skill',
  description: '技能描述',
  progressMessage: '正在执行技能...',
  contentLength: promptContent.length,
  source: 'skills',            // 或 'bundled', 'plugin', 'mcp'
  loadedFrom: 'skills',
  
  async getPromptForCommand(args, context) {
    // 读取 prompt.md
    // 替换参数占位符
    // 返回内容块
    return [{ type: 'text', text: processedPrompt }]
  }
}

10.7 SkillTool 集成

10.7.1 SkillTool 调用流程

AI 模型决定使用技能


SkillTool.call({ skillName, args })

  ├─ getSkillToolCommands(cwd) — 获取可用技能
  ├─ findCommand(skillName, commands) — 查找技能
  ├─ skill.getPromptForCommand(args, context) — 获取提示


将技能提示作为新的消息注入

  └─ 继续对话循环

10.7.2 可被 SkillTool 调用的条件

// 条件:
// 1. type === 'prompt'          (必须是提示类型)
// 2. source !== 'builtin'       (非内置命令)
// 3. 未被模型禁用               (disableModelInvocation !== true)

10.8 插件清单

10.8.1 PluginManifest

插件通过清单文件描述自身:

type PluginManifest = {
  name: string              // 插件名称
  version: string           // 版本
  description: string       // 描述
  skills?: SkillConfig[]    // 提供的技能
  tools?: ToolConfig[]      // 提供的工具
  hooks?: HooksConfig       // 提供的 Hook
  // ...
}

10.8.2 插件来源标注

// 命令描述中的来源标注
function formatDescriptionWithSource(cmd: Command): string
// 输出示例:
// "代码审查 (from plugin: code-review)"
// "安全扫描 (from bundled skill)"
// "自定义分析 (from skills directory)"

10.9 MCP 技能命令

10.9.1 MCP 提供的提示命令

function getMcpSkillCommands(
  mcpCommands: readonly Command[]
): readonly Command[] {
  return mcpCommands.filter(cmd =>
    cmd.type === 'prompt' &&
    cmd.loadedFrom === 'mcp'
  )
}

10.9.2 MCP 服务器配置层

MCP 有 6 个配置层级(从高到低):

1. enterprise  — 企业策略配置
2. dynamic     — 运行时动态添加
3. project     — 项目级配置 (.claude/mcp.json)
4. user        — 用户级配置 (~/.claude/mcp.json)
5. local       — 本地覆盖
6. claudeai    — Claude AI 平台配置

每个 MCP 服务器通过签名 (signature) 去重,同一服务器的多个配置取最高优先级。

10.10 技能缓存管理

// 清除所有命令缓存(含技能)
function clearCommandsCache(): void
// 清除:
// - loadAllCommands 缓存
// - getSkillToolCommands 缓存
// - getSlashCommandToolSkills 缓存
// - 插件缓存
// - 技能目录缓存

// 清除 memoization 缓存
function clearCommandMemoizationCaches(): void
// 仅清除:
// - loadAllCommands
// - getSkillToolCommands
// - getSlashCommandToolSkills

MIT