Excessive scroll events causing UI jitter in terminal multiplexers (4,000-6,700 scrolls/second)

Open 💬 18 comments Opened Oct 20, 2025 by rinadelph

Summary

Claude Code's streaming output causes 4,000-6,700 scroll events per second when running inside terminal multiplexers (tmux/smux), resulting in severe UI jitter and flickering. This issue was identified through comprehensive instrumentation of a tmux fork (smux) with microsecond-precision logging.

Problem Description

When Claude Code streams LLM responses, it causes excessive terminal scrolling that overwhelms the rendering capability of terminal multiplexers, creating a poor user experience with:

  • Visual jitter/flickering during streaming output
  • Scrollbar jumping erratically
  • Screen tearing effects
  • Degraded performance for 100+ second durations

Root Cause Analysis

Measured Metrics (106-second test session)

  • Total scroll events: 423,575 (logged) / 715,901 (counter)
  • Scroll rate: 4,002-6,764 scrolls/second
  • PTY read callbacks: 8,044 (avg 4,095 bytes each)
  • Linefeeds parsed: 400,930 (3,782/second)
  • Burst pattern: 94.7% of scrolls occur in sub-millisecond bursts

Timing Analysis

Scroll burst example:
- Scrolls #1-36: All within 144 microseconds
- Scroll #37: 1.26 second gap
- Scrolls #38-45: Burst of 8 in 1.7ms
- Scroll #46: 2.27 second gap
- Scrolls #47-50: Burst of 4 in microseconds

Sub-millisecond scroll timing (first 1,000 scrolls):

  • Same microsecond: 4.6%
  • 0-1ms apart: 94.7%
  • 1-10ms apart: 0.1%
  • >10ms apart: 0.6%

Data Pattern

Claude Code sends output in 4,095-byte chunks with a repeating pattern of newlines per chunk:

Pattern: 124, 36, 47, 58, 53, 46, 42, 23 newlines (then repeats)

This suggests full-screen redraws happening repeatedly, likely for:

  • Main content area
  • Status sections
  • Progress indicators
  • Syntax-highlighted code blocks

ANSI Overhead

Each line includes heavy ANSI formatting:

  • Background color: \e[48;2;55;55;55m (~20 bytes)
  • Foreground color: \e[38;2;255;255;255m (~22 bytes)
  • Content
  • Reset codes: \e[39m\e[49m (~8 bytes)

Estimated overhead: ~189 KB/second of ANSI codes alone (50 bytes/line × 3,782 lines/sec)

Technical Details

Three-Layer Instrumentation Results

We instrumented smux at three critical layers to trace data flow:

  1. PTY Raw Input (/tmp/smux_pty_raw.log - 14 MB)
  • Captured raw bytes from Claude Code's PTY
  • Hex dump + ASCII representation
  • Newline counts per chunk
  1. Linefeed Parser (/tmp/smux_linefeed.log - 11 MB)
  • Every LF/VT/FF character processed
  • 400,930 total linefeeds
  1. Scroll Trigger Detection (/tmp/smux_scroll_trigger.log - 25 MB)
  • Actual scroll events when cursor at bottom
  • 100% of scrolls had cy=24 (cursor always at screen bottom)
  • Every linefeed triggered a scroll

Why This Happens

Claude Code appears to use a full-screen redraw strategy for streaming:

// Suspected rendering loop
for await (const chunk of llmResponseStream) {
    responseBuffer += chunk;
    const renderedOutput = renderFullView(responseBuffer);  // ← Full redraw!
    process.stdout.write(renderedOutput);
}

Instead of:

// Optimal approach
for await (const chunk of llmResponseStream) {
    responseBuffer += chunk;
    const incrementalUpdate = renderOnlyNewContent(chunk);  // ← Incremental!
    process.stdout.write(incrementalUpdate);
}

Comparison to Normal Terminal Usage

vim editing:         10-50 scrolls/second
tail -f logfile:     1-100 scrolls/second
cat large file:      100-500 scrolls/second
npm install:         100-300 scrolls/second (bursts)
Claude Code:         4,000-6,700 scrolls/second (SUSTAINED)

Claude Code is 40-600x higher than typical terminal usage!

Proposed Solutions

Option 1: Incremental Updates (Recommended)

Switch from full-screen redraws to incremental updates:

  1. Only output new content to terminal
  2. Append to bottom instead of redrawing entire screen
  3. Batch UI updates at reasonable intervals (e.g., every 16ms)
  4. Optimize ANSI usage - don't reset colors on every line

Expected impact: Reduce scroll rate by 90%+ (from 4,000/sec to <400/sec)

Option 2: Use Alternative Screen Buffer

For TUI components (status bars, progress indicators):

\e[?1049h  # Enter alternative screen buffer
# Render TUI components here
\e[?1049l  # Exit back to main buffer

This would:

  • Isolate UI chrome from scrolling content
  • Prevent status updates from triggering scrolls
  • Reduce total scroll events significantly

Option 3: Batch Terminal Writes

Collect output chunks and flush at controlled intervals:

let outputBuffer = '';
let lastFlush = Date.now();

const FLUSH_INTERVAL_MS = 16;  // ~60 FPS

function writeOutput(chunk) {
    outputBuffer += chunk;
    
    if (Date.now() - lastFlush >= FLUSH_INTERVAL_MS) {
        process.stdout.write(outputBuffer);
        outputBuffer = '';
        lastFlush = Date.now();
    }
}

Temporary Workaround (User Side)

We're implementing scroll batching in smux to mitigate this issue, but this is a band-aid solution. The proper fix should be in Claude Code's rendering strategy.

Environment

  • OS: Arch Linux (kernel 6.17.2)
  • Terminal multiplexer: smux (tmux fork) with custom instrumentation
  • Terminal emulator: Various (issue occurs in all)
  • Claude Code version: Latest (2024-10-19)

Complete Analysis Document

Full technical analysis with all data and graphs available in the instrumented smux repository:

  • ROOT-CAUSE-ANALYSIS.md (complete breakdown)
  • DETECTION-READY.md (instrumentation setup)
  • Log files: 68 MB of captured data

Request

Please investigate Claude Code's terminal output strategy and consider implementing incremental updates or batched output to reduce scroll rate to reasonable levels (<100 scrolls/second).

This would significantly improve the experience for users running Claude Code in terminal multiplexers, which is a common development workflow.

Additional Context

  • Issue was detected using microsecond-precision instrumentation
  • Reproducible 100% of the time during streaming output
  • Affects all terminal multiplexers (tmux, screen, smux)
  • Native terminal emulators may also struggle with this rate
  • No data loss - all content reaches screen, just too fast

View original on GitHub ↗

18 Comments

github-actions[bot] · 8 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/4851
  2. https://github.com/anthropics/claude-code/issues/1495
  3. https://github.com/anthropics/claude-code/issues/9874

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

kylesnowschwartz · 8 months ago

This problem is not only limited to multiplexors. Using Claude with verbose output on in iTerm2 with no tmux results in the inability to scroll up while Claude is 'working.' That removes the utility of seeing the verbose output, which I would like to read as Claude works, to better understand its methodology and help gauge the appropriateness of its complete response. We gotta do something about these scroll events!

EarthmanWeb · 8 months ago

Been reviewing all the 'possible duplicates' and can't find the definitive one that will be actioned upon. I need resolution of this, how can i find which ticket to follow ad contribute to? I am NOT using TMUX (afaik), just claude code in vscode, with MCP's and this happens often, sometimes correlating with background 'compacting', sometimes correlating with MCP output that doesn't wrap properly (ie: serena, sequential thinking mcp tools) and sometimes correlating with pasting large snippets of error logs. Not specific to long threads, sometimes happens in very new threads.

tolmachevmaxim · 7 months ago

I've got the same issue.

azuline · 7 months ago

This is really ridiculous. It is frequent and bad enough for me to change to a different piece of software because it has started to cause freezes in other applications on my computer.

xandragnis · 7 months ago

Adding another data point - experiencing scrolling [and what appears to be a line-break] issue on keystroke input and with Claude streaming for each animation and 'tick'.

Environment:

  • Claude Code: 2.0.61
  • OS: Ubuntu 25.10 (questing) - development branch
  • Terminal: GNOME Terminal 3.56.2
  • VTE Library: 0.80.3-3
  • Node.js: v22.15.0
  • npm: 10.9.2
  • TERM: xterm-256color
  • COLORTERM: truecolor

Symptom:
Terminal scrolls/jumps on every keystroke during input (spacebar, backspace, any key). The effect looks like a line break or scroll happening with each keypress while typing prompts.

Additional Notes:
Using the same build, this doesn't happen using GNOME 48 Terminal - Version 3.56.2.
On Windows 11 - highest build on Powershell/pwsh and CMD iterations, no issues.

ipswitch8 · 6 months ago

Adding to this as it is closely related (same root cause), using tmux remote sessions the TUI re-rendering makes interactive use difficult or impossible due to infinite scrolling (re-rendering of previous output) within just minutes of starting any session:

  • Can't tell if output is new or just re-rendered
  • Can't distinguish thinking/done/waiting-for-input states
  • Esc stops scrolling but also cancels work (no safe "pause", and using terminal keys or mouse to force a pause is useless because it just stops at whatever random part of the content was displaying at that moment)
  • Scrollback is unusable due to constant redraws (scrollback starts from whatever is displayed at that moment, not the actual most recent output)

Request: --no-tui or --simple-output mode that appends new output normally/sequentially (no redraw) with a clear status indicator.

Environment: currently tmux over SSH, various terminal sizes, but it also happens in local terminal sessions, Windows PowerShell, WSL etc, (have tried MANY different combinations trying to find one that works but have come to realize this is not an environmental issue, it's a problem that is inherent to the TUI implementation!)

outbound · 6 months ago

Same issue here

hoblin · 6 months ago

Partial Fix: tmux synchronized output (mode 2026)

Setup: Alacritty 0.16.1 + tmux (built from git master, version next-3.7)

What we fixed

The chaotic scrolling issue is resolved by using tmux built from git master which includes synchronized output support (mode 2026) added on Dec 17, 2025 (commit 1c7e164). This is not yet in any stable release (3.6a is current stable).

For Arch users: yay -S tmux-git

tmux terminal-features config for alacritty:

tmux set -ga terminal-features 'alacritty:clipboard:ccolour:cstyle:focus:title:sync'

What remains: Strobe effect with subagent output

After the fix, a different visual artifact appears:

  • Only affects subagent output (Task tool) - main Claude output does not cause it
  • Only triggers when scrolling - no issue until subagent output fills the visible terminal space
  • Only the content area strobes - tmux status bar remains stable
  • Other panes unaffected - splitting the terminal shows the issue is isolated to the pane with subagent output

The strobe effect is a rapid full-screen flash/blink (like a strobe light), distinct from the original chaotic scrolling. Disabling sync (alacritty:sync@) did not resolve this, suggesting it may be related to how subagent output is rendered differently from main agent output.

robert-claypool · 6 months ago

Generous scrollback settings turn the scroll flood into a Ghostty memory bomb:

macOS hang report:

  • Event: hang (1756s unresponsive)
  • Memory footprint: 194.54 GB on 32GB machine
  • Deadlock: main thread in __ulock_wait2 during NSWindow _setOcclusionStateIsVisible

Environment: Ghostty 1.2.3, macOS Sequoia 15.6.1, M2 Max, 10M line scrollback

Symptoms before hang:

  • Tab switching snapped back to last tab
  • Scroll position kept resetting

Workaround: Dropped scrollback to 50K lines, it was 10 million lines (I know, probably dumb)

hoblin · 6 months ago
Generous scrollback settings turn the scroll flood into a Ghostty memory bomb:

@robept-claypool I had this problem with Ghostty on Arch. Switch to Alacritty solved the issue. RAM footprint is minimal despite the flickering render during multiple subagents output.

mjenkinsx9 · 5 months ago

You can see some of the issue below that I copy/pasted from VS Code.

### Environment 5 C • 3 P • 🗃️ 6 u a 6m o $ . 2 m ⧉ 1

  • Claude Code: 2.1.12
  • OS: Ubuntu Linux 6.8.0-90-generic (x86_64)
  • Terminal: VS Code integrated terminal
  • TERM: xterm-256color
  • COLORTERM: truecolor
  • Terminal size: 80x24
  • tmux: Not active (tmux 3.4 installed)

### Issue

Status bar elements (model indicator, token counts, icons) intermittently render inside the main output area, overlapping with tool call results. Example:

● Read(.claude/data/meetings/work/recurring/dc-ops/2026-01-05.md)
⎿ Read 142 lines 5 C • 3 P • 🗃️ 6 u a m o $ .

The status bar content (5 C • 3 P • 🗃️...) appears inline with the tool output.

### Reproduction

  • Occurs during rapid sequential tool calls (multiple file reads)
  • More frequent with longer outputs

### Notes

Running in VS Code integrated terminal, not tmux. Issue persists across sessions, even sessions on other machines using the same setup.

skshim-reco · 5 months ago

I've been experiencing this issue for over 6 months and it's severely impacting my workflow.

Environment:

  • macOS (clamshell mode with external monitor)
  • WezTerm / iTerm2
  • tmux 3.6a
  • Claude Code 2.1.12

Why tmux is essential for me:

  • SSH session persistence - I need to reconnect to ongoing sessions remotely
  • Terminal crash recovery - WezTerm crashes when switching displays (GPU context issues), and without tmux, all my work is lost

What I've tried (all failed):

  • Various terminal emulators (WezTerm, iTerm2) - same flickering
  • tmux settings (terminal-overrides, alternate screen disable) - no improvement
  • dtach/abduco as tmux alternatives - no screen buffer, so no redraw on reconnect
  • Claude Code --continue flag - doesn't help with SSH session persistence

The real problem:
Power users who rely on tmux + SSH for session persistence have no viable workaround. The only reported fix is claudecode.nvim, which requires switching to Neovim - not a reasonable ask for everyone.

It feels like this issue isn't prioritized because Anthropic developers may not use tmux-based workflows. For those of us who do, Claude Code is practically unusable for extended sessions.

Please prioritize this fix. Terminal multiplexer support is fundamental for professional development workflows.

F1LT3R · 4 months ago

This tool Claude is completely unusable in TMUX.

What a fail.

Such a huge disappointment.

cruzlauroiii · 4 months ago

A fix is available as a Claude Code plugin: scroll-fix

Install:

/plugin marketplace add cruzlauroiii/claude-code
/plugin install scroll-fix@cruzlauroiii-plugins

Root cause: both Ink renderer AND readline/prompt system emit cursor-up sequences exceeding viewport height. The plugin clamps all cursor-up per write call. Also includes Ctrl+6 freeze toggle.

PR: https://github.com/anthropics/claude-code/pull/35683

roblight · 3 months ago
A fix is available as a Claude Code plugin: scroll-fix Install: `` /plugin marketplace add cruzlauroiii/claude-code /plugin install scroll-fix@cruzlauroiii-plugins ``
/plugin marketplace add cruzlauroiii/claude-code
  ⎿  Error: The name 'claude-code-plugins' is reserved for official Anthropic marketplaces. Only repositories from
     'github.com/anthropics/' can use this name.

Suggestions? 🙏

MagnaCapax · 3 months ago

Data point: CLAUDE_CODE_NO_FLICKER=1 isolates this from the scrollback destruction bug

Tested on 2.1.89, tmux 3.4, Debian 13.

NO_FLICKER moves rendering to the alternate screen buffer, which eliminates the \e[3J scrollback destruction entirely (#16310, #2479). With scrollback destruction out of the picture, the scroll handling issues from this bug become clearly visible in isolation:

  • ~5 mouse wheel clicks to scroll 1 line inside the Claude Code pane
  • Native tmux scrolling in other panes works normally
  • Color rendering also changes (different scheme from main-screen mode)

This confirms two independent bugs:

  1. \e[3J in clearTerminal — destroys scrollback (fixed by NO_FLICKER / alt-screen)
  2. eraseLines() cursor-up overflow — causes the scroll event flood documented in this issue, and manifests as broken scroll sensitivity in alt-screen mode

Binary-patching \e[3J out of cli.js fixes only bug 1. Bug 2 persists regardless of NO_FLICKER or the \e[3J patch. PR #35683 (clamping cursor-up count to viewport height) targets the right mechanism.

Environment: Claude Code 2.1.89, tmux 3.4, Debian 13 (trixie), CLAUDE_CODE_NO_FLICKER=1

— Väinämöinen / Pulsed Media