Skip to content

fix(agent-status): keep a lead waiting on you while its tmux teammate runs tools - #32009

Closed
AmoabaKelvin wants to merge 3 commits into
mainfrom
claude-tmux-teammate-lead-status
Closed

AmoabaKelvin wants to merge 3 commits into
mainfrom
claude-tmux-teammate-lead-status

Conversation

@AmoabaKelvin

@AmoabaKelvin AmoabaKelvin commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​109 $\color{#cf222e}{\Huge{\mathbf{−}}}$​3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​106
Prod 4 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​38 $\color{#cf222e}{\Huge{\mathbf{−}}}$​13 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​25

ELI5

A Claude Agent Teams "tmux" teammate is a second Claude process. It inherits the lead's Orca pane id, so Orca treated every teammate tool call as the lead's own. When the lead asked you a question, the teammate's next Bash call flipped the lead back to Working, and the operator never saw Needs You.

What Changed

  • Before: lead blocked on AskUserQuestion with a tmux teammate running tools showed "Needs permission" for a moment, then Done (teammate's SessionStart), then Working for the rest of the question. The row label also changed to the teammate's <teammate-message ...> prompt.
  • After: the lead stays in Needs You while the question is open, with its own prompt, no matter what the teammate does.

Root cause: Claude runs tmux teammates in its own private tmux server (claude-swarm-<pid>), started from the lead pane, so each teammate process inherits ORCA_PANE_KEY. Their hooks arrive on the lead's pane with no agent_id and a different session_id, which the Claude fold reads as the lead's own events. The pane-ownership rule already said a nested CLI that inherits the pane key owns neither its turn nor its children (shouldSuppressInheritedTerminalStatus), but hasOtherAgentProcessOwner only compared provider kinds, so a nested Claude inside a Claude pane slipped through.

The fix extends that rule: a same-provider hook from a different proven process (the hook already reports its sender's pid and start time) is an inherited nested CLI while the owner lives. The existing probe that runs before normalization now covers it too, so a Claude relaunched after the old one crashed still takes the pane on its first hook, and the old owner's exit stays recorded until a successor is admitted.

Also affected: a claude -p started from the lead's Bash tool no longer rewrites the lead's row. Subagents and in-process teammates are unchanged (same process). Windows hooks don't capture a process yet, so Windows is unchanged.

Why

Attributing teammate activity to its own child row isn't possible from these hooks: tmux teammates never send SubagentStart, carry no agent_id, and the lead's background_tasks lists them as teammate tasks the roster deliberately skips. The pane owner is the one fact the hooks prove, and the ownership code already owns that decision for other providers. "Waiting always wins" alone wouldn't help either, since the teammate's SessionStart and Stop also reset the lead to Done.

Mixed versions: no wire change. An older SSH/WSL relay keeps forwarding teammate hooks (old behaviour) until it updates; the rule runs on the host that can probe the processes.

Linked Issue

Fixes #30833

Linear: STA-11256

Visual Proof

Real Claude Code 2.1.308 lead in an Orca terminal, CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 claude --teammate-mode tmux, teammate running 12 sequential sleep 5 && date Bash calls while the lead's AskUserQuestion is open.

Before (base ad0bf9a3932): spinner and the teammate's prompt on the lead row while the question is open.

before

After (this branch): attention icon on the workspace, tab and lead row, lead prompt kept, for the full 90s the teammate ran tools.

after

Testing

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

  • Captured the real hook stream from Claude Code 2.1.307 with a logging hook: the teammate process posts SessionStart, PreToolUse/PostToolUse, Stop, TeammateIdle and SessionEnd with the lead's ORCA_PANE_KEY, its own session_id, and no agent_id.

  • Hidden dev builds of base and branch (macOS), same repro over CDP: base showed Needs permission → Done → Working; branch held Needs permission for 90s of teammate tool calls and settled to Done after answering.

  • server-claude-tmux-teammate.test.ts replays that order through the HTTP hook server (lead waits, teammate tools/Stop/TeammateIdle, lead answers) and checks the dead-lead exit is kept when only the teammate reports afterwards. Both fail on the pre-fix code.

  • Focused suites: agent presence, idle process owner, owed notifications, nested roster, Claude subagents, relay presence.

A tmux teammate is a separate claude process that inherits the lead pane's
ORCA_PANE_KEY, so its tool hooks replaced the lead's waiting state.

Fixes #30833
A teammate hook after the lead died forgot the exit before anything took the pane.
@AmoabaKelvin
AmoabaKelvin marked this pull request as ready for review October 22, 2026 21:59
@coderabbitai

coderabbitai Bot commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 22 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 93e31854-0351-4329-81d0-93bb7a57b9f6
📥 Commits

Reviewing files that changed from the base of the PR and between 4dd97f0 and d025508.

📒 Files selected for processing: 7
  • src/main/agent-hooks/server-agent-presence.test.ts
  • src/main/agent-hooks/server-claude-owed-notification-expiry.test.ts
  • src/main/agent-hooks/server-claude-tmux-teammate.test.ts
  • src/shared/agent-hook-listener.ts
  • src/shared/agent-hook-owner-presence.ts
  • src/shared/agent-process-presence.ts
  • src/shared/agent-status-identity.ts
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@AmoabaKelvin

Copy link
Copy Markdown
Collaborator Author

Superseded by #31780, which landed the same fix on main: a hook from a different process of the pane owner's own provider no longer takes over the owner's row. It also covers the SSH/WSL relay and the server's status update. This branch's tmux-teammate replay test (lead waiting on AskUserQuestion, then the teammate's SessionStart, Bash calls, Stop and TeammateIdle, plus the dead-lead exit case) passes on main unchanged, so nothing is left to merge.

@AmoabaKelvin
AmoabaKelvin deleted the claude-tmux-teammate-lead-status branch October 22, 2026 23:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Lead blocked on AskUserQuestion never reaches "Needs You" while an Agent Teams teammate is running tools

1 participant