[BUG] Changing tui in settings.json blanks running fullscreen sessions not started with CLAUDE_CODE_NO_FLICKER
What's wrong
A running fullscreen Claude Code session goes permanently blank when the tui setting in ~/.claude/settings.json changes from fullscreen to default while it runs, if the session was not started with CLAUDE_CODE_NO_FLICKER.
The settings watcher (settingsChangeDetector) applies the change live, and the renderer choice re-reads tui on every render. The conversation is then laid out the default-renderer way (every grouped tool call expanded) inside the still-mounted fullscreen alternate-screen frame, which cannot scroll. Once that layout is taller than the terminal, the frame is erased and never repaints: no transcript, no composer, only the cursor parked on the composer row. Resizes do not recover it. Changing tui back to fullscreen repaints it immediately.
This matters because /tui <mode> in one session saves tui to the shared user settings, so it blanks every other long fullscreen session on the machine that was not pinned by env. Claude's own /tui message says the saved renderer "will apply to sessions started directly with claude", and switching the current session restarts it, so a live switch inside a running process looks unintended.
Environment
- Claude Code 2.1.273, macOS, Ghostty-based terminal (
TERM=xterm-256color,TERM_PROGRAM=ghostty) - Terminal 59x66 (also reproduced at 183x53 and 120x40)
Steps to reproduce
- Set
"tui": "fullscreen"in~/.claude/settings.json. Do not setCLAUDE_CODE_NO_FLICKER. - Start
claudeand have it run enough tool calls that their expanded output is taller than the terminal (for example about 30Bashcalls ofseq 1 12). - While it is idle or mid-turn, change
tuito"default"in~/.claude/settings.json(from another terminal, or run/tui defaultin a different Claude session). - About one second later (the watcher's settle time) the first session's frame is erased and stays blank.
Controls, all on the same session shape:
- 8 tool calls instead of 30 (expanded layout still fits): stays painted.
- Session started with
CLAUDE_CODE_NO_FLICKER=1: unaffected. - No settings change: unaffected.
- Changing
tuiback tofullscreen: repaints within about 2 seconds. defaulttofullscreenon a default-renderer session: remounts and keeps painting.
The terminal byte stream at the moment of the change is ESC]9;4;0 BEL, ESC]9;4;3 BEL, then a single synchronized update that erases every line (ESC[K per row) and ends with ESC[<rows>;1H ESC[<rows>;3H. After that only title updates are written.
A self-contained repro (private config dir, local fake API, no real API calls) that drives the tool calls, flips the setting and renders the result with pyte is available on request.
Expected
A running session keeps the renderer it started with; a saved tui change applies to sessions started afterwards, as the /tui message says.