Completed turns are repainted, so terminal scrollback loses the recent conversation

Status Open
Reported on v2.1.260
Maintainer reply None cached
Activity 1 comment · opened Sep 4, 2026

Summary

Scrolling up in a terminal multiplexer doesn't show the last several exchanges. You see much older output, then a gap where the recent conversation should be.

The TUI redraws its output region in place rather than emitting a linear stream of lines. Scrollback only retains what genuinely scrolled off the top, so anything overwritten by a repaint is gone. The part you most often want to re-read — the last handful of turns — is exactly the part most likely to have been repainted away.

Environment

Claude Code 2.1.260 · tmux 3.4, TERM=tmux-256color · Linux 6.8

Reproduce

  1. Run a long session in tmux with several long assistant replies and some collapsed tool outputs.
  2. Enter copy-mode and scroll up.
  3. Recent turns are missing; much older output is still there.

Why the obvious workarounds don't help

  • /resume renders through the same TUI.
  • tmux pipe-pane captures the repaints, not a transcript.
  • The session JSONL under ~/.claude/projects/<slug>/<session-id>.jsonl is complete and written live, but there's no discoverable path from "let me re-read what we said five messages ago" to that file, and its format isn't documented as stable.

This looks like a bounded fix, not an inherent tradeoff

In-place repainting is what buys the interactive features — spinners, live tool status, collapsible output, an editable input line, reflow on resize. An append-only stream can't retract a line.

But a TUI can do both: commit each completed turn as ordinary scrolled lines, and repaint only the live region at the bottom. A finished turn will never change again, so there is no reason for it to stay in the dynamic region.

If the UI is Ink-based — the bundled binary contains Ink API names (measureElement, useStdout, useInput) — then Ink's <Static> component is exactly this primitive: children of <Static> are written once, permanently, above the dynamic area, and never re-rendered. That would make the fix "move completed turns into <Static>" rather than a rewrite. I can't see the component tree, so please treat this as a suggestion rather than a diagnosis.

Why it's worth fixing rather than working around

Committing finished turns to scrollback fixes several things at once: multiplexer scroll, mouse selection and copy, claude | tee, and grep over a piped log. Every user-side workaround instead depends on parsing an undocumented transcript file.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗