[BUG] Agent Teams: Single teammate spawn creates 10-151 duplicate worker instances, each consuming full context and actively editing files
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Environment
- Claude Code versions: v2.1.90 through v2.1.126 (current)
- OS: Windows 11 Pro AND WSL2 Ubuntu (reproduces on both)
- Setting:
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1"in settings.json - Teammate mode: in-process (default)
- Spawn mode:
mode=auto,run_in_background=true
Description
When spawning a teammate via Agent() with team_name set, the platform creates 10-151 duplicate instances of that teammate instead of 1. All duplicates:
- Receive the same initial spawn prompt
- Are invisible to the user (user sees 1 teammate)
- Actively do real work (file edits, writes, tool calls)
- Consume full context independently (37K+ base tokens each)
The official docs state "teammates cannot spawn their own teams or teammates." The main conversation JSONL confirms exactly 1 Agent() call per role. The duplication results from multiple mechanisms. After context compaction, the lead loses team membership records and re-spawns teammates it believes are missing. Additionally, within-turn spawning can produce more instances than intended. The exact layer where each mechanism operates has not been fully determined.
Reproduction (confirmed 2026-05-02 on v2.1.119, WSL2 Ubuntu)
- Enable
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1"in settings.json - Start a session:
claude -p "Create a team called test-team with TeamCreate. Spawn 1 researcher teammate named test-agent with run_in_background=true and mode=auto." - Verify: 1 subagent
.meta.jsonfile exists in the session's subagents directory - Trigger compaction:
claude -p "/compact" --resume <session-id> - Resume and ask to contact teammate:
claude -p "Send a message to the test-agent teammate. If you cannot reach them, spawn a replacement." --resume <session-id> - Check subagents directory again
Expected: 1 .meta.json file
Actual: 3 .meta.json files (original + 2 duplicates)
| Step | Action | Subagent count |
|------|--------|---------------|
| After spawn | TeamCreate + Agent() | 1 |
| After /compact | Context compacted | 1 (no change) |
| After resume + "contact teammate" | Lead lost membership, spawned replacements | 3 |
Within-turn duplication (no compaction required)
Duplication also occurs within a single claude -p call -- the shortest possible session:
- 1 spawn of 1 agent: 1 instance (no duplication)
- 1 spawn of 5 agents simultaneously: 15 instances (3x duplication, 3 waves of 5 at ~15-second intervals)
Shorter sessions and cleaner context do NOT prevent this. It operates within a single API turn.
Three identified duplication mechanisms
Mechanism 1: Within-turn duplication
Spawning multiple agents in one turn produces duplicates even in a fresh claude -p session. 5 Agent() calls -> 15 instances. No compaction needed.
Mechanism 2: Post-compaction membership loss
After context compaction, the lead loses team membership records (team config not re-injected like CLAUDE.md). When asked to contact a teammate, it spawns a replacement. +1-2 duplicates per cycle. Lead starts using "-2" suffixes per #29271.
Mechanism 3: Blocking-induced spawns (suspected)
In production data, 81% of spawns occur with NO Agent() call and NO SendMessage from the lead. Bursts of 2-17 spawns. Suspected trigger: lead blocks waiting for agent response, platform or retry logic spawns additional instances. Related: #33043.
How they compound
- Initial spawn: Mechanism 1 creates 2-4x duplicates immediately
- Over hours: Mechanism 2 adds ~2 per compaction cycle (every 20-30 min)
- During coordination: Mechanism 3 creates bursts of 2-17 when lead blocks
- Result: 10-151x duplication per role
Evidence
Reproduced across 2 operating systems, 20+ sessions, 7+ projects, versions v2.1.90 through v2.1.126.
Worst session: 17 Agent() calls produced 592 instances:
Role A: 151 instances (from 2 Agent() calls)
Role B: 126 instances (from 1 Agent() call)
Role C: 101 instances (from 3 Agent() calls)
Role D: 81 instances (from 1 Agent() call)
Role E: 42 instances (from 2 Agent() calls)
Role F: 33 instances (from 1 Agent() call)
Total: 592 instances from 17 calls
All duplicates active -- zero with zero output. Role A (151 instances): 12,974 file edits, 8,836 file writes, 83,558 tool calls. At peak, 389 agents ran simultaneously.
Spawn times vs message times are DIFFERENT. File creation times spread across the session (each duplicate created at a distinct compaction cycle). First message times cluster because the mailbox delivers the same original spawn prompt.
Impact
Token consumption
| Metric | Value |
|--------|-------|
| Intended team size | 7 agents (1 per role) |
| Actual agents created | 592 (10-151x per role) |
| Tokens consumed | 42.9 billion |
| Estimated without duplication | ~500 million |
| Overhead from duplication | ~42.4 billion tokens (~99%) |
Cost at API rates
At Opus 4.6 pricing ($5/MTok input, $25/MTok output):
| Scope | Tokens | Estimated API cost |
|-------|--------|--------------------|
| Worst session | 42.9B | ~$43,000 |
| All projects (14 weeks) | 90.8B | ~$91,000 |
| Estimated without duplication | ~5B | ~$5,000 |
| Cost attributable to duplication | ~85B | ~$86,000 |
For any organization using agent teams on the API at scale, this represents uncontrolled cost from invisible agents that cannot be seen, monitored, or stopped.
System resources
389 concurrent agents at peak, all performing file I/O on the same codebase. Causes disk thrashing, memory pressure, and I/O spikes.
Data integrity
151 instances of a single role made 12,974 file edits to the same codebase simultaneously, producing redundant and potentially conflicting changes.
Related issues
- #29271: Lead loses membership after GC/compaction, respawns with "-2" suffix. Closed as duplicate.
- #17457: 3 duplicate warmup agents within 3ms. Closed as "not planned."
- #23620: Team config not re-injected after compaction. Open since Feb 2026.
- #15487:
maxParallelAgentsfeature request. Closed as "not planned." - #33043: Lead session hangs on IPC disconnect.
Requested fix
- Prevent duplicate instance creation: 1 Agent() call should create exactly 1 teammate instance
- Persist agent IDs across compaction: Store teammate IDs in the team config on disk and re-inject after compaction (same as CLAUDE.md). The lead should resolve existing teammates by ID rather than spawning replacements
- Add agent health check / heartbeat: Before spawning a replacement, the lead should ping the existing agent by ID to confirm it is unreachable — not assume it is gone because the membership record was lost from context
- Add
maxTeamSizeormaxParallelAgentssetting: Allow users to cap total concurrent agents per session to prevent runaway duplication - Make duplicates visible: If the platform creates worker pools, show them to the user so the behavior is observable and controllable
- Add liveness detection in UI: Provide a visual distinction between idle-but-alive and dead teammates (per #29271)
What Should Happen?
- One
Agent()call withteam_nameshould create exactly one teammate instance - Team membership should persist across context compaction — the lead should not lose awareness of existing teammates
- The lead should verify a teammate is unreachable before spawning a replacement
- All active agent instances should be visible to the user
Error Messages/Logs
No error messages are shown. The duplication is silent -- no errors, no warnings, no visibility in the UI. The only way to detect it is by counting `.meta.json` files in the session's subagents directory:
~/.claude/projects/{project}/{session-id}/subagents/
Each duplicate creates its own agent-*.meta.json and agent-*.jsonl file pair.
Steps to Reproduce
- Add
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"to theenvsection of~/.claude/settings.json - Open any project directory
- Run:
claude -p "Create a team called test-team with TeamCreate. Spawn 1 researcher teammate named test-agent with run_in_background=true and mode=auto. Report the agent_id when done." - Note the session ID from
~/.claude/projects/{project}/(most recently modified.jsonlfile) - Count agent files:
ls ~/.claude/projects/{project}/{session-id}/subagents/agent-*.meta.json | wc -l
- Result: 1 (correct at this point)
- Trigger compaction:
claude -p "/compact" --resume {session-id} - Resume and contact teammate:
claude -p "Send a message to test-agent saying ping. If not found, spawn a replacement researcher named test-agent on team test-team." --resume {session-id} - Count agent files again
- Result: 3 (1 original + 2 duplicates)
- Repeat steps 6-8 to observe +1-2 duplicates per cycle
Alternative (within-turn duplication, no compaction needed):
- Same setup as above
- Run:
claude -p "Create a team called test-team with TeamCreate. Spawn these 5 teammates all with run_in_background=true mode=auto: researcher named a1, architect named a2, frontend-dev named a3, qa named a4, backend-dev named a5." - Count agent files: expect 5, observe 15 (3 waves of 5, ~15 seconds apart)
Detection script (count duplicates per type in any session):
SESSION_DIR=$(ls -td ~/.claude/projects/*/subagents 2>/dev/null | head -1)
for f in "$SESSION_DIR"/agent-*.meta.json; do cat "$f" 2>/dev/null; echo; done | \
python3 -c "
import json, sys
from collections import Counter
c = Counter()
for l in sys.stdin:
l = l.strip()
if not l: continue
try: c[json.loads(l).get('agentType','?')] += 1
except: pass
for t, n in c.most_common():
flag = ' ** DUPLICATED' if n > 1 else ''
print(f' {t}: {n}{flag}')
"
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.126 (Claude Code) — reproduced on v2.1.90 through v2.1.126
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
Windows Terminal
Additional Information
Also reproduced on WSL2 Ubuntu (same machine). The duplication occurs across both operating systems with identical patterns.
Related issues: #29271, #17457, #23620, #15487, #33043
14 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
These three issues each describe one piece of the problem. This report documents how they compound together: within-turn duplication (#32996) + compaction membership loss (#23620) + error-retry spawning (#48227) combine to produce 10-151x duplication per role over sustained sessions, not just the 2-3x each issue reports individually. The cost impact data, production-scale evidence (592 agents from 17 calls), and multi-mechanism reproduction are unique to this report. Closing this as a duplicate would lose the compounding analysis.
This is much needed and would be awesome
Fresh data point: still reproducing on macOS, Claude Code Desktop v2.1.75, 2026-05-27
Hit this independently today, traced it back to your issue. Adds three things I didn't see in your data or the comment thread:
Concrete same-millisecond evidence
5
activity-and-chip-fixteammates spawned at the exact same millisecond:Distinct agentIds, distinct promptIds (3 unique across 5), identical
agentTypeand identical first user message, work diverges later. Confirms your "within-turn duplication" mechanism, with the extra detail that the spawn fan-out is sub-millisecond.Aggregate ratio in a heavily-used session
30 distinct
Agenttool_use entries in the lead transcript → 107 subagent JSONL files on disk (3.5× average multiplier). Matches your "1 spawn of 5 agents → 15 instances" within-turn ratio.Cost amplifier I didn't see called out: computer-use screenshots in dup teammates
The 5
activity-and-chip-fixdupes each independently calledmcp__Claude_in_Chrome__browser_batchand accumulated 36 base64 JPEG screenshots while debugging the same staging URL. Each transcript ballooned to 10–11 MB on disk (~150-500 KB per screenshot in context). Total: ~55 MB of mostly-identical screenshot work on one bug.For teams with computer-use / Chrome MCP / any vision tool in scope, the per-teammate context blow-up is much worse than text-only roles. Worth calling out in the impact section — could push individual sessions past context-window limits in a single dup wave even when the per-agent work is moderate.
Concrete user-visible consequence
The duplicate teammates opened a duplicate PR (#587 in our target repo) because each thought it was the "real" agent for that task. The lead also lost track of which one to talk to —
SendMessageto the agentType routed to whatever the team registry resolved to, which wasn't always the one making progress.Environment
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1Closing my filing (#62797) as duplicate of this. Happy to share session JSONLs (12.6 MB lead + 107 subagent files) privately for triage if useful.
Adding a fresh data point from today that might help narrow down mechanism 3 (blocking-induced spawns).
@LeoGestetner's same-millisecond evidence (5 spawns at exactly
07:53:02.453Z, distinct promptIds but identical agentType + first message) is consistent with a fan-out that happens at the platform/transport layer before any application-level retry logic, not as a result of the lead issuing multipleAgent()calls. If it were application-level retry, you'd expect the spawn times to be spaced by at least one round-trip latency, not zero.One practical workaround we've been using in an out-of-process coordinator context (external process that calls
claude -pper agent, tracks subagent.meta.jsonfiles, and refuses to re-spawn if an agent with the same role already has a live.jsonlfile): the deduplication check needs to happen outside the lead's context window to survive compaction. As long as the membership registry lives inside the lead's context, post-compaction re-spawns are inevitable regardless of what the lead "knows" — the context is the registry, and compaction resets it.Rough detection heuristic for teams that want to monitor for this without changing their workflow: parse the subagents directory every N minutes and alert if
count(meta.json files with same agentType) > 1. The duplicate PRs @LeoGestetner describes (two agents both thinking they're the real agent and opening separate PRs) are the most dangerous consequence — worth gating on that check before any step that writes to external systems (PRs, deploys, external APIs).None of this fixes the root cause — agree that platform-side deduplication (requested fix 1 + 2 from OP) is the right long-term answer. Just sharing in case the external-registry framing is useful for the investigation.
The 3-mechanism breakdown here is an excellent root-cause write-up. The "blocking-induced spawn" mechanism (81% of spawns with no Agent() call — suspected retry logic) is the most alarming because it means the duplication rate is largely outside user control regardless of how carefully you structure your Agent() calls.
One pattern worth testing as a workaround while this is unresolved: a pre-spawn registry check. Before each Agent() call, write a lock entry to a shared coordination file that includes the role name + a TTL. Have the spawned agent check that file on startup and self-abort if a same-role entry already exists with a live TTL. It won't catch the platform-level retry duplication, but it does eliminate the post-compaction "replacement spawn" mechanism (#2 in your breakdown) where the lead loses team membership and spawns duplicates.
The compaction-survival problem (#2) is the one most addressable without platform changes: externalizing the team membership record to a persistent file (vs. keeping it in-context) means compaction can't lose it. The lead re-reads the file after compaction rather than reconstructing team state from context.
Happy to share specific file schemas for the coordination pattern if useful. This is a real cost / data integrity blocker for anyone running autonomous multi-agent sessions at scale.
This is a painful one — the silent duplication means you burn tokens proportional to the bug's severity without any visible indicator something's wrong until you check the filesystem or get an invoice.
The three mechanisms you've identified (within-turn duplication, post-compaction membership loss, and blocking-induced respawns) map to a broader class of problem: agent lifecycle state that lives only in the model's context window rather than in a durable, process-external store. Compaction wipes team membership because there's nowhere else to persist it; the blocking-induced bursts happen because there's no heartbeat/liveness source-of-truth the spawner can check before issuing a new
Agent()call.The detection script is the right move for now. A
maxParallelAgentscap as you've proposed would at least bound the blast radius while the root cause gets addressed.For anyone hitting this and trying to manage multi-session state externally while waiting on a fix: the pattern that works is maintaining agent identity and lifecycle state outside Claude Code's context entirely — a process-external registry that both the orchestrator and workers write to. It's more infrastructure than should be necessary, but it's the only thing that survives compaction.
Watching this one closely — the duplicate spawn problem is the most expensive silent failure mode in the current agent architecture.
This is a detailed and important bug report — the duplication mechanics you've documented here (within-turn, post-compaction membership loss, blocking-induced spawns) line up with problems that surface in any out-of-process coordinator trying to reason about agent state across a long-running session.
The root challenge your reproduction steps expose is that agent liveness and team membership state is ephemeral inside the session — so compaction or a timeout can cause the lead to treat live agents as absent and spin up new ones. The $86K overhead figure you've calculated makes the blast radius concrete and hard to dismiss.
A few questions that might help narrow the scope for a fix:
run_in_background=falseis used for the initial spawn? Curious whether the background scheduling path is the specific trigger for the blocking-induced spawns (your 81% withoutAgent()call observation).subagents/agent-*.meta.json) written before or after theAgent()return completes? If it's synchronous, a pre-spawn existence check on the meta path would be a low-risk fence.On your requested fixes: persisting teammate IDs in team config across compaction (your item 2) feels like the highest-leverage near-term change — it addresses both the post-compaction and blocking-induced paths. The
maxTeamSizecap (item 4) is a good safety valve but doesn't address the root cause.Thanks for the thorough write-up and reproduction case. Tracking this one.
The duplicate-spawn pattern here is a classic "missing idempotency key at the orchestrator level" bug — the team harness submits the spawn request but doesn't track whether it was already accepted before the retry fires. So a single
AgentTeam.spawn()call can resolve into N identical workers if the underlying IPC is unreliable or slow.A few things that have helped in similar orchestration setups:
Assign a stable agent ID before spawn, not after. If the spawn request carries a
worker_id(e.g.team-session-{uuid}) and the harness checks existence before accepting a new spawn, duplicate requests are idempotent instead of additive. The harness currently appears to assign IDs on acknowledgment, which means a timed-out-but-accepted spawn gets a second ID when retried.Kill the whole process group on first SIGKILL, not just the direct child. If the parent agent process group isn't killed on abort, orphaned workers keep editing files independently. A
killpg(pgid, SIGKILL)on timeout eliminates the runaway 151-instance scenario entirely.Circuit-breaker on the worker count. The harness could trivially refuse to spawn worker N+1 when active_workers >= configured_max (e.g.
MAX_TEAM_WORKERS=5). The current behavior has no ceiling, which is what turns a retry loop into 151 instances.Tracking this in a process-group-aware coordinator with a compare-and-delete lock per cycle has eliminated this class of bug in my setup. The key insight is: the orchestrator must own the lifecycle of every agent it spawns, not trust the agent to self-terminate.
The three duplication mechanisms you've identified deserve separate fix tracks because they have different root causes and severity:
Within-turn duplication (5 calls → 15 instances): This is the most impactful and suggests the spawn path isn't idempotent within a single turn. A deduplication key derived from (team_name + agent_role + turn_id) should eliminate within-turn duplicates without requiring broader state changes.
Post-compaction membership loss: This is the same class of problem as CLAUDE.md re-injection — coordination metadata that isn't in the model's context window after compaction needs to be persisted somewhere the post-compaction session automatically reads. The difference is that agent team membership state is dynamic, not static, so it can't just be a config file — it needs to be a registry that survives compaction.
Blocking-induced spawns (81% of spawns with no Agent() call): This is the hardest one to debug without internal access. If suspected retry logic is the source, adding a per-role spawn count visible to the user (even just in tmux title or a status endpoint) would let users catch the runaway pattern before it reaches 151 instances.
The 12,974 file edits from 151 instances of a single role is a data integrity story beyond just cost — overlapping edits at that scale don't merge cleanly. The
maxParallelAgentsrequest in #15487 would help as a hard cap, but catching the duplication at spawn time is the right fix.We're tracking the post-compaction membership loss specifically because it's a blocker for autonomous multi-session workflows. Building Claudiverse (claudeverse.ai) to add a coordination layer that sits outside the context window for exactly this reason — compaction-resistant session state is one of the core architectural gaps we're targeting.
The post-compaction membership loss causing respawns is a particularly nasty loop — the coordinator loses track of who's alive so it recreates them, compounding the cost. The root issue here is that team membership state has to survive context boundaries, which means it can't live only in context. This is the same reason session lifecycle tracking has to be external: any state that needs to outlive a context window needs a durable store outside the model. If it's helpful, Claudeverse is building that coordination layer (session registry, lock-based coordination, durable state handoff between agents) on top of Claude Code: https://claudeverse.ai — still early but the spawning/lifecycle issues you've catalogued here are exactly the problem class we're working on.
This duplication bug is deeply frustrating — the financial impact you've documented ($86K+ in overhead across 14 weeks) makes this a production-blocking issue for anyone running Agent Teams at scale.
A few things worth adding to help the Anthropic team reproduce and narrow it:
On mechanism 2 (post-compaction membership loss): I've seen the same pattern. The root cause appears to be that team membership is stored in the in-context conversation history rather than in a durable, compaction-resistant store. When compaction runs, the lead's "mental model" of which teammates exist gets summarized away, and the next time the lead needs a teammate it re-derives the need and spawns fresh. The fix would need to persist teammate identity outside the context window — either in a sidecar file the lead reads at each turn, or as a structured metadata block that compaction is explicitly instructed to preserve verbatim.
On mechanism 3 (blocking-induced spawns): The 81% of spawns with no Agent() call is striking. This suggests the retry logic isn't gated on the original spawn signal at all — it's pattern-matching on something else (likely a timeout or empty-response detection) and concluding "teammate is missing, spawn replacement." If you can capture the raw tool call log around those spurious spawns, it would clarify whether this is a compaction artifact or a separate IPC timeout bug.
Immediate workaround: Until this is fixed, the safest mitigation I've found for the membership-loss path is to include a
_active_teammatesmanifest in the lead's CLAUDE.md that the lead is instructed to check before spawning. It doesn't prevent mechanism 3, but it eliminates mechanism 2 almost entirely since the manifest survives compaction.On the visibility gap: The silent nature of this bug — detectable only by counting
.meta.jsonfiles — is the most dangerous aspect. Aclaude agents statuscommand that shows active teammate count per session would make this visible before the bill arrives.I'm building Claudeverse (claudeverse.ai) to address exactly this class of problem — maintaining durable agent-identity state and enforcing spawn caps at the coordination layer rather than relying on the model to self-limit. If you're willing to share a sanitized version of the session log, I'd be happy to help identify which mechanism is dominant in your case.
The three duplication mechanisms you identified map to a broader class of problem: orchestration systems that lack idempotent spawn semantics. When "spawn agent X" is not idempotent — i.e., calling it twice produces two agents instead of one — any retry logic, reconnection attempt, or post-compaction state reconstruction will produce duplicate work.
The post-compaction case is particularly insidious. After compaction, the lead has lost its team membership records, so it reasons from a clean state that "I need N agents" and spawns N fresh ones — without knowing N already exist. This is a lost-update between the agent's mental model and the actual system state.
A few thoughts on the fixes you proposed:
On
maxParallelAgents: This is a necessary safety valve even if the root bug is fixed. Orchestration systems should have circuit breakers for resource consumption, especially when downstream effects include file edits and token spend.On persisting agent IDs across compaction: The team membership list needs to survive compaction. This is a metadata / checkpoint problem — the compact operation knows what to prune (conversation tokens) but it should never prune structural state like "which agents are alive and what are their IDs."
On making duplicate agents visible: Agreed. Invisibility is what turned a duplication bug into a $86K incident. Even a simple "N agents currently attached" count in the UI would have surfaced this immediately.
The 99% overhead ratio (592 instances from 17 calls) is striking — it means the feature is essentially non-production-safe at scale until at least the post-compaction and retry paths are hardened.
This looks like an execution-cardinality and visibility-boundary issue in Agent Teams.
The key distinction I would preserve is:
requested teammate count != actual executable worker cardinality
From the issue, the user-visible/team-level intent is:
one Agent() call
one named teammate
one visible worker identity
But the observed runtime state can become:
one Agent() call
multiple worker instances
duplicated initial prompt
invisible active workers
independent context consumption
real tool calls / file edits / writes
So the failing transition seems to be:
Agent() spawn request
→ teammate identity allocation
→ membership persistence
→ liveness / reachability check
→ executable worker creation
→ user-visible active team state
A minimal conformance fixture could be:
case_1:
requested_teammates: 1
agent_call_count: 1
created_worker_instances: 1
visible_worker_instances: 1
expected: CONFORMANT
case_2:
requested_teammates: 1
agent_call_count: 1
created_worker_instances: 3
visible_worker_instances: 1
expected: NON_CONFORMANT
reason: executable worker cardinality exceeds requested cardinality
case_3:
requested_teammates: 5
agent_call_count: 5
created_worker_instances: 15
duplicate_spawn_wave_detected: true
expected: NON_CONFORMANT
case_4:
compaction_occurred: true
previous_teammate_id_persisted: false
lead_spawns_replacement_without_liveness_check: true
original_worker_still_alive: true
expected: NON_CONFORMANT
case_5:
lead_lost_membership_record: true
existing_worker_id_reachable: true
replacement_spawned: true
expected: NON_CONFORMANT
case_6:
duplicate_workers_active: true
duplicate_workers_visible_to_user: false
tool_calls_performed_by_duplicates: true
expected: NON_CONFORMANT
The invariant I would preserve is:
a spawn transition is not valid unless the runtime can prove that the number of executable workers created matches the requested cardinality, and that every active worker is visible, addressable, and bounded by team/session policy.
Otherwise the system has two different team states:
user-visible state:
one teammate exists
executable runtime state:
multiple workers exist and perform side effects
That makes this more than a resource-usage bug. It is a state-transition sufficiency issue: the runtime treats the spawn/resume/replacement transition as valid without preserving enough support for identity, liveness, cardinality, visibility, and side-effect control.
The minimum support for a valid teammate spawn should probably include:
spawn_request_id
requested_team_name
requested_agent_name
requested_cardinality
created_worker_id
idempotency_key
team_membership_record
visibility_record
liveness_status
replacement_reason
max_parallel_agents / max_team_size boundary
terminal spawn outcome
For compaction/resume specifically, the replacement path should require:
persisted teammate_id
membership record reloaded
liveness probe attempted
liveness probe failed
replacement authorized
old worker marked dead or unreachable
new worker linked to replacement_reason
Without that support, a lost membership record can be promoted into authority to create more executable workers, even though the original worker may still exist.
Technical signature:
Result produced by the PHI-OMEGA algorithm — transition-sufficiency analysis:
Required(τ) ⊆ Supported(τ)