第八章:扩展机制——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 { name: string , version?: string , description?: string , author?: { name: string ; email?: string ; url?: string }, homepage?: string , repository?: string , license?: string , keywords?: string [], dependencies?: DependencyRef[], 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>, 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 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 repository: string enabled?: boolean isBuiltin?: boolean sha?: string 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 { const marketplace = loadPluginsFromMarketplaces() const session = loadSessionOnlyPlugins() const builtin = getBuiltinPlugins() const merged = mergePluginSources(marketplace, session, builtin) const verified = verifyAndDemote(merged) cachePluginSettings(verified.enabled) return verified }
8.2.6 插件设置注入
插件设置作为最低优先级基础层 注入设置级联:
1 2 3 4 5 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 const pluginSettings = getPluginSettingsBase()let mergedSettings: SettingsJson = {}if (pluginSettings) { mergedSettings = mergeWith(mergedSettings, pluginSettings, settingsMergeCustomizer) }
安全限制 :通过 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() await loadAllPlugins() reloadCommands() reloadAgents() reloadHooks() reinitializeMcpServers() 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 type Command = CommandBase & (PromptCommand | LocalCommand | LocalJSXCommand)type CommandBase = { name: string description?: string aliases?: string [] argumentHint?: string whenToUse?: string isEnabled?: () => boolean isHidden?: () => boolean userInvocable?: boolean disableModelInvocation?: boolean loadedFrom: 'commands_DEPRECATED' | 'skills' | 'plugin' | 'managed' | 'bundled' | 'mcp' version?: string kind?: string } type PromptCommand = { type : 'prompt' contentLength?: number 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, context): Promise <ContentBlockParam[]> }
每个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 - Writeargument-hint: "[message]" arguments: - messagewhen_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
模型覆盖(sonnet、opus、inherit)
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 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(), ]) const deduped = deduplicateByResolvedPath([...all]) 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 function discoverSkillDirsForPaths (filePaths: string [] ): void { for (const filePath of filePaths) { walkUpFindingSkillDirs(filePath) } } 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 content = substituteArguments(content, args, this .arguments) content = content.replace('${CLAUDE_SKILL_DIR}' , this .skillRoot) content = content.replace('${CLAUDE_SESSION_ID}' , getSessionId()) content = await executeShellCommandsInPrompt(content, this .shell) return [{ type : 'text' , text: content }] }
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 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) { 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) } 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 function formatCommandsWithinBudget ( commands: Command[], budgetTokens: number , ): string { }
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 文件
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 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) { if (input.team_name && input.name) { return spawnTeammate(input) } const agentDef = resolveAgentType(input.subagent_type || 'general-purpose' ) const tools = assembleToolPool(agentDef.tools, 'acceptEdits' ) let worktreePath: string | undefined if (input.isolation === 'worktree' ) { worktreePath = await createAgentWorktree(slug) } const isAsync = input.run_in_background || agentDef.background || isCoordinatorMode() 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 export function getBuiltInAgents ( ): AgentDefinition [] { if (isEnvTruthy(process.env.CLAUDE_AGENT_SDK_DISABLE_BUILTIN_AGENTS) && getIsNonInteractiveSession()) { return [] } 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 permissionMode?: PermissionMode maxTurns?: number background?: boolean isolation?: 'worktree' | 'remote' memory?: 'user' | 'project' | 'local' hooks?: HooksSettings 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 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 } }
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 const inputSchema = z.object({ to: z.string().describe('接收者:Agent 名/ID、"*" 广播、teammate 名' ), summary: z.string().optional().describe('5-10 字摘要' ), message: z.union([ z.string(), StructuredMessage, ]), })
结构化消息类型 :
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 async function createAgentWorktree (slug: string ): Promise <string > { validateSlug(slug) const worktreePath = join(gitRoot, '.claude/worktrees' , flatSlug) await exec(`git worktree add ${worktreePath} -b worktree-${flatSlug} ` ) copySettingsLocalJson(worktreePath) configureGitHooksPath(worktreePath) symlinkNodeModules(worktreePath) copyWorktreeIncludeFiles(worktreePath) installCommitAttributionHook(worktreePath) 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 const shouldAvoidPrompts = canShowPermissionPrompts !== undefined ? !canShowPermissionPrompts : agentPermissionMode === 'bubble' ? false : isAsync
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 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 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' ) { const config = getMcpConfigByName(spec) const client = await connectToServer(spec, config) agentClients.push(client) } else { 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 () => { }, } }
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
递进关系 :
插件 是最顶层的扩展容器,可以包含技能、Agent 定义、Hooks、MCP 等所有组件
技能 可独立存在于文件系统,也可作为插件的一部分
Agent 定义 决定了子 Agent 的能力范围,可引用 MCP 服务器和预加载技能
多 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
BuiltinPluginDefinition、LoadedPlugin 类型定义
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 任务状态 + 通知