# VS Code Shell Integration (OSC 633)

> VS Code's marks for prompts, commands and their output, with the command line and properties added to OSC 133's.

- **Sequence:** `OSC 633 ; Ps [ ; 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:** [Terminal shell integration, VS Code documentation](https://code.visualstudio.com/docs/terminal/shell-integration#_vs-code-custom-sequences-osc-633-st)

`OSC 633` is the VS Code terminal's version of [OSC 133](https://control-codes.page/osc/prompt/index.html.md):
marks a shell's integration script sends so that the terminal knows where
each prompt, command and output is. VS Code uses them to decorate commands
with their status, to move between them, and to know the working directory.

| `Ps` | Marks |
| --- | --- |
| `A` | the start of a prompt |
| `B` | the end of the prompt, where the command line starts |
| `C` | just before the command's output |
| `D [ ; exit-code ]` | the end of the command; with no exit code, no command ran, as for an empty line or Ctrl+C |
| `E ; command-line [ ; nonce ]` | the exact command line |
| `P ; Name=Value` | a property: `Cwd`, `IsWindows` (`True` or `False`), or `HasRichCommandDetection` |

`E` exists because reading the command off the screen is unreliable. Its
command line escapes `\` as `\\` and writes `;`, and every character at or
below space, as `\xAB`; the optional nonce, which VS Code gives the
script, shows the sequence came from it, and some protections are relaxed
when it matches. VS Code's documentation asks other terminals to ignore
these, and scripts to send them only when `TERM_PROGRAM` is `vscode`
([shell integration](https://code.visualstudio.com/docs/terminal/shell-integration#_vs-code-custom-sequences-osc-633-st)). Its source knows further sub-commands that
it marks as unfinished and not to be used
([`shellIntegrationAddon.ts`](https://github.com/microsoft/vscode/blob/1.140.0/src/vs/platform/terminal/common/xterm/shellIntegrationAddon.ts#L103)).

A default xterm has no `OSC 633` 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 does not recognize `OSC 633` either: its OSC parser in
`osc.zig` has no state for the number, so the string is dropped, and the
cases pass.

## 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 | [83edd49](https://github.com/ghostty-org/ghostty/tree/83edd491e3024ae5e50393d62877b8897da1cccd) | No | ignored |
| Konsole | 26.11.70, [a24c3d71](https://invent.kde.org/utilities/konsole/-/tree/a24c3d71be3684f24d030aa2dbe9bd723d985233) | No | not among the OSC numbers it handles ([`Vt102Emulation.h`](https://invent.kde.org/utilities/konsole/-/blob/a24c3d71be3684f24d030aa2dbe9bd723d985233/src/Vt102Emulation.h#L189-L205)) |
| 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) |
| VS Code | 1.140.0, its [documentation](https://code.visualstudio.com/docs/terminal/shell-integration) | Yes | its own shell integration ([documentation](https://code.visualstudio.com/docs/terminal/shell-integration#_vs-code-custom-sequences-osc-633-st)) |

## Validation

### OSC633-1: The marks do not show

Input, one step per line:

```text
\e]633;A\a$\s
\e]633;B\a
ls
\e]633;E;ls\a
\e]633;C\a
```

Expected screen:

```text
|$_ls__|
cursor 1,5
reply none
```

### OSC633-2: Nor does a property, and the working directory is not set

Input, one step per line:

```text
A
\e]633;P;Cwd=/tmp\a
B
```

Expected screen:

```text
|AB____|
pwd ""
reply none
```

---

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