mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-09-21 21:03:38 +08:00
Consolidate agent harness course into 19 lessons
This commit is contained in:
@@ -2,32 +2,34 @@
|
||||
|
||||
[English](README.md) · [中文](README.zh.md) · [日本語](README.ja.md)
|
||||
|
||||
s01 → ... → s13 → s14 → `s15` → [s16](../s16_autonomous_agents/) → s17 → s18 → s19 → s20 → s21
|
||||
s01 → ... → s13 → s14 → `s15` → [s16](../s16_mcp_plugin/) → s17 → s18 → s19
|
||||
|
||||
> *「1 つの Agent だけでは扱いきれないなら、チームメイトで分担する。」* — 永続チームメイト、メッセージ配信、協調プロトコル。
|
||||
> *「1 つの Agent で仕事全体を抱えきれないなら、チームメイトで分担する。」* — 永続チームメイト、共有タスクの Claim、任意の worktree、協調プロトコル。
|
||||
>
|
||||
> **Harness レイヤー**:チーム — 複数 Agent を並行動作させながら制御を保つ。
|
||||
> **Harness レイヤー**:Team — 複数の Agent が Lead の管理下で仕事を分担し、状態を共有する仕組み。
|
||||
|
||||
---
|
||||
|
||||
## 問題
|
||||
|
||||
Agent にバックエンド全体のリファクタリングを頼む場合、設定読み込み、認証、テストを同時に扱うことになる。1 つの Agent が順番に処理することもできるが、時間がかかり、初期の詳細は徐々にコンテキストから抜けていく。
|
||||
Agent にバックエンド全体のリファクタリングを依頼するとする。作業範囲は設定の読み込み、認証、テストにまたがる。1 つの Agent でも順番に処理できるが、時間がかかり、初期の詳細は少しずつコンテキストから抜けていく。
|
||||
|
||||
このような仕事は並列化に向いている。しかし、通常のユーザーはチーム構成ではなく目的だけを伝える:
|
||||
この仕事は並列化に向いている。ただし、ユーザーは通常、チーム構成ではなく目標を伝える:
|
||||
|
||||
```text
|
||||
このサンプルバックエンドをリファクタリングしてください。
|
||||
設定読み込み、認証ロジック、テストを整理し、
|
||||
既存インターフェースを保ったままテストを通してください。
|
||||
設定の読み込み、認証、テストを整理し、既存インターフェースを保ち、
|
||||
テストが通ることを確認してください。
|
||||
```
|
||||
|
||||
そのため Harness は、単に Agent を増やすだけでなく、次の 4 点を解決する必要がある:
|
||||
Harness は、つながった 6 つの問題を扱う必要がある:
|
||||
|
||||
1. 並列化が有効かを誰が判断し、追加 Agent の起動を誰が確認するか。
|
||||
2. チームメイトが複数の依頼にまたがって、どう身元とコンテキストを保つか。
|
||||
3. モデルに受信箱を繰り返し確認させず、結果をどう Lead へ戻すか。
|
||||
4. 終了と計画承認を、どう追跡可能で強制可能なプロトコルにするか。
|
||||
1. 並列作業が有効だと誰が判断し、追加の Agent を誰が承認するのか。
|
||||
2. 各チームメイトは、複数の割り当てをまたいで識別子とコンテキストをどう保つのか。
|
||||
3. モデルに受信箱をポーリングさせず、結果を Lead へどう返すのか。
|
||||
4. IDLE のチームメイトは、次の指示を待たずに ready task を引き受けられるか。
|
||||
5. 並列編集が衝突し得る時、タスクはどの作業ディレクトリを使うのか。
|
||||
6. shutdown と計画承認を、追跡できて実際に制約をかけるプロトコルにするにはどうするか。
|
||||
|
||||
---
|
||||
|
||||
@@ -35,24 +37,25 @@ Agent にバックエンド全体のリファクタリングを頼む場合、
|
||||
|
||||

|
||||
|
||||
s15 は単一 Agent の Harness の外側に、Lead が管理するチームランタイムを追加する:
|
||||
s15 は、単一 Agent の Harness に Lead 管理のチームランタイムを加える:
|
||||
|
||||
- **Lead** はユーザーとの会話を維持し、分担案を提示して確認を待つ。
|
||||
- **チームメイト** は独立した Agent Loop をバックグラウンドスレッドで実行し、作業後は IDLE になる。
|
||||
- **MessageBus** はファイル受信箱を通して、通常メッセージ、結果、制御イベントを運ぶ。
|
||||
- **ランタイム配信** は Lead の受信箱を消費し、チームイベントを次のターンへ注入する。
|
||||
- **協調プロトコル** は `type`、`request_id`、状態遷移で終了と計画承認を扱う。
|
||||
- **計画ゲート** は、必要な計画が承認されるまで `bash` と `write_file` を遮断する。
|
||||
- **Lead** はユーザーとの会話を担当し、分担案を示して確認を待つ。
|
||||
- **チームメイト** は独立した Agent Loop を実行し、WORK と IDLE を行き来する。
|
||||
- **MessageBus** は、ファイルベースの受信箱で通常メッセージ、結果、制御イベントを運ぶ。
|
||||
- **ランタイム配信** は Lead の受信箱を消費し、チームイベントを次のターンへ追加する。
|
||||
- **共有タスクボード** により、IDLE のチームメイトは ready task を探し、ロック下で Claim できる。
|
||||
- **任意の worktree** は、必要なタスクだけを別の作業ディレクトリへ紐付ける。紐付けのないタスクは通常のリポジトリディレクトリを使う。
|
||||
- **型付きプロトコルと計画ゲート** は shutdown と承認状態を明示し、必要な計画が承認されるまで変更系ツールを止める。
|
||||
|
||||
モデルはタスクを理解して分担を決める。コードは配信、ライフサイクル、プロトコル制約を担う。
|
||||
これらはすべて Team Harness レイヤーの一部である。タスク発見のために別の Agent Loop は要らず、worktree が別種の Agent を作るわけでもない。
|
||||
|
||||
---
|
||||
|
||||
## 仕組み
|
||||
|
||||
### 1. Lead はチーム案を示し、確認を待つ
|
||||
### 1. Lead はチーム案を示し、ユーザーの確認を待つ
|
||||
|
||||
チームメイトの起動は、コスト、並行度、ワークスペースを書き換える主体を変える。この境界を通常のツール呼び出しの中に隠してはいけない。Lead の system prompt は次のように定める:
|
||||
チームメイトを起動すると、コスト、並行度、ワークスペースを編集できる主体が変わる。Lead のシステムプロンプトは、その境界を明示する:
|
||||
|
||||
```python
|
||||
"When parallel work would help, first propose a small team with clear "
|
||||
@@ -60,35 +63,35 @@ s15 は単一 Agent の Harness の外側に、Lead が管理するチームラ
|
||||
"spawn_teammate before the user confirms."
|
||||
```
|
||||
|
||||
最初の依頼に対して、Lead はまず分担案だけを返す:
|
||||
最初の要求に対して、Lead は分担案だけを示す:
|
||||
|
||||
```text
|
||||
次の 3 方向で並行処理することを提案します。
|
||||
- config:設定読み込みの整理
|
||||
- auth:認証ロジックのリファクタリング
|
||||
- tests:回帰テストの追加
|
||||
3 つの領域を並行して進めることを提案します:
|
||||
- config:設定の読み込みを整理
|
||||
- auth:認証をリファクタリング
|
||||
- tests:回帰テストを追加
|
||||
|
||||
確認後にチームメイトを起動します。
|
||||
```
|
||||
|
||||
ユーザーが「始めてください」と返した後で、Lead は `spawn_teammate` を呼ぶ。ユーザーが目的を示し、Lead がチームを設計し、ユーザーが実行境界を確認する。
|
||||
ユーザーが「始めてください」と返した後、Lead は `spawn_teammate` を呼べる。ユーザーが目標を示し、Lead がチームを設計し、ユーザーが実行境界を確認する。
|
||||
|
||||
### 2. 各チームメイトは独立したループを持つ
|
||||
|
||||
s06 の Subagent は 1 回限りの呼び出しだが、チームメイトは永続する実行単位である:
|
||||
s06 の subagent は 1 回限りの呼び出しである。チームメイトは永続する実行単位だ:
|
||||
|
||||
| | s06 Subagent | s15 チームメイト |
|
||||
| | s06 Subagent | s15 Teammate |
|
||||
|---|---|---|
|
||||
| ライフサイクル | 1 回の呼び出し後に終了 | 終了要求まで `WORK → IDLE → WORK` |
|
||||
| コンテキスト | 1 つのタスクだけ | 複数の依頼をまたいで保持 |
|
||||
| 通信 | 1 回だけ結果を返す | メッセージを受け取り、イベントを送る |
|
||||
| 協調 | 一方向の委任 | Lead との双方向協調 |
|
||||
| ライフサイクル | 1 回の呼び出し後に終了 | shutdown まで `WORK → IDLE → WORK` |
|
||||
| コンテキスト | 1 つのタスクにだけ存在 | 割り当てをまたいで保持 |
|
||||
| 通信 | 1 回だけ結果を返す | メッセージを受け取りイベントを送る |
|
||||
| 協調 | 一方向の委譲 | Lead との双方向協調 |
|
||||
|
||||
`spawn_teammate_thread()` はチームメイトごとに system prompt、messages、ツールを作り、daemon thread でループを実行する。Lead はチームメイトの終了を待たずに、別の依頼や結果を調整できる。
|
||||
`spawn_teammate_thread()` は、各チームメイト専用のシステムプロンプト、messages、ツール、現在の作業ディレクトリ状態を用意し、daemon thread でループを実行する。チームメイトの作業中も Lead は調整を続けられる。`lead` と `agent` はランタイム識別子として予約されるが、`MessageBus` はコーディネーターの受信箱として `lead` を引き続き受け付ける。
|
||||
|
||||
### 3. MessageBus は通信をモデルのコンテキスト外に置く
|
||||
|
||||
Lead とチームメイトが同じ messages 配列を共有すると、あるチームメイトのツール結果が別のチームメイトの推論へ混ざる。`MessageBus` は各 Agent に `.mailboxes/<name>.jsonl` 受信箱を与える:
|
||||
Lead とチームメイトは同じ messages 配列を共有できない。共有すると、あるチームメイトのツール結果が別のチームメイトの推論へ混ざる。`MessageBus` は Agent ごとに `.mailboxes/<name>.jsonl` 受信箱を用意する:
|
||||
|
||||
```python
|
||||
class MessageBus:
|
||||
@@ -102,21 +105,27 @@ class MessageBus:
|
||||
"metadata": metadata or {},
|
||||
}
|
||||
with self._changed:
|
||||
append_jsonl(self._path(to_agent), msg)
|
||||
with open(self._path(to_agent), "a") as f:
|
||||
f.write(json.dumps(msg) + "\n")
|
||||
self._changed.notify_all()
|
||||
|
||||
def wait_for_messages(self, agent):
|
||||
def wait_for_messages(self, agent, timeout=None):
|
||||
deadline = None if timeout is None else time.monotonic() + timeout
|
||||
with self._changed:
|
||||
while not self.peek(agent):
|
||||
self._changed.wait()
|
||||
remaining = (None if deadline is None
|
||||
else deadline - time.monotonic())
|
||||
if remaining is not None and remaining <= 0:
|
||||
return []
|
||||
self._changed.wait(remaining)
|
||||
return self._read_unlocked(agent)
|
||||
```
|
||||
|
||||
ロックは複数スレッドによる受信箱ファイルの破損を防ぐ。`Condition` により、IDLE のチームメイトはポーリングせずイベント到着まで待機できる。
|
||||
ロックは、チームメイトによる受信箱ファイルの並行アクセスを保護する。`Condition` はメッセージ到着時にチームメイトを起こし、IDLE 中の短い timeout にも使える。
|
||||
|
||||
### 4. 受信イベントはランタイムが自動配信する
|
||||
### 4. 受信イベントはランタイムが配信する
|
||||
|
||||
`read_inbox()` はメッセージを読み、受信箱ファイルを削除する。そのため Lead の消費入口は `consume_lead_inbox()` だけにする:
|
||||
`read_inbox()` は受信箱ファイルを読み取って削除するため、Lead 側の消費処理は `consume_lead_inbox()` だけにする:
|
||||
|
||||
```python
|
||||
def consume_lead_inbox():
|
||||
@@ -127,33 +136,165 @@ def consume_lead_inbox():
|
||||
return messages
|
||||
```
|
||||
|
||||
メインループのイベントスレッドは、新しいメッセージが届くと Lead を起こす:
|
||||
メインループの隣で動くイベントスレッドが、新しいメッセージの到着時に Lead を起こす:
|
||||
|
||||
```text
|
||||
MessageBus → consume_lead_inbox
|
||||
→ プロトコル状態を更新
|
||||
→ [Team events] を history へ注入
|
||||
→ [Team events] を history に追加
|
||||
→ Lead の次ターンを開始
|
||||
```
|
||||
|
||||
`check_inbox` はモデルのツールではない。メッセージの到着はランタイムの責務であり、モデルはコンテキストへ配信済みのイベントだけを処理する。
|
||||
`check_inbox` はモデルのツールではない。メッセージの到着と消費はランタイムが担当し、モデルはコンテキストへ配信済みのイベントを処理する。
|
||||
|
||||
### 5. 結果と IDLE は別のイベント
|
||||
### 5. 結果と IDLE は別のイベントである
|
||||
|
||||
チームメイトが 1 件の作業を終えると、ランタイムは次の順序で 2 つのイベントを送る:
|
||||
チームメイトが 1 つの割り当てを終えると、ランタイムは 2 つのイベントを順に送る:
|
||||
|
||||
```text
|
||||
result: "認証をリファクタリングし、関連テストが通りました。"
|
||||
idle_notification: "Waiting for more work."
|
||||
```
|
||||
|
||||
`result` は「今回の作業で何が得られたか」、`idle_notification` は「新しい仕事を受けられるか」を表す。1 つの曖昧な「done」では両者を区別できない。
|
||||
`result` は「この割り当てで何ができたか」、`idle_notification` は「このチームメイトが次の仕事を受けられるか」を表す。曖昧な「完了」だけでは、両方の状態を表せない。
|
||||
|
||||
IDLE になったチームメイトは終了しない。通常メッセージで WORK に戻り、`shutdown_request` で終了ハンドシェイクを始める。
|
||||
IDLE のチームメイトは終了しない。直接メッセージか ready task を受けると WORK に戻り、`shutdown_request` を受けると段階的な shutdown handshake を始める。
|
||||
|
||||
### 6. 制御メッセージには型と request_id を使う
|
||||
### 6. IDLE は受信箱を先に確認し、その後 ready task を探す
|
||||
|
||||
通常の協調は自由文でよいが、終了と承認を意図の推測に任せてはいけない。制御イベントは構造化する:
|
||||
IDLE ではメッセージを優先し、その後に共有タスクボードを確認する:
|
||||
|
||||
```python
|
||||
while True:
|
||||
inbox = BUS.wait_for_messages(name, IDLE_SCAN_INTERVAL)
|
||||
if inbox:
|
||||
should_stop = handle_messages(inbox)
|
||||
if should_stop or messages[-1]["role"] == "user":
|
||||
break
|
||||
continue
|
||||
|
||||
task = claim_next_task(name)
|
||||
if task:
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": f"[Auto-claimed task {task.id}] {task.subject}",
|
||||
})
|
||||
break
|
||||
```
|
||||
|
||||
shutdown、計画承認、Lead からの直接指示は、空き時間に見つけた仕事より先に扱う。メッセージも ready task もなければ、チームメイトは IDLE を続ける。別のチームメイトが前提タスクを完了すると、blocked task が ready になることもある。
|
||||
|
||||
### 7. 発見と Claim を分け、Claim はアトミックに行う
|
||||
|
||||
走査は候補を探すだけで、状態を変更しない:
|
||||
|
||||
```python
|
||||
def scan_unclaimed_tasks() -> list[Task]:
|
||||
return [
|
||||
task for task in list_tasks()
|
||||
if task.status == "pending"
|
||||
and task.owner is None
|
||||
and can_start(task.id)
|
||||
]
|
||||
```
|
||||
|
||||
候補一覧は一時点の snapshot にすぎない。別のチームメイトも同じタスクを見る可能性があるため、所有権の変更は `task_lock` で保護した `claim_task()` 内で行う:
|
||||
|
||||
```python
|
||||
def claim_task(task_id: str, owner: str) -> str:
|
||||
with task_lock:
|
||||
task = load_task(task_id)
|
||||
if task.status != "pending" or task.owner is not None:
|
||||
return "Task is no longer available"
|
||||
if _owner_in_progress(owner):
|
||||
return "Owner must complete its current task first"
|
||||
if not can_start(task_id):
|
||||
return "Task is blocked"
|
||||
cwd, error = task_worktree_cwd(task)
|
||||
if error:
|
||||
return f"Cannot claim {task_id}: {error}"
|
||||
task.owner = owner
|
||||
task.status = "in_progress"
|
||||
save_task(task)
|
||||
teammate_assignments[owner] = {"task_id": task.id, "cwd": cwd}
|
||||
return f"Claimed {task.id}"
|
||||
```
|
||||
|
||||
複数のチームメイトが同じ候補を発見しても、`in_progress` へ進められる Claim は 1 つだけである。現在のタスクを完了するまで、チームメイトは次のタスクを Claim できない。worktree の紐付けが壊れている場合、リポジトリディレクトリへ戻さず Claim を失敗させる。
|
||||
|
||||
### 8. Claim した仕事は同じ WORK ループを再利用する
|
||||
|
||||
Claim に成功すると、ランタイムはタスク ID、件名、説明をチームメイトの messages へ追加する:
|
||||
|
||||
```text
|
||||
ready task が現れる
|
||||
→ IDLE のチームメイトが発見
|
||||
→ claim_task が owner と in_progress を記録
|
||||
→ タスクがチームメイトの messages に入る
|
||||
→ WORK
|
||||
→ complete_task
|
||||
→ result + idle_notification
|
||||
→ IDLE
|
||||
```
|
||||
|
||||
チームメイトは、Lead が直接割り当てた時と同じモデル呼び出し、ファイルツール、Shell、計画ゲート、結果通知、shutdown protocol を使う。タスク発見は、既存の WORK ループへの別の入口である。
|
||||
|
||||
### 9. タスクがツールの作業ディレクトリを選ぶ
|
||||
|
||||
`Task.worktree` は任意フィールドである:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Task:
|
||||
id: str
|
||||
subject: str
|
||||
description: str
|
||||
status: str
|
||||
owner: str | None
|
||||
blockedBy: list[str]
|
||||
worktree: str | None = None
|
||||
```
|
||||
|
||||
並列編集を別ディレクトリに分けたい時、Lead は worktree を作成してタスクへ紐付けられる:
|
||||
|
||||
```python
|
||||
create_worktree(name="auth-refactor", task_id="task_1234")
|
||||
```
|
||||
|
||||
`create_worktree` は Lead 専用ツールである。pending、owner なし、worktree 未設定のタスクを受け取り、名前、パス、ブランチ、Git registry を確認する。checkout の作成後にだけタスクへ紐付ける。Git が失敗を返しても branch や登録済み checkout が残った場合は partial operation を報告し、task は未紐付けのまま、それらを manual recovery 用に保持する。チームメイトが使うのはタスクツールとファイルツールである。
|
||||
|
||||
Claim 時に、解決済みのディレクトリを `teammate_assignments` へ保存する。チームメイトの `bash`、`read_file`、`write_file` wrapper は assignment からディレクトリを読む。worktree のないタスクは `WORKDIR` に解決されるため、worktree は opt-in である:
|
||||
|
||||
```python
|
||||
cwd, error = task_worktree_cwd(task)
|
||||
if not error:
|
||||
teammate_assignments[owner] = {
|
||||
"task_id": task.id,
|
||||
"cwd": cwd,
|
||||
}
|
||||
```
|
||||
|
||||
`complete_task(task_id, owner)` は、呼び出し元が進行中タスクの owner か確認する。ランタイムが assignment を削除するのは完了に成功した時だけである。失敗時はタスクのディレクトリを維持し、チームメイトが修正して再試行できるようにする。タスクの `worktree` 紐付けは checkout を削除するまで残る。
|
||||
|
||||
> Worktree が分離するのは Git の作業ディレクトリとブランチであり、sandbox ではない。Shell コマンドは親プロセスに許可されたパスやリソースへアクセスできる。
|
||||
|
||||
### 10. Worktree のクリーンアップはデフォルトで作業を残す
|
||||
|
||||
モデル向けの `remove_worktree(name)` tool は、`pending` または `in_progress` のタスクに紐付いた worktree の削除を拒否する。タスク完了後も tracked、untracked、ignored file をすべて未コミットデータとして扱い、clean な checkout だけを `--force` なしで削除する。
|
||||
|
||||
低レベルの Python helper は、host が別途ユーザーの明示的な確認を得た場合のために `discard_changes=True` を残すが、この parameter はモデルの tool schema にはない。変更のある worktree は削除せず、user が確認できる状態で残す。どちらの削除経路でも `wt/<name>` ブランチはリポジトリに残り、upstream のない clean な local commit も保持される。削除成功後は checkout が存在しないため、タスクの worktree 紐付けを解除する。
|
||||
|
||||
```text
|
||||
clean worktree → ディレクトリを削除し、wt/<name> ブランチは保持
|
||||
changed worktree → model tool は拒否し、保持か破棄かを user が決める
|
||||
pending/running task → 削除を拒否
|
||||
```
|
||||
|
||||
タスク完了と worktree cleanup も分かれている。`complete_task` はタスク結果を記録し、Lead はその後に worktree を確認、merge、keep、remove できる。
|
||||
|
||||
### 11. 制御メッセージには型と request_id を使う
|
||||
|
||||
通常の協調には自由形式のテキストを使えるが、shutdown と承認を意図の推測に任せるべきではない。これらは構造化メッセージを使う:
|
||||
|
||||

|
||||
|
||||
@@ -171,22 +312,22 @@ class ProtocolState:
|
||||
pending_requests: dict[str, ProtocolState] = {}
|
||||
```
|
||||
|
||||
終了プロトコルは次の経路を通る:
|
||||
shutdown の流れは次の通り:
|
||||
|
||||
```text
|
||||
Lead が pending の shutdown request を作る
|
||||
→ shutdown_request(request_id) をチームメイトへ送る
|
||||
→ チームメイトが現在の手順を終える
|
||||
→ shutdown_response(request_id) を Lead へ返す
|
||||
→ request_id で元の要求を特定する
|
||||
→ pending が approved になり、チームメイトループが終了する
|
||||
→ shutdown_request(request_id) がチームメイトの受信箱に入る
|
||||
→ チームメイトが現在のステップを終える
|
||||
→ shutdown_response(request_id) が Lead へ戻る
|
||||
→ request_id で元の request を特定する
|
||||
→ pending が approved になり、チームメイトの loop が終了する
|
||||
```
|
||||
|
||||
ID は要求と応答を対応付け、型は誤った応答による状態変更を防ぎ、状態は重複応答の再適用を防ぐ。
|
||||
ID は応答を 1 つの request に対応付け、型は不一致の応答による状態変更を防ぎ、status は同じ応答の二重適用を防ぐ。
|
||||
|
||||
### 7. 計画承認は実行も制約する
|
||||
### 12. 計画承認は実行も制約する
|
||||
|
||||
計画プロトコルは逆方向に流れる:
|
||||
計画プロトコルは逆方向に進む:
|
||||
|
||||
```text
|
||||
Lead → plan_request
|
||||
@@ -194,7 +335,7 @@ Lead → plan_request
|
||||
Lead → plan_approval_response(request_id, approve, feedback)
|
||||
```
|
||||
|
||||
「承認まで待つ」と伝えるだけでは確実なゲートにならない。そこでツール dispatch が計画状態を検査する:
|
||||
ツール dispatch がゲートを強制する:
|
||||
|
||||
```python
|
||||
def _run_teammate_tool(name, block, handlers):
|
||||
@@ -206,32 +347,38 @@ def _run_teammate_tool(name, block, handlers):
|
||||
return handlers[block.name](**block.input)
|
||||
```
|
||||
|
||||
状態が `required`、`pending`、`rejected` の間、チームメイトはファイルを読み、計画を提出または修正できるが、Shell 実行やファイル書き込みはできない。承認応答で `approved` になった後にだけツールが解放される。
|
||||
状態が `required`、`pending`、`rejected` の間、チームメイトはファイルを読み、計画を提出または修正できるが、Shell コマンドの実行とファイルの書き込みはできない。承認応答で状態が `approved` になると、ツールを使えるようになる。
|
||||
|
||||
---
|
||||
|
||||
## 一連の実行例
|
||||
|
||||
```text
|
||||
s15 >> このサンプルバックエンドをリファクタリングしてください。
|
||||
設定読み込み、認証、テストを整理し、
|
||||
既存インターフェースを保ってテストを通してください。
|
||||
s15 >> バックエンドのリファクタリングを共有タスクボードに分解し、
|
||||
設定、認証、テストを可能な範囲で並行実行してください。
|
||||
認証には worktree を使い、既存インターフェースを保ち、
|
||||
テストが通ることを確認してください。
|
||||
|
||||
Lead: config、auth、tests の 3 方向で並行処理することを提案します。
|
||||
チームを開始しますか?
|
||||
Lead:config、auth、tests の 3 領域に分けることを提案します。
|
||||
チームを起動しますか?
|
||||
|
||||
s15 >> 始めてください
|
||||
|
||||
[teammate] config spawned
|
||||
[teammate] auth spawned
|
||||
[teammate] tests spawned
|
||||
[bus] auth → lead (result) ...
|
||||
[bus] auth → lead (idle_notification) ...
|
||||
[task] config created
|
||||
[task] auth created → worktree auth-refactor
|
||||
[task] tests created
|
||||
[teammate] alice spawned
|
||||
[teammate] bob spawned
|
||||
[claim] alice → config (cwd: repository)
|
||||
[claim] bob → auth (cwd: .worktrees/auth-refactor)
|
||||
[complete] auth
|
||||
[bus] bob → lead (result) ...
|
||||
[bus] bob → lead (idle_notification) ...
|
||||
[wake: 2 team events → new turn]
|
||||
Lead: 認証の結果を受け取りました。残りの作業も調整します。
|
||||
Lead:認証タスクの結果を受け取りました。残りの作業を調整します。
|
||||
```
|
||||
|
||||
端末には、ユーザー要求、Lead の分担、起動、メッセージ、結果、IDLE、終了イベントが表示される。ユーザーが Lead を指名したり、受信箱の確認を頼んだりする必要はない。
|
||||
ターミナルには、ユーザーの要求、Lead の提案、タスク状態、Claim、選択されたディレクトリ、結果、IDLE 遷移、制御イベントが表示される。ユーザーが Lead を指定したり、受信箱の確認を依頼したりする必要はない。
|
||||
|
||||
---
|
||||
|
||||
@@ -239,13 +386,15 @@ Lead: 認証の結果を受け取りました。残りの作業も調整しま
|
||||
|
||||
| コンポーネント | s14 | s15 |
|
||||
|---|---|---|
|
||||
| Agent | 1 つ | 1 つの Lead + 永続チームメイト |
|
||||
| ユーザーフロー | 依頼を直接実行 | チーム案を提示してから起動を確認 |
|
||||
| 通信 | なし | ファイル受信箱 + 自動イベント配信 |
|
||||
| Agent | 1 つの Agent | 1 つの Lead と永続チームメイト |
|
||||
| ユーザーフロー | 要求を実行 | チーム案を示してから起動確認 |
|
||||
| 通信 | なし | ファイル受信箱とランタイム配信 |
|
||||
| ライフサイクル | 1 つのループ | チームメイトの `WORK / IDLE / shutdown` |
|
||||
| 共有作業 | Lead の既存タスクツール | IDLE 走査とチームメイトのアトミックな Claim |
|
||||
| 作業ディレクトリ | リポジトリの `WORKDIR` | デフォルトは `WORKDIR`、タスクごとに worktree を選択可能 |
|
||||
| 結果通知 | 現在の Agent の出力 | `result` と `idle_notification` を分離 |
|
||||
| 制御 | なし | 終了と計画承認プロトコル |
|
||||
| 強制 | チーム制約なし | 必須計画が変更系ツールをゲート |
|
||||
| 制御 | なし | 型付き shutdown と計画承認プロトコル |
|
||||
| 強制 | チーム向け制約なし | 必須計画が変更系ツールをゲート |
|
||||
|
||||
---
|
||||
|
||||
@@ -256,12 +405,12 @@ cd learn-claude-code
|
||||
python s15_agent_teams/code.py
|
||||
```
|
||||
|
||||
まず通常の依頼を入力する:
|
||||
通常の要求を入力する:
|
||||
|
||||
```text
|
||||
このサンプルバックエンドをリファクタリングしてください。
|
||||
設定読み込み、認証ロジック、テストを整理し、
|
||||
既存インターフェースを保ったままテストを通してください。
|
||||
バックエンドのリファクタリングを共有タスクボードへ分解し、依存関係が
|
||||
許す範囲で設定、認証、テストを並行実行してください。認証には worktree
|
||||
を使い、既存インターフェースを維持して、最後に結果をまとめてください。
|
||||
```
|
||||
|
||||
Lead がチーム案を示したら、次のように返す:
|
||||
@@ -270,14 +419,16 @@ Lead がチーム案を示したら、次のように返す:
|
||||
始めてください
|
||||
```
|
||||
|
||||
`spawned`、`result`、`idle_notification`、`plan_approval_*`、`shutdown_*` の各イベントと、`.mailboxes/` のファイルが生成・消費される流れを確認する。
|
||||
`.tasks/` が `pending`、`in_progress`、`completed` と変化する様子、`.mailboxes/` が `result` と `idle_notification` を配信する様子、紐付けたタスクにだけ `.worktrees/` が作られることを確認する。直接メッセージがタスクボード走査より優先されることと、`complete_task` の失敗後もチームメイトの作業ディレクトリが変わらないことも確認できる。
|
||||
|
||||
---
|
||||
|
||||
## 次へ
|
||||
|
||||
s15 では、Lead が各チームメイトへ明示的に仕事を割り当てる。次のセッションでは共有タスクボードを IDLE のチームメイトに公開し、実行可能な仕事を自ら見つけて claim できるようにする。
|
||||
チームランタイムは、委譲、共有タスクの Claim、任意の作業ディレクトリを扱えるようになった。ただし、ツールは今も Python コードへ直接定義している。
|
||||
|
||||
次へ:[s16 Autonomous Agents](../s16_autonomous_agents/)。
|
||||
次のレッスンでは、標準の発見・呼び出しプロトコルを使って外部ツールへ接続する。
|
||||
|
||||
<!-- translation-sync: zh@v2, en@v2, ja@v2 -->
|
||||
次へ:[s16 MCP Tools](../s16_mcp_plugin/)。
|
||||
|
||||
<!-- translation-sync: zh@v3, en@v3, ja@v3 -->
|
||||
|
||||
Reference in New Issue
Block a user