[BUG] Kitty keyboard protocol gated on terminal-name allow-list instead of CSI ? u capability — capable terminals (Alacritty) denied
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 setKITTY_WINDOW_ID, and reportsTERM=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
- Open Alacritty (0.13+; tested 0.17.0) — confirm
printf '\e[?u\e[c'returns a\e[?...ureply (protocol supported). - Run
claudenormally (no env tweaks). - Press Shift+Enter → submits instead of inserting a newline. Press Ctrl+Backspace → deletes one character instead of a word.
- Now run
env KITTY_WINDOW_ID=1 claudein 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-setupwrites the legacy Shift+Return binding for Alacritty), alacritty/alacritty#5273 (XTVERSIONwontfix).
Is this a regression?
No — long-standing behavior of the identity-based detection path.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗