[BUG] Ctrl+D at empty prompt does not exit under fullscreen rendering (NO_FLICKER=1 / tui: fullscreen)
Edit 2026-04-20 (shortly after filing): Scrubbed the original claim that Ctrl+C-pressed-twice also fails under fullscreen. That was a speculation from static binary reading that did not survive empirical testing — Ctrl+C-twice does exit cleanly. This issue is now scoped to Ctrl+D only; the root-cause and suggested-fix sections were trimmed accordingly.
Summary
Under fullscreen rendering (any of CLAUDE_CODE_NO_FLICKER=1, /tui fullscreen, or "tui": "fullscreen" in settings.json), Ctrl+D at an empty prompt does nothing — the byte is consumed silently. In default (non-fullscreen) mode, Ctrl+D at an empty prompt exits the session as expected.
The in-binary help text still advertises Ctrl+D as an exit path ("Ctrl+D Delete character / Exit if line empty"), and #960 established the intent: "ctrl+d deletes forward, for the special case where input is empty it quits" (@wolffiex, 2025-05-07). So this is a regression of the documented exit behavior in the fullscreen code path.
Ctrl+C-pressed-twice, /exit, and /quit all terminate cleanly under fullscreen mode.
Environment
- Claude Code: v2.1.114
- OS: macOS 15 (Darwin 25.3.0, arm64)
- Terminal: Warp
- Shell: zsh
Steps to reproduce
CLAUDE_CODE_NO_FLICKER=1 claude(or start normally and run/tui fullscreen).- At the prompt with empty input, press Ctrl+D.
- Expected: session exits. Actual: nothing happens.
Contrast — without CLAUDE_CODE_NO_FLICKER / with tui: "default", Ctrl+D at an empty prompt exits the session as documented.
Root cause (from binary analysis v2.1.114)
Fullscreen mode is gated by the Uq() function:
function Uq(H = soH) {
if (BK(process.env.CLAUDE_CODE_NO_FLICKER)) return false;
if (EH(process.env.CLAUDE_CODE_NO_FLICKER)) return true;
if (/* tmux -CC */) return false;
switch (k8().tui) { case "fullscreen": return true; case "default": return false; }
return /* growthbook tengu_pewter_brook default false */;
}
When Uq() returns true, Claude Code switches to Ink + raw mode + alt-screen, bypassing Node readline.
In default mode Ctrl+D hits readline's handler:
// readline module — runs in default mode only
if (key.ctrl) {
if (key.name === "c") { ... }
else if (key.name === "d") { this.close(); return; }
}
In fullscreen mode that handler never runs. The app-level input handler has $H.ctrl bindings for prevWord, nextWord, startOfLine, endOfLine, delete-char, etc., but no ctrl + d → exit binding. The 0x04 byte is dropped.
#39498 (closed) describes a related but distinct cleanup bug in the Ctrl+D exit path (terminal reset skipped on exit). Both point at the fullscreen input layer not being fully integrated with the exit plumbing.
Suggested fix
Bind ctrl + d on empty input to the same exit path as /exit (or /quit) inside the fullscreen input handler, and ensure it flushes terminal resets (bracketed paste, focus reporting, raw mode) on the way out — cross-reference #39498.
Workarounds until this is fixed
/exit, /quit, or Ctrl+C pressed twice all exit cleanly under fullscreen mode.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗