anthropics / anthropics/claude-code
[BUG] Changing tui in settings.json blanks running fullscreen sessions not started with CLAUDE_CODE_NO_FLICKER
- Dominant language
- Python
- Stars
- 145k
- Forks
- 23.1k
- PR merge metrics
- PR metrics pending
Description
### 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 ` 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
1. Set `"tui": "fullscreen"` in `~/.claude/settings.json`. Do not set `CLAUDE_CODE_NO_FLICKER`.
2. Start `claude` and have it run enough tool calls that their expanded output is taller than the terminal (for example about 30 `Bash` calls of `seq 1 12`).
3. While it is idle or mid-turn, change `tui` to `"default"` in `~/.claude/settings.json` (from another terminal, or run `/tui default` in a different Claude session).
4. 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 `tui` back to `fullscreen`: repaints within about 2 seconds.
- `default` to `fullscreen` on 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[;1H ESC[;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.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at the settingsChangeDetector and the renderer-selection path that re-reads tui during rendering. Reproduce with a fullscreen session, enough expanded tool output to exceed the terminal, and a live settings.json change; done means the running session keeps its initial renderer and continues painting, while later sessions use the saved setting.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100