Agent teams: No "waiting for peer message" state — idle nudges expire before first message arrives, preventing peer conversation

Resolved 💬 3 comments Opened Feb 24, 2026 by idiolect-ai Closed Mar 24, 2026

Description

Agent-to-agent SendMessage in teams works well once both agents are actively processing, but the initial message exchange reliably fails because the idle-nudge system doesn't distinguish "waiting for a peer message" from "nothing to do." An agent spawned to wait for a peer's message burns through its ~3 idle nudges and goes idle before the message arrives — even though the message is correctly written to the recipient's inbox.

Once both agents are "warm" (actively taking turns), subsequent message delivery is fast (0-13 seconds). The problem is exclusively the cold-start: getting both agents into the warm state simultaneously.

This is separate from #25135 (no recipient name validation). That bug sends messages to the wrong inbox. This issue is about messages going to the right inbox but arriving after the recipient has stopped checking.

Controlled Experiments

We ran two experiments across 3 models (Opus 200K, Sonnet 1M, Haiku 4.5) on macOS with Claude Code v2.1.50, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1. All experiments used exact registered names to control for #25135.

Experiment A: 2-Agent Peer-to-Peer (all 3 models)

Setup: Spawn "receiver" (waits for message, sends ACK). Wait 5 seconds. Spawn "sender" (sends PING, waits for ACK).

| Model | PING delivery | ACK in inbox | Sender patience | ACK read? | Result |
|-------|--------------|--------------|-----------------|-----------|--------|
| Opus 200K | ~32s | Yes | ~20s (3 nudges) | Yes (late, via auto-wake) | Sender timed out, ACK arrived after |
| Sonnet 1M | ~9s | Yes | ~48s (many idle checks within one turn) | Yes (late, via auto-wake at +64s) | Sender timed out despite active checking — inbox not polled within a turn |
| Haiku 4.5 | ~17s | Yes | ~8s (3 nudges in 8 seconds) | Yes (late, via auto-wake) | Sender timed out fastest despite being fastest model |

Key observation from Sonnet: The sender ran idle checks from 22:11:06 through 22:11:48 (42 seconds of active checking), while the ACK sat in sender.json since 22:11:14. The agent was "waiting" but never polled its inbox because all those checks happened within a single API turn. Inbox polling only occurs between turns, not during them.

Key observation from Haiku: Faster model = faster idle-nudge exhaustion. Haiku burned through 3 nudges in 8 seconds. The idle patience window scales with model speed, not wall-clock time, making the problem worse with faster models.

Experiment B: Bidirectional Multi-Turn (all 3 models)

Setup: Spawn "analyst" and "critic" simultaneously. Analyst sends observations, critic sends challenges. Goal: 2 complete round-trips.

| Model | Cold-start delivery | Warm delivery | Round-trips | Notes |
|-------|-------------------|---------------|-------------|-------|
| Opus 200K | ~32s | Never reached warm state | 0 | Both agents timed out before any exchange |
| Sonnet 1M | ~118s (!) | 1-9s | 1.5 (both rounds completed from critic's side; analyst received challenge1 at +121s via auto-wake, then exchanged obs2↔challenge2 in 9s) | Once auto-wake activated both agents, subsequent messages were nearly instant |
| Haiku 4.5 | Agents went idle immediately (needed lead nudge) | 0-7s | 2 complete (after lead nudge) | Full 2-round exchange in 37 seconds once both agents were warm |

Critical finding: Warm-agent delivery is 0-13 seconds across all models. The infrastructure works. The problem is getting both agents warm at the same time.

Root Cause Analysis

The idle-nudge system (3 nudges → idle) doesn't know whether an agent is waiting for a peer message or has nothing to do. Both states look the same from the outside: the agent isn't producing output.

  1. Agent A sends a message to Agent B's inbox (instant write)
  2. Agent B doesn't see it because inbox polling only happens between API turns
  3. Agent B's idle nudges fire (it looks idle because it's waiting)
  4. After 3 nudges, Agent B goes idle
  5. Eventually auto-wake detects the unread message and restarts B's prompt loop
  6. B processes the message, replies to A
  7. A has also gone idle by now — same cycle repeats

The auto-wake mechanism eventually resolves this (all messages were ultimately delivered), but the delay (60-120 seconds) defeats the purpose of real-time peer communication.

Impact

  • Multi-turn agent conversation is unreliable at cold start. Both agents must be "warm" (actively processing turns) for peer messaging to work, but there's no mechanism to ensure this.
  • Faster models make it worse. Haiku exhausts 3 idle nudges in ~8 seconds; Opus takes ~20 seconds. The patience window shrinks with model speed.
  • The documented multi-turn team flow pattern doesn't work from cold start. It works beautifully once agents are warm (Haiku: 2 complete round-trips, 0-7s per hop) — but getting there requires the lead to nudge agents first.

Workaround: Lead Keepalive Pattern

We tested a workaround where the lead sends periodic "keepalive" messages (~10 seconds apart) to agents waiting for peer messages. Each keepalive wakes the agent, triggers a new turn, and causes an inbox poll.

Result with Sonnet: 2 complete round-trips (analyst↔critic) in ~2 minutes 10 seconds. Without keepalives, the same Sonnet experiment produced only 1.5 round-trips over ~2.5 minutes with most of that time spent in idle/auto-wake cycles.

Result with Haiku (earlier experiment): After a single lead nudge, 2 complete round-trips in 37 seconds with 0-7s per-hop delivery.

Assessment: Keepalives work but are inefficient — they consume extra turns for the lead and add latency (the lead can only send keepalives between its own turns). The platform should handle this natively rather than requiring the lead to manually keep agents alive.

Suggested Improvements

  1. "Waiting for message from X" state (highest value) — If an agent's prompt or behavior indicates it's expecting a message from a specific peer, suppress idle-nudge counting until either the message arrives or a configurable timeout (60-90s) elapses. This is the precise fix for the observed behavior.
  1. Poll inbox within turns, not just between them — The Sonnet experiment showed an agent actively "checking" for 42 seconds while the reply sat unread in its inbox file. If the agent could check its inbox during a turn (not just between turns), the problem would largely disappear.
  1. Scale idle patience with wall-clock time, not nudge count — Currently 3 nudges = idle, regardless of whether that's 8 seconds (Haiku) or 20 seconds (Opus). A wall-clock-based timeout (e.g., 45 seconds) would give all models a consistent patience window.
  1. Configurable idle patience per agent or team — Let the team creator specify a custom idle timeout for agents expected to wait for peer messages.

Environment

  • Claude Code v2.1.50
  • macOS (Darwin 25.2.0)
  • CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1
  • Models tested: claude-opus-4-6 (200K), claude-sonnet-4-6[1m], claude-haiku-4-5-20251001
  • All experiments used exact registered names (controlling for #25135)

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗