Kitty keyboard protocol detection ignores KITTY_WINDOW_ID when TERM_PROGRAM is set

Resolved 💬 3 comments Opened Feb 23, 2026 by sstraus Closed Feb 27, 2026

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

  1. 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 ? u query with CSI ? flags u
  1. 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

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗