Agent Teams: lead session stops processing teammate responses until manual keystroke (interactive TTY, default mode)

Status Closed — not planned
Reported on v2.1.83
Maintainer reply None cached
Activity 12 comments · opened Mar 25, 2026 · closed Jun 25, 2026

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?

When using Agent Teams in default mode (interactive TTY, not tmux), the lead session stops processing teammate responses after teammates finish their work. The teammate completes, goes idle ("Crunched for Xm"), and the lead remains stuck at "Idle · Waiting for results..." indefinitely.

The moment I click into the lead's terminal window and press any key (even without submitting), the teammate's response is immediately processed and the lead continues.

This happens consistently across sessions. In one test, a teammate sat in "Crunched" state for 30+ minutes before I manually clicked into the window and pressed a key to unstick the lead.

This is the lead-side counterpart to #34668 (which reports the teammate side stalling) and is likely caused by the same root issue identified in #26426: the InboxPoller is implemented as a React hook (setInterval inside the Ink TUI component tree) and only fires when the Ink render loop is active. When the lead is idle (no tool calls, no stdin events), the render loop throttles and inbox polling stalls.

What Should Happen?

The lead should process teammate responses immediately when they arrive, regardless of whether the user is actively interacting with the lead's terminal window.

Steps to Reproduce

  1. Start Claude Code in default teammate mode (interactive TTY, no tmux)
  2. Create a team and dispatch a teammate via TeamCreate + Task
  3. Switch focus to a different terminal window/tab (do not interact with the lead's terminal)
  4. Wait for the teammate to complete its work and go idle
  5. Observe the lead remains at "Idle" / "Waiting for results..." for 5-30+ minutes
  6. Click into the lead's terminal and press any key
  7. The lead immediately processes the teammate's response and continues

Workarounds We Tested (None Worked)

| Approach | Result |
|----------|--------|
| iTerm2 anti-idle (ASCII 0 null byte every 60s) | ❌ No effect — null byte doesn't trigger Ink's keypress handler |
| SIGWINCH signal (pkill -SIGWINCH) to lead process | ❌ No effect — signal is delivered but doesn't wake inbox polling |
| Direct PTY write (echo -ne '\x1d' > /dev/ttysXXX) | ❌ No effect — byte reaches PTY but doesn't trigger Ink re-render |
| PostToolUse:SendMessage hook sending SIGWINCH | ❌ Hook may not fire (Task tool uses internal completion path, not SendMessage) |
| Manual keystroke in focused terminal | ✅ Only thing that works — immediate response |

Root Cause Analysis

The InboxPoller is a React hook using setInterval(1000ms) inside the Ink TUI (per #26426's analysis). When the lead session is idle:

  1. No stdin events → Ink's render loop enters low-frequency mode
  2. setInterval callbacks are starved (timer coalescing + render loop throttling)
  3. Teammate messages accumulate in inbox JSON files, unread
  4. Manual keystroke → stdin event → Ink re-render → setInterval fires → messages delivered

Why signals and PTY writes don't work: The issue is not simply that the Node.js event loop is sleeping. If it were, SIGWINCH would wake it. The fact that signals are delivered but don't trigger inbox polling suggests the stall is specifically in Ink's rendering/timer scheduling layer, not the underlying event loop. Only a genuine stdin keypress event triggers Ink's full input processing pipeline, which re-activates the render cycle and associated timers.

Suggested Fix

Decouple InboxPoller from the React render loop. Run inbox polling as a standalone setInterval in the main Node.js event loop (not as a React hook), or use fs.watch on the inbox directory for push-based notification instead of timer-based polling.

Claude Model

Opus

Is this a regression?

Yes — this was not present ~4-6 weeks ago. Likely introduced when idle CPU consumption was optimized (addressing issues like #17148, #22131), which throttled the Ink render loop.

Claude Code Version

2.1.83

Platform

Anthropic API (Max)

Operating System

macOS (Darwin 24.6.0, Apple Silicon)

Terminal/Shell

iTerm2 / zsh

Additional Information

  • iTerm2 has DisableAppNap = 1 and NSAppSleepDisabled = 1 — App Nap is not the cause
  • macOS timer coalescing is enabled (kern.timer.coalescing_enabled = 1) which may compound the issue
  • 18+ concurrent Claude Code sessions running in parallel
  • Related issues: #34668 (teammate side), #26426 (non-interactive/SDK mode), #24246 (delayed idle status)

View original on GitHub ↗

11 Comments

github-actions[bot] · 5 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/34668
  2. https://github.com/anthropics/claude-code/issues/36418
  3. https://github.com/anthropics/claude-code/issues/26426

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

zzelner · 5 months ago

This has become a nightmare for us. Please help!! @bcherny

jasonswearingen · 5 months ago

i see this also, on Windows, along with general agent-teams stop sending updates to team-lead.

MekhailS · 5 months ago

Stable reproduces for us on long enough CC agent teams sessions

danielnoah1 · 5 months ago

I see this on macOS. Claude Code has become unusable @bcherny

kyzzen · 4 months ago

Confirming on Linux (WSL2) — same behavior as described.

Additional observation: The lead unsticks not only on a keystroke, but specifically on arrow-down + highlight (selecting any agent in the list without pressing Enter). This suggests the wake trigger is the TUI selection/focus change event in the agent picker, not necessarily a raw stdin keypress. This may narrow the root cause from "any Ink input event" to specifically the agent-list component's onHighlightItem or equivalent selection handler re-triggering the render cycle.

Environment:

  • Claude Code v2.1.100
  • Linux 6.6.87.2-microsoft-standard-WSL2
  • Anthropic API (Max)
  • bash / Windows Terminal
kyzzen · 4 months ago

Workaround: PreToolUse hook that forces TaskList polling

We found a reliable workaround using the hook system. The root cause appears to be the Ink render loop stalling when the lead goes idle — no re-render means queued teammate SendMessage deliveries never flush to the UI.

The fix: a PreToolUse:TeamCreate hook that injects an additionalContext instruction telling the lead to poll TaskList every 30 seconds. This keeps the render loop active and messages flow without the arrow-key trick.

Hook script (team_lead_anti_idle.py):

#!/usr/bin/env python3
"""PreToolUse hook: inject anti-idle instruction when a team is created."""
import json
import sys

ANTI_IDLE = (
    "IMPORTANT: While waiting for teammates to complete work and send results via SendMessage, "
    "you MUST run TaskList every 30 seconds to check progress. Do NOT go idle between checks. "
    "This prevents a known UI rendering bug where teammate messages are not delivered until you interact."
)

def main():
    event = json.loads(sys.stdin.read())
    if event.get("tool_name") != "TeamCreate":
        sys.exit(0)

    print(json.dumps({
        "hookSpecificOutput": {
            "hookEventName": "PreToolUse",
            "permissionDecision": "allow",
            "permissionDecisionReason": "Anti-idle instruction for team lead",
            "additionalContext": ANTI_IDLE,
        }
    }))
    sys.exit(0)

if __name__ == "__main__":
    main()

settings.json entry:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "TeamCreate",
        "hooks": [
          {
            "type": "command",
            "command": "python3 '/path/to/team_lead_anti_idle.py'"
          }
        ]
      }
    ]
  }
}

Why it works: The TaskList tool calls force Ink to re-render, which processes the queued teammate message deliveries. The additionalContext field in the hook output gets injected as a system-reminder, so the lead treats it as a firm instruction rather than a suggestion.

Tested on: v2.1.100, Linux WSL2, Anthropic API (Max). Teammate messages delivered reliably across multiple team sessions without any manual keystrokes.

ParkerM2 · 4 months ago

I noticed this around 2-3 weeks ago. Completely ruins my workflow plugin that orchestrates the Claude Agent Teams.

Screenshot of the bug in action while typing this comment. All "grey" team-agents in bottom status line are idle, messages are in the team-lead inbox. 👎

<img width="2299" height="773" alt="Image" src="https://github.com/user-attachments/assets/05bc9f92-85a4-4401-a086-d9b69f86ab59" />

bobloy · 4 months ago

Reproduced on Windows 11 with Windows Terminal + PowerShell at v2.1.113 — filed as #51167 (now closed as a duplicate of this) with full diagnostics before I found this issue. Same symptom: parent with CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 dispatches teammates via TeamCreate + parallel Agent() calls, teammates complete cleanly, parent stays idle indefinitely until an input event hits the terminal. Your InboxPoller-on-Ink-render-hook analysis matches what I'm seeing from the Windows side; this isn't a macOS-only timer-coalescing or App-Nap problem.

Process-level evidence from the stalled parent, for what it's worth:

  • CPU delta over a 5s sample while stalled: ~94ms (heartbeat only). A non-stalled parent actively working in the same state: ~720ms. Consistent with "event loop alive but callbacks starved," not hard-frozen.
  • Thread wait reasons at stall time: 32 Unknown, 4 EventPairLow, 2 UserRequest across 38 threads.
  • Ruled out Windows-specific red herrings: powercfg /powerthrottling disable on claude.exe (green-leaf confirmed absent), foreground/occlusion state, Windows Terminal "Always on top", software renderer, QuickEdit selection mode. None of them affect the repro.

One data point that may narrow the wake mechanism and that I don't see tested in the macOS reports: on Windows Terminal, giving the parent window focus alone wakes the parent — no click or keystroke required. Alt-Tabbing into the terminal from another app is sufficient. I haven't verified the mechanism; I suspect some focus-related byte (xterm focus reporting, mouse-tracking focus events, or a Windows Terminal side-channel) lands on stdin and traverses the same input pipeline a keystroke would, but that's a guess. Regardless of the exact path, the observation seems consistent with the InboxPoller hypothesis — it just means the set of "wake events" is broader than keystrokes. Most manual tests in the macOS reports seem to involve clicking into the terminal, which conflates focus change with mouse input; might be worth isolating.

If focus-alone-wakes holds up generally, there may be a cheap mitigation path that doesn't require restructuring InboxPoller off the React hook: on teammate report delivery, have the lead process nudge its own input pipeline somehow (a benign byte written to stdin, or whatever focus-in does internally). The input pipeline fires, Ink renders once, the starved setInterval gets serviced. Less clean than fs.watch or decoupling the poller from the render loop, but potentially a short-term unblock for wave-based multi-agent workflows without touching the TUI architecture.

The Windows process diagnostics on #51167 are still there if they're useful to whoever picks up the fix.

vignzpie · 3 months ago

Reproduces on Linux (and inside tmux), Claude Code 2.1.150 — still live.

Hit this today on a long-running Agent Teams session. Same symptom as the OP: the lead is stuck at "Idle · Waiting for results…" while a finished teammate's message sits unprocessed in the inbox.

Environment

  • Claude Code 2.1.150
  • Debian 13 (trixie), Linux 6.12.75 aarch64 (Raspberry Pi 5)
  • Agent Teams, in-process teammate mode (switchable agent views in one session, ← for agents — not tmux split-pane), interactive TTY hosted inside a tmux session. (OP noted "not tmux"; adding that it also reproduces when the interactive TTY itself is a tmux session, in-process mode — distinct from the split-pane case in #24108.)

On-disk evidence (single timezone)

  • Lead's last turn (session transcript JSONL last write): 23:58:11
  • Teammate completion → lead inbox (team-lead.json): "PR #140 re-pushed, ready to re-gate" + {"type":"idle_notification","idleReason":"available"}, written 00:08:17 — 10 min after the lead had already gone idle.
  • 00:43 (35+ min later): lead still idle, zero new turns in its transcript; the message remains unread in the inbox file.
  • A keystroke into the lead session drains and processes it immediately — matching the OP.

Observation:

Consistent with the OP and #26426: the InboxPoller setInterval lives inside the Ink render loop, which throttles when the lead is idle (no stdin/tool events), so delivered inbox messages aren't injected until input revives the loop. The inbox→lead-turn path stalls specifically in the idle state; #50779 covers the tool_use-chain deferral — same path, unreliable in both states.

Still live on the latest version (2.1.150). Happy to share raw inbox/transcript artifacts if useful.

github-actions[bot] · 2 months ago

Closing for now — inactive for too long. Please open a new issue if this is still relevant.

Showing cached comments. Read the full discussion on GitHub ↗