# Kitty Keyboard Protocol Specification ## Metadata | Field | Value | |---|---| | Institute | Molodetz Institute — Research & Retrieval Division | | Subject | tui-framework-design | | Document type | Source Dossier | | Tier | 1 | | Source title | Comprehensive keyboard handling in terminals - kitty | | Source URL | https://sw.kovidgoyal.net/kitty/keyboard-protocol/ | | Source publisher / author | Kovid Goyal / kitty project | | Source type | standard | | Source date (published) | Unknown — not stated | | Date researched | 2026-10-10 | | Researched by | tai (agent), model: Muse Spark, on behalf of retoor | | Research method | direct page fetch | | Confidence | High | | Status | Active | ## Summary The authoritative specification of the kitty keyboard protocol: `CSI unicode-key-code:alternate-key ; mods:event-type ; text-as-codepoints u` key encoding, the five progressive-enhancement flags, the push/pop/query mechanism, the modifier bitmask, the functional key code table, and the support-detection procedure. Read to settle exactly which bytes enable bare-modifier key reporting and what a Shift press looks like on the wire. ## Key findings - Key event form: `CSI unicode-key-code:alternate-key ; mods:event-type u`, plus optional `;text-as-codepoints` tail (only with flag 16). Text keys use the codepoint as the number (shift+a is key `97`, mods shift). - Progressive-enhancement flags: 1 disambiguate escape codes, 2 report event types, 4 alternate keys, 8 all keys as escape codes, 16 associated text. Enable with `CSI flags ; mode u` (mode 1 set-all default, 2 set-bits, 3 clear-bits); stack discipline via `CSI > flags u` push (default 0) and `CSI < number u` pop (default 1); query via `CSI ? u`, reply `CSI ? flags u`. - Bare modifier press events are reported only with flag 8 (all keys as escape codes); without it there is no way to observe a lone Shift press at all. Flag 8 also converts every text key to escape-code form (no plain UTF-8 bytes) and implies disambiguation. - Event types (needs flag 2) are a `:type` subfield on the modifier parameter: 1 press (default when absent), 2 repeat, 3 release. Without flag 2, repeats arrive indistinguishable from presses. - Modifier mask is `1 + bits` with shift=1, alt=2, ctrl=4, super=8, hyper=16, meta=32, caps_lock=64, num_lock=128; absent field defaults to 1 (no modifiers). For modifier-key events the mask reflects state including the current event, so a bare left-Shift press is `CSI 57441 ; 2 u` and its release is `CSI 57441 ; 1 : 3 u`. - Functional codes: ESCAPE `27u`, ENTER `13u`, TAB `9u`, BACKSPACE `127u`, arrows `1A/1B/1C/1D`, LEFT_SHIFT `57441u`, RIGHT_SHIFT `57447u`, LEFT_CTRL `57442u`, F1-F12 keep legacy `~`/letter forms. - Main and alternate screens maintain independent keyboard-mode stacks, so pushing flags after entering the alternate screen never leaks into the shell's mode. - Recommended detection: send the `CSI ? u` query followed by a primary-device-attributes request; a DA1 reply with no kitty reply means unsupported. Partial implementations are detected by set-then-query. ## Pros / strengths - It is the normative document: exact byte sequences, flag semantics, event-type encoding, and the full functional table in one place, with rationale notes (e.g. why Enter/Tab/Backspace keep legacy bytes under flag 1). - Explicitly covers graceful degradation (unsupported terminals ignore the push) and the alternate-screen stack split, which is exactly what a fullscreen TUI needs. ## Cons / limitations / caveats - Dense single page (navigation-heavy HTML); the functional table mixes `u` and legacy `~`/letter forms, so a reader must track which form applies under which flags. - The spec permits partial implementations while discouraging them, so set-then-query is the only honest capability check; a push-and-hope client must still parse legacy input as fallback. ## Relevance to tai Directly load-bearing for double-Shift detection in the TUI demo: it proves bare Shift is unobservable without flag 8, fixes the push sequence (`CSI > 10 u` for flags 8+2, pop with `CSI < u`), the press encoding (`57441;2u`), and the repeat/release filtering rule (ignore `:2`/`:3` for tap detection). Drove the decision to push best-effort with no query round-trip and to parse legacy and CSI-u input side by side, plus a double-Escape fallback for terminals without kitty support. ## Changelog | Date | Change | |---|---| | 2026-10-10 | Initial dossier created. |