-
Notifications
You must be signed in to change notification settings - Fork 18.5k
[BUG] Terminal scrolls to top during agent execution (Windows Terminal + PowerShell) #34794
Description
Description
While Claude Code is executing tools/commands, the terminal viewport jumps to the topmost position of the PowerShell/terminal buffer. This happens repeatedly during agent work, forcing the user to scroll back down constantly. Expected behavior: maintain the current scroll position so the user can continue working.
Root Cause Analysis (from cli.js v2.1.76 source)
Claude Code uses Ink (React-based terminal UI) for rendering. Ink's rendering strategy:
- On each re-render, it moves the cursor UP to the start of the component area
- Erases all previous lines (
eraseLines(height)) - Writes the new content
The core rendering code (from the bundled @inquirer/core and Ink output):
// Moves cursor up, erases, and rewrites
this.write(
cursorDown(this.extraLinesUnderPrompt) +
eraseLines(this.height) +
newContent
)Where eraseLines is:
eraseLines = (count) => {
let str = "";
for (let i = 0; i < count; i++)
str += eraseLine + (i < count - 1 ? cursorUp() : "");
if (count) str += cursorLeft;
return str;
}The problem: When the output grows large (streaming responses, tool results), eraseLines(this.height) moves the cursor far up in the terminal buffer. On Windows Terminal, this cursor movement causes the viewport to follow the cursor to the top of the render area, even if the user has scrolled away.
This is a fundamental issue with Ink's diff-based terminal rendering on Windows Terminal. macOS Terminal.app and iTerm2 are also affected (per #34400, #34765).
Steps to Reproduce
- Start Claude Code in Windows Terminal (PowerShell)
- Give it a multi-step task (e.g., searching files, running commands)
- While it's working, scroll up to read previous output
- Observe: viewport snaps to top of terminal buffer on each re-render
Suggested Fix
Option A: Use alternate screen buffer for the active render area
Ink supports alternate screen buffer mode which prevents scroll interference:
// Enter alternate screen before rendering
process.stdout.write('\x1b[?1049h');
// Exit alternate screen when done
process.stdout.write('\x1b[?1049l');Option B: Minimize re-render height
Instead of erasing the entire component and redrawing, only erase/redraw the lines that actually changed (incremental rendering).
Option C: Disable cursor movement when user has scrolled
Detect if the user has scrolled away from the bottom and suppress cursor-up movements until they scroll back.
Environment
- OS: Windows 11 Pro 10.0.26200
- Terminal: Windows Terminal
- Shell: PowerShell / bash (Git Bash)
- Claude Code: 2.1.76
- Source: cli.js SHA-256
38b8fd29d0817e5f75202b2bb211fe959d4b6a4f2224b8118dabf876e503b50b
Related Issues
- [Bug] Scroll position resets to top during agent execution #34400 — Scroll position resets to top during agent execution (macOS/iTerm)
- Scroll position resets to top of session while processing #34765 — Scroll position resets to top of session while processing
- [BUG] Forces scroll to top when outputting code (NOT just when scrolling) #33814 — Forces scroll to top when outputting code
- [BUG] SCROLL INTO-TOP ALWAYS ON CLAUDE-CODE CLI #34052 — Scroll to top always on CLI
- Terminal scrolls to top on every new output in certain sessions #34503 — Terminal scrolls to top on every new output
- Forced scroll to bottom when window gains focus (Windows Terminal + WSL2) #33624 — Forced scroll when window gains focus (Windows Terminal + WSL2)