# Kitty Notifications (OSC 99)

> Show desktop notifications with titles, icons, buttons and updates: kitty's notification protocol.

- **Sequence:** `OSC 99 ; metadata ; payload 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:** [Desktop notifications, kitty documentation](https://sw.kovidgoyal.net/kitty/desktop-notifications/)

`OSC 99 ; metadata ; payload ST` shows a notification on the desktop, with
more to it than iTerm2's [OSC 9](https://control-codes.page/osc/notify/index.html.md) or
[OSC 777](https://control-codes.page/osc/rxvt/index.html.md): a title and a body, an icon, buttons, an urgency, a
time to expire, and the ability to update or close one already shown and to
be told when it is clicked or closed. Its definition is kitty's
[Desktop notifications](https://sw.kovidgoyal.net/kitty/desktop-notifications/).
Both `;` must be there even with no metadata, so the simplest is
`OSC 99 ; ; Hello world ST`.

The metadata is `key=value` pairs separated by `:`, each key one letter. A
few of them:

| Key | Means |
| --- | --- |
| `i` | the notification's identifier, which ties several sequences to one notification |
| `d` | `0` while there is more to come, `1`, the default, when it is complete |
| `p` | what the payload is: `title`, the default, `body`, `icon`, `buttons`, `close`, or `?` to ask what is supported |
| `e` | `1` if the payload is Base64 |
| `u` | the urgency, `0` to `2` |
| `a` | what clicking it does: `focus` the window, `report` it back to the program |

So `OSC 99 ; i=1:d=0 ; Hello ST` followed by `OSC 99 ; i=1:p=body ; world ST`
shows one notification titled `Hello` with the body `world`. A program asks
whether the terminal has the protocol with `OSC 99 ; i=id:p=? ; ST`, and a
terminal that has it answers with the keys and values it supports.

A default xterm does not have it and ignores it
([the OSC numbers it knows](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L3476-L3504)).
The cases follow xterm. libghostty-vt parses the sequence and does nothing
with it, not even answering `p=?`, so it ignores it the same way and
passes. Its desktop notifications come from OSC 9 and OSC 777 instead.

## Validation

### OSC99-1: Nothing on screen

Input, one step per line:

```text
A
\e]99;;Hello world\e\\
\e]99;i=1:d=0;Hello\e\\
\e]99;i=1:p=body;World\e\\
B
```

Expected screen:

```text
|AB____|
cursor 1,3
reply none
bell 0
```

### OSC99-2: The question is not answered

Input, one step per line:

```text
\e]99;i=1:p=?;\e\\
```

Expected screen:

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

---

This is the Markdown version of <https://control-codes.page/osc/kitty-notify/>. 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>.
