Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 16 章:Sub-Agent 与 Team — 多智能体协作

核心问题:当任务复杂到一个 Agent 无法高效完成时 — 既要探索代码库、又要制定计划、还要并行修改多个模块 — 如何将一个 Agent 拆分为多个协作单元,同时确保它们之间的上下文隔离、权限安全和通信顺畅?

单个 Agent 的能力边界是清晰的:它有一个 agentic loop、一份 system prompt、一个上下文窗口。当任务涉及多文件并行修改、代码探索与编辑分离、或者需要不同权限级别的操作时,单 Agent 模式会遭遇上下文膨胀、串行瓶颈和权限冲突三大问题。

Claude Code 的解决方案是构建一套三层协作模型 — 从最简单的 Sub-Agent 委派,到继承上下文的 Fork 分叉,再到完整的 Team 多智能体协作系统。每一层都解决特定的复杂度需求,同时保持向下兼容。


16.1 概述:从单 Agent 到多 Agent

为什么需要多 Agent

单 Agent 架构在以下场景面临瓶颈:

  1. 任务分解:一个复杂任务(如“重构整个模块的错误处理“)包含多个独立子任务,串行执行效率低下
  2. 并行执行:Pro 用户有充足的 API 配额,多个 Agent 可以并行探索代码、并行修改文件
  3. 上下文隔离:代码探索产生的大量搜索结果不应污染编辑 Agent 的上下文窗口
  4. 权限分离:探索型任务只需只读权限,编辑型任务需要写入权限,混在一起增加安全风险

三层协作模型

Claude Code v2.1.86 实现了三层递进的多 Agent 协作:

复杂度递增 ──────────────────────────────────────────────▶

┌──────────────┐   ┌──────────────┐   ┌──────────────────┐
│  Sub-Agent   │   │    Fork      │   │      Team        │
│              │   │              │   │                  │
│ - 独立上下文  │   │ - 继承上下文  │   │ - 独立进程       │
│ - 任务完成即终 │   │ - 共享 Cache │   │ - 双向通信       │
│ - 结果直接返回 │   │ - 结果返回   │   │ - 共享任务列表    │
│ - 可嵌套      │   │ - 不可嵌套   │   │ - 存活到 shutdown│
└──────────────┘   └──────────────┘   └──────────────────┘
    简单委派            廉价并行          完整协作
维度Sub-AgentForkTeam
创建方式Agent({subagent_type})Agent()(省略 type)TeamCreate + Agent({name, team_name})
上下文独立(仅 prompt)继承父 Agent 完整上下文独立(team lead 初始化)
通信结果返回给父 Agent结果返回给父 AgentSendMessage 双向通信
生存期完成即终止完成即终止存活直到 shutdown
进程模型父进程内 agentic loop父进程内 agentic loop独立进程(tmux/pane/in-process)
Cache 共享否是否
可嵌套是否否(flat roster)

整体架构

用户 (REPL / CLI)
    │ prompt
    ▼
┌────────────────────────────────────────────────┐
│            主 Agent (team-lead)                  │
│  system prompt + tool registry + agentic loop   │
└───┬──────────────┬──────────────┬──────────────┘
    │              │              │
    ▼              ▼              ▼
┌─────────┐  ┌─────────┐  ┌──────────────────┐
│SubAgent │  │  Fork   │  │     Team         │
│独立 SP   │  │继承 SP  │  │  ┌──────────┐   │
│独立历史  │  │继承历史  │  │  │Teammate A│   │
│av() loop│  │av() loop│  │  └─────┬────┘   │
└────┬────┘  └────┬────┘  │        │        │
     │            │       │  SendMessage     │
     ▼            ▼       │        │        │
 tool_result  output_file │  ┌─────┴────┐   │
 (同步返回)   (异步通知)   │  │Teammate B│   │
                          │  └──────────┘   │
                          │  TaskList(共享)  │
                          └──────────────────┘

设计决策:三层模型遵循“渐进式复杂度“原则 — 简单任务用 Sub-Agent(零配置),需要共享上下文时用 Fork(零额外成本),只有真正的多方协作才需要 Team(完整通信基础设施)。这避免了“为简单任务付出复杂代价“的反模式。

小结:多 Agent 协作解决的是单 Agent 的上下文膨胀、串行瓶颈和权限冲突问题。三层模型(Sub-Agent → Fork → Team)让用户按需选择复杂度,而不是一刀切地引入协作开销。


16.2 Agent 工具实现

Agent 工具是整个多 Agent 系统的入口 — 无论是创建 Sub-Agent、Fork 还是 Teammate,都通过同一个 Agent 工具触发,由内部路由逻辑决定走哪条路径。理解这个工具的 Schema 和路由机制是理解整个多 Agent 系统的基础。

Agent 工具的 Schema 定义

Agent 工具注册在 13_ui_rendering.js:69364,工具名通过变量 M7(值为 "Agent")引用:

// 13_ui_rendering.js:69364-69393 — Agent tool definition
f_9 = {
    async prompt({ agents, tools, getToolPermissionContext, allowedAgentTypes }) {
        let T = tlH(H, O),           // mergeAgentDefinitions: merge built-in + custom agents
            z = neH(T, K, M7);       // filterByPermissions: exclude denied agent types
        return await A_9(z, false, $) // generatePromptDescription: build tool prompt text
    },
    name: M7,                         // "Agent"
    searchHint: "delegate work to a subagent",
    aliases: [ep],
    maxResultSizeChars: 1e5,           // 100KB result cap
    async description() { return "Launch a new agent" },
    get inputSchema() { return oo6() },   // getInputSchema
    get outputSchema() { return ag1() },  // getOutputSchema
    async call({ prompt, subagent_type, description, model,
                 run_in_background, name, team_name, mode,
                 isolation, cwd }, w, Y, D, j) {
        // ... core dispatch logic
    }
}

输入 Schema 定义于 13_ui_rendering.js:69327-69349,分为基础参数和扩展参数两层:

// 13_ui_rendering.js:69327-69349 — Input schema (two-layer design)
// Layer 1: basic parameters (always available)
rg1 = pH(() => h.object({
    description: h.string().describe("A short (3-5 word) description"),
    prompt: h.string().describe("The task for the agent to perform"),
    subagent_type: h.string().optional(),
    model: h.enum(["sonnet", "opus", "haiku"]).optional(),
    run_in_background: h.boolean().optional()
}));

// Layer 2: team/isolation extensions (merged on top of base)
og1 = pH(() => {
    let H = h.object({
        name: h.string().optional(),
        team_name: h.string().optional(),
        mode: JX8().optional()        // getPermissionModeSchema
    });
    return rg1().merge(H).extend({
        isolation: h.enum(["worktree"]).optional(),
        cwd: h.string().optional()
    })
});

完整参数列表:

参数类型必填说明
promptstring是子 Agent 的任务指令
descriptionstring是3-5 词的任务摘要
subagent_typestring?否Agent 类型标识。省略时:fork 实验开启则 fork,否则 general-purpose
modelenum否模型覆盖:"sonnet" / "opus" / "haiku"
run_in_backgroundboolean?否是否后台运行,完成后自动通知
namestring?否Agent 名称,使其可通过 SendMessage({to: name}) 寻址
team_namestring?否团队名称,省略则使用当前团队上下文
modestring?否权限模式(如 "plan" 要求计划审批)
isolationenum?否隔离模式,"worktree" 创建独立 git worktree
cwdstring?否自定义工作目录,与 isolation: "worktree" 互斥

7 种 subagent_type

系统内置了多种 Agent 类型,每种类型有不同的工具集和权限:

类型工具限制模型权限模式说明
general-purpose全部 ["*"]inheritacceptEdits默认通用 Agent,完整工具集
Explore只读(Read, Glob, Grep 等)haikuacceptEdits代码探索专用,不能编辑
Plan只读inheritacceptEdits规划专用,不能编辑
statusline-setupRead + EditsonnetacceptEdits状态栏配置
fork全部 ["*"]inheritbubble继承上下文的子任务(特殊类型)

每个内置类型以对象形式定义:

// Built-in agent type structure
{
    agentType: string,              // type identifier
    whenToUse: string,              // usage scenario description
    tools: string[],                // available tools, ["*"] = all
    disallowedTools: string[],      // explicitly blocked tools
    maxTurns: number,               // max agentic loop iterations
    model: string,                  // "inherit" or specific model
    permissionMode: string,         // permission mode
    source: "built-in",
    baseDir: "built-in",
    getSystemPrompt: () => string   // system prompt generator
}

Explore 和 Plan 的只读限制通过工具集过滤实现:

// 11_api_streaming.js:16291 — read-only vs write tool sets
lK1 = new Set(["Read", "Glob", "Grep", "ToolSearch", "LSP", "TaskGet", "TaskList"])
QK1 = new Set(["Edit", "Write", "NotebookEdit"])  // write tools excluded for Explore/Plan

权限模式继承(mode 参数)

Agent 工具的 mode 参数控制子 Agent 的权限级别。权限层次从高到低:

bypassPermissions  →  跳过所有检查(--dangerously-skip-permissions)
acceptEdits        →  自动接受文件编辑(SubAgent 默认)
auto               →  自动决策
default            →  标准权限检查
plan               →  计划模式,需要审批
bubble             →  冒泡到父 Agent(Fork 默认)
// 13_ui_rendering.js:69545 — SubAgent permission setup
let i = {
    ...P.toolPermissionContext,
    mode: v.permissionMode ?? "acceptEdits"  // default: acceptEdits
};

设计决策:Sub-Agent 默认使用 acceptEdits 而非 default,因为子 Agent 需要自主完成任务,频繁的权限弹窗会阻塞整个 agentic loop。acceptEdits 在安全性和自主性之间取得平衡 — 文件编辑自动放行,但危险的 Bash 命令仍需确认。

Worktree 隔离(isolation 参数)

当多个 Agent 可能修改同一个代码库时,Git Worktree 提供了天然的文件系统隔离:

// 13_ui_rendering.js:69550-69553 — create worktree for agent
if (S === "worktree") {
    let fH = `agent-${HH.slice(0,8)}`;  // HH = lx() generated UUID
    e = await reH(fH)                    // createAgentWorktree
}

Worktree 在 {gitRoot}/.claude/worktrees/{agent-id}/ 下创建独立工作目录,分支名为 worktree-{agent-id}。这确保每个 Agent 在自己的分支上工作,不会产生文件冲突。

小结:Agent 工具是多 Agent 系统的统一入口,通过 subagent_type、name/team_name、isolation 三组参数分别控制 Agent 类型选择、团队协作模式和文件隔离策略。Schema 的两层设计(基础 + 扩展)确保简单场景不需要理解复杂参数。


16.3 Sub-Agent 执行引擎

Sub-Agent 的执行引擎是整个多 Agent 系统的核心 — 它管理 Agent 实例的创建、上下文构建、agentic loop 执行和结果返回。理解这个引擎的工作方式,才能理解 Fork 和 Team 在其基础上的扩展。

Agent 类型路由

Agent.call() 方法(13_ui_rendering.js:69394)首先进行类型路由 — 根据输入参数决定创建 Sub-Agent、Fork 还是 Teammate:

// 13_ui_rendering.js:69439-69460 — type routing inside call()
let Z = _ ?? (Hb() ? void 0 : Od.agentType);
// _ = subagent_type parameter
// Hb() = isForkExperimentEnabled (currently returns false)
// Od.agentType = "general-purpose" (default fallback)

let k = Z === void 0;  // true = fork mode

if (k) {
    // Fork path: check nested fork guard
    if (w.options.querySource === `agent:builtin:${KyH.agentType}` || O_9(w.messages))
        throw Error("Fork is not available inside a forked worker.");
    v = KyH  // use fork definition
} else {
    // SubAgent path: find matching type in active agents
    let fH = w.options.agentDefinitions.activeAgents;
    let n = KH.find((l) => l.agentType === Z);
    if (!n) throw Error(`Agent type '${Z}' not found. Available agents: ...`);
    v = n
}

路由决策树:

Agent.call() 被调用
    │
    ├─ 有 name + team_name? ──── yes ──→ Teammate 生成路径(见 16.4)
    │
    ├─ subagent_type 省略 + fork 实验开启?
    │   ├─ yes → Fork 路径(检查嵌套防护)
    │   └─ no  → 回退到 general-purpose
    │
    └─ subagent_type 指定? ──→ 查找匹配的 Agent 定义

Agent 实例创建流程

整个 Sub-Agent 生命周期在 Agent.call() 中完成:

Agent.call() 被调用
    │
    ├─ 1. 参数校验(team_name 权限、嵌套限制)
    │
    ├─ 2. Agent 类型路由(fork vs subagent_type 查找)
    │
    ├─ 3. MCP Server 依赖检查(requiredMcpServers)
    │
    ├─ 4. 模型解析 LvH() (resolveModel)
    │     └─ 优先级:环境变量 > 调用参数 > Agent 定义 > 父 Agent 继承
    │
    ├─ 5. Worktree 创建(若 isolation === "worktree")
    │
    ├─ 6. System Prompt 构建
    │     ├─ Fork:复用父 Agent 的 renderedSystemPrompt
    │     └─ SubAgent:调用 agent.getSystemPrompt() + 独立构建
    │
    ├─ 7. 消息构建
    │     ├─ Fork:继承父 Agent 消息历史 + fork 指令
    │     └─ SubAgent:仅包含用户 prompt 消息
    │
    ├─ 8. 分支:同步 vs 异步
    │     ├─ 异步(run_in_background=true):注册任务后立即返回
    │     └─ 同步:阻塞等待 agentic loop 完成
    │
    └─ 9. 结果返回 / 异步通知

模型选择优先级由 LvH() (resolveModel) 函数决定:

1. CLAUDE_CODE_SUBAGENT_MODEL 环境变量  → 最高优先级
2. Agent.call() 中的 model 参数          → 用户指定
3. Agent 定义中的 model 字段             → frontmatter 定义
4. "inherit"(继承父级模型)              → 默认行为

Context 隔离 vs 共享策略

Sub-Agent 和 Fork 在上下文处理上有根本差异:

Sub-Agent 模式 — 完全隔离:

// 13_ui_rendering.js:69512-69530 — SubAgent independent context
else {
    // call agent definition's getSystemPrompt
    x = await EeH([vH], E, fH)   // buildAgentSystemPrompt
    // message history contains only the user prompt
    B = [d_({ content: H })]      // createUserMessage
}

Fork 模式 — 继承共享:

// 13_ui_rendering.js:69497-69511 — Fork context inheritance
if (k) {
    // reuse parent agent's system prompt
    if (w.renderedSystemPrompt) I = w.renderedSystemPrompt;
    else { /* rebuild full system prompt */ }

    // inherit parent's message history + add fork instructions
    B = T_9(H, D)  // buildForkMessages
}

Fork 指令由 $_9() (generateForkWorkerRules) 函数生成,施加严格的行为约束:

STOP. READ THIS FIRST.
You are a forked worker process. You are NOT the main agent.
RULES (non-negotiable):
1. Do NOT spawn sub-agents; execute directly.
2. Do NOT converse, ask questions, or suggest next steps
3. USE your tools directly: Bash, Read, Write, etc.
4. If you modify files, commit your changes before reporting
5. Keep your report under 500 words
6. Your response MUST begin with "Scope:"
...

隔离属性对比:

属性Sub-AgentFork
System Prompt独立(Agent 定义生成)继承父 Agent
消息历史仅包含 prompt继承完整上下文
工具集由 Agent 定义决定与父 Agent 相同
Prompt Cache独立与父共享(核心优势)
权限模式acceptEdits(默认)bubble(冒泡到父 Agent UI)

设计决策:Fork 的核心价值是 Prompt Cache 共享。由于 Fork 继承父 Agent 的完整 system prompt 和消息历史,API 调用时可以复用已缓存的 KV 对,大幅降低首次 token 延迟和成本。这就是为什么 Fork 不允许指定不同 model — 不同模型无法复用父 Agent 的 cache。

子 Agent 的 System Prompt 构建

Sub-Agent 的 system prompt 通过 EeH() (buildAgentSystemPrompt) 独立构建,流程与主 Agent 类似但有简化:

// 13_ui_rendering.js:65220 — context difference for Explore/Plan
e = H.agentType === "Explore" || H.agentType === "Plan" ? HH : C,
// HH = lightweight context (no gitStatus)
// C = full context (with gitStatus)
// Explore/Plan get simplified system context

Agentic Loop 执行

子 Agent 通过 av() (runAgenticLoop) 进入独立的 agentic loop(13_ui_rendering.js:65180):

// 13_ui_rendering.js:65375-65390 — core agentic loop execution
for await (let RH of zC({        // coreAgenticLoop
    messages: I,
    systemPrompt: fH,
    userContext: i,
    systemContext: e,
    toolUseContext: jH,
    options: XH,
    ...
})) {
    // each RH is one API response turn
    yield RH
}

同步 vs 异步执行

同步执行(默认,13_ui_rendering.js:69662):

// Simplified pseudocode for synchronous agent execution
let NH = av({...qH, override: { agentId: fH }});  // runAgenticLoop
let KH = [];  // collect all messages

while (true) {
    // race: API response vs auto-background signal
    let yH = s ? await Promise.race([NH.next(), s]) : { result: await NH.next() };

    if (yH.type === "background") {
        // auto-backgrounded: switch to async continuation
        jH = true;
        Tg(vH, async () => { /* finish remaining turns in background */ });
        break
    }

    if (yH.result.done) break;
    KH.push(yH.result.value);
}

// build result
let JH = Ob_(KH, mH, p);  // buildAgentResult
return { data: { status: "completed", ...JH } }

自动后台化:当同步 Agent 运行时间超过 120 秒,系统自动将其转为后台执行:

// 13_ui_rendering.js:69268 — auto-background threshold
function ng1() {       // getAutoBackgroundMs
    if (lH(process.env.CLAUDE_AUTO_BACKGROUND_TASKS) ||
        B_("tengu_auto_background_agents", false))
        return 120000;  // 120 seconds before auto-backgrounding
    return 0
}

异步执行(run_in_background=true,13_ui_rendering.js:69603):

// Simplified pseudocode for async agent execution
let vH = _y_({  // registerAsyncTask
    agentId: fH, description: q, prompt: H,
    selectedAgent: v, setAppState: R, toolUseId: w.toolUseId
});

// launch agentic loop in background
Tg(KH, () => $H(() => fb_({  // scheduleBackgroundTask
    taskId: vH.agentId,
    abortController: vH.abortController,
    makeStream: (l) => av({...qH}),  // create agentic loop stream
    metadata: p,
    ...
})));

// return immediately
return {
    data: {
        isAsync: true,
        status: "async_launched",
        agentId: vH.agentId,
        outputFile: I5(vH.agentId),    // getOutputFilePath
        canReadOutputFile: n
    }
}

结果返回与通知

异步 Agent 完成后通过 S8H() (sendTaskNotification, 11_api_streaming.js:17346) 发送 XML 格式通知:

<task_notification>
    <task_id>{id}</task_id>
    <output_file>{path}</output_file>
    <status>completed</status>
    <description>Agent "xxx" completed</description>
    <result>{agent output}</result>
    <usage>
        <total_tokens>...</total_tokens>
        <tool_uses>...</tool_uses>
        <duration_ms>...</duration_ms>
    </usage>
</task_notification>

通知消息通过 bw() (injectMessage) 注入到用户消息流,父 Agent 在下一个 turn 处理它。

任务状态机

Agent 任务有三种终态:

                    ┌──────────┐
                    │ pending  │
                    └────┬─────┘
                         │
                    ┌────▼─────┐
                    │ running  │
                    └──┬───┬───┬─┘
                       │   │   │
              ┌────────┘   │   └────────┐
              ▼            ▼            ▼
        ┌──────────┐ ┌──────────┐ ┌──────────┐
        │completed │ │  failed  │ │  killed  │
        └──────────┘ └──────────┘ └──────────┘
          eh_()        Hy_()        E8H()
// 11_api_streaming.js:17470-17498 — task terminal states
function eh_(H, _) {   // markCompleted → "completed"
    Z4(q, _, ($) => ({ ...$, status: "completed", result: H }))
}

function Hy_(H, _, q) { // markFailed → "failed"
    Z4(H, q, ($) => ({ ...$, status: "failed", error: _ }))
}

function E8H(H, _) {    // killTask → "killed" (user abort or timeout)
    Z4(H, _, ($) => {
        $.abortController?.abort();
        return { ...$, status: "killed" }
    })
}

小结:Sub-Agent 执行引擎的核心在于类型路由(Fork vs Sub-Agent vs Teammate)、上下文策略(隔离 vs 继承)和执行模式(同步 vs 异步 + 自动后台化)。120 秒自动后台化机制确保同步 Agent 不会无限期阻塞用户交互,而 XML 通知格式则为异步结果提供了结构化的回传通道。


16.4 Team 协调系统

当任务复杂到需要多个 Agent 长期并行工作、彼此通信、共享任务列表时,Sub-Agent 和 Fork 的“完成即终止“模型就不够用了。Team 系统提供了完整的多 Agent 协作基础设施 — 包括团队生命周期管理、共享任务系统和结构化通信协议。

TeamCreate / TeamDelete 生命周期

TeamCreate(14_html_parser.js:22815-22895)创建一个新团队:

// 14_html_parser.js:22838-22843 — TeamCreate input schema
xl1 = pH(() => h.strictObject({
    team_name: h.string().describe("Name for the new team"),
    description: h.string().optional(),
    agent_type: h.string().optional().describe('Type/role of the team lead')
}));

// Tool registration
pl1 = {
    name: "TeamCreate",  // variable Qx
    searchHint: "create a multi-agent swarm team",
    shouldDefer: true,
    isEnabled() { return dq() },  // isTeamsFeatureEnabled
    ...
}

团队创建后的操作:

  1. 创建 ~/.claude/teams/{team-name}/config.json(包含 members 数组)
  2. 创建 ~/.claude/tasks/{team-name}/ 任务目录
  3. 设置当前 Agent 为 team lead

TeamDelete(变量 OAH = "TeamDelete")负责清理:

  • 删除 ~/.claude/teams/{team-name}/config.json
  • 清理任务目录
  • 重置 teamContext 状态

Team 配置文件结构

~/.claude/
├── teams/{team-name}/
│   └── config.json              # 团队配置
├── tasks/{team-name}/           # 共享任务列表
└── inbox/{agent-name}/          # 消息收件箱

config.json 中的 members 数组记录每个 Teammate 的元数据:

// Member metadata stored in config.json
p.members.push({
    agentId: M,            // "name@teamName" format
    name: j,               // sanitized display name
    agentType: T,          // agent type definition
    model: f,              // model selection
    prompt: O,             // initial prompt
    color: R,              // UI display color
    tmuxPaneId: W,         // terminal pane identifier
    cwd: J,                // working directory
    backendType: P.backend.type  // "in-process" | "splitpane" | "tmux"
});

Teammate 生成流程

Teammate 通过 Agent 工具携带 name + team_name 参数触发(13_ui_rendering.js:69417-69438):

// 13_ui_rendering.js:69417-69438 — teammate creation path
if (W && O) {  // W=teamName, O=name
    // teammate spawning path
    let vH = await __9({           // spawnTeammate
        name: O, prompt: H, description: q,
        team_name: W, use_splitpane: true,
        plan_mode_required: z === "plan",
        model: J ?? fH?.model,
        agent_type: _,
        invokingRequestId: D?.requestId
    }, w);
    return { data: { status: "teammate_spawned", ...vH.data } }
}

__9() (spawnTeammate) → cg1() (routeTeammateBackend) 实现三种后端:

// 13_ui_rendering.js:68931-68940 — backend routing
async function cg1(H, _) {        // routeTeammateBackend
    if (Rm()) return aH9(H, _);   // forceInProcess → inProcessBackend
    try { await p7H() }           // detectPaneBackend
    catch ($) {
        // pane backend unavailable, fallback to in-process
        return _o6(), aH9(H, _)   // resetPaneState, inProcessBackend
    }
    if (H.use_splitpane !== false) return gg1(H, _);  // splitpaneBackend
    return dg1(H, _)              // tmuxBackend
}

三种后端对比:

后端函数进程模型适用场景
in-processaH9() (inProcessBackend)父进程内非终端环境、API 模式
splitpanegg1() (splitpaneBackend)iTerm2 分屏面板macOS + iTerm2
tmuxdg1() (tmuxBackend)tmux 窗口Linux / tmux 环境

Splitpane 后端的启动流程(gg1(), 13_ui_rendering.js:68537):

// Simplified pseudocode for splitpane teammate launch
async function gg1(H, _) {        // splitpaneBackend
    let D = await ha6(K, Y);       // deduplicateName
    let j = TeH(D);                // sanitizeName
    let M = ty(j, Y);              // generateAgentId: "name@teamName"

    // create iTerm2 split pane
    let { paneId, isFirstTeammate } = await ka7(j, R);  // createPane

    // build CLI command for the new pane
    let v = [
        `--agent-id ${M}`, `--agent-name ${j}`,
        `--team-name ${Y}`, `--agent-color ${R}`,
        `--parent-session-id ${v_()}`,
        A ? "--plan-mode-required" : "",
        T ? `--agent-type ${T}` : ""
    ];
    let x = `cd ${J} && env ${S} ${k} ${v}${E}`;
    await Na7(W, x, !X);  // sendCommandToPane

    // register in team config
    p.members.push({ agentId: M, name: j, ... });
    await g7H(Y, p);      // writeTeamConfig

    // send initial prompt to teammate inbox
    await RK(j, { from: x5, text: O, ... }, Y);  // writeToInbox
}

设计决策:Teammate 使用独立进程(tmux/pane)而非线程,是因为每个 Teammate 需要运行完整的 Claude Code REPL 实例,拥有独立的 system prompt、工具注册表和权限上下文。进程级隔离天然避免了共享状态带来的并发问题。

安全约束

Teammate 有严格的安全限制,防止层级爆炸:

// 13_ui_rendering.js:69415 — flat roster enforcement
if (Q5() && W && O)   // isTeammate() && teamName && name
    throw Error("Teammates cannot spawn other teammates — the team roster is flat.");

// 13_ui_rendering.js:69416 — in-process background restriction
if (QJ() && W && K === true)  // isInProcessTeammate() && background
    throw Error("In-process teammates cannot spawn background agents.");

Task 系统(TaskCreate / TaskList / TaskUpdate / TaskGet)

Task 系统是 Team 协作的核心调度机制。任务存储在 ~/.claude/tasks/{team-name}/ 目录下,所有 Teammate 共享。

四个任务工具:

// 13_ui_rendering.js:6929-6932 — task tool names
var yv = "TaskCreate";
var CqH = "TaskGet";
var bqH = "TaskList";
var gy = "TaskUpdate";

TaskCreate(14_html_parser.js:21060-21212):

  • 创建任务,包含 subject、description、activeForm、metadata
  • 初始状态为 pending
  • 支持 blocks/blockedBy 依赖关系

TaskUpdate(14_html_parser.js:21346-21463):

  • 更新状态:pending → in_progress → completed
  • 设置 owner 分配任务给特定 Teammate
  • 管理阻塞依赖关系

TaskList(14_html_parser.js:21647-21714):

  • 显示所有任务的摘要视图
  • Teammate 协议:完成当前任务后调用 TaskList 寻找下一个可用任务

TaskGet:

  • 获取单个任务的详细信息

任务依赖与阻塞

任务之间可以通过 blocks/blockedBy 建立依赖关系:

Task A (pending)
    │ blocks
    ▼
Task B (pending, blockedBy: [A])
    │ blocks
    ▼
Task C (pending, blockedBy: [B])

当 Task A 完成时,Task B 的 blockedBy 列表中移除 A,若列表清空则 Task B 变为可执行状态。这实现了简单的 DAG(有向无环图)调度。

任务状态机:

┌─────────┐    owner assigned     ┌─────────────┐    work done     ┌───────────┐
│ pending │ ──────────────────▶  │ in_progress │ ───────────────▶ │ completed │
└─────────┘                      └─────────────┘                  └───────────┘
     │                                  │
     │ (blockedBy not empty)            │ (abandoned)
     ▼                                  ▼
┌─────────┐                      ┌───────────┐
│ blocked │                      │  pending  │ (reassignable)
└─────────┘                      └───────────┘

小结:Team 系统通过 TeamCreate/TeamDelete 管理生命周期,通过 config.json 记录成员信息,通过 Task 系统(四个工具 + blocks/blockedBy 依赖)实现任务调度。三种后端(in-process/splitpane/tmux)适配不同的终端环境,而 flat roster 约束确保团队结构不会无限嵌套。


16.5 团队通信协议

Team 的 Teammate 之间需要可靠的通信机制 — 既要支持自由文本消息用于日常协调,又要支持结构化协议消息用于 shutdown 和 plan approval 等系统级操作。Claude Code 选择了基于文件系统的收件箱模型,简单、可靠且跨进程。

SendMessage 工具实现

SendMessage(14_html_parser.js:23562-23604)是 Team 通信的唯一通道:

// 14_html_parser.js:23562-23604 — SendMessage tool definition
// Input schema
Ql1 = pH(() => h.object({
    to: h.string().describe('Recipient: teammate name, or "*" for broadcast'),
    summary: h.string().optional().describe("5-10 word preview"),
    message: h.union([h.string(), Ul1()])  // free text or structured protocol
}));

// Tool registration
el1 = {
    name: TP,                // "SendMessage"
    searchHint: "send messages to agent teammates (swarm protocol)",
    isEnabled() { return dq() },      // isTeamsFeatureEnabled
    isConcurrencySafe() { return false },
    isReadOnly(H) { return typeof H.message === "string" },
    ...
}

消息路由

单播(by name)— il1() (sendDirectMessage, 14_html_parser.js:23343):

async function il1(H, _, q, $) {   // sendDirectMessage
    // H = recipient name, _ = message text, q = summary
    let K = $.getAppState();
    let O = n4(K.teamContext);       // getTeamName
    let T = _K() || (Q5() ? "teammate" : x5);  // getSenderName

    await RK(H, {                    // writeToInbox
        from: T, text: _, summary: q,
        timestamp: new Date().toISOString(),
        color: z                     // sender color
    }, O);

    return { data: { success: true, message: `Message sent to ${H}'s inbox` } }
}

广播(to: "*")— nl1() (broadcastMessage, 14_html_parser.js:23371):

async function nl1(H, _, q) {      // broadcastMessage
    let $ = q.getAppState();
    let K = n4($.teamContext);       // getTeamName
    let O = await iC(K);            // readTeamConfig

    let A = [];
    for (let f of O.members) {
        if (f.name.toLowerCase() === T.toLowerCase()) continue;  // skip self
        A.push(f.name)
    }

    // send to each teammate individually
    for (let f of A) await RK(f, { from: T, text: H, ... }, K);

    return {
        data: {
            success: true,
            message: `Message broadcast to ${A.length} teammate(s)`,
            recipients: A
        }
    }
}

RK() (writeToInbox) 将消息写入文件系统的收件箱:~/.claude/inbox/{agent-name}/。

消息投递与轮询

消息投递遵循“写入 → 轮询 → 注入“的三步流程:

Agent A 的 agentic loop 正在执行(busy 状态)
    │
    ├── Agent B 调用 SendMessage → RK() 写入 A 的收件箱文件
    │
    ├── A 的当前 turn 结束
    │     ├── 系统检查收件箱(500ms 轮询间隔)
    │     └── 将未读消息作为 user-role 消息注入对话
    │
    └── A 在下一个 turn 处理消息

对于 in-process Teammate,消息通过内存队列传递:

// 11_api_streaming.js:17322-17343 — in-process message queue
function sh_(H, _, q) {  // addPendingMessage
    Z4(H, q, ($) => ({
        ...$, pendingMessages: [...$.pendingMessages, _]
    }))
}

function dX7(H, _, q) {  // consumePendingMessages
    let $ = _().tasks[H];
    if (!pD($) || $.pendingMessages.length === 0) return [];
    let K = $.pendingMessages;
    Z4(H, q, (O) => ({ ...O, pendingMessages: [] }));
    return K
}

空闲检测与通知

Teammate 在每轮 turn 结束后自动进入 idle 状态。这是正常行为,不代表 Teammate 已完成工作:

// System prompt explanation (14_html_parser.js:22762-22769)
// "Teammates go idle after every turn - this is completely normal and expected.
//  A teammate going idle immediately after sending you a message does NOT mean
//  they are done or unavailable. Idle simply means they are waiting for input."

Idle 状态通过 Hooks 系统触发 TeammateIdle 事件:

// 04_git_operations.js:9100 — hooks including TeammateIdle
hooks: new Set(["PreToolUse", "PostToolUse", "Notification",
    "UserPromptSubmit", "SessionStart", "SessionEnd", "Stop",
    "SubagentStop", "PreCompact", "PostCompact",
    "TeammateIdle", "TaskCreated", "TaskCompleted"])

结构化协议消息

除了自由文本消息,SendMessage 还支持三种结构化协议消息:

// 14_html_parser.js — structured message type schema
Ul1 = pH(() => h.discriminatedUnion("type", [
    h.object({
        type: h.literal("shutdown_request"),
        reason: h.string().optional()
    }),
    h.object({
        type: h.literal("shutdown_response"),
        request_id: h.string(),
        approve: xj(),               // booleanSchema
        reason: h.string().optional()
    }),
    h.object({
        type: h.literal("plan_approval_response"),
        request_id: h.string(),
        approve: xj(),
        feedback: h.string().optional()
    })
]));
消息类型方向说明
shutdown_requestlead → teammate请求关闭 Teammate
shutdown_responseteammate → lead确认/拒绝关闭
plan_approval_responselead → teammate审批/拒绝计划

Shutdown 协议流程:

team-lead                              teammate
    │                                      │
    ├── SendMessage({                      │
    │     to: "worker",                    │
    │     message: {                       │
    │       type: "shutdown_request"       │
    │     }                                │
    │   })                                 │
    │                                      │
    │                                      ├── receives shutdown_request
    │                                      ├── SendMessage({
    │                                      │     to: "team-lead",
    │                                      │     message: {
    │                                      │       type: "shutdown_response",
    │                                      │       request_id: "...",
    │                                      │       approve: true
    │                                      │     }
    │                                      │   })
    │                                      └── process terminates
    ├── receives shutdown confirmation
    └── cleans up team resources

Shutdown 审批逻辑(ol1(), 14_html_parser.js:23438-23491):

async function ol1(H, _) {           // handleShutdownApproval
    let $ = uM();                     // getCurrentAgentId
    let K = _K() || "teammate";       // getAgentName

    // find teammate's pane info
    let f = A.members.find((w) => w.agentId === $);
    if (f) O = f.tmuxPaneId, T = f.backendType;

    // send shutdown confirmation message
    await RK(x5, { from: K, text: gH(z), ... }, q);  // writeToInbox

    // terminate teammate process
    if (T === "in-process") {
        let f = $F($, A.tasks);       // findInProcessTask
        if (f?.abortController) f.abortController.abort();
    } else {
        // external process: exit via exit code
        setImmediate(async () => { await k9(0, "other") });  // exitProcess
    }
}

Plan Approval 协议:

// 14_html_parser.js:23514 — approve plan
async function sl1(H, _, q) {         // approvePlan
    if (!t0($.teamContext))            // isTeamLead
        throw Error("Only the team lead can approve plans.");

    let z = {
        type: "plan_approval_response",
        requestId: _, approved: true,
        timestamp: new Date().toISOString(),
        permissionMode: T              // elevated permission mode
    };
    await RK(H, { from: x5, text: gH(z), ... }, K);  // writeToInbox
}

// 14_html_parser.js:23539 — reject plan
async function tl1(H, _, q, $) {      // rejectPlan
    let T = {
        type: "plan_approval_response",
        requestId: _, approved: false,
        feedback: q,                   // rejection feedback
        timestamp: new Date().toISOString()
    };
    await RK(H, { from: x5, text: gH(T), ... }, O);
}

Teammate 系统提示附录

所有 Teammate 会自动附加通信指南到 system prompt:

// 13_ui_rendering.js:55007-55017 — teammate communication appendix
var br6 = `
# Agent Teammate Communication

IMPORTANT: You are running as an agent in a team. To communicate with anyone:
- Use the SendMessage tool with \`to: "<name>"\` to send messages to specific teammates
- Use the SendMessage tool with \`to: "*"\` sparingly for team-wide broadcasts

Just writing a response in text is not visible to others on your team -
you MUST use the SendMessage tool.

The user interacts primarily with the team lead. Your work is coordinated
through the task system and teammate messaging.
`;

设计决策:消息收件箱基于文件系统而非 IPC(进程间通信),因为 Teammate 可能运行在不同的 tmux/pane 会话中,甚至是不同的 Claude Code 进程实例。文件系统是这些进程之间唯一可靠的共享媒介。这种设计牺牲了一些延迟(500ms 轮询间隔),换取了极高的可靠性和简单性。

小结:Team 通信协议分为两层 — 自由文本消息用于日常协调(单播 + 广播),结构化协议消息用于系统级操作(shutdown + plan approval)。基于文件系统的收件箱模型保证了跨进程通信的可靠性,而 500ms 轮询间隔在延迟和资源消耗之间取得平衡。


16.6 Agent 类型系统

Agent 类型系统决定了每个 Agent “能做什么” — 它控制工具集、权限模式、模型选择和 system prompt。除了内置类型外,用户还可以通过 .claude/agents/ 目录定义自定义 Agent 类型。

预定义 Agent 类型的工具约束

工具集过滤由 Er() (resolveAgentTools, 13_ui_rendering.js:9185) 函数实现:

function Er(H, _, q = false, $ = false) {  // resolveAgentTools
    let { tools: K, disallowedTools: O, source: T, permissionMode: z } = H;

    // filter base tool set
    let A = $ ? _ : DF6({           // filterToolsByContext
        tools: _, isBuiltIn: T === "built-in",
        isAsync: q, permissionMode: z
    });

    // apply disallowedTools exclusion
    let f = new Set(O?.map((R) => Jf(R).toolName) ?? []);
    let w = A.filter((R) => !f.has(R.name));

    // tools: ["*"] → use all filtered tools
    if (K === undefined || (K.length === 1 && K[0] === "*"))
        return { hasWildcard: true, resolvedTools: w };

    // specific tool list → keep only matching
    // ...
}

DF6() (filterToolsByContext, 13_ui_rendering.js:9163) 实现上下文感知的工具过滤链:

全部工具
  │
  ├─ MCP 工具 (mcp__*) ──────────────────────── 始终通过
  │
  ├─ 团队管理工具 (Agent, TeamCreate 等)
  │   └─ 非内置 Agent → 移除
  │
  ├─ 异步 Agent 工具过滤
  │   ├─ 基本:仅允许读写工具 (iC_ set)
  │   └─ 例外:in-process Teammate 可用团队工具 (ZC7 set)
  │
  └─ Agent 定义的 tools/disallowedTools ──── 最终过滤

被排除的元工具集:

// 13_ui_rendering.js:7380 — meta tools excluded from sub-agents
GvH = new Set([nL, Vj, EqH, M7, dO, jI])
// nL = "EnterWorktree", Vj = "ExitWorktree", EqH = "AskUserQuestion"
// M7 = "Agent", dO = "EnterPlanMode", jI = "ExitPlanMode"

可用于异步 Agent 的工具集:

// 13_ui_rendering.js:7380 — tools available to async agents
iC_ = new Set([
    cq, sk, yC, bK, FA, A5,  // Read, Glob, Grep, etc.
    ...Jn,                     // other read-only tools
    P7, z$, WG, Cw, iM, Sj, cC_, FC_  // Write, Edit, Bash, etc.
])

// Team-specific tools (available to in-process teammates)
ZC7 = new Set([
    yv, CqH, bqH, gy,  // TaskCreate, TaskGet, TaskList, TaskUpdate
    TP, Vv, hr, WvH     // SendMessage, CronCreate, CronDelete, CronList
])

Fork 类型的特殊定义

Fork 不通过 subagent_type 选择,而是通过省略 subagent_type 触发(需 fork 实验开启):

// 13_ui_rendering.js:69062-69072 — Fork type definition
KyH = {
    agentType: "fork",                  // Fg1 variable
    whenToUse: "Implicit fork - inherits full conversation context. " +
               "Not selectable via subagent_type; triggered by omitting " +
               "subagent_type when the fork experiment is active.",
    tools: ["*"],                       // all tools
    maxTurns: 200,
    model: "inherit",                   // inherit parent's model
    permissionMode: "bubble",           // bubble permissions to parent
    source: "built-in",
    baseDir: "built-in",
    getSystemPrompt: () => ""           // empty (uses parent's system prompt)
}

Fork 的嵌套防护 — 防止 Fork 中再 Fork:

// 13_ui_rendering.js:69443 — nested fork guard
if (w.options.querySource === `agent:builtin:${KyH.agentType}` || O_9(w.messages))
    throw Error("Fork is not available inside a forked worker.");

// O_9() (hasForkInstructionTag) checks for fork instruction tag in messages
function O_9(H) {
    return H.some((_) => {
        let q = _.message.content;
        return q.some(($) => $.type === "text" && $.text.includes(`<${i4_}>`))
    })
}

设计决策:Fork 不允许嵌套,因为 Fork 继承完整上下文,嵌套 Fork 会导致上下文爆炸(每层 Fork 都携带前一层的完整上下文),且 cache 无法跨层共享。通过 O_9() (hasForkInstructionTag) 检测消息中的 fork 指令标签来阻止。

自定义 Agent(.claude/agents/ 目录)

自定义 Agent 从 .claude/agents/ 目录加载,支持项目级和用户级:

  • 项目级:.claude/agents/*.md
  • 用户级:~/.claude/agents/*.md
// 09_data_processing.js:12743 — directories watched for agent definitions
return [...UI4.filter((H) => H !== ".git"), ".claude/commands", ".claude/agents"]

Agent 定义文件格式

Agent 定义使用 Markdown frontmatter 格式:

---
tools:
  - Read
  - Glob
  - Grep
  - Bash
disallowedTools:
  - Write
  - Edit
maxTurns: 50
model: sonnet
---

# My Custom Agent

You are a code review agent. Your job is to...

## Rules
1. Never modify files directly
2. Report findings in structured format
...

支持的 frontmatter 字段:

// 13_ui_rendering.js:53828-53835 — agent definition schema
disallowedTools: h.array(h.string()).optional(),
maxTurns: h.number().int().positive().optional(),
// ... plus tools, model, permissionMode

加载流程:

  1. tlH() (mergeAgentDefinitions) 合并内置 Agent 和自定义 Agent 定义
  2. neH() (filterByPermissions) 根据权限规则过滤可用类型
  3. 文件名(去掉 .md 后缀)即为 subagent_type 的值

小结:Agent 类型系统通过工具集限制(tools + disallowedTools)、权限模式和模型选择三个维度定义每种 Agent 的能力边界。自定义 Agent 定义文件使用 Markdown frontmatter 格式,存放在 .claude/agents/ 目录下,让用户可以为特定场景定制专用 Agent。


16.7 设计启示

本节提炼 Claude Code 多 Agent 系统中可迁移到其他项目的设计经验。

进程级隔离 vs 线程级共享

Claude Code 为 Teammate 选择了进程级隔离(tmux/pane 独立进程),而非线程级共享。这个决策带来了几个关键优势:

  • 故障隔离:一个 Teammate 崩溃不会影响其他成员
  • 状态隔离:每个进程有独立的 system prompt、工具注册表和权限上下文,不存在共享状态竞争
  • 环境隔离:每个 Teammate 可以有不同的 CWD 和环境变量

代价是通信延迟(文件系统 500ms 轮询)和资源开销(每个进程一个完整 REPL 实例)。但对于 Agent 场景,正确性远比延迟重要。

任务驱动 vs 消息驱动协作

Team 系统同时实现了两种协作范式:

  • 任务驱动:通过 TaskList 共享任务,Teammate 完成一个任务后自动 pick 下一个。适合可分解为独立子任务的工作
  • 消息驱动:通过 SendMessage 自由通信,适合需要协调的复杂工作

两种范式并非互斥 — Teammate 可以在执行任务过程中通过消息请求协助,也可以通过消息协调任务的分配。

渐进式复杂度

三层模型(单 Agent → Sub-Agent → Team)遵循按需引入复杂度的原则:

场景推荐模式复杂度
简单的代码搜索委派Explore Sub-Agent零配置
需要父上下文的并行任务Fork共享 cache,零额外成本
多文件并行修改Sub-Agent + Worktree文件隔离
长期运行的多方协作Team完整通信基础设施

这种设计避免了“为了一个简单任务而引入整个 Team 基础设施“的过度工程化。

Git Worktree 作为自然隔离单元

使用 Git Worktree 作为文件系统隔离的方案极为精妙:

  1. 天然的版本控制:每个 Agent 在独立分支上工作,变更可追踪
  2. 零配置合并:Agent 完成后,用户可以通过标准 Git 工作流合并结果
  3. 自动清理:无变更的 Worktree 自动删除,有变更的保留供用户审查
  4. Sparse Checkout 优化:大型 monorepo 可以只检出相关目录
// Worktree cleanup strategy (13_ui_rendering.js:69580-69602)
// No changes (HEAD commit unchanged) → auto-delete worktree and branch
// Has changes → keep worktree, return path and branch to parent agent

这种“按需保留“策略避免了 Agent 产生大量废弃 Worktree 的问题。

消息系统的简约设计

Team 的消息系统刻意保持简约 — 没有消息队列中间件、没有 gRPC、没有 WebSocket。仅使用文件系统 + 轮询:

  • 写入:将消息写入 ~/.claude/inbox/{agent-name}/
  • 读取:500ms 轮询检查收件箱
  • 投递:将未读消息注入 Agent 的对话流

这种设计的可靠性来自文件系统的原子性保证,而非复杂的分布式协议。对于 Agent 场景(通信频率低、每条消息价值高),这是一个极好的工程权衡。


速查表

7 种 Agent 类型对比表

类型工具限制模型权限模式maxTurns说明
general-purpose全部 ["*"]inheritacceptEdits-默认通用 Agent
Explore只读(Read/Glob/Grep)haikuacceptEdits-代码探索,不能编辑
Plan只读inheritacceptEdits-架构规划,不能编辑
statusline-setupRead + EditsonnetacceptEdits-状态栏配置
fork全部 ["*"]inheritbubble200继承上下文,不可嵌套
自定义 Agentfrontmatter 定义frontmatterfrontmatterfrontmatter.claude/agents/*.md

关键函数索引

混淆名推测英文名文件:行号功能描述
f_9agentToolDefinition13_ui_rendering.js:69364Agent 工具定义对象
A_9()generatePromptDescription13_ui_rendering.js:69100生成 Agent 工具的 prompt 描述文本
oo6()getInputSchema13_ui_rendering.js:69327Agent 工具输入 Schema
ag1()getOutputSchema13_ui_rendering.js:69350Agent 工具输出 Schema
av()runAgenticLoop13_ui_rendering.js:65180子 Agent agentic loop 入口
Er()resolveAgentTools13_ui_rendering.js:9185解析 Agent 定义的工具限制
DF6()filterToolsByContext13_ui_rendering.js:9163按上下文过滤可用工具集
KyHforkAgentDefinition13_ui_rendering.js:69062Fork Agent 类型定义对象
OddefaultAgentType13_ui_rendering.js默认 Agent 类型 (general-purpose)
T_9()buildForkMessages13_ui_rendering.js:68985构建 Fork 指令消息
$_9()generateForkWorkerRules13_ui_rendering.js:69020生成 Fork worker 规则文本
O_9()hasForkInstructionTag13_ui_rendering.js:69443检查消息是否包含 fork 标签
LvH()resolveModel13_ui_rendering.js:69460模型选择优先级解析
ng1()getAutoBackgroundMs13_ui_rendering.js:69268获取自动后台化阈值(120s)
__9()spawnTeammate13_ui_rendering.js:68942Teammate 生成入口
cg1()routeTeammateBackend13_ui_rendering.js:68931Teammate 后端路由
gg1()splitpaneBackend13_ui_rendering.js:68537Splitpane 后端 Teammate 生成
dg1()tmuxBackend13_ui_rendering.js:68659Tmux 后端 Teammate 生成
aH9()inProcessBackend13_ui_rendering.js:68806In-process Teammate 生成
_y_()registerAsyncTask11_api_streaming.js:17501注册异步 Agent 任务
QX7()registerSyncTask11_api_streaming.js:17535注册同步 Agent 任务
S8H()sendTaskNotification11_api_streaming.js:17346发送任务完成通知
E8H()killTask11_api_streaming.js:17389终止运行中的 Agent
eh_()markCompleted11_api_streaming.js:17470标记 Agent 完成
Hy_()markFailed11_api_streaming.js:17486标记 Agent 失败
pl1teamCreateTool14_html_parser.js:22843TeamCreate 工具定义
el1sendMessageTool14_html_parser.js:23599SendMessage 工具定义
il1()sendDirectMessage14_html_parser.js:23343单播消息发送
nl1()broadcastMessage14_html_parser.js:23371广播消息发送
ol1()handleShutdownApproval14_html_parser.js:23438Shutdown 审批处理
sl1()approvePlan14_html_parser.js:23514Plan 审批处理
tl1()rejectPlan14_html_parser.js:23539Plan 拒绝处理
RK()writeToInbox14_html_parser.js写入收件箱文件
v48()createGitWorktree17_system_prompt_full.js:2778Git Worktree 创建
reH()createAgentWorktree17_system_prompt_full.js:3128Agent Worktree 创建
a7H()deleteAgentWorktree17_system_prompt_full.js:3156Agent Worktree 删除
tlH()mergeAgentDefinitions13_ui_rendering.js合并内置 + 自定义 Agent 定义
neH()filterByPermissions15_hooks_system.js:7129按权限规则过滤 Agent 类型
EeH()buildAgentSystemPrompt13_ui_rendering.js:69512构建 Sub-Agent 的 system prompt
Rm1()bubblePermission13_ui_rendering.js:55019权限冒泡处理函数

Team 文件结构

~/.claude/
├── teams/{team-name}/
│   └── config.json              # 团队配置(members 数组)
│       {
│         "members": [
│           {
│             "agentId": "worker@my-team",
│             "name": "worker",
│             "agentType": "general-purpose",
│             "model": "sonnet",
│             "prompt": "initial task...",
│             "color": "#ff6b6b",
│             "tmuxPaneId": "%42",
│             "cwd": "/path/to/project",
│             "backendType": "splitpane"
│           }
│         ]
│       }
│
├── tasks/{team-name}/           # 共享任务列表
│   └── {task-id}.json           # 单个任务文件
│       {
│         "id": "task-abc123",
│         "subject": "Refactor error handling",
│         "description": "...",
│         "status": "in_progress",
│         "owner": "worker",
│         "blocks": ["task-def456"],
│         "blockedBy": []
│       }
│
└── inbox/{agent-name}/          # 消息收件箱
    └── {timestamp}.json         # 单条消息文件

Task 状态机

                  ┌───────────────────────────────────────────┐
                  │                                           │
                  ▼                                           │
            ┌──────────┐                                      │
     ┌──────│ pending  │──────┐                               │
     │      └──────────┘      │                               │
     │           │            │                               │
     │  (blockedBy)    (owner assigned)                       │
     │           │            │                               │
     │      ┌────▼─────┐     │                          (abandoned)
     │      │ blocked  │     │                               │
     │      └────┬─────┘     │                               │
     │           │            │                               │
     │   (deps resolved)     │                               │
     │           │            │                               │
     │           ▼            ▼                               │
     │      ┌──────────────────┐                              │
     │      │   in_progress    │──────────────────────────────┘
     │      └────────┬─────────┘
     │               │
     │          (work done)
     │               │
     │          ┌────▼─────┐
     └─────────│ completed │
               └───────────┘

关键常量速查

常量值含义
自动后台化阈值120,000 ms (120s)同步 Agent 超时转后台
邮箱轮询间隔500 msTeammate 收件箱检查频率
Teammate 终止清理延迟3,000 ms (3s)终止后等待清理
输出截断恢复重试3 次 (Bo_ = 3)maxOutputTokens 截断重试
Fork maxTurns200Fork Agent 最大轮次
Agent 结果上限100,000 chars (100KB)maxResultSizeChars
Cron 任务上限50最大定时任务数
重复任务过期604,800,000 ms (7 days)recurringMaxAgeMs

权限模式层次

bypassPermissions  ──▶  跳过所有检查(--dangerously-skip-permissions)
        │
   acceptEdits     ──▶  自动接受文件编辑(SubAgent 默认)
        │
       auto        ──▶  自动决策(配置文件指定)
        │
      default      ──▶  标准权限检查(正常用户交互)
        │
       plan        ──▶  计划模式,需要 team lead 审批
        │
      bubble       ──▶  冒泡到父 Agent UI(Fork 默认)