Claude Code Agent Teams 逆向工程:架構與協定

機器翻譯 原文.

Banner for Claude Code Agent Teams 逆向工程:架構與協定

內容

前言

Claude Code(v2.1.47)內建一項稱為 Agent Teams 的實驗性功能:多個 Claude Code 工作階段透過領隊與隊友的拓樸結構,協調共同的工作。我一直在開發 Hive,這是一套協調多個代理程式進行程式開發的工具,目標類似,架構卻截然不同,因此我想了解 Anthropic 的做法在底層是如何運作的。

這篇文章記錄了我透過以下方式找到的資訊:

  1. 閱讀官方文件
  2. 檢查先前團隊工作階段留在磁碟上的實際產物
  3. 讓 Claude 分析 Claude Code 二進位執行檔(v2.1.47),找出實作細節(哈!)

目錄

1. 架構概觀

代理程式團隊由四個元件組成:

元件 角色
領隊 建立團隊並啟動隊友的主要 Claude Code 工作階段
隊友 各自獨立的 Claude Code 執行個體,每個都有自己的上下文視窗
任務清單 以個別 JSON 檔案儲存在磁碟上的共用工作項目
信箱 每個代理程式各自用來接收訊息的收件匣檔案

整個協調層都以檔案為基礎。位於 ~/.claude/ 的檔案系統是唯一的協調基礎:

~/.claude/
├── teams/{team-name}/
│   ├── config.json                  # team membership registry
│   └── inboxes/{agent-name}.json    # per-agent mailbox
└── tasks/{team-name}/
    ├── .lock                        # flock() for concurrent task claiming
    ├── .highwatermark               # auto-increment counter
    ├── 1.json                       # individual task files
    ├── 2.json
    └── ...

這從根本上就是一種去中心化的設計。領隊也只是一個多了額外工具(TeamCreate、TeamDelete、SendMessage)的 Claude 工作階段。沒有背景行程。協調是透過存取共用檔案來達成的。

在進行中的工作階段裡,如果你請 Claude 組建團隊來執行某種任務,再於另一個視窗執行以下指令,就能即時觀察檔案系統的更新。

watch -n 0.5 'tree ~/.claude/teams/ 2>/dev/null; echo "---"; tree ~/.claude/tasks/ 2>/dev/null'

例如,使用以下提示詞:

can you spawn an agent team to examine this codebase?
  - have one look for bugs
  - have one look for complexity
  - have one look for good things to call out and play devil's advocate against the other two agents

我觀察到以下結果:

teams
└── code-review
    ├── config.json
    └── inboxes
        ├── bug-hunter.json
        ├── complexity-analyst.json
        ├── devils-advocate.json
        └── team-lead.json

團隊設定

位於 ~/.claude/teams/{team-name}/config.json 的團隊設定包含一個 members 陣列,隊友會讀取它來找到彼此:

{
  "members": [
    { "name": "team-lead", "agentId": "abc-123", "agentType": "leader" },
    {
      "name": "researcher",
      "agentId": "def-456",
      "agentType": "general-purpose"
    }
  ]
}

名稱是主要的定址機制(雖然有 UUID,但並不用於路由)。所有訊息傳遞與任務指派都使用 name 欄位。

2. 共用任務清單

檔案格式

每個任務都以個別 JSON 檔案儲存在 ~/.claude/tasks/{team-name}/ 中。以下是先前工作階段留下的真實範例:

{
  "id": "1",
  "subject": "Hunt for bugs across the codebase",
  "description": "...",
  "activeForm": "Hunting for bugs",
  "owner": "bug-hunter",
  "status": "completed",
  "blocks": [],
  "blockedBy": []
}

任務結構:

欄位 型別 說明
id string 數字 ID,透過 .highwatermark 自動遞增
subject string 祈使句形式的標題(例如「執行測試」)
description string 詳細需求與驗收標準
activeForm string 現在進行式,用於旋轉指示器顯示(「正在執行測試」)
status string pending → in_progress → completed(或 deleted)
blocks string[] 被此任務阻擋的任務 ID
blockedBy string[] 此任務開始前必須先完成的任務 ID

並行控制

兩個特殊檔案負責協調:

  • .lock:一個 0 位元組的檔案,用於檔案系統層級的互斥(flock())。我在自己電腦上觀察到的 42 個任務目錄中,全都有這個檔案。
  • .highwatermark:包含單一整數(例如 "3"、"13"),代表自動遞增時下一個可用的任務 ID。

任務認領

任務認領使用檔案鎖定來避免競爭條件。隊友會優先認領 ID 最小的任務。如果任務的 blockedBy 陣列不是空的,就必須等所有阻擋它的任務都進入最終狀態,才能認領。

觀察:大多數任務目錄都是空的

我電腦上的 42 個任務目錄中,只有 5 個包含實際的任務 JSON 檔案。其餘 37 個都只有 .lock 和 .highwatermark。這很可能表示任務完成後會被清理,或者這些工作階段中,Claude 使用了內部任務清單(自任務清單功能推出後便已提供),但沒有拆分出子任務檔案。

3. 代理程式之間的通訊

信箱模式

每個代理程式在 ~/.claude/teams/{team-name}/inboxes/{agent-name}.json 都有一個 JSON 陣列檔案。以下是先前工作階段中的真實收件匣,當時領隊將工作指派給 controlplane-agent:

[
  {
    "from": "team-lead",
    "text": "{\"type\":\"task_assignment\",\"taskId\":\"1\",\"subject\":\"Phase 2: Control-plane - remove participants/presence\",\"description\":\"Remove multiplayer code from the control-plane package...\",\"assignedBy\":\"team-lead\",\"timestamp\":\"2026-02-18T02:37:16.890Z\"}",
    "timestamp": "2026-02-18T02:37:16.890Z",
    "read": false
  }
]

請注意這種 JSON 中嵌入 JSON 的編碼方式:text 欄位是 JSON 字串,內容包含序列化後的訊息物件。外層封套有 from、text、timestamp 和 read 欄位。

訊息類型

type 欄位位於 text 承載內容中,支援以下類型:

類型 方向 用途
task_assignment 領隊 → 隊友 指派任務並附上完整細節
message 任意成員 → 任意成員 傳送私訊給單一收件者
broadcast 領隊 → 全體 將相同訊息傳送給每位隊友
shutdown_request 領隊 → 隊友 要求正常關閉
shutdown_response 隊友 → 領隊 同意或拒絕關閉
plan_approval_request 隊友 → 領隊 提交計畫以供審查
plan_approval_response 領隊 → 隊友 核准或拒絕,並提供回饋
idle_notification 隊友 → 領隊 隊友的回合結束時自動傳送

傳遞機制

寫入路徑:寄件者在收件者的收件匣 JSON 陣列檔案中附加一筆新項目。

讀取路徑:收件者輪詢自己的收件匣檔案。新訊息會以合成對話回合的形式注入(看起來就像是使用者傳送的)。

廣播:就是將相同訊息寫入每位隊友的收件匣檔案。Token 成本隨團隊規模線性增加。

通訊就只是附加寫入檔案 + 讀取檔案。從傳送到接收之間的延遲,取決於收件者的輪詢間隔。

隊友間私訊的可見性

當隊友傳送私訊給另一位隊友時,傳給領隊的閒置通知中會包含一段簡短摘要。這讓領隊能了解隊友間的協作情況,而不必取得完整訊息內容。

4. 代理程式的啟動與生命週期

隊友的建立方式

每位隊友都是一個獨立的 claude CLI 行程。領隊透過 Task 工具,使用 team_name 和 name 參數來啟動隊友。啟動的行程會設定以下環境變數:

  • CLAUDE_CODE_TEAM_NAME:在啟動的隊友上自動設定
  • CLAUDE_CODE_PLAN_MODE_REQUIRED:如果需要計畫審核,則設為 true

上下文初始化

隊友會載入與任何新工作階段相同的專案上下文:

  • 工作目錄中的 CLAUDE.md 檔案
  • MCP 伺服器
  • 技能
  • 領隊提供的啟動提示詞

領隊的對話歷史不會傳給隊友。 每位隊友都從頭開始,只有啟動提示詞作為上下文。

內部實作

根據對 Claude Code v2.1.47 二進位執行檔的分析,隊友的上下文透過 AsyncLocalStorage 管理,包含以下欄位:

  • agentId、agentName、teamName
  • parentSessionId、color
  • planModeRequired

主要內部函式:

  • isTeammate() / isTeamLead():角色偵測
  • waitForTeammatesToBecomeIdle():供領隊使用的同步原語
  • getTeammateContext() / setDynamicTeamContext():執行期上下文管理

閒置偵測

每個 LLM 回合結束後,隊友都會自動進入閒置狀態,並向領隊傳送 idle_notification。這是正常的待命狀態,而非錯誤或停滯。向閒置的隊友傳送訊息就會喚醒它(下一次輪詢會讀取收件匣中的訊息)。

關閉協定

  1. 領隊向隊友傳送 shutdown_request
  2. 隊友可以同意(正常結束),也可以拒絕(提供說明並繼續工作)
  3. 透過 TeamDelete 清理團隊,移除 ~/.claude/teams/{team-name}/ 和 ~/.claude/tasks/{team-name}/
  4. 只要還有隊友處於活動狀態,清理就會失敗;必須先關閉這些隊友

權限繼承

隊友會在啟動時繼承領隊的權限模式。如果領隊執行時使用 --dangerously-skip-permissions,所有隊友也會使用。啟動後可以變更個別隊友的模式,但無法在啟動時為各個隊友分別設定。

5. 品質關卡與 Hook

Agent Teams 整合了 Claude Code 的 Hook 系統,用來把關品質:

TeammateIdle Hook

在隊友即將進入閒置狀態時觸發。結束代碼 2 會將 stderr 作為回饋傳送,並阻止隊友進入閒置,讓它繼續工作。

{
  "hook_event_name": "TeammateIdle",
  "teammate_name": "researcher",
  "team_name": "my-project"
}

TaskCompleted Hook

在任務即將被標記為完成時觸發。結束代碼 2 會阻止任務完成,並將 stderr 作為回饋傳回。

{
  "hook_event_name": "TaskCompleted",
  "task_id": "task-001",
  "task_subject": "Implement user authentication",
  "task_description": "Add login and signup endpoints",
  "teammate_name": "implementer",
  "team_name": "my-project"
}

這會在兩種情況下觸發:(1) 任何代理程式透過 TaskUpdate 明確將任務標記為完成時;或 (2) 代理程式團隊中的隊友結束回合時,仍有進行中的任務。

Hook 處理器類型

類型 說明
command Shell 指令碼。透過 stdin 接收 JSON,以結束代碼表示決策。
prompt 單回合 LLM 評估。回傳 {ok, reason}。
agent 具備讀取工具的多回合子代理程式。最多 50 回合。

6. Token 成本

當隊友以規劃模式執行時,代理程式團隊使用的 Token 約為標準工作階段的 7 倍。每位隊友都是獨立的 Claude 執行個體,各自維持完整的上下文視窗。

基準參考

  • Claude Code 平均使用成本:約 $6/開發者/天
  • 代理程式團隊:在基準之上,大致隨團隊規模成比例增加

7. 架構總覽

面向 Claude Code Agent Teams
協調基礎 平面檔案(~/.claude/tasks/、~/.claude/teams/)
任務格式 每個任務一個 JSON 檔案 + 用於認領的 .lock
訊息傳遞 JSON 收件匣檔案(附加寫入 + 輪詢)
代理程式生命週期 自行管理的 CLI 行程
工作隔離 共用工作目錄
合併策略 無(代理程式直接編輯檔案)
重試/升級處理 手動(由領隊決定,或由使用者介入)
拓樸 領隊 + 扁平化的隊友結構,支援點對點訊息傳遞
排程 自行認領(隊友取得下一個任務)
狀態持久性 僅靠檔案;不支援在行程內恢復隊友
品質關卡 Shell Hook(TeammateIdle、TaskCompleted)
Token 追蹤 僅限個別工作階段,不跨代理程式彙總
停滯偵測 手動(使用者察覺隊友已停止)
並行控制 隱含決定(團隊規模 = 隊友數量)
相依性模型 任務檔案上的 blocks/blockedBy

資料來源

官方文件

磁碟上的產物(Claude Code v2.1.47)

在 /Users/tau/.claude/ 觀察到:

  • 包含 config.json 和 inboxes/{agent-name}.json 檔案的團隊目錄
  • 包含 .lock、.highwatermark 以及個別任務 JSON 檔案的任務目錄
  • 一則從 team-lead 傳給 cp-agent 的任務指派訊息範例,時間戳記為 2026-02-18T02:37:16.890Z

二進位分析

Claude Code 二進位執行檔 v2.1.47。透過字串分析辨識出的內部函式:getTeamName、getAgentName、getAgentId、isTeammate、isTeamLead、waitForTeammatesToBecomeIdle、getTeammateContext、setDynamicTeamContext、createTeammateContext。AsyncLocalStorage 上下文欄位:agentId、agentName、teamName、parentSessionId、color、planModeRequired。

Hive 程式碼庫