[Bug] FleetView TUI render loop frozen while attached to background fleet session
Bug Description
Summary: claude agents (FleetView) TUI stops processing input while attached to a
background fleet session. It still READS stdin but never acts on it; the render loop
is frozen.
Frequency: 4 occurrences in ~3 hours on one machine. Each within 2–74 min of attaching
to a session view. The fleet LIST layer never wedged; the bg workers themselves ran
4–12 h with no issue.
Evidence:
- Keystrokes ARE consumed: the read-only tty fd (5r in lsof) advances by exactly the
escape-sequence length per keypress.
- Nothing happens: tmux capture-pane | md5 byte-identical across keypresses, cursor
position never changes, CPU flat (~0.05s per 6s).
- SIGWINCH does not force a redraw (screen hash unchanged).
- sample <pid>: main thread 3580/3601 samples in kevent64 — normal libuv idle wait,
so not a spin or mutex deadlock. Binary is stripped, no symbol names.
- Gotcha for whoever reproduces this: fd 0/1/2/4/6 are dup'd from one open file
description and their offset counts terminal OUTPUT (3.1 MB in 74 min), not input.
Measuring fd 0 gives a misleading "not reading" verdict.
Excluded (each tested): tmux copy-mode; two attached clients with different sizes;
window-size pinned to manual; daemon restart (uptime continuous, binary mtime unchanged
during an episode); machine memory pressure (6 other bg sessions kept producing output);
terminal resize.
Versions: reproduces on both 2.1.226 (latest) and 2.1.220 (stable). The .220 viewer
wedged in ~2 min.
Impact: the viewer is the only way to interact with a background fleet session, so a
wedge blocks all interaction. Workaround is kill
claude agents. Unsent draft text survives (it lives on the session side).
Secondary issue found while testing: a different-version client can take over as daemon.
Installing 2.1.220 to a separate npm --prefix dod daemon
share the same socket path (/tmp/cc-daemon-<uid>/<hash>), so when the global binary was
auto-updated and the running daemon self-restarte daemon and
supervised the fleet for 3 minutes. Its log: "post-takeover prewarm burst — respawned
0/11 stale workers, 11 refused in 0s" — it judges stale and
tried to respawn them.
Environment: macOS 26, Apple M2 Max, tmux 3.6a, iTerm2, 8–11 bg workers under one
transient daemon.
Environment Info
- Platform: win32
- Terminal: xterm-256color
- Version: 2.1.226
- Feedback ID: a759326d-4788-4946-b243-1febc92ec93e
Errors
[]
3 Comments
Running into the same thing on M2 Pro. The frozen-but-consuming-input pattern makes it really hard to tell if the session is stuck or just slow -- you keep pressing keys and nothing changes so you either wait too long or force-kill prematurely.
One thing I noticed that correlates with triggering this: attaching to a background session that had already completed one or more sub-tasks before you opened the fleet view. The TUI seems to miss the state transitions that happened while it wasn't watching, so the render cycle has nothing to reconcile and just idles permanently.
Until this is fixed, a workaround I've been using: open a second terminal, run
claude agents --jsonto poll status, and only open the interactive TUI view when you actually need to send input. Ugly but avoids burning time waiting on a frozen screen.Worth noting for the Anthropic team: the blocking workaround (kill claude agents and re-attach) resets the view context, which means any in-progress dispatch you had open is lost. That makes this more than a cosmetic bug -- it interrupts mid-run human-in-the-loop gates.
(Disclosure: I'm building Claudiverse, tooling that adds a web-based fleet dashboard on top of Claude Code sessions, partly because of this class of issue. Happy to share reproduction data if it helps narrow the root cause.)
Thanks — the idle-wait framing is consistent with what I measured, and it's
worth pinning down where our repros differ.
First, a correction to my own report: the auto-filled Environment Info says
Platform: win32. That's wrong — the template picked it up incorrectly. Theactual environment is the one described in the body: macOS 26, Apple M2 Max,
tmux 3.6a, iTerm2, Claude Code 2.1.226 (also reproduced on 2.1.220). Flagging
in case it affected triage routing.
Where your description lines up with my evidence:
sample <pid>during awedge put the main thread at 3580/3601 samples in
kevent64— a normal libuvidle wait, not a spin and not a mutex deadlock. That's the signature you'd
expect if the render loop simply has no pending work to reconcile, so
"reconciler has nothing queued" fits the profile better than "loop is blocked
on something."
Where it doesn't line up: in my four occurrences the wedge happened
2–74 minutes after attaching, not at attach time. If missing the state
transitions that occurred before the fleet view opened were sufficient on its
own, I'd expect the view to be dead from the first frame — not to render
correctly for over an hour and then stop. So either there's a second trigger
that fires later, or the missed-transition state only becomes fatal once some
subsequent event tries to reconcile against it.
Two questions on your repro, if you have them handy:
delay, roughly what range across occurrences?
did any session you attached to with zero completed sub-tasks also wedge?
That second one is what separates "missed transitions are the cause" from
"missed transitions are correlated with something else" — e.g. longer-running
sessions simply have more completed sub-tasks and more elapsed time.
Yes to the reproduction data — please share it.
On the
claude agents --jsonpolling workaround: useful for the "is it stuckor just slow" question, and I'll use it for that. Worth noting for anyone
finding this later that it doesn't address the blocked path itself — the TUI
is still the only way to send input, so the moment you actually need to
respond to a gate you're back in the frozen view.
We weren't able to reproduce this. Could you provide steps to trigger the issue — what you ran, what happened, and what you expected? This issue will be closed automatically if there's no activity within 7 days.