[FEATURE] TeamDelete: --discard-stale flag to force-cleanup zombie teammates with isActive=true

Resolved 💬 1 comment Opened Apr 27, 2026 by TAHertweck Closed May 30, 2026

Problem

TeamDelete refuses to clean up a team when any member's isActive flag is true, even when the underlying tmux pane is already dead (e.g., killed externally because the agent's session JSONL never bootstrapped — see the Ink/TUI render-crash failure mode).

Concrete failure mode I keep hitting in a harness setup:

  1. Main spawns a teammate via Agent({subagent_type, name, team_name}).
  2. The teammate's Claude Code process registers in the team config at ~/.claude/teams/<team>/config.json with isActive: true and a tmuxPaneId.
  3. The Claude Code TUI renderer crashes during initialization (Ink/React render error). The tmux pane stays alive (PID alive) but the agent's session JSONL at ~/.claude/projects/<proj>/<session>/subagents/agent-<id>.jsonl is never written. Agent is unresponsive to SendMessage.
  4. I detect the zombie and tmux kill-pane -t %<id> to free the resources.
  5. The team config still flags the dead teammate as isActive: true. I attempt TeamDelete.
  6. TeamDelete returns Cannot cleanup team with N active member(s): <name>. Use requestShutdown to gracefully terminate teammates first.
  7. requestShutdown to a dead-but-flagged-active member never returns (no session to receive it).

The team is genuinely orphaned but the cleanup API has no escape hatch.

Current workaround (implementation-detail-aware)

Force-modify the team config JSON directly:

config_path = Path.home() / ".claude/teams" / team_name / "config.json"
config = json.loads(config_path.read_text())
for member in config["members"]:
    if member.get("isActive") and is_pane_dead(member.get("tmuxPaneId")):
        member["isActive"] = False
config_path.write_text(json.dumps(config, indent=2))
# Now TeamDelete accepts.

This works today but is implementation-detail manipulation of internal state. Future Claude Code releases that change the team config layout, location, or add validation would break it.

Proposed feature

A --discard-stale (or equivalent) parameter on TeamDelete that:

  1. Bypasses the isActive guard.
  2. Optionally checks per-member liveness (tmux pane alive? recent JSONL write?) and only discards genuinely-stuck members. Passing all members through if every one is live would still respect the safety check.
  3. Logs the discarded members for audit (which were forced, why).

Equivalent could also be a per-call flag on requestShutdown like force_terminate=true that updates the logical state without requiring a live session.

Use case context

I'm building a multi-agent feature-team harness (persistent PM + Architect across features, ephemeral scout + engineer per task). When an agent crashes during spawn-init (Ink/TUI render error), there's no clean recovery path through the documented APIs — every recovery requires force-modifying internal state files.

Tracking this dependency in our planning at .agent-planning/platform/PLT-060-HarnessReliabilityHardening/FEATURE_DESIGN.md (FR-8 force-mod is the workaround; this issue is the retirement path).

Adjacent issues

  • #19077 — sub-agents cannot spawn sub-sub-agents (architectural, separate)
  • #38806 — bypassPermissions exclusion for .claude/** (separate; relevant context for why agents crash during spawn-init in our setup)
  • #15858, #17127 — settings hot-reload (separate; affects when settings take effect for spawned subagents)

Repro

# Pseudocode — runs in a Claude Code session
TeamCreate({team_name: "test"})
result = Agent({
    subagent_type: "harness-engineer-sonnet",
    name: "stuck",
    team_name: "test",
    run_in_background: true,
    prompt: "task_id: x | feature_id: y"
})
# Wait for spawn-init crash (rare but reproducible enough to hit in 5 of 50 runs in our setup)
# OR: simulate by manually killing the tmux pane immediately after spawn

# Now:
TeamDelete()  # FAILS: "Cannot cleanup team with 1 active member(s): stuck"

# Force-mod workaround:
# (manually edit ~/.claude/teams/test/config.json to set stuck.isActive = false)

TeamDelete()  # SUCCEEDS

Environment

  • Claude Code: 2.1.119 (CLI)
  • Platform: Linux (Ubuntu)
  • Backend: tmux

Thanks for considering. Happy to provide more detail on the harness architecture or the specific failure traces if useful.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗