# iTerm2 Extensions (OSC 1337)

> iTerm2's own commands: inline images, marks, user variables, the clipboard and the working directory, and its other OSC extensions.

- **Sequence:** `OSC 1337 ; Pt 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:** [Proprietary Escape Codes, iTerm2 documentation](https://iterm2.com/documentation-escape-codes.html)

iTerm2, the macOS terminal, puts most of its own commands under one OSC
number, `1337`, as `OSC 1337 ; Key=value ST`; it used `OSC 50` once, and
moved because xterm uses `50` for fonts. Their definition is iTerm2's
[Proprietary Escape Codes](https://iterm2.com/documentation-escape-codes.html)
page and the pages it links to:

| `Pt` | Does | libghostty-vt |
| --- | --- | --- |
| `AddAnnotation=message` | attach a note to the text at the cursor, and show it | ignored |
| `AddHiddenAnnotation=message` | attach a note without showing it | ignored |
| `Block=id=name;attr=start` | mark where a block of text starts, or with `attr=end` ends, for folding and copy buttons | ignored |
| `Button=type=copy;block=name` | add a button that copies a block; `type=custom` adds one that sends a code back | ignored |
| `Capabilities` | ask which features the terminal has; answered `OSC 1337 ; Capabilities=features ST`, from iTerm2's feature reporting protocol | not recognized; ignored, so not answered |
| `ClearCapturedOutput` | erase the output captured from the last command | ignored |
| `ClearScrollback` | erase the scrollback | ignored |
| `Copy=:base64` | put text on the clipboard | passed to the host, as [OSC 52](https://control-codes.page/osc/clipboard/index.html.md) |
| `CopyToClipboard=name` | copy all the text that follows to a clipboard, until `EndCopy` | ignored |
| `CurrentDir=dir` | report the shell's working directory | kept, as [OSC 7](https://control-codes.page/osc/cwd/index.html.md) |
| `CursorShape=n` | `0` block, `1` bar, `2` underline, from Konsole | ignored |
| `Custom=id=secret:pattern` | a sequence a script defines itself | ignored |
| `Disinter` | bring back a session that was buried | ignored |
| `EndCopy` | end `CopyToClipboard` | ignored |
| `File=args:base64` | show a file, usually an image, inline in the text, or download it | ignored |
| `FileEnd` | end a file sent with `MultipartFile` | ignored |
| `FilePart=base64` | one piece of a file sent with `MultipartFile` | ignored |
| `HighlightCursorLine=yes` | show or hide the cursor guide, a highlight on the cursor's line | ignored |
| `MultipartFile=args` | start a file sent in pieces, as `File` does at once, for tmux | ignored |
| `OpenURL=:base64` | ask to open a URL, with the user's permission | ignored |
| `PopKeyLabels` | restore the Touch Bar's labels from the stack | ignored |
| `PushKeyLabels` | save the Touch Bar's labels on a stack | ignored |
| `RemoteHost=user@host` | report the user and host the shell is on | ignored |
| `ReportCellSize` | ask for a cell's size in points; answered `OSC 1337 ; ReportCellSize=h;w;scale ST` | not answered |
| `ReportVariable=base64` | ask for one of iTerm2's variables | not answered |
| `RequestAttention=yes` | bounce the dock icon; `once`, `no`, or `fireworks` at the cursor | ignored |
| `RequestUpload=format=tgz` | ask the user for files to upload | ignored |
| `SetBackgroundImageFile=base64` | show a picture behind the text, with the user's permission | ignored |
| `SetBadgeFormat=base64` | set the badge, text drawn in the corner of the session | ignored |
| `SetColors=key=value` | change one of the session's colors | ignored |
| `SetKeyLabel=key=value` | label a Touch Bar key | ignored |
| `SetMark` | set a mark to jump back to | ignored |
| `SetProfile=name` | change the session's profile | ignored |
| `SetProfileProperty=key=base64` | change one setting of the session's profile, given as JSON | not recognized; ignored |
| `SetUserVar=name=base64` | set a variable iTerm2 can show, such as in a tab title | ignored |
| `ShellIntegrationVersion=n` | report the version of iTerm2's shell integration | ignored |
| `StealFocus` | bring the window forward | ignored |
| `UnicodeVersion=n` | choose Unicode 8's or 9's character widths | ignored |
| `UpdateBlock=id=name;action=fold` | fold or unfold a block | not recognized; ignored |

That is every key iTerm2 documents, in its
[Proprietary Escape Codes](https://iterm2.com/documentation-escape-codes.html)
page and in the pages it sends a reader to for
[images](https://iterm2.com/documentation-images.html),
[badges](https://iterm2.com/documentation-badges.html) and
[feature reporting](https://iterm2.com/feature-reporting/). libghostty-vt
recognizes all but three, without regard to case, and acts on two, `Copy` and
`CurrentDir`; it consumes the rest without doing anything. The three it does
not know, `Capabilities`, `SetProfileProperty` and `UpdateBlock`, are newer,
and it ignores them all the same.

iTerm2 has a few extensions outside `1337` as well:

| Sequence | Does | libghostty-vt |
| --- | --- | --- |
| `OSC 4 ; -1 ; ? ST`, `OSC 4 ; -2 ; ? ST` | ask for the default foreground and background, through the [palette](https://control-codes.page/osc/palette/index.html.md) query | not answered |
| `OSC 6 ; 1 ; bg ; red ; brightness ; n ST` | color the tab; the same for `green` and `blue`; see [OSC 6](https://control-codes.page/osc/color-mode/index.html.md) | ignored |
| [`OSC 21337`](https://control-codes.page/osc/iterm2-status/index.html.md) | set the tab's status text and indicator | ignored |
| [`OSC P`](https://control-codes.page/osc/linux-palette/index.html.md) | change a color, the Linux console's way | ignored |

and it documents others that this site gives pages of their own:
[notifications](https://control-codes.page/osc/notify/index.html.md) with `OSC 9`, [progress](https://control-codes.page/osc/progress/index.html.md) with
`OSC 9 ; 4`, FinalTerm's [shell integration](https://control-codes.page/osc/prompt/index.html.md) marks with
`OSC 133`, [hyperlinks](https://control-codes.page/osc/hyperlink/index.html.md), and its answer to
[XTVERSION](https://control-codes.page/csi/xtversion/index.html.md), `iTerm2` and its version.

A default xterm has none of these and ignores them
([the OSC numbers it knows](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L3476-L3504)).
`OSC 6` is xterm's own, for turning its special colors on and off, but
iTerm2's string does not parse as that and changes nothing
([`do_osc`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L4197-L4249));
`OSC 4 ; -1` is a negative color number, where xterm stops
([`ChangeAnsiColorRequest`](https://github.com/ThomasDickey/xterm-snapshots/blob/xterm-411a/misc.c#L2980-L3029)).
The cases follow xterm, so the one where libghostty-vt keeps the working
directory is a known difference.

## Support

| Terminal | Version | Support | Notes |
| --- | --- | --- | --- |
| VT220 | [manual](https://vt100.net/docs/vt220-rm/), 2nd ed., 1984 | No | OSC is not among the controls it recognizes ([§4.2](https://vt100.net/docs/vt220-rm/chapter4.html#S4.2)) |
| VT510 | [manual](https://vt100.net/docs/vt510-rm/), 1st ed., 1993 | No | ignores an OSC string ([chapter 4](https://vt100.net/docs/vt510-rm/chapter4.html)) |
| xterm | patch 412, [xterm-411a](https://github.com/ThomasDickey/xterm-snapshots/tree/xterm-411a) | No | ignored |
| libghostty-vt | [0f171f6](https://github.com/ghostty-org/ghostty/tree/0f171f650a1cbbd6df4a2573b6b0c7de57cc6d90) | Partly | acts on `Copy` and `CurrentDir` and consumes the rest (ITERM2-1) |
| Konsole | 26.11.70, [a24c3d71](https://invent.kde.org/utilities/konsole/-/tree/a24c3d71be3684f24d030aa2dbe9bd723d985233) | Partly | only inline images (`File`, `MultipartFile`) and `ReportCellSize` |
| iTerm2 | 3.7.3, its documentation | Yes | [Proprietary Escape Codes](https://iterm2.com/documentation-escape-codes.html) |
| ConEmu | build 230724, its [documentation](https://conemu.github.io/en/AnsiEscapeCodes.html) | No | not in its [ANSI escape codes](https://conemu.github.io/en/AnsiEscapeCodes.html) |

## Validation

### ITERM2-1: The working directory

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

Input, one step per line:

```text
\e]1337;CurrentDir=/home/user\a
```

Expected screen:

```text
|______|
pwd ""
```

### ITERM2-2: The clipboard changes nothing on screen

Input, one step per line:

```text
A
\e]1337;Copy=:SGVsbG8=\a  # "Hello"
B
```

Expected screen:

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

### ITERM2-3: The rest are consumed

Input, one step per line:

```text
A
\e]1337;SetMark\a
\e]1337;SetUserVar=name=dmFsdWU=\a
\e]1337;RemoteHost=user@example.com\a
\e]1337;CursorShape=1\a
\e]1337;File=inline=1:SGVsbG8=\a
B
```

Expected screen:

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

### ITERM2-4: Questions are not answered

Input, one step per line:

```text
\e]1337;ReportCellSize\a
\e]1337;ReportVariable=c2Vzc2lvbi5uYW1l\a
\e]4;-1;?\a
```

Expected screen:

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

### ITERM2-5: Tab colors

Input, one step per line:

```text
A
\e]6;1;bg;red;brightness;255\a
B
```

Expected screen:

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

### ITERM2-6: Newer keys are ignored too

Input, one step per line:

```text
A
\e]1337;Capabilities\a
\e]1337;SetProfileProperty=Cursor Type=Mg==\a
\e]1337;UpdateBlock=id=b;action=fold\a
B
```

Expected screen:

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

---

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