[BUG] Named Agent-tool teammates overwrite their lead's background job resumeSessionId; a respawn of the lead after a teammate's turn resumes the teammate's transcript

Status Open
Reported on v2.1.283
Maintainer reply None cached
Activity 0 comments · opened Sep 29, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (closest: #79757, #82489, #89624 — all about a resumed or backgrounded session minting a new id; none covers a teammate rewriting its lead's job pointer)
  • [x] This is a single bug report
  • [x] I am using the latest version of Claude Code (observed on 2.1.283; the code path is unchanged in the 2.1.284 changelog)

What's Wrong?

A named Agent-tool subagent (Agent tool with name, which runs as a separate process with --agent-name <n> --team-name session-<job id> under the tmux swarm backend) inherits the lead's CLAUDE_JOB_DIR and CLAUDE_CODE_SESSION_KIND=bg. On every turn, a process with those two variables writes its own session id into ~/.claude/jobs/<job>/state.json → resumeSessionId. So each teammate turn repoints the lead's job record at the teammate's transcript. A live lead writes its own id back on its next turn (measured: 7 s later), so nothing is visible while the lead keeps taking turns.

If the lead's process is gone while the pointer names a teammate, the next respawn of the job resumes the teammate's conversation under the lead's name and job. The lead's own transcript is intact on disk but unreachable from the agents view: the row shows the lead's name, and opening it shows the teammate's conversation. Sending it a prompt continues the teammate's transcript.

Respawn paths that follow the pointer:

  • claude --bg --resume <lead-session-id> — measured: the prompt lands in the teammate's transcript, the lead's is untouched.
  • The agents-view attach-stall restart ("Session not responding — restarting it…", event tengu_bg_attach_stall_respawn) — observed on five real sessions over six days. In every case the lead's bg-pty-host had been SIGSTOPped by a local disk-pressure watchdog, so it could not redraw on attach, the daemon killed it and resumed resumeSessionId, which a teammate had written.
  • claude stop <job> then a wake, and the daemon's idle retire then a wake, use the same field. Not separately measured (see below).

Side effects seen on the way:

  • A lead respawn rebuilds ~/.claude/teams/session-<job>/config.json and deletes its inboxes/ folder, so teammates that outlive the lead's respawn can no longer be messaged.
  • claude stop <job> prints "stopped" for a SIGSTOPped session but leaves its process alive; a --bg --resume issued then starts a copy under a new session id.

What Should Happen?

resumeSessionId should be written only by the job's own lead process — for example by not inheriting CLAUDE_JOB_DIR (or by clearing CLAUDE_CODE_SESSION_KIND) in teammate processes. claude --bg --resume <session-id> should resume that session id, not whatever the job pointer currently says. Teammates should not become the job's resume target under any path.

Error Messages/Logs

# ~/.claude/jobs/<job>/state.json, polled every 2 s while a lead with one named teammate ran
# (job e0368c13, lead e0368c13-7a64-4234-a98e-585caf374e79, teammate b005fd4e-82ba-49f2-8897-a49b3bfdfc22)
resumeSessionId = e0368c13-...   # lead idle
resumeSessionId = b005fd4e-...   # teammate takes a turn
resumeSessionId = e0368c13-...   # 7 s later: lead's next turn writes it back
resumeSessionId = b005fd4e-...   # lead process stopped, teammate poked: stays here
# then: claude --bg --resume e0368c13-7a64-4234-a98e-585caf374e79 "append X to a file"
# → "append X" appears in b005fd4e-....jsonl; e0368c13-....jsonl unchanged

Agents view on the real incidents: Session not responding — restarting it… followed by the row (lead's name) showing the teammate's conversation.

Steps to Reproduce

  1. claude --bg --name exp-lead "spawn one teammate named exp-mate via the Agent tool (pass name: exp-mate), then end your turn".
  2. Poll ~/.claude/jobs/<job>/state.json: when exp-mate starts, resumeSessionId becomes exp-mate's session id; it flips back on the lead's next turn.
  3. Stop the lead's process (kill its worker, or SIGSTOP it), then send exp-mate a message (write to its inbox). resumeSessionId becomes exp-mate's id and stays.
  4. claude --bg --resume <lead-session-id> "append X to a file" — the prompt runs in exp-mate's transcript; the lead's transcript is unchanged.
  5. Set resumeSessionId back to the lead's id by hand and repeat step 4 — the prompt now runs in the lead's transcript. (This edit is the workaround.)

Claude Model

Not model dependent (daemon/job bookkeeping).

Is this a regression?

Unknown — first noticed with named Agent-tool subagents on 2.1.28x; the same --team-name process model is used by TeamCreate teammates.

Claude Code Version

2.1.283 (also present in the job/daemon files on 2.1.284)

Platform

Not platform dependent (daemon/job bookkeeping).

Operating System

macOS (darwin arm64), native install

Terminal/Shell

iTerm2 / zsh; the takeover surfaces in the agents view (claude agents)

Additional Information

Related: #79757 (job record names a transcript other than the real conversation), #82489 (backgrounding mints a new id without the transcript), #89624 (resumeSessionId points to itself on --bg -r). #89624's observation that resumeSessionId is always the session's own id is the same write path: every bg-kind process writes its own id there on every turn; the bug here is that a teammate process shares the lead's job dir and so writes into the lead's record.

Workaround used: stop the lead's process if it is still alive, set resumeSessionId back to the lead's session id in state.json, back up ~/.claude/teams/session-<job>/ (the respawn deletes its inboxes), then claude --bg --resume <lead-session-id>.

View original on GitHub ↗