anthropics / anthropics/claude-code

[BUG] Changing tui in settings.json blanks running fullscreen sessions not started with CLAUDE_CODE_NO_FLICKER

Open
#94,879 0 comments 0 reactions 0 assignees View on GitHub
area:tui bug has repro platform:macos
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.