Skip to content

Terminal Comparison ​

How Otty's escape-sequence support compares to other modern terminals. Use this when porting a TUI between terminals or deciding which protocols are safe to rely on.

Methodology ​

Symbols:

  • ✓ — fully implemented (mode is honored, response is correct)
  • ◐ — partially implemented (parsed without errors, but behavior is incomplete — e.g. the iTerm2 inline-image protocol only accepts its multipart form)
  • ❌ — not implemented (unknown / ignored / replied as not-supported)

The Otty column reflects what the terminal actually honors today — verified against the source, not the documentation. Where a sequence is parsed but the underlying mode is a no-op, it is marked ❌, not ✓.

Standard DEC private modes ​

These are the modes set with DECSET CSI ? Pn h and reset with DECRST.

ModeNamextermiTerm2KittyWezTermAlacrittyGhosttyOtty
?1DECCKM — App cursor keys✓✓✓✓✓✓✓
?6DECOM — Origin mode✓✓✓✓✓✓✓
?7DECAWM — Auto-wrap✓✓✓✓✓✓✓
?9X10 mouse (legacy)✓✓✓✓❌✓❌
?12Blinking cursor✓✓✓✓✓✓✓
?25DECTCEM — Cursor visible✓✓✓✓✓✓✓
?47Alt screen (legacy)✓✓✓✓❌✓✓
?1000Mouse: button events✓✓✓✓✓✓✓
?1002Mouse: cell-motion✓✓✓✓✓✓✓
?1003Mouse: all-motion✓✓✓✓✓✓✓
?1004Focus in/out✓✓✓✓✓✓✓
?1005Mouse: UTF-8 encoding✓✓✓✓✓✓✓
?1006Mouse: SGR encoding✓✓✓✓✓✓✓
?1016Mouse: SGR-Pixel✓✓✓✓❌✓❌
?1047Alt screen + clear on exit✓✓✓✓❌✓✓
?1049Alt screen + save cursor✓✓✓✓✓✓✓
?2004Bracketed paste✓✓✓✓✓✓✓
?2026Synchronized output (BSU/ESU)⚠️ partial✓✓✓✓✓✓
?2027Grapheme-cluster mode❌❌❌❌❌✓❌
?2031Color-scheme update notify❌❌✓✓✓✓✓
?2048In-band resize notify❌❌✓✓❌✓❌

Identification & queries ​

SequenceWhat it asksxtermiTerm2KittyWezTermAlacrittyGhosttyOtty
CSI cPrimary DA✓✓✓✓✓✓✓
CSI > cSecondary DA✓✓✓✓✓✓✓
CSI > qXTVERSION✓✓✓✓✓✓✓
CSI 5 n / 6 nDSR — status / cursor pos✓✓✓✓✓✓✓
CSI ? Pn $ pDECRQM mode status✓✓✓✓✓✓✓
CSI 14 tText-area size in px✓✓✓✓✓✓✓
CSI 16 tCell size in px✓✓✓✓❌✓✓
CSI 18 tText-area size in cells✓✓✓✓✓✓✓
CSI 22 JKitty scroll-then-erase❌❌✓❌❌✓✓
CSI ? uKitty keyboard-flags query❌❌✓✓✓✓✓
DCS $ q … STDECRQSS — request current setting✓✓✓✓❌✓◑
DCS + q … STXTGETTCAP — terminfo cap query✓❌✓✓❌✓❌

Vendor extensions ​

ProtocolSequenceOriginxtermiTerm2KittyWezTermAlacrittyGhosttyOtty
Kitty graphicsAPC G …Kitty❌❌✓✓❌✓✓
iTerm2 inline imageOSC 1337 File=iTerm2❌✓❌✓❌❌◐ multipart only
SixelDCS q …DEC✓❌❌✓❌✓❌
Kitty keyboardCSI > 1 u …Kitty❌❌✓✓✓✓✓
HyperlinkOSC 8xterm/VTE❌✓✓✓✓✓✓
ClipboardOSC 52xterm✓✓✓✓✓✓✓
Indexed paletteOSC 4 / 104xterm✓✓✓✓✓✓✓
Dynamic colorsOSC 10 / 11 / 12xterm✓✓✓✓✓✓✓
Shell integrationOSC 133 (FTCS)FinalTerm❌✓✓✓❌✓✓
VSCode shell integrationOSC 633VSCode❌❌❌❌❌❌❌
CWD reportOSC 7VTE❌✓✓✓❌✓✓
iTerm2 SetUserVarOSC 1337 SetUserVar=iTerm2❌✓❌✓❌❌❌
ConEmu progressOSC 9 ; 4ConEmu❌❌❌✓❌✓✓
Kitty notificationOSC 99Kitty❌❌✓❌❌✓✓
iTerm2 notificationOSC 9iTerm2❌✓❌✓❌✓✓
xterm color stackCSI [Pm] # P/Q/Rxterm✓❌❌❌❌✓✓
Terminal Resume (TRP)OSC 88Otty❌❌❌❌❌❌◐ experimental
Program statusOSC 7501Rex❌❌❌❌❌❌✓

Behavior notes ​

CSI ? Pn $ p — DECRQM ​

Otty answers DECRQM for both ANSI modes (CSI Pn $ p) and DEC private modes (CSI ? Pn $ p), replying with DECRPM CSI ? Pn ; state $ y. The state follows the DEC convention: 1 = set, 2 = reset (supported but currently off), 4 = not recognized. Every private mode listed in the table above reports a truthful set/reset state; any mode Otty doesn't implement replies 4 rather than pretending to support it. The one nuance is ?2026: the live synchronized-output state lives inside the parser and isn't queryable, so Otty always answers 2 (reset) — which is exactly what nvim, zellij, and Ghostty probe for to decide whether to emit BSU/ESU.

CSI ? 2026 h/l — Synchronized Output ​

Between BSU and ESU, Otty buffers all output and paints it in a single frame, so a full-screen redraw never tears or flickers. A short safety timeout flushes the buffer if a program enables synchronized output and then dies without sending ESU, so a crash can't freeze the pane.

CSI > q — XTVERSION ​

Otty replies with DCS > | otty(<version>) ST, where <version> is the build version. Programs that recognize the otty( prefix can gate features on it.

Selective erase & character protection — DECSCA / DECSED / DECSEL ​

Otty implements the VT220 character-protection family:

  • DECSCA (CSI <n> " q) marks subsequently written cells as protected (n=1) or erasable (n=0/2).
  • DECSED (CSI ? <n> J) and DECSEL (CSI ? <n> K) erase only the erasable cells, leaving protected ones in place.

Protection is per-cell and independent of SGR (SGR 0 does not clear it; only DECSCA 0/2, DECSTR, or RIS do), and it is saved/restored with the cursor by DECSC / DECRC.

Support across terminals is uneven. xterm and Ghostty implement the family; Alacritty does not — it has no DECSCA and ignores the selective-erase private variants, so CSI ? 2 J finds nothing protectable and clears the screen like a plain erase. That gap is what motivated adding the family to Otty.

Notable gaps ​

DCS q … — Sixel ​

Not parsed. The underlying vte parser treats DCS hooks as no-ops and the Otty fork doesn't add a Sixel decoder. Modern equivalents (Kitty graphics) cover the same ground for new code; Sixel remains the only option for legacy tools (gnuplot, img2sixel, lsix).

DCS $ q … / DCS + q … — DECRQSS & XTGETTCAP ​

Partial (◑). Both are DCS-framed queries: DECRQSS asks the terminal to echo back a current setting; XTGETTCAP asks for a terminfo capability. Otty answers the cursor-style DECRQSS (DCS $ q SP q ST → DCS 1 $ r <Ps> SP q ST), so tmux and TUIs can read back the active cursor shape after a DECSCUSR change. Other DECRQSS targets (SGR, scrolling region, …) and XTGETTCAP are still not answered — vte doesn't dispatch general DCS payloads — so programs probing those fall back to their defaults.

?2048 — In-band resize notifications ​

Not implemented. Programs that opt in expect a CSI 48 ; … t report on every resize instead of relying on SIGWINCH. Otty ignores the DECSET and the program falls back to SIGWINCH, which works on macOS.

?1016 — SGR-Pixel mouse ​

Not implemented. vte doesn't recognize mode 1016, so Otty reports mouse events in cell coordinates via SGR mode (?1006) instead of pixel coordinates. Apps that request pixel precision degrade gracefully to cell precision.

OSC 633 — VSCode shell integration ​

Not parsed. VSCode's integrated-terminal scripts emit OSC 633 in parallel to OSC 133. Otty users running Set-PSReadLineOption-style integrations see the bracketed escapes echoed to the screen.

OSC 1337 single-segment File= ​

Only the multipart form is parsed. The single-segment form (OSC 1337 ; File=<base64-attrs>:<base64-data> ST) — the default emitted by imgcat and most shell scripts — is dropped. Larger images that don't fit in one OSC payload work; the common small case doesn't.

OSC 88 — Terminal Resume Protocol ​

Experimental and Otty-specific. The handshake is wired up — Otty parses arm / clear / query and answers query with OSC 88 ; supported ; v=1 ST — but persisting a pane's resume spec and replaying it end-to-end is still in progress. No other terminal implements OSC 88. See OSC 88 and github.com/Otty-sh/osc-88.

OSC 7501 — Program Status ​

The Program Status Protocol (rev 0.4), from Superlogical's Rex. Otty implements rev 0.4: all five states, blocked kinds, hierarchical ids with clear by subtree, and the ? feature query. The most urgent record drives the tab badge, the Dock icon, Inbox and notifications. Where a terminal only understands OSC 9;4, a program can send both. See OSC 7501.

See also ​

Otty