# Kitty Color Protocol, or DECSWT (OSC 21)

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

- **Sequence:** `OSC 21 ; key = value ; … ST`
- **ECMA-48:** [§8.3.89 OSC – Operating System Command, p. 51](https://archive.org/details/ecma-48-5th-edition-june-1991/page/n64/mode/1up)
- **Specification:** [Setting and querying colors, kitty documentation](https://sw.kovidgoyal.net/kitty/color-stack/#setting-and-querying-colors)

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

| In | `OSC 21 ; Pt ST` is | So `OSC 21 ; foreground=? ST` |
| --- | --- | --- |
| DEC's VT520, and xterm when set up as one | **DECSWT**, Set Window Title: `Pt` becomes the title, as with [OSC 2](https://control-codes.page/osc/title/index.html.md) | makes the title `foreground=?` |
| kitty, Ghostty and others | the **kitty color protocol**, below | is answered with the foreground color |
| xterm as it is by default, a VT420 | nothing: DECSWT is a VT520 function | is ignored |

xterm takes `OSC 21` as DECSWT only when its terminal ID is 520 or more,
and otherwise ignores it
([`do_osc`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L4172-L4180)).
A program that wants kitty's colors should therefore first find out
what it is talking to, with [XTVERSION](https://control-codes.page/csi/xtversion/index.html.md) or
[DA](https://control-codes.page/csi/da/index.html.md), 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](https://control-codes.page/osc/palette/index.html.md) and [OSC 10 to 19](https://control-codes.page/osc/dynamic/index.html.md). Its definition is
kitty's
[Setting and querying colors](https://sw.kovidgoyal.net/kitty/color-stack/#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`.

| Field | Does |
| --- | --- |
| `key=?` | asks for the color; the answer is `OSC 21 ; key=rgb:rr/gg/bb ST` |
| `key=color` | sets it, in the color forms `XParseColor` takes |
| `key=` | makes it *dynamic*, such as a selection drawn in reverse video |
| `key` | puts 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

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e]21;foreground=?;background=?;1=?\a
```

Expected screen:

```text
|______|
reply none
```

### OSC21-2: Setting the foreground leaves OSC 10 alone

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e]21;foreground=#ff0000\e\\
\e]10;?\a
```

Expected screen:

```text
|______|
reply \e]10;rgb:0000/0000/0000\a
```

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

*A known difference: libghostty-vt does not pass this case.*

Input, one step per line:

```text
\e]21;1=#00ff00\e\\
\e]4;1;?\a
```

Expected screen:

```text
|______|
reply \e]4;1;rgb:cdcd/0000/0000\a
```

### OSC21-4: Not a window title

Input, one step per line:

```text
\e]2;Window\a
\e]21;foreground=white\a  # DECSWT, on a VT520
```

Expected screen:

```text
|______|
title "Window"
```

### OSC21-5: Nothing on screen

Input, one step per line:

```text
A
\e]21;foreground=green;cursor=;background\a
B
```

Expected screen:

```text
|AB____|
cursor 1,3
```

---

This is the Markdown version of <https://control-codes.page/osc/kitty-color/>. On that page every validation case runs live in libghostty-vt, the terminal emulation core of Ghostty, compiled to WebAssembly.

The validation cases are written in the notation described in <https://control-codes.page/notation/index.html.md>.
