Skip to main content
Module 2: Multi-Agent 3 / 6
Intermediate Session 9 Agent Teams Communication

Agent Teams & Communication

Explore how TeammateManager and JSONL message bus enable multi-agent collaboration.

March 20, 2026 20 min read

What You’ll Learn

Subagents (Session 4) solve the context isolation problem for individual subtasks. But what about sustained, ongoing collaboration? What if you need one agent writing code while another reviews it, both maintaining their own context over many turns?

This is where Agent Teams come in — multiple Claude Code instances running side by side, each with its own context window, communicating through a shared message bus.

By the end of this session, you’ll understand:

  • How Agent Teams differ from subagents
  • The TeammateManager coordination layer
  • How the JSONL message bus enables inter-agent communication
  • Team topology: names, roles, and messaging patterns
  • Practical setups for common multi-agent workflows

The Problem

Subagents are powerful but ephemeral. They spawn, do a task, return a result, and disappear. Their context is discarded. This is perfect for one-off research or exploration, but it falls apart for ongoing collaboration:

Subagent Limitation:

  Turn 1: Spawn reviewer agent → reviews code → result → context gone
  Turn 2: Spawn reviewer agent → has no memory of Turn 1 review
  Turn 3: Spawn reviewer agent → starts from scratch again

  Each review is isolated. The reviewer can't track
  whether its previous feedback was addressed.

You also run into context pollution at scale. If you’re building a complex feature, the implementer’s context fills up with code, while review feedback piles on top. Eventually, the single context window can’t hold both the implementation details and the review history.

What you need is persistent agents with independent contexts that can talk to each other:

Agent Teams:

  ┌─────────────────┐     ┌─────────────────┐
  │  Implementer    │     │  Reviewer        │
  │  (own context)  │◄───►│  (own context)   │
  │                 │     │                  │
  │  Remembers all  │     │  Remembers all   │
  │  code written   │     │  review feedback │
  └─────────────────┘     └─────────────────┘
         │                        │
         └──────────┬─────────────┘

            ┌───────▼────────┐
            │  JSONL Message │
            │  Bus (shared)  │
            └────────────────┘

How It Works

Enabling Agent Teams

Agent Teams is an experimental feature activated with an environment variable:

export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1

Once enabled, you can create teammates from within a Claude Code session using keyboard shortcuts:

ShortcutAction
Shift+Up / Shift+DownSelect a teammate
Shift+TabEnter delegate mode (send a task to a teammate)
Ctrl+TView the task list across all teammates

Each teammate runs as a separate Claude Code process with its own terminal, its own context window, and its own conversation history.

TeammateManager

The TeammateManager is the coordination layer that tracks all active teammates in a session. It maintains a registry of who’s active, their roles, and their communication channels:

┌──────────────────────────────────────────────────┐
│                TeammateManager                    │
│                                                   │
│  Registry:                                        │
│  ┌─────────────────────────────────────────┐     │
│  │  Name: "implementer"                    │     │
│  │  Role: "Write and modify source code"   │     │
│  │  Status: active                         │     │
│  │  Context: [independent message array]   │     │
│  ├─────────────────────────────────────────┤     │
│  │  Name: "reviewer"                       │     │
│  │  Role: "Review code and suggest fixes"  │     │
│  │  Status: active                         │     │
│  │  Context: [independent message array]   │     │
│  ├─────────────────────────────────────────┤     │
│  │  Name: "tester"                         │     │
│  │  Role: "Write and run tests"            │     │
│  │  Status: active                         │     │
│  │  Context: [independent message array]   │     │
│  └─────────────────────────────────────────┘     │
│                                                   │
│  Message Bus: ~/.claude/teams/session-xyz.jsonl   │
│                                                   │
└──────────────────────────────────────────────────┘

Each teammate in the registry has:

  • Name — A unique identifier used for addressing messages
  • Role — A description that shapes the teammate’s behavior
  • Status — Whether the teammate is active, idle, or finished
  • Context — An independent message array (the teammate’s own conversation)

The JSONL Message Bus

Teammates communicate through a file-based JSONL message bus. Each message is a single line of JSON appended to a shared file:

Communication Flow:

  Implementer                    Reviewer
  ┌──────────┐                  ┌──────────┐
  │ writes   │    message.jsonl │ reads     │
  │ code     │───────────────►  │ message   │
  │          │                  │ reviews   │
  │ reads    │  ◄───────────────│ sends     │
  │ feedback │    message.jsonl │ feedback  │
  └──────────┘                  └──────────┘

A message on the bus looks like:

{"from": "implementer", "to": "reviewer", "type": "request", "content": "I've finished the auth middleware in src/middleware/auth.ts. Please review for security issues.", "timestamp": "2026-03-20T10:15:30Z"}
{"from": "reviewer", "to": "implementer", "type": "response", "content": "Found 2 issues: (1) JWT secret is hardcoded on line 15, use env var. (2) No rate limiting on login endpoint.", "timestamp": "2026-03-20T10:16:45Z"}
{"from": "implementer", "to": "reviewer", "type": "request", "content": "Fixed both issues. JWT secret now from process.env.JWT_SECRET, added rate-limiter-flexible on /login. Ready for re-review.", "timestamp": "2026-03-20T10:18:20Z"}

Why JSONL? It has several advantages over network-based communication:

  • Append-only — No conflict when multiple agents write simultaneously
  • Persistent — Messages survive if an agent restarts
  • Inspectable — You can read the file to see the full communication history
  • Simple — No server, no ports, no networking — just a file

SendMessage Tool

Teammates communicate using the SendMessage tool:

{
  "type": "tool_use",
  "name": "SendMessage",
  "input": {
    "to": "reviewer",
    "content": "The auth middleware is ready for review. Key files: src/middleware/auth.ts, src/routes/auth.ts"
  }
}

The receiving teammate sees the message in their next turn as a system notification, similar to how background task completions are reported (Session 8).

Context Isolation at Scale

The fundamental advantage of Agent Teams over a single agent is context isolation. Compare:

Single Agent (200K context):
  ┌──────────────────────────────────────────────┐
  │  System prompt          ~3K tokens           │
  │  Implementation code    ~50K tokens          │
  │  Review feedback        ~20K tokens          │
  │  Test output            ~15K tokens          │
  │  Documentation          ~10K tokens          │
  │  ─────────────────────────────────────       │
  │  Total: ~98K tokens     (49% capacity)       │
  │  All competing for the same context window   │
  └──────────────────────────────────────────────┘

Agent Team (200K x 3 contexts):
  ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────┐
  │  Implementer    │  │  Reviewer        │  │  Tester          │
  │  ~53K tokens    │  │  ~23K tokens     │  │  ~18K tokens     │
  │  (27% capacity) │  │  (12% capacity)  │  │  (9% capacity)   │
  │                 │  │                  │  │                  │
  │  Deep code      │  │  Deep review     │  │  Deep test       │
  │  context        │  │  context         │  │  context         │
  └─────────────────┘  └─────────────────┘  └─────────────────┘
  Total: 600K tokens available, each domain has room to breathe

Each teammate can go deep in its domain without crowding out the others. The reviewer can hold extensive review history without reducing the implementer’s available context for code.

Key Insight

Teams give each agent its own context window, solving the context pollution problem at a larger scale than subagents. Subagents are stateless — they spawn, execute, and vanish. Teammates are stateful — they persist across many turns, accumulate domain knowledge, and engage in ongoing dialogue.

This mirrors how real engineering teams work. A code reviewer doesn’t forget their previous reviews when you ask them to look at the next pull request. A QA engineer remembers the bugs they found last week when testing this week’s build. Persistent context enables accumulated expertise.

The JSONL message bus is the glue that makes this work. Without it, the teammates would be isolated silos. With it, they form a collaborative team where each member contributes their specialized perspective while maintaining their own coherent context.

The design choice to use file-based messaging (JSONL) instead of network protocols is deliberate. Files are simple, debuggable, and don’t require infrastructure. You can cat the message bus to see exactly what agents are saying to each other. This transparency is critical for trust — you always know what’s happening between your agents.

Hands-On Example

Setting Up an Implementer + Reviewer Team

Here’s how to set up a two-agent team for a feature development workflow:

Terminal 1 — Implementer:
  $ export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
  $ claude
  > I'm the implementer. I'll write the code for the
    notification system.

Terminal 2 — Reviewer:
  $ export CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
  $ claude
  > I'm the reviewer. I'll review code that the implementer
    produces and provide security and quality feedback.

Once both are running, the workflow looks like this:

Implementer                         Reviewer
────────────                        ────────────
Writes notification model
  └── src/models/notification.ts

Sends: "Model ready for review"
                          ────────►
                                    Reviews model
                                    Sends: "Add index on
                                    userId for query perf"
                          ◄────────

Adds index, continues to
write API endpoints
  └── src/routes/notifications.ts

Sends: "Endpoints ready"
                          ────────►
                                    Reviews endpoints
                                    Sends: "LGTM, but add
                                    pagination to GET /list"
                          ◄────────

Adds pagination, marks
feature complete

Three-Agent Team: Implement, Review, Test

For larger features, add a testing agent:

Team Configuration:

  Implementer                Reviewer                 Tester
  ┌─────────────┐           ┌─────────────┐          ┌─────────────┐
  │ Writes code │──message──│ Reviews code │          │ Writes tests│
  │             │           │ for quality  │          │ Runs tests  │
  │             │◄─feedback─│ and security │          │             │
  │             │           └─────────────┘          │             │
  │             │──────────message────────────────── │             │
  │             │◄─────────test results──────────────│             │
  └─────────────┘                                    └─────────────┘

  Workflow:
  1. Implementer writes feature code
  2. Reviewer reviews it (in parallel with step 3)
  3. Tester writes test cases based on the feature spec
  4. Implementer addresses review feedback
  5. Tester runs tests against the updated code
  6. All agents converge: code + reviews + green tests

Communication Patterns

Three patterns dominate agent team communication:

1. Request-Response (most common):

Implementer → Reviewer: "Please review src/auth.ts"
Reviewer → Implementer: "Found 2 issues: ..."

2. Broadcast (announce to all):

Implementer → All: "Breaking change: renamed User to Account
in all models. Update your references."

3. Delegate (assign a task):

Implementer → Tester: "Write unit tests for the new
  notification model. Cover: create, read, mark-as-read,
  delete. Expected file: src/models/notification.test.ts"

When to Use Teams vs. Subagents

CriteriaSubagentsAgent Teams
Task durationShort, one-offSustained, multi-turn
Context needsDiscarded after usePersistent across turns
CommunicationResult returned onceOngoing dialogue
Setup costZero (automatic)Explicit setup required
Typical useExploration, researchImplementation, review
Number of agents1-3 ephemeral2-4 persistent
Context windowsParent + temporary childAll independent, all persistent

Rule of thumb: If the task is “find X and report back,” use a subagent. If the task is “work on X with me over the next 30 minutes,” use a teammate.

Debugging Team Communication

Since the message bus is a plain JSONL file, you can inspect it:

# See all messages between agents
cat ~/.claude/teams/session-xyz.jsonl | python3 -m json.tool

# Filter messages from a specific agent
grep '"from": "reviewer"' ~/.claude/teams/session-xyz.jsonl

# Count messages per agent
grep -o '"from": "[^"]*"' ~/.claude/teams/session-xyz.jsonl | sort | uniq -c

This transparency means you can always audit what your agents are discussing, catch miscommunication early, and understand how the team coordinated.

What Changed

Single AgentAgent Teams
One context window for everythingIndependent context per teammate
Context fills up with mixed concernsEach agent focuses on its domain
No persistent collaborationTeammates maintain ongoing dialogue
Review requires loading review + code contextReviewer has dedicated context for review history
Sequential: write, then review, then testParallel: reviewer and tester work while implementer codes
One perspective on the codeMultiple specialized perspectives

Next Session

This wraps up the core multi-agent concepts. Session 10 explores Team Protocols — the structured communication patterns and conventions that make agent teams predictable and effective at scale.