Team shutdown_request acknowledged but teammates never terminate; TeamDelete blocked until session ends

Resolved 💬 4 comments Opened Apr 17, 2026 by todd-w-shaffer Closed May 28, 2026

Summary

SendMessage accepts type: "shutdown_request" and returns success + a
request ID, but teammates never terminate. TeamDelete is then
blocked for the life of the session.

Unclear from outside whether shutdown_request is a declared protocol
or forwarded free-form content — the
{"success": true, "request_id": "shutdown-<ts>@<name>"} response
suggests first-class handling, but we can't confirm against the tool
schema. Either way, there's currently no way to clean up teams from
within a session.

Filed as a follow-up to the #44971 investigation (now fixed in 2.1.105).

Environment

  • Claude Code 2.1.105 (installed 2026-04-13)
  • macOS
  • Plugin: Coolant

consumes SubagentStart/SubagentStop hooks

Reproduction

  1. TeamCreate({name: "test-team"})
  2. Spawn 2-4 teammates via Agent({team_name: "test-team", name: "alpha", ...})
  3. Let at least one teammate complete a turn so it's idle in mailbox
  4. Send shutdown:

``json
SendMessage({
"to": "alpha",
"type": "shutdown_request",
"message": {"type": "shutdown_request", "reason": "..."},
"recipient": "alpha",
"content": "..."
})
``

  1. Observe response: {"success": true, "request_id": "shutdown-<ts>@alpha"}
  2. Observe teammate: wakes (SubagentStart), processes message, goes

idle (SubagentStop), sends idle_notification, does NOT terminate

  1. TeamDelete({name: "test-team"}) → fails with

"Cannot cleanup team with N active members"

What we tried

Three rounds of escalating shutdown attempts across all 4 teammates in
a live test:

Round 1 — Broadcast:

SendMessage({
  "to": "*",
  "type": "broadcast",
  "summary": "Shutdown request",
  "message": {"type": "shutdown_request", "reason": "Investigation complete."}
})

Round 2 — Per-teammate with explicit type: "shutdown_request":

SendMessage({
  "to": "alpha",
  "type": "shutdown_request",
  "message": {"type": "shutdown_request", "reason": "Investigation complete."},
  "recipient": "alpha",
  "content": "Investigation complete."
})

Response: {"success": true, "message": "Shutdown request sent to alpha. Request ID: shutdown-1776305814048@alpha"}

Round 3 — Plain text asking teammates to approve pending request:

SendMessage({
  "to": "alpha",
  "summary": "Please exit",
  "message": "Your work is complete. Please respond to the pending shutdown request by approving it."
})

Evidence

Each teammate's inbox at ~/.claude/teams/<team>/inboxes/<name>.json
shows all messages delivered and marked "read": true. Teammates
received and processed the shutdown requests but did not terminate.

Repeated sequence across all rounds, for each teammate:

  1. SendMessage delivers shutdown_request → CC returns success + request ID
  2. SubagentStart fires (teammate wakes)
  3. Teammate processes message, goes idle
  4. SubagentStop fires
  5. idle_notification sent to team lead
  6. Teammate remains alive in team

Question for Anthropic

Is type: "shutdown_request" declared in SendMessage's tool schema as
a recognized type, or is it free-form content that SendMessage happens
to forward to the inbox? The request-ID format in the response
suggests explicit handling, but we can't confirm from the outside.
This determines whether the bug is "protocol exists and is ignored"
or "user tried to invoke a protocol that doesn't exist."

Impact

  • TeamDelete cannot clean up teams while teammates are alive
  • No documented way to terminate teammates from inside a session
  • Users iterating on team configs must restart the whole CC session
  • Stale team state accumulates on disk under ~/.claude/teams/<name>/

Asks

If shutdown_request IS a declared protocol: teammates should honor
it and terminate.

If it ISN'T: TeamDelete needs a force option (or some documented
path to terminate members), because there's currently no way to clean
up teams within a session.

View original on GitHub ↗

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