Skip to content

第15章 Skill 与插件系统

开篇引言

在前面的章节中,我们深入分析了 Claude Code 的工具系统、权限模型和多 Agent 协作架构。这些机制构成了系统的核心骨骼,但真正赋予 Claude Code 生命力的,是其高度可扩展的 Skill 与插件系统。

想象一个开发者的日常场景:团队内部有一套定制化的代码审查规范,希望 Claude Code 在每次代码变更后自动执行检查;或者需要为特定框架编写一套部署流程,让模型在用户说出 /deploy 时自动执行一系列预定义操作。传统的工具系统虽然强大,但每添加一种新能力都需要修改核心代码。这就引出了一个根本性的架构问题:如何在不修改系统核心的前提下,让用户和社区自由扩展 Claude Code 的能力?

Claude Code 的回答是构建了三层递进的扩展体系:Skill(技能) 提供了声明式的能力描述机制,通过 Markdown 文件即可定义新技能;Plugin(插件) 在 Skill 之上增加了组件化封装,支持技能、Hooks、MCP 服务器的捆绑分发;Hooks(钩子) 则深入到工具执行的生命周期中,允许在关键节点插入自定义逻辑。三者协同工作,配合统一的 Slash 命令系统,形成了一个既灵活又安全的扩展架构。

本章将从源码层面深入剖析这套扩展体系的设计与实现,揭示其背后的架构决策和工程智慧。


本章要点

  • Skill 系统的三种来源:文件系统 Skill(.claude/skills/ 目录下的 Markdown 文件)、Bundled Skill(编译到 CLI 二进制中的内置技能)、MCP Skill(通过 MCP 协议远程加载的技能),以及它们如何统一转换为 Command 对象
  • BundledSkillDefinition 类型:内置技能的声明式定义,包括名称、描述、触发条件、允许的工具列表、执行上下文等关键字段的设计考量
  • SkillTool 的完整生命周期:从输入验证、权限检查、命令查找,到 inline/fork 两种执行模式的分流机制
  • Plugin 系统的分层架构:BuiltinPlugin(内置插件)与 Marketplace Plugin(市场插件)的双轨机制,以及 LoadedPlugin 类型如何统一表示两者
  • Hooks 的四种类型:command(Shell 命令)、prompt(LLM 提示)、agent(Agent 验证器)、http(HTTP 回调),以及它们在 PreToolUse/PostToolUse 等事件节点上的精密执行逻辑
  • Slash 命令系统的统一注册架构:80+ 命令的分类管理、优先级机制和动态加载策略
  • 三个子系统的协作关系:Skill 定义能力,Plugin 封装和分发能力,Hooks 在执行时拦截和增强能力

15.1 Skill 系统

Claude Code 的扩展体系由 Skill、Plugin 和 Hooks 三层构成,它们通过统一的 Slash 命令系统对外暴露。下图展示了三个子系统之间的关系:

15.1.1 Skill 的本质:声明式能力描述

在 Claude Code 的架构中,Skill 本质上是一种声明式的能力描述。每个 Skill 最终都被转换为一个 Command 对象,其中最重要的是 getPromptForCommand 方法——它返回一段 prompt 内容,指导模型如何完成特定任务。这种设计意味着,添加新能力不需要编写任何 TypeScript 代码,只需创建一个 Markdown 文件并用 frontmatter 声明元数据即可。

Command 类型定义在 src/types/command.ts 中,是一个联合类型:

typescript
// 文件: src/types/command.ts

export type PromptCommand = {
  type: 'prompt'
  progressMessage: string
  contentLength: number
  argNames?: string[]
  allowedTools?: string[]
  model?: string
  source: SettingSource | 'builtin' | 'mcp' | 'plugin' | 'bundled'
  hooks?: HooksSettings
  skillRoot?: string
  context?: 'inline' | 'fork'
  agent?: string
  effort?: EffortValue
  paths?: string[]
  getPromptForCommand(
    args: string,
    context: ToolUseContext,
  ): Promise<ContentBlockParam[]>
}

export type Command = CommandBase &
  (PromptCommand | LocalCommand | LocalJSXCommand)

这里的 source 字段清晰地标记了命令的来源:builtin 表示硬编码的内部命令(如 /help/clear),bundled 表示编译进二进制的内置 Skill,plugin 表示来自插件,mcp 表示来自 MCP 服务器。这个字段在后续的权限检查、遥测上报、prompt 截断等环节都起到了关键的分流作用。

15.1.2 skills/ 目录结构

Skill 系统的源码组织在 src/skills/ 目录下:

src/skills/
  bundledSkills.ts       -- Bundled Skill 注册表与类型定义
  loadSkillsDir.ts       -- 文件系统 Skill 加载器
  mcpSkillBuilders.ts    -- MCP Skill 构建器注册表
  bundled/
    index.ts             -- 所有 Bundled Skill 的初始化入口
    simplify.ts          -- /simplify 代码审查技能
    updateConfig.ts      -- /update-config 配置管理技能
    keybindings.ts       -- /keybindings 快捷键管理技能
    verify.ts            -- /verify 验证技能
    claudeApi.ts         -- /claude-api API 开发技能
    batch.ts             -- /batch 批量处理技能
    loop.ts              -- /loop 循环执行技能
    remember.ts          -- /remember 记忆技能
    stuck.ts             -- /stuck 卡住恢复技能
    debug.ts             -- /debug 调试技能
    ... 更多内置技能

这个目录结构体现了清晰的职责分离:bundledSkills.ts 负责类型定义和注册机制,loadSkillsDir.ts 负责从磁盘加载用户自定义 Skill,bundled/ 目录存放所有编译到二进制中的内置 Skill 实现。

15.1.3 BundledSkillDefinition 类型

BundledSkillDefinition 是定义内置 Skill 的核心类型,位于 src/skills/bundledSkills.ts

typescript
// 文件: src/skills/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[]>
}

每个字段都承载着精确的设计意图:

  • whenToUse:详细描述 Skill 的适用场景,在 SkillTool 的 prompt 中呈现给模型,帮助模型判断何时应自动调用该 Skill
  • allowedTools:声明该 Skill 执行时需要的工具白名单,SkillTool 会通过 contextModifier 临时将这些工具添加到权限系统中
  • context'inline' 表示 Skill 内容直接展开到当前对话中,'fork' 表示在独立的 sub-agent 中执行,隔离上下文和 token 预算
  • files:附加的参考文件,在首次调用时惰性提取到磁盘,模型可以通过 Read/Grep 工具按需访问
  • disableModelInvocation:设为 true 时,模型无法通过 SkillTool 自动调用该 Skill,仅允许用户通过 / 前缀手动触发

files 字段的设计尤其值得关注。由于 Bundled Skill 编译进二进制文件中,没有磁盘上的文件目录可供模型读取。通过 files 字段,Skill 可以声明一组参考文件,系统会在首次调用时将它们提取到 getBundledSkillsRoot() 下的安全目录中:

基于 VitePress 构建