^[control-codes live in libghostty-vt

Operating system commands

OSC 21 Kitty Colors, or DECSWT

Two meanings for one number: kitty's protocol for querying and setting colors, and DEC's VT520 Set Window Title, which xterm follows.

OSC 21 ; key = value ; … ST
ECMA-48
§8.3.89 OSC – Operating System Command, p. 51
Specification
Setting and querying colors, kitty documentation

OSC 21 means two different things, and a program cannot use it without knowing which terminal it is talking to:

InOSC 21 ; Pt ST isSo OSC 21 ; foreground=? ST
DEC’s VT520, and xterm when set up as oneDECSWT, Set Window Title: Pt becomes the title, as with OSC 2makes the title foreground=?
kitty, Ghostty and othersthe kitty color protocol, belowis answered with the foreground color
xterm as it is by default, a VT420nothing: DECSWT is a VT520 functionis ignored

xterm takes OSC 21 as DECSWT only when its terminal ID is 520 or more, and otherwise ignores it (do_osc). A program that wants kitty’s colors should therefore first find out what it is talking to, with XTVERSION or DA, rather than send OSC 21 and risk renaming the window.

The kitty color protocol

OSC 21 ; key=value ; … ST does with one number what xterm does with OSC 4 and OSC 10 to 19. Its definition is kitty’s Setting and querying colors. Each key is a palette number, 0 to 255, or the name of a special color: foreground, background, cursor, cursor_text, selection_background, selection_foreground, visual_bell, and transparent_background_color1 to 7.

FieldDoes
key=?asks for the color; the answer is OSC 21 ; key=rgb:rr/gg/bb ST
key=colorsets it, in the color forms XParseColor takes
key=makes it dynamic, such as a selection drawn in reverse video
keyputs it back as it started

One sequence can carry any number of fields, so foreground=white ; foreground=? sets a color and asks for it at once. kitty’s document also says what to answer for a color with no fixed value (key= with nothing after it) and for a key the terminal does not know (unknown= and the key in Base64), and defines OSC 30001 and OSC 30101 to push and pop all the colors.

A default xterm, a VT420, ignores OSC 21 altogether, so kitty’s fields neither answer nor become a title there. The cases follow it.

libghostty-vt implements it, on the same colors OSC 4 and OSC 10 change, so setting foreground changes what OSC 10 ; ? reports. Where it departs from kitty’s document is in what it leaves out: it gives no answer for a key it does not know or for one with no color set, such as cursor_text, and it does not have OSC 30001 and OSC 30101. The cases where it answers or a color changes are known differences.

Validation

OSC21-1: Questions are not answered

\e]21;foreground=?;background=?;1=?\a
|______|
reply none

OSC21-2: Setting the foreground leaves OSC 10 alone

\e]21;foreground=#ff0000\e\\
\e]10;?\a
|______|
reply \e]10;rgb:0000/0000/0000\a

OSC21-3: Nor does setting a palette color change OSC 4

\e]21;1=#00ff00\e\\
\e]4;1;?\a
|______|
reply \e]4;1;rgb:cdcd/0000/0000\a

OSC21-4: Not a window title

\e]2;Window\a
\e]21;foreground=white\a  # DECSWT, on a VT520
|______|
title "Window"

OSC21-5: Nothing on screen

A
\e]21;foreground=green;cursor=;background\a
B
|AB____|
cursor 1,3
Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.