[BUG] Win11: TUI render-loop frame pacing degraded ~2× between 2.1.159 → 2.1.207 (bisected + instrumented; #67406 follow-up)

Open 💬 0 comments Opened Jul 11, 2026 by bejek

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?

Persistent TUI rendering stutter on Windows 11 that survived every environmental fix. I bisected it to first-bad = 2.1.160 (last-good = 2.1.159) and then instrumented the render loop with a ConPTY harness: the TUI frame cadence degrades in three measurable stages between 2.1.159 and 2.1.207. Follow-up to #67406, which was auto-closed by ant-github-proxy[bot] on 2026-06-25 while the stutter was still reproducible (my 2026-06-16 comment on 2.1.178 noted "rendering stutter persists").

Method: spawn claude in a raw ConPTY (120×35), timestamp every output chunk. "Spinner window" = 0.5–4.0 s after submitting a prompt, before the first API token arrives — the animation cadence there is purely local, so the metric is API- and network-independent. Two runs per version; both runs agree.

Local render tick (spinner window):

| Version | median | p95 | stalls >100 ms per 3.5 s |
|---|---|---|---|
| 2.1.159 | 62 ms (~16 fps) | 140 ms | 7 |
| 2.1.160 | 62 ms | 299–376 ms | 8–9 (incl. 2–3 × >250 ms) |
| 2.1.183 | 63 ms | 127–266 ms | 8–10 |
| 2.1.207 | 99–109 ms (~9–10 fps) | 218–235 ms | 16–17 |

Streaming-phase tick (while tokens render):

| Version | median gap | stalls >100 ms |
|---|---|---|
| 2.1.159 | 62 ms | 1–4 |
| 2.1.160 | 62 ms | 6–15 (max gap up to 829 ms) |
| 2.1.183 | 108–109 ms | 65–81 |
| 2.1.207 | 96–108 ms | 34–45 |

Three-stage regression:

  1. 2.1.160: long frame hitches appear (p95 explodes to 300–376 ms; >250 ms stalls). Matches perceived onset of stutter. The 2.1.160 changelog is dominated by background-daemon/agent-view infrastructure fixes; 2.1.159's changelog says only "Internal infrastructure improvements".
  2. By 2.1.183: streaming-phase tick rate halves (62 → ~108 ms median) while the idle spinner tick is still 62 ms.
  3. By 2.1.207: the tick is ~100 ms everywhere, including the idle spinner.

Additional data points:

  • Typing-echo cadence (event-driven, not frame-scheduled) is a perfect 30 ms with zero stalls on all versions — raw output throughput is fine; the regression is in frame scheduling.
  • The ~108 ms tick on 2.1.207 is terminal-independent: measured identically with and without WT_SESSION set. No terminal choice works around it.
  • Synchronized-output markers (ESC[?2026h/l) are emitted 1 pair/frame in 2.1.159 already, so marker emission is not the new variable.
  • 2.1.207's changelog says "Fixed terminal freezing during streaming of very long lists…" — the frame pacing regression is still present there.
  • Perceptually the degradation arrived in visible steps across versions (I noticed roughly four "levels" of choppiness between 2.1.154 and current before measuring anything) — consistent with the staged regression above.
  • With disableAgentView: false the agent-view path multiplies the problem — subjectively 1–2 fps, effectively unusable (that path was the subject of #67406).

Possibly intentional? Then please make it configurable. The staged tick-rate reduction lines up with CPU-optimization changelog entries ("Reduced CPU usage ~37% during streaming" in 2.1.191, "Reduced per-frame rendering work" in 2.1.196, "live-preview updates don't re-render screen" in 2.1.203). If the ~10 fps tick is a deliberate CPU/battery trade-off, it is invisible on 60 Hz laptop panels but very visible on high-refresh desktop monitors. In that case: please expose a knob (e.g. CLAUDE_CODE_MAX_FPS or a renderFps setting) so desktop users can opt back into the 2.1.159-era 16 fps — I'll happily trade the CPU back.

What Should Happen?

~60 ms (16 fps) frame cadence with no >250 ms hitches during spinner animation and token streaming, as measured in 2.1.153–2.1.159 on the same machine, same terminal, same settings.

Error Messages/Logs

No error output — this is a performance regression, not a crash. Measured chunk-timing summaries (median / p95 / max inter-flush gap, spinner window):

2.1.159 run1: p50 62.2 ms | p95 140.0 | max 251 | 7x >100ms
2.1.159 run2: p50 61.9 ms | p95 140.3 | max 207 | 7x >100ms
2.1.207 run1: p50 99.3 ms | p95 218.2 | max 312 | 16x >100ms
2.1.207 run2: p50 108.9 ms | p95 235.4 | max 376 | 17x >100ms

Full raw chunk-timing series (JSONL, all tested versions) available on request.

Steps to Reproduce

  1. Windows 11 Pro (26200), Windows Terminal 1.24, PowerShell 7, high-refresh monitor (120 Hz makes it obvious).
  2. claude install 2.1.207, open claude, submit any prompt.
  3. Watch the spinner animation and token streaming: visible hitching, ~10 fps cadence.
  4. claude install 2.1.159, repeat step 2–3: smooth ~16 fps cadence, no hitches.
  5. Instrumented repro (recommended): spawn claude in a ConPTY via pywinpty, timestamp every output read, submit a prompt, and compare inter-flush gap medians in the 0.5–4.0 s window after Enter (before the first token arrives). ~100-line Python harness available on request.

Config used during all tests: disableAgentView: true; reproduces identically with tui: fullscreen and tui: default, and with CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 / CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT=1.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

2.1.159

Claude Code Version

2.1.207 (Claude Code)

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Windows Terminal

Additional Information

Environmental causes ruled out before bisecting (none had any effect): RivaTuner/RTSS overlay (was hook-injected into WindowsTerminal.exe — fully uninstalled), MSI Afterburner, Rainmeter, NetSpeedTray, NVIDIA G-Sync windowed/fullscreen combinations, background CPU/RAM load (idle CPU of the claude process tree is <1% of one core on all versions; no extra daemon processes).

Hardware: Ryzen 7 7800X3D, RTX 4080 SUPER, 3440×1440@120Hz + 1440×2560@75Hz portrait.

Related issues: #67406 (same machine, bot-closed as Completed without a human response while the stutter persisted), #60440 (WT flicker during streaming).

Verified workaround: pinning 2.1.159 restores the 62 ms tick. I currently stay on latest and endure the stutter because I don't want to lose newer features (workflows, background subagents) — which is why I'd love to see this fixed or made configurable.

View original on GitHub ↗