Kitty keyboard protocol detection ignores KITTY_WINDOW_ID when TERM_PROGRAM is set
Bug
Claude Code's terminal detection function checks TERM_PROGRAM before KITTY_WINDOW_ID. When a third-party terminal emulator sets TERM_PROGRAM to its own name (as is convention) AND sets KITTY_WINDOW_ID=1 to signal kitty keyboard protocol support, the detection returns the custom name, which isn't in the kitty-capable allow-list ["iTerm.app", "kitty", "WezTerm", "ghostty"]. As a result, the kitty keyboard push sequence (CSI > 1 u) is never sent, and Shift+Enter doesn't work.
Reproduction
- Run Claude Code inside a terminal emulator that:
- Sets
TERM_PROGRAM=<custom-name>(e.g.,tuicommander) - Sets
KITTY_WINDOW_ID=1 - Correctly responds to
CSI ? uquery withCSI ? flags u
- Observe that Shift+Enter does not insert a newline (kitty keyboard mode is never activated)
Root Cause
In the terminal detection function (minified as $tD() in v2.1.50), TERM_PROGRAM is checked at priority ~4, while KITTY_WINDOW_ID is at priority ~16:
// Priority ~4: returns raw TERM_PROGRAM value
if (process.env.TERM_PROGRAM) return process.env.TERM_PROGRAM;
// ... many checks in between ...
// Priority ~16: would return "kitty" but is never reached
if (process.env.KITTY_WINDOW_ID) return "kitty";
The kitty keyboard push is then gated on the allow-list:
const kittyTerminals = ["iTerm.app", "kitty", "WezTerm", "ghostty"];
if (kittyTerminals.includes(detectedTerminal)) {
stdout.write(kittyPushSequence);
}
Suggested Fix
Option A (preferred): Check KITTY_WINDOW_ID before or alongside TERM_PROGRAM. Any terminal that sets KITTY_WINDOW_ID is explicitly declaring kitty protocol support and should be treated as kitty-capable regardless of its name:
if (process.env.KITTY_WINDOW_ID) return "kitty";
// ... then check TERM_PROGRAM
Option B: Add KITTY_WINDOW_ID as a separate signal for the kitty-capable allow-list check, independent of terminal name detection:
const isKittyCapable = kittyTerminals.includes(terminal) || !!process.env.KITTY_WINDOW_ID;
Option C (quick fix): Add "tuicommander" to the allow-list alongside the existing terminals.
Affected Context
TUI Commander is a Tauri-based terminal manager that embeds Claude Code. It implements the kitty keyboard protocol (query response + key encoding) but sets TERM_PROGRAM=tuicommander per convention. Current workaround: setting TERM_PROGRAM=kitty to pass the allow-list.
Environment
- Claude Code v2.1.50 (compiled binary, macOS arm64)
- TUI Commander v0.5.1
- macOS 15.4
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗