第八章:扩展机制——Plugins、Skills与Multi-Agent

“一个系统的生命力,取决于它允许别人在上面做什么。”


8.1 扩展机制全景

Claude Code 的扩展体系由三个递进层次组成:

  • 插件(Plugins):最重量级的扩展单元,可提供命令、Agent、Skills、Hooks、MCP/LSP 服务器、设置注入
  • 技能(Skills):轻量级的"可复用工作流模板",一个 Markdown 文件定义一个工作流
  • 多Agent(Multi-Agent):通过 AgentTool 和 SendMessageTool 实现任务分解与并行执行
graph TB subgraph 插件系统["插件系统(Plugins)"] P1[Marketplace 插件] P2[Session 插件
--plugin-dir] P3[内置插件
@builtin] end subgraph Skills系统["Skills系统(Skills)"] S1[内置Skills
bundled/] S2[用户Skills
~/.claude/skills/] S3[项目Skills
.claude/skills/] S4[MCP Skills
skill://] end subgraph 多Agent["多 Agent 架构"] A1[协调者模式
Coordinator] A2[直接派生
AgentTool] A3[团队/群体
Swarm] end P1 --> |提供| S4 P1 --> |提供| Commands[斜杠命令] P1 --> |提供| Agents[Agent 定义] P1 --> |提供| Hooks[Hook 处理器] P1 --> |提供| MCP[MCP 服务器] P1 --> |注入| Settings[设置基础层] S1 --> SkillTool[Skill 工具] S2 --> SkillTool S3 --> SkillTool S4 --> SkillTool A1 --> AgentTool[Agent 工具] A2 --> AgentTool A3 --> SendMsg[SendMessage 工具]

8.2 插件系统(Plugins)

8.2.1 插件架构概览

插件是 Claude Code 中最完整的扩展单元。一个插件可以同时提供多种扩展组件:

组件类型 目录/文件 说明
命令(Commands) commands/*.md 斜杠命令
Agent 定义 agents/*.md 自定义 Agent 类型
技能(Skills) skills/*/SKILL.md 工作流模板
Hooks hooks/hooks.json 生命周期钩子
MCP 服务器 .mcp.json 外部工具协议服务器
LSP 服务器 .lsp.json 语言服务器
输出样式 output-styles/ 自定义输出格式
设置注入 settings.json 注入设置基础层

8.2.2 插件目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
my-plugin/
├── .claude-plugin/
│ └── plugin.json # 清单文件(元数据 + 组件声明)
├── commands/ # 斜杠命令(*.md 文件)
│ ├── build.md
│ └── deploy.md
├── agents/ # AI Agent 定义(*.md 文件)
│ └── test-runner.md
├── skills/ # 技能目录(每个子目录含 SKILL.md)
│ └── my-skill/
│ └── SKILL.md
├── output-styles/ # 自定义输出样式
├── hooks/ # Hook 配置
│ └── hooks.json
├── .mcp.json # MCP 服务器配置
├── .lsp.json # LSP 服务器配置
└── settings.json # 插件设置(作为最低优先级基础层)

8.2.3 插件清单(plugin.json)

位于 <plugin-root>/.claude-plugin/plugin.json,通过 PluginManifestSchema(Zod)校验:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// schemas.ts(精简版)
{
// 元数据
name: string, // 唯一标识,kebab-case
version?: string, // Semver 版本
description?: string,
author?: { name: string; email?: string; url?: string },
homepage?: string,
repository?: string,
license?: string,
keywords?: string[],
dependencies?: DependencyRef[], // "name" 或 "name@marketplace"

// 组件声明
commands?: string | string[] | Record<string, CommandMetadata>,
agents?: string | string[],
skills?: string | string[],
outputStyles?: string | string[],
hooks?: string | HooksSettings | Array<string | HooksSettings>,
mcpServers?: string | Record<string, McpServerConfig>,
lspServers?: string | Record<string, LspServerConfig>,

// 配置
settings?: Record<string, unknown>, // 仅允许白名单 key
userConfig?: Record<string, PluginUserConfigOption>,
}

8.2.4 插件类型定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// types/plugin.ts
type BuiltinPluginDefinition = {
name: string
description: string
version?: string
skills?: BundledSkillDefinition[]
hooks?: HooksSettings
mcpServers?: Record<string, McpServerConfig>
isAvailable?: () => boolean
defaultEnabled?: boolean
}

type LoadedPlugin = {
name: string
manifest: PluginManifest
path: string
source: string // e.g., "my-plugin@marketplace-name"
repository: string
enabled?: boolean
isBuiltin?: boolean
sha?: string // Git commit SHA 版本锁定
commandsPath?: string
commandsPaths?: string[]
agentsPath?: string
agentsPaths?: string[]
skillsPath?: string
skillsPaths?: string[]
hooksConfig?: HooksSettings
mcpServers?: Record<string, McpServerConfig>
lspServers?: Record<string, LspServerConfig>
settings?: Record<string, unknown>
}

8.2.5 插件加载流程

sequenceDiagram participant CLI as CLI 启动 participant Loader as pluginLoader participant MP as Marketplace participant Cache as 插件缓存 participant Deps as 依赖解析器 participant Settings as 设置级联 CLI->>Loader: loadAllPlugins() par 并行加载三类来源 Loader->>MP: loadPluginsFromMarketplaces() Note over MP: 读取 enabledPlugins 配置
验证企业策略白名单 MP->>Cache: 从缓存或 clone 获取 Loader->>Loader: loadSessionOnlyPlugins() Note over Loader: --plugin-dir CLI flag Loader->>Loader: getBuiltinPlugins() Note over Loader: 内存中注册的内置插件 end Loader->>Loader: mergePluginSources() Note over Loader: 优先级: session > marketplace > builtin Loader->>Deps: verifyAndDemote() Note over Deps: 检查插件依赖是否满足
降级不满足依赖的插件 Loader->>Settings: cachePluginSettings() Note over Settings: 合并所有启用插件的 settings
存入 pluginSettingsBase Loader-->>CLI: PluginLoadResult { enabled, disabled, errors }

关键加载步骤pluginLoader.ts):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function assemblePluginLoadResult(): PluginLoadResult {
// 1. Marketplace 插件(读取 enabledPlugins 配置,验证企业策略)
const marketplace = loadPluginsFromMarketplaces()

// 2. Session 插件(--plugin-dir CLI flag,始终启用)
const session = loadSessionOnlyPlugins()

// 3. 内置插件(内存 BUILTIN_PLUGINS Map)
const builtin = getBuiltinPlugins()

// 4. 合并(session > marketplace > builtin)
const merged = mergePluginSources(marketplace, session, builtin)

// 5. 依赖验证(不满足的降级为 disabled)
const verified = verifyAndDemote(merged)

// 6. 缓存插件设置到设置级联的最低层
cachePluginSettings(verified.enabled)

return verified
}

8.2.6 插件设置注入

插件设置作为最低优先级基础层注入设置级联:

1
2
3
4
5
// settingsCache.ts
let pluginSettingsBase: Record<string, unknown> | undefined

export function setPluginSettingsBase(settings): void { ... }
export function getPluginSettingsBase(): Record<string, unknown> | undefined { ... }
1
2
3
4
5
6
7
8
// settings.ts:loadSettingsFromDisk()
// 插件设置作为最低优先级基础层
const pluginSettings = getPluginSettingsBase()
let mergedSettings: SettingsJson = {}
if (pluginSettings) {
mergedSettings = mergeWith(mergedSettings, pluginSettings, settingsMergeCustomizer)
}
// 然后按优先级合并 user → project → local → flag → policy

安全限制:通过 PluginSettingsSchema 白名单过滤,当前仅允许 agent 字段:

1
2
3
const PluginSettingsSchema = lazySchema(() =>
SettingsSchema().pick({ agent: true }).strip()
)

8.2.7 插件生命周期

stateDiagram-v2 [*] --> 注册: initBuiltinPlugins() 注册 --> 加载: loadAllPlugins() 加载 --> 启用: 满足依赖 + 企业策略通过 加载 --> 禁用: 不满足依赖 / 被用户禁用 启用 --> 激活: 按需加载组件(memoized) 激活 --> 热重载: 设置变更触发 热重载 --> 激活: clearPluginCache() + refreshActivePlugins() 启用 --> 禁用: 用户通过 /plugin 禁用 禁用 --> 启用: 用户通过 /plugin 启用

刷新机制refresh.ts):

1
2
3
4
5
6
7
8
9
async function refreshActivePlugins() {
clearPluginCache() // 清除 memoized 加载结果
await loadAllPlugins() // 完整重新加载(含网络请求)
reloadCommands() // 重新加载命令
reloadAgents() // 重新加载 Agent 定义
reloadHooks() // 重新加载 Hooks
reinitializeMcpServers() // 重新初始化 MCP 服务器
updateAppState() // 更新应用状态
}

8.2.8 Marketplace 管理

插件通过 Marketplace 分发。Marketplace 支持多种来源类型:

来源类型 说明
github GitHub owner/repo
git 任意 Git URL
url 直接 URL 指向 marketplace.json
npm npm 包
file / directory 本地路径
settings 内联在 settings.json

缓存布局

1
2
3
4
5
6
7
8
9
10
~/.claude/plugins/
├── cache/ # 版本化插件安装
│ └── <marketplace>/
│ └── <plugin>/
│ └── <version>/
├── data/ # 持久化插件数据(更新时保留)
│ └── <plugin-id>/ # 暴露为 ${CLAUDE_PLUGIN_DATA}
├── npm-cache/ # NPM 包缓存
├── marketplaces/ # Marketplace 清单
└── known_marketplaces.json # Marketplace 注册表

8.3 Skills系统

8.3.1 Skills概述

Skills是"可复用的工作流模板",比插件更轻量——一个 Markdown 文件定义一个工作流。Skills可以被用户通过 /name 调用,也可以被模型通过 Skill 工具自动调用。

graph LR User["/commit"] --> Parse[解析斜杠命令] Model["Skill({skill:'commit'})"] --> SkillTool[SkillTool] Parse --> Find[findCommand()] SkillTool --> Find Find --> Execute{执行模式?} Execute -->|inline| Inject[注入 Prompt 到对话] Execute -->|fork| SubAgent[启动子 Agent 执行]

8.3.2 Skills类型定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// types/command.ts
type Command = CommandBase & (PromptCommand | LocalCommand | LocalJSXCommand)

type CommandBase = {
name: string
description?: string
aliases?: string[]
argumentHint?: string
whenToUse?: string // 触发场景(帮助模型判断何时调用)
isEnabled?: () => boolean
isHidden?: () => boolean
userInvocable?: boolean // 用户可通过 /name 调用
disableModelInvocation?: boolean // 禁止模型调用
loadedFrom: 'commands_DEPRECATED' | 'skills' | 'plugin' | 'managed' | 'bundled' | 'mcp'
version?: string
kind?: string // e.g., 'workflow'
}

type PromptCommand = {
type: 'prompt'
contentLength?: number // Token 估算用
allowedTools?: string[] // Skills授予的工具权限
model?: string // 模型覆盖
source: SettingSource | 'builtin' | 'mcp' | 'plugin' | 'bundled'
hooks?: HooksSettings // 调用时注册的 Hooks
skillRoot?: string // Skills根目录
context: 'inline' | 'fork' // 执行模式
agent?: string // fork 模式的 Agent 类型
effort?: EffortValue // 努力级别覆盖
paths?: string[] // 条件激活的 glob 模式
getPromptForCommand(args, context): Promise<ContentBlockParam[]>
}

8.3.3 SKILL.md 格式

每个Skills是一个目录,包含一个 SKILL.md 文件,使用 YAML Frontmatter + Markdown 正文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
---
name: commit
description: 分析变更并生成提交信息
allowed-tools:
- Bash(git:*)
- Read
- Write
argument-hint: "[message]"
arguments:
- message
when_to_use: "当用户要求提交代码时使用"
model: sonnet
effort: high
context: inline
user-invocable: true
disable-model-invocation: false
paths:
- "**/*.go"
- "**/*.ts"
hooks:
PreToolUse:
- matcher: Bash
hooks: [...]
---

# 提交工作流

## 步骤
1. 运行 `git status` 查看变更
2. 分析变更内容,生成提交信息
3. 使用 `$message` 作为提交信息(如果提供)

## 变量
- `$message`: 用户指定的提交信息
- `${CLAUDE_SKILL_DIR}`: Skills文件所在目录
- `${CLAUDE_SESSION_ID}`: 当前会话 ID

Frontmatter 字段详解

字段 类型 说明
name string 显示名(可选,默认取目录名)
description string 单行描述
allowed-tools string[] 授予的工具权限模式
argument-hint string 参数提示
arguments string[] 命名参数(用于 $name 替换)
when_to_use string 触发场景描述(帮助模型自动调用)
model string 模型覆盖(sonnetopusinherit
effort string/number 努力级别(low/medium/high/max 或整数)
context 'inline'/'fork' 执行模式
agent string fork 模式使用的 Agent 类型
paths string[] 条件激活的 glob 模式
user-invocable boolean 是否允许用户调用
disable-model-invocation boolean 是否禁止模型调用
hooks HooksSettings 调用时注册的 Hooks
shell 'bash'/'powershell' ! 命令使用的 Shell

8.3.4 Skills发现与加载

Skills从多个位置加载,优先级从高到低:

1
2
3
4
5
① 企业管理目录   <managed-path>/.claude/skills/     企业策略强制Skills
② 用户目录 ~/.claude/skills/ 个人全局Skills
③ 项目目录 .claude/skills/ 项目级Skills
④ 额外目录 --add-dir 指定的路径 附加Skills
⑤ 遗留目录 .claude/commands/ 已废弃的命令格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// loadSkillsDir.ts
export const getSkillDirCommands = memoize(async function(
projectRoot: string
): Promise<{ commands: Command[]; conditionalCommands: Command[] }> {
// 并行加载所有来源
const [managed, user, project, additional, legacy] = await Promise.all([
loadManagedSkills(),
loadUserSkills(),
loadProjectSkills(projectRoot),
loadAdditionalDirSkills(),
loadLegacyCommands(),
])

// 去重(基于 realpath 解析后的路径)
const deduped = deduplicateByResolvedPath([...all])

// 分离条件激活Skills(有 paths frontmatter)和无条件Skills
return {
commands: deduped.filter(c => !c.paths?.length),
conditionalCommands: deduped.filter(c => c.paths?.length > 0),
}
})

动态发现:当模型操作文件时,系统会从文件路径向上查找新的 .claude/skills/ 目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 动态发现嵌套Skills
function discoverSkillDirsForPaths(filePaths: string[]): void {
for (const filePath of filePaths) {
walkUpFindingSkillDirs(filePath)
}
}

// 条件激活(paths frontmatter 匹配时激活)
function activateConditionalSkillsForPaths(filePaths: string[]): void {
for (const skill of conditionalCommands) {
if (skill.paths.some(glob => matchesAny(filePaths, glob))) {
activateSkill(skill)
}
}
}

8.3.5 Skills执行流程

sequenceDiagram participant User as 用户/模型 participant REPL as REPL/SkillTool participant Find as findCommand() participant Content as getPromptForCommand() participant Hooks as registerSkillHooks() participant Agent as 子 Agent(fork) User->>REPL: /commit "fix bug" 或 Skill({skill:"commit"}) REPL->>Find: 查找命令 Find-->>REPL: PromptCommand alt context: 'inline'(默认) REPL->>Content: getPromptForCommand(args) Content->>Content: 替换 $arguments Content->>Content: 替换 ${CLAUDE_SKILL_DIR} Content->>Content: 执行 ! 内联 Shell 命令 Content-->>REPL: ContentBlockParam[] REPL->>Hooks: registerSkillHooks() REPL-->>User: 注入 Prompt + allowedTools + model 覆盖 else context: 'fork' REPL->>Agent: executeForkedSkill() Agent->>Agent: runAgent() 独立执行 Agent-->>REPL: 执行结果 REPL-->>User: 返回结果文本 end

内容生成getPromptForCommand):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
async function getPromptForCommand(args: string, context): Promise<ContentBlockParam[]> {
let content = this.rawContent

// 1. 替换 $arguments
content = substituteArguments(content, args, this.arguments)

// 2. 替换环境变量
content = content.replace('${CLAUDE_SKILL_DIR}', this.skillRoot)
content = content.replace('${CLAUDE_SESSION_ID}', getSessionId())

// 3. 执行内联 Shell 命令(! 前缀行)
content = await executeShellCommandsInPrompt(content, this.shell)

// 4. 返回文本块
return [{ type: 'text', text: content }]
}

8.3.6 SkillTool:模型调用Skills的入口

SkillTool 是模型调用Skills的标准接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// SkillTool.ts
const SkillTool: ToolDef = {
name: 'Skill',
inputSchema: z.object({
skill: z.string().describe('Skills名称'),
args: z.string().optional().describe('Skills参数'),
}),

async validateInput({ skill }, context) {
const commands = await getAllCommands(context)
const command = findCommand(commands, skill)
if (!command || command.type !== 'prompt') return { valid: false }
if (command.disableModelInvocation) return { valid: false }
return { valid: true }
},

async checkPermissions({ skill }, context) {
// 检查 deny 规则、allow 规则、安全属性自动允许
const rule = getRuleByContentsForTool('Skill', skill)
if (rule?.type === 'deny') return { behavior: 'deny' }
if (rule?.type === 'allow') return { behavior: 'allow' }
return { behavior: 'ask' }
},

async call({ skill, args }, context) {
const command = findCommand(await getAllCommands(context), skill)

if (command.context === 'fork') {
return executeForkedSkill(command, skill, args, context)
}

// inline 模式:注入 Prompt 并返回 contextModifier
const result = processPromptSlashCommand(command, args)
return {
output: `Launching skill: ${skill}`,
contextModifier: {
allowedTools: command.allowedTools,
model: command.model,
effort: command.effort,
},
}
},
}

8.3.7 内置Skills一览

Skills 功能 特性门控
update-config 配置 settings.json、hooks、权限
keybindings 快捷键自定义
debug 启用/读取调试日志
loremIpsum Lorem ipsum 生成器
simplify 代码复审和清理
batch 批量处理
stuck 故障排除
verify 验证代码变更是否有效 ant-only
skillify 将当前会话捕获为可复用Skills ant-only
remember 审查和组织自动记忆 ant-only
loop 定时循环执行 Prompt AGENT_TRIGGERS
scheduleRemoteAgents 远程 Agent 调度 AGENT_TRIGGERS_REMOTE
claudeApi 构建/调试 Claude API 应用 BUILDING_CLAUDE_APPS

8.3.8 Skills可见性管理

Skills对模型的可见性通过 skill_listing attachment 管理,受 token 预算约束:

1
2
3
4
5
6
7
8
// prompt.ts
function formatCommandsWithinBudget(
commands: Command[],
budgetTokens: number, // 上下文窗口的 1%
): string {
// 按优先级排列,在预算内尽可能多地展示Skills
// 超出预算时截断低优先级Skills
}

8.4 Multi-Agent协调

8.4.1 三种工作模式

Claude Code 支持三种 Agent 协作模式:

graph TB subgraph 直接派生["直接派生模式(默认)"] Main1[主 Agent] -->|AgentTool| Worker1A[子 Agent A
同步/异步] Main1 -->|AgentTool| Worker1B[子 Agent B
同步/异步] end subgraph 协调者模式["协调者模式(Coordinator)"] Coord[协调者
纯编排,不直接工具调用] -->|AgentTool| Worker2A[Worker A
始终异步] Coord -->|AgentTool| Worker2B[Worker B
始终异步] Coord -->|SendMessage| Worker2A Worker2A -->|task-notification| Coord Worker2B -->|task-notification| Coord end subgraph 群体模式["团队/群体模式(Swarm)"] Lead[Team Lead] -->|Mailbox| Mate1[Teammate A] Lead -->|Mailbox| Mate2[Teammate B] Mate1 -->|Mailbox| Mate2 Mate2 -->|Mailbox| Mate1 end
模式 触发方式 父 Agent 角色 Worker 执行 通信方式
直接派生 默认 自己也做工作 + 委派 同步或异步 返回值 + SendMessage
协调者 CLAUDE_CODE_COORDINATOR_MODE=1 纯编排,不用直接工具 始终异步 SendMessage + task-notification XML
团队/群体 Agent Swarms 特性门控 Team Lead 持久化对等 Agent Mailbox 文件

8.4.2 AgentTool:子 Agent 派生

AgentTool 是派生子 Agent 的核心工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// AgentTool.tsx(精简)
const AgentTool: ToolDef = {
name: 'Agent',
inputSchema: z.object({
prompt: z.string(),
description: z.string(),
subagent_type: z.string().optional(),
model: z.enum(['sonnet', 'opus', 'haiku']).optional(),
run_in_background: z.boolean().optional(),
isolation: z.enum(['worktree']).optional(),
name: z.string().optional(),
}),

async call(input, context) {
// 1. 路由决策
if (input.team_name && input.name) {
return spawnTeammate(input) // 群体模式
}

// 2. 解析 Agent 定义
const agentDef = resolveAgentType(input.subagent_type || 'general-purpose')

// 3. 组装工具池(独立权限模式)
const tools = assembleToolPool(agentDef.tools, 'acceptEdits')

// 4. Worktree 隔离(如果指定)
let worktreePath: string | undefined
if (input.isolation === 'worktree') {
worktreePath = await createAgentWorktree(slug)
}

// 5. 判断同步 vs 异步
const isAsync = input.run_in_background
|| agentDef.background
|| isCoordinatorMode()

// 6. 执行
if (isAsync) {
registerAsyncAgent(agentId)
void runAsyncAgentLifecycle(agentId, agentDef, tools, input.prompt)
return { status: 'async_launched', agentId, outputFile }
} else {
return runAgent(agentId, agentDef, tools, input.prompt)
}
},
}

8.4.3 内置 Agent 类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// builtInAgents.ts
export function getBuiltInAgents(): AgentDefinition[] {
// SDK 用户可通过环境变量禁用所有内置 Agent
if (isEnvTruthy(process.env.CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS) &&
getIsNonInteractiveSession()) {
return []
}

// 协调者模式:替换为 worker Agent
if (isCoordinatorMode()) {
return getCoordinatorAgents()
}

const agents = [GENERAL_PURPOSE_AGENT, STATUSLINE_SETUP_AGENT]

if (areExplorePlanAgentsEnabled()) {
agents.push(EXPLORE_AGENT, PLAN_AGENT)
}

if (isNonSdkEntrypoint) {
agents.push(CLAUDE_CODE_GUIDE_AGENT)
}

if (feature('VERIFICATION_AGENT')) {
agents.push(VERIFICATION_AGENT)
}

return agents
}

各 Agent 定位

Agent 类型 模型 工具权限 特点
general-purpose 默认子 Agent 模型 全部工具 通用任务执行
Explore haiku(外部)/ inherit(内部) 只读工具 快速文件搜索,不加载 CLAUDE.md
Plan inherit 只读工具 架构规划,不加载 CLAUDE.md
verification inherit 只读 + 后台 对抗性测试验证
statusline-setup sonnet Read + Edit 状态栏配置
claude-code-guide - 只读 + Web Claude Code 使用指南

8.4.4 自定义 Agent 定义

用户可通过 Markdown 文件在 .claude/agents/ 中定义自定义 Agent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
---
name: my-agent
description: "当需要执行某类任务时使用此 Agent"
model: inherit
tools: [Read, Edit, Bash]
permissionMode: acceptEdits
maxTurns: 50
background: true
isolation: worktree
mcpServers:
- my-server
- another-server: { command: "node", args: ["server.js"] }
---

你是一个专门处理数据库迁移的 Agent。

## 规则
- 始终在 worktree 中工作
- 先备份再修改

Agent 定义类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type BaseAgentDefinition = {
agentType: string // 唯一标识
whenToUse: string // 何时使用的描述
tools?: string[] // 工具白名单('*' = 全部)
disallowedTools?: string[] // 工具黑名单
model?: string // 模型('inherit'、'haiku'、'sonnet'、'opus')
permissionMode?: PermissionMode
maxTurns?: number // 最大轮数
background?: boolean // 始终后台执行
isolation?: 'worktree' | 'remote'
memory?: 'user' | 'project' | 'local'
hooks?: HooksSettings // 会话级 Hooks
mcpServers?: AgentMcpServerSpec[]
skills?: string[] // 预加载的技能
color?: AgentColorName
}

解析优先级

1
2
内置 Agent → 插件 Agent → 用户 Agent → 项目 Agent → Flag Agent → Policy Agent
(后者覆盖前者同名定义)

8.4.5 协调者模式(Coordinator Mode)

协调者模式通过环境变量 CLAUDE_CODE_COORDINATOR_MODE=1 激活:

1
2
3
4
5
6
7
// coordinatorMode.ts
export function isCoordinatorMode(): boolean {
if (feature('COORDINATOR_MODE')) {
return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
}
return false
}

协调者系统提示词核心内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
export function getCoordinatorSystemPrompt(): string {
return `You are Claude Code, an AI assistant that orchestrates tasks across workers.

## 1. 角色
你是一个**协调者**。你的工作是:
- 帮助用户达成目标
- 指挥 worker 研究、实现和验证代码变更
- 综合结果并与用户沟通
- 能直接回答的问题不委派

## 2. 可用工具
- **Agent** — 派生新 worker
- **SendMessage** — 向已有 worker 发送后续指令
- **TaskStop** — 停止运行中的 worker

## 3. Worker 结果
Worker 结果以 <task-notification> XML 格式到达:
<task-notification>
<task-id>{agentId}</task-id>
<status>completed|failed|killed</status>
<summary>...</summary>
<result>...</result>
</task-notification>

## 4. 工作流阶段
Research → Synthesis → Implementation → Verification`
}

协调者工具上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export function getCoordinatorUserContext(mcpClients, scratchpadDir) {
let content = `Workers have access to these tools: ${workerTools}`

if (mcpClients.length > 0) {
content += `\nWorkers also have MCP tools from: ${serverNames}`
}

if (scratchpadDir && isScratchpadGateEnabled()) {
content += `\nScratchpad directory: ${scratchpadDir}
Workers can read and write here without permission prompts.`
}

return { workerToolsContext: content }
}

8.4.6 SendMessageTool:Agent 间通信

SendMessageTool 支持三种通信模式:

graph TB SendMessage[SendMessageTool] SendMessage -->|to=agentId| InProcess[进程内 Agent] SendMessage -->|to=teammate| Mailbox[Mailbox 文件] SendMessage -->|to="*"| Broadcast[广播所有 Teammate] SendMessage -->|to="bridge:id"| Remote[远程 Agent] SendMessage -->|to="uds:/path"| UDS[Unix Socket 通信] InProcess --> Running{Agent 状态?} Running -->|运行中| Queue[queuePendingMessage()] Running -->|已停止| Resume[resumeAgentBackground()]
1
2
3
4
5
6
7
8
9
// SendMessageTool.ts(精简)
const inputSchema = z.object({
to: z.string().describe('接收者:Agent 名/ID、"*" 广播、teammate 名'),
summary: z.string().optional().describe('5-10 字摘要'),
message: z.union([
z.string(),
StructuredMessage, // shutdown_request | shutdown_response | plan_approval_response
]),
})

结构化消息类型

1
2
3
4
5
const StructuredMessage = z.discriminatedUnion('type', [
z.object({ type: z.literal('shutdown_request'), reason: z.string().optional() }),
z.object({ type: z.literal('shutdown_response'), request_id: z.string(), approve: boolean }),
z.object({ type: z.literal('plan_approval_response'), request_id: z.string(), approve: boolean, feedback: z.string().optional() }),
])

8.4.7 Worktree 隔离

当 Agent 需要文件系统隔离时,使用 Git Worktree:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// worktree.ts
async function createAgentWorktree(slug: string): Promise<string> {
// 1. 验证 slug 合法性
validateSlug(slug) // 严格正则白名单

// 2. 创建 worktree
const worktreePath = join(gitRoot, '.claude/worktrees', flatSlug)
await exec(`git worktree add ${worktreePath} -b worktree-${flatSlug}`)

// 3. 后处理
copySettingsLocalJson(worktreePath) // 复制本地设置
configureGitHooksPath(worktreePath) // 配置 git hooks
symlinkNodeModules(worktreePath) // 符号链接 node_modules
copyWorktreeIncludeFiles(worktreePath) // 复制 .worktreeinclude 文件
installCommitAttributionHook(worktreePath) // 安装提交归属 hook

return worktreePath
}

Worktree 生命周期

stateDiagram-v2 [*] --> 创建: createAgentWorktree(slug) 创建 --> 使用中: Agent 在隔离环境工作 使用中 --> 检查变更: hasWorktreeChanges() 检查变更 -->|有变更| 保留: 返回路径给用户 检查变更 -->|无变更| 清理: removeAgentWorktree() 保留 --> [*] 清理 --> [*] 使用中 --> 过期清理: cleanupStaleAgentWorktrees(cutoffDate) 过期清理 --> [*]

8.4.8 权限冒泡(Permission Bubbling)

子 Agent 的权限处理有多种模式:

权限模式 行为 适用场景
acceptEdits 自动接受编辑操作 普通 Worker
bubble 权限对话框冒泡到父终端 Fork 子 Agent
plan 需要 Team Lead 审批 团队模式
1
2
3
4
5
6
7
// runAgent.ts
const shouldAvoidPrompts =
canShowPermissionPrompts !== undefined
? !canShowPermissionPrompts
: agentPermissionMode === 'bubble'
? false // bubble 模式:始终显示提示(冒泡到父终端)
: isAsync // 异步 Agent 默认抑制提示

8.4.9 任务通知机制

后台 Agent 完成后,通过 XML 格式通知协调者:

1
2
3
4
5
6
7
8
9
10
11
<task-notification>
<task-id>agent-a1b2c3d4</task-id>
<status>completed</status>
<summary>Agent "Investigate auth bug" completed</summary>
<result>Found null pointer in src/auth/validate.ts:42...</result>
<usage>
<total_tokens>15234</total_tokens>
<tool_uses>8</tool_uses>
<duration_ms>45000</duration_ms>
</usage>
</task-notification>
1
2
3
4
5
6
7
8
// LocalAgentTask.tsx
function enqueueAgentNotification(agentId, status, description, result, usage) {
const message = formatTaskNotificationXml(agentId, status, description, result, usage)
enqueuePendingNotification({
value: message,
mode: 'task-notification',
})
}

8.5 Agent MCP 服务器

Agent 可以定义自己专属的 MCP 服务器,在启动时连接、结束时清理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// runAgent.ts
async function initializeAgentMcpServers(agentDefinition, parentClients) {
if (!agentDefinition.mcpServers?.length) {
return { clients: parentClients, tools: [], cleanup: async () => {} }
}

for (const spec of agentDefinition.mcpServers) {
if (typeof spec === 'string') {
// 引用已配置的 MCP 服务器名称
const config = getMcpConfigByName(spec)
const client = await connectToServer(spec, config)
agentClients.push(client)
} else {
// 内联定义新的 MCP 服务器
const [name, config] = Object.entries(spec)[0]
const client = await connectToServer(name, { ...config, scope: 'dynamic' })
newlyCreatedClients.push(client) // 新建的需要在结束时清理
}
}

return {
clients: [...parentClients, ...agentClients],
tools: agentTools,
cleanup: async () => { /* 关闭 newlyCreatedClients */ },
}
}

8.6 扩展机制间的关系

graph TB Plugin[插件
重量级扩展单元] -->|提供| Skill[技能
轻量工作流] Plugin -->|提供| AgentDef[Agent 定义
自定义 Agent 类型] Plugin -->|提供| Hook[Hooks
生命周期钩子] Plugin -->|提供| MCPServer[MCP 服务器
外部工具协议] Plugin -->|注入| BaseSetting[设置基础层] Skill -->|被调用| SkillTool2[Skill 工具] AgentDef -->|被使用| AgentTool2[Agent 工具] MCPServer -->|提供工具| AgentDef SkillTool2 -->|fork 模式| AgentTool2 AgentTool2 -->|派生| Worker[Worker Agent] Worker -->|使用| SkillTool2 Hook -->|PreToolUse| Worker Hook -->|PostToolUse| Worker

递进关系

  1. 插件是最顶层的扩展容器,可以包含技能、Agent 定义、Hooks、MCP 等所有组件
  2. 技能可独立存在于文件系统,也可作为插件的一部分
  3. Agent 定义决定了子 Agent 的能力范围,可引用 MCP 服务器和预加载技能
  4. 多 Agent 协调使用 Agent 定义来派生 Worker,Worker 又可以调用技能

8.7 设计原则总结

# 原则 具体体现
1 分层递进 插件(重)→ 技能(轻)→ 命令(最轻),复杂度递减
2 Markdown 即配置 技能和 Agent 定义用 Markdown + Frontmatter,降低创建门槛
3 隔离执行 Worktree 提供文件系统隔离,fork 模式提供上下文隔离
4 权限最小化 每个 Agent 有独立工具池和权限模式
5 异步优先 协调者模式下所有 Worker 强制异步,最大化并行度
6 消息驱动 task-notification XML + SendMessage 实现松耦合通信
7 动态发现 技能按需发现和条件激活,避免加载不相关内容
8 优先级覆盖 插件 → 用户 → 项目 → Flag → Policy,后者覆盖前者
9 白名单安全 插件设置仅允许特定 key 通过,MCP 受 pluginOnly 策略控制
10 幂等刷新 插件热重载清除所有缓存后完整重建,无增量状态问题

8.8 核心文件速查表

文件 职责
src/plugins/builtinPlugins.ts 内置插件注册表(注册、启用/禁用状态查询)
src/plugins/bundled/index.ts initBuiltinPlugins() 入口
src/types/plugin.ts BuiltinPluginDefinitionLoadedPlugin 类型定义
src/utils/plugins/pluginLoader.ts 插件加载主流程:loadAllPlugins()createPluginFromPath()
src/utils/plugins/schemas.ts PluginManifestSchema(Zod)清单校验
src/utils/plugins/refresh.ts refreshActivePlugins() 热重载
src/utils/plugins/loadPluginCommands.ts 加载插件命令
src/utils/plugins/loadPluginAgents.ts 加载插件 Agent 定义
src/utils/plugins/loadPluginHooks.ts 加载插件 Hooks
src/skills/bundledSkills.ts 内置技能注册:registerBundledSkill()
src/skills/loadSkillsDir.ts 文件技能加载、动态发现、条件激活
src/skills/bundled/index.ts initBundledSkills() 初始化所有内置技能
src/tools/SkillTool/SkillTool.ts Skill 工具实现(模型调用入口)
src/tools/SkillTool/prompt.ts 技能列表格式化和 token 预算管理
src/tools/AgentTool/AgentTool.tsx Agent 工具主逻辑(路由、派生、异步管理)
src/tools/AgentTool/runAgent.ts Agent 执行引擎(MCP 初始化、工具过滤)
src/tools/AgentTool/builtInAgents.ts 内置 Agent 注册表
src/tools/AgentTool/loadAgentsDir.ts Agent 定义解析(Markdown、JSON、插件)
src/tools/AgentTool/forkSubagent.ts Fork 实验(上下文继承的子 Agent)
src/tools/AgentTool/resumeAgent.ts Agent 恢复(从磁盘 transcript 恢复)
src/tools/SendMessageTool/SendMessageTool.ts Agent 间通信(进程内、Mailbox、远程)
src/coordinator/coordinatorMode.ts 协调者模式逻辑 + 系统提示词
src/utils/worktree.ts Worktree 创建/清理(文件系统隔离)
src/tasks/LocalAgentTask/LocalAgentTask.tsx 后台 Agent 任务状态 + 通知