You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The CLI renders its zone (editor, status line, output) in the terminal's main buffer. This means all zone content is subject to terminal reflow on resize, causing visual corruption and scrollback bleed. The terminal reflows content without notifying the application, and no escape sequence can prevent it.
Feature
Switch the CLI to render in the alternate screen buffer during operation. The alternate buffer provides full screen ownership with no scrollback, eliminating reflow and scrollback corruption entirely.
History (completed responses, tool output, etc.) must not be lost. When a response completes, the CLI briefly exits the alternate buffer, writes the formatted response to the main buffer (creating real scrollback), and re-enters the alternate buffer. On exit, the user can scroll up in the main buffer to see all session output.
Functionality
Alternate buffer lifecycle
Enter alternate buffer on startup
Exit alternate buffer on clean exit (/quit, Ctrl+C)
Exit alternate buffer on crash/signal (cleanup handler for SIGTERM, SIGINT, uncaught exceptions). If the process dies without exiting the alternate buffer, the user is stuck on a blank screen (recoverable with reset but bad UX)
Zone rendering
The CLI owns the entire screen. Zone renders from a known position without relative cursor tracking
Resize handling becomes: clear the alternate buffer and redraw. No position recovery, no heuristics, no reflow prediction
The narrow/widen heuristic, pendingResize flag, and notifyResize() complexity are no longer necessary
History flush to main buffer
On response complete: exit alternate buffer, write formatted response content to main buffer, re-enter alternate buffer
Minimise time in main buffer -- pre-build the output string before the swap
One flush per completed response, not per line
Content written to main buffer must be human-readable when the user exits and scrolls up (formatted text, not raw ANSI zone frames)
Cleanup handler
Register signal/exit handlers that ensure \x1b[?1049l (exit alternate buffer) is sent before the process terminates
Must cover: clean exit, SIGTERM, SIGINT, uncaught exception, unhandled rejection
What this replaces
Zone position tracking via cursorUp(lastVisibleCursorRow)
The pendingResize flag and narrow/widen resize heuristic
notifyResize() propagation chain
The "content shorter than screen" startup padding hack
The entire class of scrollback corruption / history bleed bugs
In-app scrollback / history browsing during a session (separate issue, builds on this)
Scroll regions (DECSTBM) for normal-operation rendering
DSR-based position queries
Guidance
POC verified
A bash POC (alt-buffer-poc.sh in bananabot9000/claude-sandbox) confirms:
Sync-wrapped buffer swap is imperceptible at real-world speeds (no sleep)
History lines appear in main buffer scrollback after exit
Resize in alternate buffer is clean -- just redraw
Sync output (\x1b[?2026h)
Already used in the codebase's render() method. Does NOT prevent flicker during buffer swaps (buffer switch is a screen state change, not buffered output). However, the swap is fast enough that flicker is invisible without sync. Sync does NOT work through tmux (tmux intercepts/swallows the sequence on older versions).
The flush writes what the user would want to see if they scrolled up after exiting: the assistant's response text, tool call summaries, code blocks -- the same content currently visible in the zone during streaming, but as final static text. Not the raw ANSI rendering frames.
Phase 0 investigation
Full investigation at projects/claude-cli/investigations/resize-position-tracking.md in the fleet repo. Covers 10 approaches with trade-off tables, compatibility matrices, and terminal behaviour constraints.
Summary
The CLI renders its zone (editor, status line, output) in the terminal's main buffer. This means all zone content is subject to terminal reflow on resize, causing visual corruption and scrollback bleed. The terminal reflows content without notifying the application, and no escape sequence can prevent it.
Feature
Switch the CLI to render in the alternate screen buffer during operation. The alternate buffer provides full screen ownership with no scrollback, eliminating reflow and scrollback corruption entirely.
History (completed responses, tool output, etc.) must not be lost. When a response completes, the CLI briefly exits the alternate buffer, writes the formatted response to the main buffer (creating real scrollback), and re-enters the alternate buffer. On exit, the user can scroll up in the main buffer to see all session output.
Functionality
Alternate buffer lifecycle
/quit, Ctrl+C)resetbut bad UX)Zone rendering
pendingResizeflag, andnotifyResize()complexity are no longer necessaryHistory flush to main buffer
Cleanup handler
\x1b[?1049l(exit alternate buffer) is sent before the process terminatesWhat this replaces
cursorUp(lastVisibleCursorRow)pendingResizeflag and narrow/widen resize heuristicnotifyResize()propagation chainWhat this does NOT include
Guidance
POC verified
A bash POC (
alt-buffer-poc.shin bananabot9000/claude-sandbox) confirms:sleep)Sync output (
\x1b[?2026h)Already used in the codebase's
render()method. Does NOT prevent flicker during buffer swaps (buffer switch is a screen state change, not buffered output). However, the swap is fast enough that flicker is invisible without sync. Sync does NOT work through tmux (tmux intercepts/swallows the sequence on older versions).History flush sequence
Re-entering the alternate buffer clears it. A full zone redraw is required after every flush.
Existing infrastructure that applies
Viewportclass already implements a stateful scroll window over an unbounded bufferRenderer.render()already usescursorAt()for absolute positioning (used in the narrow-resize path)syncStart/syncEndprimitives already existrender()(trailing empty row removal) prevents overwriting the full screen when the zone is smaller than the terminalCleanup handler pattern
What "formatted history" means
The flush writes what the user would want to see if they scrolled up after exiting: the assistant's response text, tool call summaries, code blocks -- the same content currently visible in the zone during streaming, but as final static text. Not the raw ANSI rendering frames.
Phase 0 investigation
Full investigation at
projects/claude-cli/investigations/resize-position-tracking.mdin the fleet repo. Covers 10 approaches with trade-off tables, compatibility matrices, and terminal behaviour constraints.