Team UI indicators persist after force-deleting team files (zombie teammates)

Status Closed — not planned
Maintainer reply None cached
Activity 13 comments · opened Feb 23, 2026 · closed Jun 5, 2026

Bug Description

When a team is created with teammates and the teammate processes are killed manually (Ctrl+C in tmux panes, then exit), the teammate UI indicators persist in the lead agent's session — showing spinning animations, teammate count, and a ticking time counter — even though no agents are actually running and no tokens are being consumed.

Steps to Reproduce

  1. Create a team with TeamCreate and spawn 3 teammates via Task tool
  2. While teammates are still running, manually kill them:
  • Switch to each teammate's tmux pane
  • Press Ctrl+C to interrupt the running agent
  • Type exit to close the tmux pane
  1. Return to the lead agent's session
  2. Result: UI still shows "3 teammates" with spinning indicators, time counter ticking, but 0 tokens used
  3. Attempting TeamDelete fails with "Cannot cleanup team with 3 active member(s)"
  4. Even force-deleting files (rm -rf ~/.claude/teams/team-name ~/.claude/tasks/team-name) does not clear the UI indicators
  5. Only restarting the Claude Code session clears the stale state

Expected Behavior

Either:

  • The lead agent should detect that teammate tmux panes have been killed and clean up the in-memory state automatically (heartbeat/health check)
  • TeamDelete should support a --force flag to clean up even when agents are listed as active but their processes are dead
  • The UI should reconcile in-memory state against actual tmux pane status — if the pane no longer exists, clear the teammate indicator

Root Cause Analysis

The UI reads teammate state from in-memory AppState, not from the filesystem or tmux process status. When a teammate's tmux pane is killed externally (Ctrl+C + exit), the lead agent's AppState is never notified — the teammate is still listed as isActive: true in the team config, and the in-memory state retains the stale entry.

The TeamDelete tool refuses to operate if any members are listed as active in the config, creating a deadlock — the agents are dead but still "active" according to the config, so TeamDelete won't run and there's no way to clear the state without restarting the session.

Environment

  • Claude Code version: latest (Feb 2026)
  • OS: macOS (Darwin 25.1.0)
  • Shell: zsh

Screenshot

The UI shows "3 teammates" with spinning indicators and time counter ticking, but no tokens are being consumed.

View original on GitHub ↗

12 Comments

github-actions[bot] · 6 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/26955
  2. https://github.com/anthropics/claude-code/issues/25371
  3. https://github.com/anthropics/claude-code/issues/27610

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

daern91 · 6 months ago

This is not a duplicate of the suggested issues. The linked root issue #26202 is about deleted skills persisting in Cowork UI, which is unrelated. This issue is specifically about team/teammate zombie indicators persisting in the CLI after manually killing tmux panes (Ctrl+C + exit). The in-memory AppState for teams is not reconciled when teammate processes die externally. #25371 describes the same underlying TeamDelete limitation but was also closed in the duplicate chain. Keeping this open.

junaidtitan · 6 months ago

We hit the same zombie teammate problem. Built cozempic with a doctor check that detects stale team directories and cleans them up — open source.

pip install cozempic
cozempic doctor        # detects stale teams (>24h, no config, no activity)
cozempic doctor --fix  # removes them

Also checkpoints team state continuously so you can see what agents were doing before they went zombie. Feedback welcome.

kaita · 5 months ago

Additional reproduction case: TeamCreate failure → orphaned agent process

Version: 2.1.69 (macOS, Darwin 24.6.0)

Steps to reproduce

  1. TeamCreate with team name code-review-triage
  2. Spawn 3 agents via Agent tool — one fails to join team due to a transient error
  3. TeamDelete → fails ("Cannot cleanup with active members")
  4. Send shutdown_request to remaining agents → TeamDelete succeeds
  5. The first failed agent (spawned before team was properly set up) is now orphaned — still running as a background process but not part of any team

Observed behavior

  • "Composing..." / timer continues counting up in the parent session
  • ps aux | grep claude confirms the orphaned agent process is still alive (PID visible)
  • No team files exist in ~/.claude/teams/
  • Manually kill <PID> resolves the UI indicator

Workaround

After team operations involving failures/retries, run:

ps aux | grep claude | grep agent

and manually kill any orphaned agent processes.

Suggestion

When TeamDelete succeeds, it should also send SIGTERM to all processes that were spawned with --team-name <deleted-team>, regardless of whether they successfully joined the team.

junaidtitan · 5 months ago

does this happen even with guard mode on?

kaita · 5 months ago

Sorry for the delayed reply.

I did see this in my environment while running Claude Code in plan permission mode with custom local guard hooks enabled, although I'm not sure that matches exactly what you mean by "guard mode."

Since upgrading to v2.1.72, I haven't been able to reproduce it again so far.

kaita · 5 months ago

Update: Reproduced on v2.1.72 via clean shutdown path

I need to correct my earlier comment — I stated this wasn't reproducing on v2.1.72, but I've now hit it again under different conditions that narrow down the root cause.

Environment: v2.1.72, macOS Darwin 24.6.0, zsh

Reproduction scenario

This time, no force-kill was involved. The entire lifecycle completed cleanly:

  1. TeamCreate → team gas-code-review created
  2. Spawned 3 agents via Agent tool — all completed work and sent results
  3. Sent shutdown_request to all 3 → all responded with shutdown_approved
  4. Received teammate_terminated for all 3
  5. TeamDelete → succeeded ("Cleaned up directories and worktrees")
  6. Verified: team directory gone, no orphaned processes
  7. UI indicators (spinner, teammate count, timer) persisted

Key difference from the original report

The original issue described zombie indicators after Ctrl+C + exit (force-killing tmux panes). This reproduction shows that even when every step of the graceful shutdown path succeeds, the UI state falls out of sync.

Evidence from session log analysis

Session ID: 498e7420-68b5-4780-a2be-fe6797cc7249

I found two notable anomalies in the session transcript:

1. Message ordering anomaly — teammate_terminated arrives before shutdown_approved:

All three agents had their teammate_terminated (system) event delivered to the lead before their shutdown_approved response. For example:

system: teammate_terminated "architect-reviewer has shut down."
architect-reviewer: shutdown_approved (04:27:20.014Z)  ← arrives after terminated

This happened for all 3 agents. The tmux pane exits (triggering teammate_terminated) before the shutdown_approved message finishes delivery, creating a race condition. If the UI processes terminated first and drops the agent from tracking, the subsequent shutdown_approved may be ignored — leaving the internal counter in an inconsistent state.

Confirmed with a second team in the same session: I created another team (issue-analysis, 2 agents) immediately after. The exact same ordering anomaly occurred for both agents:

system: teammate_terminated "log-analyst has shut down."
log-analyst: shutdown_approved (04:55:30.603Z)  ← arrives after terminated

system: teammate_terminated "comment-drafter has shut down."
comment-drafter: shutdown_approved (04:55:31.851Z)  ← arrives after terminated

This is 100% reproducible across 5/5 agents in 2 separate teams within one session.

2. Batched message delivery:

The lead agent was generating a long report when shutdown responses arrived. All 9+ teammate messages (idle notifications, terminated events, shutdown approvals) were buffered and delivered as a single batch. The last message in the batch had a truncated closing tag (</teammate-messag instead of </teammate-message>), suggesting a buffer overflow or parse error in batch processing.

Updated root cause hypothesis

This isn't solely a process-detection problem. Two likely contributing factors:

  1. Race condition in event ordering: teammate_terminated arriving before shutdown_approved may cause the UI to miscount active agents (terminated agent's shutdown_approved gets orphaned).
  2. TeamDelete doesn't explicitly reset UI indicator state: The backend data (teamName field) correctly transitions to None after TeamDelete, but the UI indicator layer doesn't subscribe to this event for cleanup — it appears to track teammates independently.

The fix likely needs to ensure that TeamDelete unconditionally clears all teammate UI indicators, regardless of the shutdown sequence's event ordering.

daern91 · 5 months ago

I'm still seeing it with version 2.1.77 as well

arimxyer · 5 months ago

Additional variant: teammate ignores shutdown protocol (no external kill)

I'm hitting the same TeamDelete deadlock but from a different trigger — no manual kills involved.

Scenario

  1. Create a team with TeamCreate, spawn 5+ teammates
  2. All teammates complete their tasks and mark them completed via TaskUpdate
  3. Send shutdown_request to each teammate via SendMessage
  4. 4 of 5 teammates respond with shutdown_approved and terminate normally
  5. 1 teammate goes idle but never responds to shutdown requests — keeps sending idle_notification messages indefinitely
  6. TeamDelete refuses: "Cannot cleanup team with 1 active member(s)"
  7. Multiple retry shutdown_request messages are ignored
  8. Even plain text messages asking it to approve shutdown are ignored
  9. Session is stuck — can't delete the team, can't create a new team ("Already leading team X")

Key difference from OP

No external process kill — the teammate's process is still running, it just won't acknowledge the shutdown protocol. The agent completed its work, marked its task done, but the shutdown handshake never completes. This happened with oh-my-claudecode:writer (haiku) and oh-my-claudecode:analyst (opus) agent types in the same session, so it's not model-specific.

Impact

This blocks the entire team workflow — you can't create a new team while leading one, and you can't delete the current team. The only workaround is ending the session entirely.

Suggested fixes (in addition to OP's)

  • TeamDelete --force flag that terminates all members regardless of state
  • Timeout on shutdown requests — if no shutdown_response within N seconds, force-terminate
  • Allow TeamDelete when all tasks are completed, even if members are still "active"
suatkocar · 4 months ago

+1 — experiencing the same zombie teammates issue. Subscribed for updates.

cguerin · 3 months ago

Adding a data point not yet covered in the thread: the per-task X dismiss button in the task overlay UI is also a no-op for stuck task entries. Tested today on macOS (Claude Desktop, in-process teammate mode via Agent({ run_in_background: true })):

  1. Spawned 6 teammates (3 authors + 3 rechecks) under one team for a multi-hour iteration
  2. All 6 completed their work and marked tasks done; orchestrator verified on disk
  3. Sent shutdown_request to all 6 → all returned success, 0 actually terminated
  4. TeamDelete failed with the expected "6 active member(s)" error
  5. rm -rf ~/.claude/teams/<team> to clear the bookkeeping
  6. kill -TERM on all 12 leftover claude --resume PIDs (each teammate had a parent + helper PID pair)
  7. Verified: zero teammate subprocesses, team config gone, worktrees removed, work cleanly merged
  8. The task overlay still shows ~16 "Running" entries from the long-since-completed work
  9. Clicking the X next to each entry does nothing — they remain "Running"

Confirms the existing root-cause hypothesis (UI tracks teammates independently of disk/process state) and adds one more failure mode: the UI's own dismissal control is also broken, so there's truly no in-session recovery. Restarting the session is the only known workaround.

github-actions[bot] · 2 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

Showing cached comments. Read the full discussion on GitHub ↗