[BUG] Kitty keyboard protocol gated on terminal-name allow-list instead of CSI ? u capability — capable terminals (Alacritty) denied

Open 💬 3 comments Opened Jun 26, 2026 by severindupouy

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Environment

  • Claude Code: 2.1.193 (single-file compiled binary, embedded Bun 1.4.0)
  • Terminal: Alacritty 0.17.0
  • OS: Linux x86_64
  • Shell: fish

Summary

Claude Code decides whether to enable the kitty keyboard protocol by identifying the terminal by name against an allow-list, rather than by the terminal's capability reply to CSI ? u. Terminals that fully implement the kitty keyboard protocol but are not on the allow-list — and cannot be name-identified — are silently left in legacy input mode. Alacritty is the concrete case: Shift+Enter and Ctrl+Backspace do not work, even though Alacritty correctly speaks the protocol.

Mechanism (as documented in the now-mis-closed #27868, observed in v2.1.50, still current in 2.1.193):

The kitty keyboard push (CSI > 1 u) is gated on a terminal-name allow-list:

const kittyTerminals = ["iTerm.app", "kitty", "WezTerm", "ghostty"];
if (kittyTerminals.includes(detectedTerminal)) {
  stdout.write(kittyPushSequence); // CSI > 1 u
}

detectedTerminal comes from name/identity signals (TERM_PROGRAM, XTVERSION, KITTY_WINDOW_ID, $TERM). It is not derived from the CSI ? u capability response. So a terminal that proves protocol support via CSI ? u but whose name is not on the list never receives the push.

Why Alacritty specifically can never pass identity detection

Probing Alacritty 0.17.0 directly:

# XTVERSION (CSI > q) — terminal name/version
sent:  \x1b[>q
reply: \x1b[?6c                # only the primary-DA fence — NO DCS >| name reply

# kitty keyboard flags (CSI ? u) — capability
sent:  \x1b[?u
reply: \x1b[?0u\x1b[?6c        # CSI ? 0 u  => protocol SUPPORTED (flags currently 0)
  • Alacritty answers CSI ? u → the protocol is fully supported.
  • Alacritty does not answer XTVERSION, does not set TERM_PROGRAM, does not set KITTY_WINDOW_ID, and reports TERM=alacritty. So none of the identity channels can mark it kitty-capable.
  • Alacritty not answering XTVERSION is deliberate and permanent — the maintainer rejected it as wontfix (alacritty/alacritty#5273), even after a working PR, on the grounds that terminal-name/version detection is the wrong model for feature detection. So identity-based detection can never work for Alacritty by design; only capability-based detection can.

Proof that the only thing missing is identification, not capability

Launching with a faked kitty marker makes Claude send the push, and Alacritty honors it — Shift+Enter and Ctrl+Backspace immediately work:

env KITTY_WINDOW_ID=1 claude   # both keys now native in Alacritty

This confirms Alacritty fully honors the protocol flags once pushed; the push is being withheld purely on identity grounds.

What Should Happen?

When the terminal responds to CSI ? u with a valid CSI ? <flags> u reply, Claude Code should treat it as kitty-keyboard-capable and send the push sequence regardless of terminal name — i.e. detect the capability, not the identity. This matches the expected behavior already requested in #62423 ("When the terminal responds positively to the kitty keyboard protocol query (CSI ? u), Claude Code should use it"), extended to the case where the terminal is not on the name allow-list at all.

Capability-first detection also aligns with where the terminal ecosystem is deliberately heading (Alacritty's wontfix on XTVERSION is an explicit rejection of identity-based feature detection), and would fix not just Alacritty but any current/future spec-compliant terminal that isn't hard-coded into the list.

Suggested change (mirrors #27868's proposal, generalized): gate the push on the CSI ? u response, with the name allow-list and KITTY_WINDOW_ID kept only as fallbacks for terminals that don't answer the query.

Steps to Reproduce

  1. Open Alacritty (0.13+; tested 0.17.0) — confirm printf '\e[?u\e[c' returns a \e[?...u reply (protocol supported).
  2. Run claude normally (no env tweaks).
  3. Press Shift+Enter → submits instead of inserting a newline. Press Ctrl+Backspace → deletes one character instead of a word.
  4. Now run env KITTY_WINDOW_ID=1 claude in the same Alacritty → both keys work natively.

Additional Context

  • #27868 reported this exact identity-vs-capability gating and was auto-closed as a duplicate of #18135 — but #18135 is an unrelated JetBrains/JediTerm rendering bug closed as not-planned. The precise defect is therefore currently untracked.
  • Related: #62423 (legacy XTMODKEYS sent even when kitty protocol is advertised), #16066 (/terminal-setup writes the legacy Shift+Return binding for Alacritty), alacritty/alacritty#5273 (XTVERSION wontfix).

Is this a regression?

No — long-standing behavior of the identity-based detection path.

View original on GitHub ↗

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