[FEATURE] TeamDelete: --discard-stale flag to force-cleanup zombie teammates with isActive=true
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:
- Main spawns a teammate via
Agent({subagent_type, name, team_name}). - The teammate's Claude Code process registers in the team config at
~/.claude/teams/<team>/config.jsonwithisActive: trueand atmuxPaneId. - 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>.jsonlis never written. Agent is unresponsive toSendMessage. - I detect the zombie and
tmux kill-pane -t %<id>to free the resources. - The team config still flags the dead teammate as
isActive: true. I attemptTeamDelete. TeamDeletereturnsCannot cleanup team with N active member(s): <name>. Use requestShutdown to gracefully terminate teammates first.requestShutdownto 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:
- Bypasses the
isActiveguard. - 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.
- 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.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗