[BUG] Agent view: TUI freeze on entry, mouse-tracking leak on kill, orphaned daemons on close — Windows 11, 2.1.143
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported as a single tracking issue
- [x] This is a single bug report covering three tightly coupled defects in one feature (agent view) — splitting them would lose the causal chain
- [x] I am using the latest version of Claude Code
Summary
The agent view feature shipped in the 2.1.140+ release line exhibits three distinct defects on Windows that compound into a positive feedback loop. This issue documents the full chain, root cause hypothesis, and suggested fixes. Several existing reports (#58653, #48629, #34076, #59563, #59511, #42606, #50032, #38578) each capture one slice of this. None capture the full interaction, and the duplicate-marking has left no single tracking issue for terminal-mode restoration on abnormal exit.
I'll refer to the three defects as D1 / D2 / D3 throughout.
Environment
| | |
|---|---|
| OS | Windows 11 |
| Claude Code | 2.1.143 (npm/Volta install at %LOCALAPPDATA%\Volta\bin\claude) |
| Shell | PowerShell 7.5.5 |
| Terminals (both reproduce) | Windsurf integrated (xterm.js 6.1.0-beta.168), Microsoft Windows Terminal |
| Subscription | Claude Max |
| Model | Opus 4.7 (1M context) |
| MCP servers | 12 connected |
| Workload | 3 concurrent Windsurf projects, 5–8 parallel agent tasks (heavy parallel use) |
Symptom chain — three defects that compound
D1 — Agent view freezes the entire TUI on entry
This is the headline failure. Entering agent view via either left-arrow shortcut from an active session, or claude agents standalone, locks the TUI: keyboard input is ignored, the output viewport will not scroll (input composer still scrolls — confirming the input layer is alive but the renderer is wedged). Only external Stop-Process recovers.
2.1.143's changelog asserts:
Fixed: on Windows, pressing ← in claude agents while a response was streaming could leave the agents list unresponsive to all input
This fix is not effective in my environment. The freeze reproduces on left-arrow with streaming, on left-arrow while idle, and on claude agents as a fresh command. Reproduction rate at the time of filing: ~100% (5/5 attempts after a clean process slate; see D3 for what "clean" means and why it matters).
D2 — Mouse-tracking modes not released on abnormal exit
When Claude Code is killed externally while agent view is active (the only escape from D1), the disable sequences for DECSET 1000/1002/1003/1006 are never emitted. The parent shell remains in SGR mouse-tracking mode indefinitely.
Concrete artifact — captured from a real Windows Terminal session after killing Claude Code via Get-Process claude | Stop-Process -Force while agent view was open:
[I[555;17;1M[555;17;2M[555;18;3M[555;18;4M[555;19;4M[555;19;5M[555;20;6M[555;21;7M
[555;22;8M[555;23;9M[555;23;10M[555;25;12M[555;25;13M[555;26;14M[555;27;15M[555;27;16M
…continues unbounded with every cursor movement…
These are CSI < button ; col ; row M SGR mouse-event reports leaking as literal stdout because the shell is in mouse-tracking mode but Claude Code is no longer there to consume them.
Manual recovery (this should not be necessary):
[Console]::Write([char]27 + "[?1000l" + [char]27 + "[?1002l" + [char]27 + "[?1003l" + [char]27 + "[?1006l")
This is the same defect class as #58653 (open, labeled platform:macos but reproduces on Windows), #48629 (closed as duplicate), #34076 (closed as duplicate), and #59563 (open). The cluster needs a single tracking issue.
D3 — Orphan-process cascade (the multiplier)
Not strictly an agent-view bug, but it's what makes D1+D2 catastrophic on Windows over time.
Windows does not propagate SIGHUP-equivalent on terminal close. When a user hard-closes a frozen terminal (the standard escape from D1), the claude process and all its child agent processes become orphaned. They continue running indefinitely. After ~24 hours of normal heavy use I accumulated 34 orphaned claude processes consuming ~20 GB combined RSS (on a 64 GB workstation, which is why I noticed before OOM):
PS> Get-Process claude | Measure-Object
Count : 34
PS> Get-Process claude | Measure-Object WorkingSet64 -Sum
Sum : 20,331,495,424
These zombies hold file locks on claude.exe (blocking reinstall/upgrade), compete for terminal I/O when a new session enters agent view (further degrading D1), and silently consume system resources.
The feedback loop
D1 freezes the user → forces the only-available recovery (hard-close terminal) → which triggers D2 (mouse-tracking leak in shell) and D3 (orphaned process pool) → which makes D1 worse next time. This is why the feature degrades meaningfully within a single workday of heavy use rather than failing once and being recoverable.
Reproduction (D1 → D2)
1. claude # in any project
2. Send a prompt that streams for >5 seconds
3. While streaming, press ← to enter agent view → TUI freezes (D1)
4. From a separate shell: Get-Process claude | Stop-Process -Force
5. Return to original terminal pane
6. Move mouse over the pane → unbounded escape-sequence output (D2)
Tested on 2.1.143; symptoms persist across both Windsurf integrated terminal and standalone Windows Terminal, indicating the bug is in Claude Code's TUI layer, not the terminal emulator.
Root cause hypothesis
D2 is a missing terminal-state restoration on abnormal exit. The fix pattern is well-established in TUI applications (vim, htop, less, kitty all do this correctly):
- Register a signal/event handler that emits
\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?1004lonSIGINT,SIGTERM, and on WindowsCTRL_CLOSE_EVENT/CTRL_LOGOFF_EVENT/CTRL_SHUTDOWN_EVENTviaSetConsoleCtrlHandler. - Register an
atexithandler as a backstop for process-managed shutdowns. - On
process.on('uncaughtException')and'unhandledRejection'— emit the restore sequence before re-throwing/exiting. This is what bites on the agent-view freeze: the renderer likely throws in a way that bypasses the normal cleanup path.
D1 — the freeze likely indicates a deadlock or unbounded render loop in the agent view's session-list reconciliation when stale sessions are present. Note in my repro: the agent view contained entries flagged "stuck on a startup dialog" — D1 fires when the dashboard tries to render this stale state. Suggested:
- Add a render timeout / watchdog in the agent-view component that drops back to the session list on detected stall.
- Filter or auto-prune sessions in a "starting" or "opening" state that have not transitioned in N seconds — these may be artifacts of D3 (orphaned daemons that never reported completion). Related: #59511.
D3 — on Windows the daemon spawn path needs to register itself in a Windows job object with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE so that closing the parent console actually terminates the children. This is the only reliable cross-process cleanup primitive on Windows.
Severity
Blocker for adoption by heavy parallel users on Windows. The agent view is the entry point to the new multi-session workflow shipped in the 2.1.140+ release line. Its current state on Windows is:
- Freezes on entry (D1) → only recovery is force-kill (D2) → which corrupts the shell (D2) and orphans children (D3).
- The documented workaround ("don't open agent view") makes the feature inaccessible.
- Users on lower-memory Windows machines than mine (64 GB) will likely hit OOM before they accumulate the zombie count I did.
What I can provide
- Process tree captures with PIDs/paths/RSS at the moment of accumulation
~/.claude/session-state JSONL showing the "stuck on a startup dialog" entries that correlate with D1- A clean before/after capture of the SGR sequences from D2 (full byte stream)
- A short screen recording of the full D1→D2 reproduction in real time if useful for triage — the escape-sequence cascade is much more visceral on video than in a static capture.
Related issues — recommend linking to this thread
This bug appears to be the umbrella for a cluster that has accumulated over months:
- #58653 — D2 symptom on macOS agent view (open,
platform:macos— reproduces on Windows too, see this issue) - #59563 — D2 symptom on macOS via SSH disconnect (open)
- #59511 — D1-adjacent: agent-view session-open hang (open)
- #42606 — D2 via Ctrl+G external editor on macOS (open)
- #48629 — D2 symptom on Windows (closed as duplicate, no tracking link)
- #34076 — D2 from multi-instance Claude on Windows (closed as duplicate, no tracking link)
- #50032 — D2 via Ctrl+G with mitigation analysis (closed as duplicate)
- #38578 — terminal corruption regression from prior D2 fix in 2.1.83 (closed)
- #14479 — TUI escape sequences flooding chat (closed, related ANSI escape handling)
- #18418 — escape sequences in tool output corrupting
--resume(closed, stale) - #23581 — feature request for
--no-mouseflag (closed as duplicate)
Strongly recommend this issue become the single tracking thread for D1/D2/D3 and that the closed-as-duplicate issues above be linked here so reporters can subscribe to a real resolution.
Claude Code Version
2.1.143
Platform
Anthropic API (Claude Max)
Operating System
Windows
Terminal/Shell
PowerShell (Windows Terminal and Windsurf integrated terminal both reproduce)
6 Comments
Follow-up: D1 reproduces in 2.1.141, not a 2.1.143-specific regression
After further testing tonight, D1 (the agents view freeze) is not exclusive to 2.1.143. It also reproduces in 2.1.141 under Windsurf's integrated terminal. Behavior matrix from my environment:
| Version | Windows Terminal | Windsurf integrated terminal (xterm.js 6.1.0-beta.168) |
|---|---|---|
| 2.1.141 | Agents view opens;
claude daemonerrors but TUI does not freeze | Freezes on agents view entry || 2.1.143 | Freezes on agents view entry | Freezes on agents view entry |
Suggests the underlying renderer issue is present across the 2.1.140+ release line, with Windsurf's terminal environment triggering it more reliably than Microsoft Windows Terminal does. The 2.1.143 changelog entry I quoted in the original report doesn't fix it on either terminal in my environment.
Additional finding: install corruption from in-IDE update
Worth documenting in case it affects other reporters. Earlier today, I ran
npm install -g @anthropic-ai/claude-code@<version>from inside Windsurf's integrated terminal to upgrade. The install completed without visible error, but the package'sbin/claude.exewas missing after install — the platform-specific postinstall (install.cjs, which fetches the win32-x64 binary from the optional platform sub-package) did not run, or did not persist its output.Symptoms:
claude --versionworked initially (Volta shim cached an earlier valid invocation path)claudeinvocations produced:'"...\bin\claude.exe"' is not recognized as an internal or external commandTest-Path "...\node_modules\@anthropic-ai\claude-code\bin\claude.exe"returnedFalsecli-wrapper.cjs,install.cjs,package.json,node_modules) were all presentManual recovery — ran the postinstall script directly:
After this,
bin/claude.exeappeared and the install has been stable across multiple sessions (including force-killed sessions, which I'd worried might re-corrupt it — they don't).Hypothesis: when
npm install -gruns inside Windsurf's integrated terminal, something in the environment (sandboxing? PATH manipulation? fnm interaction?) prevents postinstall scripts from executing or persisting their output reliably, leading to a broken-but-not-obviously-broken install. Running the same install command from a plain external PowerShell does not exhibit this. This may explain some of the "Subprocess initialization did not complete" reports from other Windows users (#55562 and others linked there) — a partial install with a missing binary would manifest as an initialization timeout.Suggested user-facing mitigation if this is reproducible at the package level: detect missing
bin/claude.exeon first invocation and either re-runinstall.cjsautomatically or print a clear error pointing the user at it, rather than passing the broken path to cmd.exe and producing the crypticis not recognizederror.Also hitting D1 (TUI freeze / keyboard input ignored, mouse still works) on Claude Code 2.1.153 on Windows 11.
Timing is inconsistent:
claude agents— keyboard never works in the session list.No reliable repro trigger that I've found — happens on both fresh launches and longer-running sessions. Would love a
--no-mouseflag or adisableMousesetting as a workaround in the meantime, since keyboard-only navigation is my preference.I am having this same problem in Ghostty on Mac.
Reproduced on macOS, still present in the latest release (v2.1.204) — adding a data point since the OP is Windows 11 / 2.1.143.
Environment
claude -r(resume) opening the FleetView / agent viewBehavior (matches D1)
Running
claude -ropens the multi-session FleetView home ("N awaiting input · N working · N completed") and the TUI wedges on entry:claude -rsits inS+(interruptible sleep), notD. Only an externalkillrecovers the terminal.Orphaned daemons (D3) — note the macOS difference
At the time of the freeze, the frozen
claude -rhad spawned the background multi-session infra:claude daemon run ... --origin transientclaude bg-spare ...andclaude bg-pty-host ...(mixed versions 2.1.203 and 2.1.204)Unlike the Windows report where daemons accumulate to ~20 GB, on macOS these did exit cleanly once the parent
claude -rwas force-killed (reparented + reaped). So on macOS the orphan-accumulation half of D3 does not reproduce, but the daemon/PTY-host fan-out on FleetView entry is identical.Workaround
claude -c/claude --continueresumes the latest session directly and bypasses the FleetView picker entirely — no freeze.Reproduction: mouse-reporting state leaks through a remote PTY/WebSocket session
We are shipping Claude Code to developers inside AWS Lambda MicroVMs.
Environment
2.1.210zshwhen the session disconnectsObserved behavior
When the MicroVM or WebSocket ends before Claude Code exits normally, moving the mouse at the restored local shell prints text such as:
``
text
``35;191;8M35;187;10M35;183;11M
The complete terminal events are SGR mouse reports of the form:
ESC [ < 35 ; column ; row M
35 represents mouse movement with no button pressed. This proves that the local terminal emulator is still in xterm mouse-reporting mode after Claude Code is gone.
This is not shell output from the MicroVM. Claude Code previously sent DECSET mouse-mode instructions through the remote PTY, and those instructions changed the state of the developer's local terminal emulator.
Concrete verification
A normal Claude Code 2.1.210 shutdown emits cleanup including:
ESC[?1006l
ESC[?1003l
ESC[?1002l
ESC[?1000l
ESC[?1004l
ESC[?2031l
ESC[?2004l
ESC[?25h
On an abrupt MicroVM/WebSocket disconnect, those bytes never arrive because the remote process has no opportunity to perform its normal shutdown.
Restoring stdin from raw mode is insufficient. Raw mode is a local TTY input setting, while mouse reporting is persistent state in the terminal emulator.
Impact
Users are developers and should not need to understand ANSI escape sequences or run reset after an infrastructure disconnect. The failure appears after they have already returned to their local shell, which makes it look like terminal corruption.
Mitigation implemented in our client
Our terminal client now:
The cleanup is one-shot and deliberately avoids a destructive full terminal reset.
Upstream request
Please provide a documented, supported setting that disables mouse reporting independently of other TUI behavior. CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 avoids the issue, but changing the entire rendering mode should not be required merely to disable mouse tracking.
This is especially important for remote PTY, SSH, container, and WebSocket environments, where the process that enabled the terminal mode may disappear before it can disable it.
Related reports: #61936 and #23581.
Still reproducing on 2.1.220 (Windows 11 Pro 26200, Windows Terminal 1.24.11911.0), so this survived the 2.1.143 → 2.1.220 range. Adding a data point on the D2 residue, and a correction on the workaround suggested above — it does not apply to agent view.
D2 residue, identified by coordinate range
After a freeze on agent view entry, the input box receives literal text such as
5;55;23M. That is the tail ofESC[<35;55;23M— an SGR mouse report (DECSET 1006), button 35 = motion with no button held. The terminal was 153×51 at the time, so col 55 / row 23 falls inside the viewport, which rules out other sources for those digits. Same shape as the35;191;8M35;187;10M35;183;11Mreported in the comment above.Worth noting the residue does not require an external kill. It also appears when the TUI recovers on its own: while the event loop is blocked the terminal keeps writing mouse reports into stdin, they queue in the pipe, and the coalesced read on resume can't be consumed atomically by the input parser — the tail renders as literal text in the prompt. That matches the observed pattern of it happening on most freezes but not all, depending on whether the mouse moved during the stall.
CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1does not apply to agent viewThe workaround suggested earlier in this thread doesn't cover the case this issue is about. From the fullscreen docs:
I set it and confirmed no effect on agent view — it only disabled fullscreen rendering for ordinary sessions, at the cost of the mouse there.
No usable workaround if you actually use agent view
CLAUDE_CODE_DISABLE_MOUSE=1suppresses the residue at the source (no mouse reports means nothing to leak), but costs wheel scrolling, click-to-expand, URL clicking and in-app selection. In agent view that is a significant regression.CLAUDE_CODE_DISABLE_MOUSE_CLICKS=1keeps the wheel, but mouse capture stays on, so the residue returns.claude -cbypasses the picker and therefore the freeze, but gives up the multi-session UI that agent view exists for.So the current choice is between losing the mouse and losing the mitigation. A supported way to disable mouse reporting independently of rendering mode — as requested in #23581 and in the comment above — would at least make D2 avoidable without giving up fullscreen features, though it would not address D1.
D3 is not reproducing here
On this machine after a day of heavy parallel use: 46
conhost.exe, of which only 1 had a dead parent; 26claude.exe, of which 23 had a liveclaude.exeparent (a normal subagent tree). So the orphan cascade is not universal even where D1 and D2 both reproduce. Mentioning it because raw process count alone is misleading — checking whetherParentProcessIdis still alive viaGet-CimInstance Win32_Processis the actual discriminator, and killing by name risks taking out live sessions.