# Phase 7: Multi-Agent Team System — Specification

**Priority:** P6 · **Effort:** 1–2 weeks · **Dependencies:** Phases 1, 4, 6 (partial)  
**Reference:** `claude-code-main/src/utils/swarm/`, `src/tasks/InProcessTeammateTask/`, `src/tools/shared/spawnMultiAgent.ts`

---

## 1. Problem Statement

Claude Code has a full multi-agent collaboration system where a "lead" agent can spawn "teammate" agents that run in parallel, communicate via a mailbox system, and coordinate on complex tasks. Agents can:

- Be spawned with names and identities (`name`, `team_name`)
- Communicate via `SendMessage` (inter-agent messaging)
- Run in separate tmux panes, iTerm2 panes, or in-process
- Have their permission modes inherited from the lead
- Be tracked in team files for persistence and reconnection

pi-subagents can only spawn independent background agents with no coordination or communication between them.

---

## 2. Design

### 2.1. Architecture Overview

```
┌─────────────────────────────────────────────┐
│              Lead Agent (parent)              │
│  spawns teammates via Agent(tool) with       │
│  Agent(... { name, team_name })               │
├─────────────────────────────────────────────┤
│           Mailbox System                      │
│  Each agent has an inbox/outbox.              │
│  SendMessage tool writes to recipient inbox.  │
│  Agents poll their inbox between turns.       │
├─────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐      │
│ │Teammate A│ │Teammate B│ │Teammate C│ ...  │
│ │ (in-proc)│ │ (in-proc)│ │ (in-proc)│      │
│ └──────────┘ └──────────┘ └──────────┘      │
├─────────────────────────────────────────────┤
│         Team File (.pi/teams/<name>.json)     │
│  Members, identities, join times, subscrip-   │
│  tions, backend type. Survives /resume.      │
└─────────────────────────────────────────────┘
```

### 2.2. MVP Scope (Phase 7a)

Start with **in-process teammates only** — same Node.js process, AsyncLocalStorage isolation. Skip tmux/iTerm2 backends initially.

### 2.3. Spawning

The `Agent` tool gains two new parameters:

```typescript
{
  name: Type.Optional(Type.String({ description: "Name for the spawned agent. Makes it addressable via SendMessage({to: name})." })),
  team_name: Type.Optional(Type.String({ description: "Team name. Uses current team context if omitted." })),
}
```

When `name` is provided, the agent is spawned as a teammate instead of a fire-and-forget background agent:
1. A team file is created (or appended to) at `.pi/teams/<team_name>.json`
2. A mailbox directory is created at `.pi/teams/<team_name>/mailboxes/<name>/`
3. The agent runs in-process with an AsyncLocalStorage-based isolated context
4. The agent's `Agent` tool is removed (teammates cannot spawn sub-agents in MVP)

### 2.4. Inter-Agent Messaging

New tool: `SendMessage`

```typescript
pi.registerTool(defineTool({
  name: "SendMessage",
  parameters: Type.Object({
    to: Type.String({ description: "Name of the recipient agent." }),
    message: Type.String({ description: "The message to send." }),
  }),
  execute: async (_, params) => {
    // Write to recipient's mailbox
    // Return { status: "delivered" }
  },
}));
```

Messaging flow:
1. Agent A calls `SendMessage({ to: "agent-b", message: "..." })`
2. Message is written to `agent-b`'s inbox (`.pi/teams/<team>/mailboxes/agent-b/inbox/`)
3. `agent-b`'s execution loop checks for pending messages between turns
4. Messages appear as user messages in `agent-b`'s conversation

### 2.5. Team File

```json
{
  "version": 1,
  "name": "my-team",
  "createdAt": "2026-05-12T00:00:00.000Z",
  "leadAgentId": "lead@my-team",
  "members": [
    {
      "agentId": "researcher@my-team",
      "name": "researcher",
      "agentType": "Explore",
      "model": "claude-haiku-4-5-20251001",
      "color": "blue",
      "joinedAt": 1700000000000,
      "subscriptions": [],
      "backendType": "in-process"
    }
  ]
}
```

### 2.6. Agent Identity Format

Agents use `name@team_name` as their agent ID (e.g., `researcher@my-team`). This is:
- Deterministic (same name + team = same ID)
- Addressable (SendMessage uses the `name` part)
- Unique within a team

### 2.7. In-Process Isolation

In-process teammates use `AsyncLocalStorage` to isolate their tool context. Each teammate gets:
- Its own copy of the tool pool
- Its own file state cache
- Its own abort controller
- Its own conversation history
- Shared API connection (not duplicated)

---

## 3. API Changes

### 3.1. Agent Tool — New Parameters

```typescript
name: Type.Optional(Type.String({
  description: "Name for this agent. Makes it addressable via SendMessage({to: name}).",
})),
team_name: Type.Optional(Type.String({
  description: "Team name. Creates or joins a team. Required when name is set.",
})),
```

### 3.2. New Tool: `SendMessage`

```typescript
name: "SendMessage"
parameters: {
  to: String  // Recipient agent name
  message: String  // Message content
}
returns: {
  status: "sent" | "not_found" | "stopped"
}
```

### 3.3. New Tool: `SpawnTeam` (optional MVP)

```typescript
name: "SpawnTeam"
parameters: {
  team_name: String
  prompt: String // Initial directive for all members
}
```

---

## 4. Integration Points

| File | Change |
|---|---|
| `src/index.ts` | New `SendMessage` tool, team-aware Agent tool |
| `src/types.ts` | Team types, mailbox types, new tool params |
| `src/team-manager.ts` | **CREATE** — team file management, member tracking |
| `src/mailbox.ts` | **CREATE** — inbox/outbox message delivery |
| `src/in-process-teammate.ts` | **CREATE** — in-process agent isolation and lifecycle |
| `src/index.ts` | /agents menu updates for team view |

---

## 5. Edge Cases

| Case | Behavior |
|---|---|
| Team file missing | Created on first teammate spawn |
| Duplicate teammate name | Numeric suffix appended (researcher → researcher-2) |
| SendMessage to unknown name | Returns `"not_found"` |
| Teammate completes | Team file updated, mailbox cleaned up |
| Lead agent completes | Team disbanded |
| /resume with active team | Teammates restored from team file |
| Teammate spawns from teammate | Refused (MVP limitation — leads only) |
| Name without team_name | Runs as normal background agent (no team) |

---

## 6. Testing Plan

| Test | What it verifies |
|---|---|
| Spawn teammate with name | Agent registered in team file |
| SendMessage delivery | Message written to mailbox, readable by recipient |
| Teammate receives message | Pending messages appear in conversation |
| Duplicate name handling | `researcher` → `researcher-2` |
| Team file creation | `.pi/teams/<name>.json` created with correct schema |
| Team file persistence | Survives /resume, teammates re-register |
| In-process isolation | Teammate has own tool context, doesn't pollute parent |
| Teammate cannot spawn | Agent tool blocked for non-lead agents |
