SendMessage to teammates: batched 40-min deliveries, silent success to nonexistent 'main', and queued messages resurrecting stopped agents

Status Open
Reported on v2.1.222
Maintainer reply None cached
Activity 0 comments · opened Aug 6, 2026

Version: Claude Code 2.1.222 · macOS arm64 · CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1

Summary

Three related defects in SendMessage delivery to in-process teammates, measured on a multi-agent coordination workload. The third is a composition of the first with agent stop/liveness semantics and is the one a fix must not miss.

1. Delivery is batched with long delays (measured: 40 minutes)

A coordinator sent a GO authorization to a teammate at ~16:40; it was delivered at ~17:20 in a six-message batch together with five other messages sent over the intervening window. The teammate sat blocked for 40 minutes waiting on an authorization that had been granted, and its own interim reports were correspondingly late outbound. Message crossings caused duplicate work and a near-wrong merge decision (the coordinator acted on a stale state report while the correction was sitting undelivered in a batch).

Expected: near-real-time delivery, or documented batching semantics so sequenced protocols (GO/verdict handoffs) can be designed around them. As it stands, same-minute delivery cannot be assumed and nothing tells the sender the message is still queued.

2. Sends to a nonexistent recipient succeed silently

Two reports addressed to main (a natural guess for "the top-level agent" — nothing warns it isn't an addressable name) returned success and were never delivered to anyone. A send to an unaddressable recipient should error, not report success.

3. Composition: batched deliveries draining into a STOPPED agent resurrect it, self-perpetuatingly

Measured overnight on the same box: an agent was stopped, and queued/batched messages addressed to it continued draining in one at a time. Each late delivery touched the stopped agent's transcript — re-animating it enough to count as "recent activity." An external safety guard that refuses a session teardown while any agent shows recent activity was re-armed by each successive drip, refusing five consecutive times over several hours; the state could not clear until the drain finished. The loop is self-perpetuating because messages about the stuck state (status queries, retries under a re-send policy adopted precisely because of defect 1) join the same queue.

Expected: delivery to a stopped agent is dropped, dead-lettered back to the sender, or at minimum does not register as activity on the stopped agent. Combined with defect 1, the current behavior means stopping an agent does not quiesce it for an unbounded window.

Why this matters

Multi-agent teams coordinate through these messages. Batched/lossy delivery breaks any sequenced protocol (authorization gates, stop orders, merge verdicts) — a stop order that arrives 40 minutes late is a correctness problem, not a latency problem. The workaround burden is real: we now re-send any unacknowledged GO/verdict after ~10 minutes and require explicit acks for anything sequenced, which defect 3 then turns into extra resurrection traffic.

Repro sketch

  1. Spawn an in-process teammate (Agent with name, run_in_background: true) that does slow multi-step work.
  2. From the parent, SendMessage to it every few minutes; have the teammate log wall-clock receipt times. Observe multi-message batches with delays far exceeding send cadence (tens of minutes under load).
  3. SendMessage to recipient main — observe success with no delivery.
  4. Stop a teammate that has undelivered queued messages; watch its transcript mtime — it keeps advancing as the queue drains, long after the stop.

View original on GitHub ↗