Semantic Prompt Marks (OSC 133)
Mark the boundaries between prompt, input, and output so the terminal can navigate, select, and time commands.
- 0x1B
- ESC
- 0x5D
- ]
- 0x31 0x33 0x33
- 133
- 0x3B
- ;
- ____
- c
- 0x3B
- ;
- ____
- ...
- 0x1B
- ESC
- 0x5C
- \
OSC 133 is the semantic prompt protocol. Shell integration scripts emit these marks around prompts, user input, and command output so the terminal emulator knows the structure of the shell session. With those marks in hand the terminal can offer features like jump to previous prompt, select the previous command's output, and per-command runtime tracking.
The protocol was pioneered as Per Bothner's semantic prompts proposal
and is widely supported (iTerm2, Wezterm, Kitty, and now Wintty). Each
command starts with a single-letter c selector that names the boundary,
followed by an optional payload of key=value options.
c | Wintty action name | Meaning |
|---|---|---|
A | fresh_line_new_prompt | Start a fresh line, begin a new prompt. |
B | end_prompt_start_input | End of prompt, start of user input. Terminates at C/P. |
C | end_input_start_output | End of input, start of command output. |
D | end_command | End of the running command (optionally with exit status). |
I | end_prompt_start_input_terminate_eol | Like B, but input is terminated by end-of-line. |
L | fresh_line | Insert a fresh line if not already at column 1. |
N | new_command | Same as A. Wintty never implicitly closes a command. |
P | prompt_start | Explicit prompt start. Optional after A or N. |
The terminal uses these marks to attach a semantic content tag (prompt, input, output) to every cell as text is written, which is what enables features like "select the previous command's output".
Most commands accept a trailing semicolon-separated list of options:
| Option | Type | Used by | Meaning |
|---|---|---|---|
aid | string | A, B, C, D, I, N, P | Application identifier; pairs related marks. |
cl | enum | A, N | Cursor-movement class for click-to-move: line, m, v, w. |
k | char | A, N, P | Prompt kind: i initial, r right-side, c continuation, s secondary. |
err | string | D | Human-readable error message. |
redraw | enum | A, N | Kitty extension: 0 no redraw, 1 full redraw, last (Ghostty/Wintty extension) only last line. |
special_key | bool | A, N | Parsed but unused: shell binds a special key for click-to-move-cursor. |
click_events | enum | A, N | 1 absolute click coordinates, 2 coordinates relative to the prompt area. 0 is rejected. |
cmdline | string | C | The command line, $'...'-decoded. Parser-level only. |
cmdline_url | string | C | The command line, URL-percent-decoded. Parser-level only. |
The D (end command) command additionally takes a bare positional integer
before any key=value options to report the exit status, for example
OSC 133;D;1;aid=abc ST.
Mark a prompt, the user's input, command output, and the result:
# Right before printing PS1:
printf '\033]133;A\033\\'
# After PS1, just before reading input:
printf '\033]133;B\033\\'
# After the user pressed enter, before the command runs:
printf '\033]133;C\033\\'
# After the command finishes, with exit code 0:
printf '\033]133;D;0\033\\'
Annotate the prompt as a continuation prompt:
printf '\033]133;P;k=c\033\\'
Wintty implements OSC 133 against the spec with the following notes:
- The
cloption is parsed for all four values (line,m,v,w) and is stored on the screen's semantic prompt state. The shell can also request SGR mouse events withclick_events, which takes priority overclfor click-to-move-cursor support.click_eventsis not a boolean:1asks for absolute click coordinates and2asks for coordinates relative to the prompt area.click_events=0is not a valid value and is discarded, leavingclin charge. - The
special_keyoption is parsed and validated but nothing reads it, so binding a special key for click-to-move-cursor has no effect today. - The
redrawoption recognizes0,1, and the Wintty/Ghostty extensionlast(Bash-only behavior: redraw only the last line of the prompt on resize). - The
cmdlineandcmdline_urldecoders exist and are correct: the first decodes as if it were a Bash$'...'-quoted string, the second is URL-percent-decoded. Nothing in the terminal calls them, though, so this is true of the parser rather than of a running session. Shipping a command line onCis harmless but is not recorded anywhere. - The
Ncommand is handled exactly likeA. The spec allowsNto first terminate an open command with a matchingaid, but Wintty does no explicit command tracking, so there is nothing to terminate and nothing is closed. - The
aidoption is parsed and then goes nowhere. The semantic prompt command is not encodable for the C API (itsCtype isvoid), so no embedding application can readaid, and Wintty itself does not use it for command tracking.
Tip
Shells usually do not emit OSC 133 out of the box. Wintty ships shell integration scripts that inject the marks at the right points for Bash, Zsh, Fish, PowerShell, cmd, and Elvish. Nushell is the exception: its script only wraps
sshandsudoand emits no OSC 133 at all, so prompt marks, jump-to-prompt, and per-command timing do not work under Nushell. For every other shell, make sure shell integration is enabled.
- Shell integration: overview of Wintty's shell integration features.
- Working directory reporting (OSC 7): emitted by the same shell integration scripts.
- The original semantic prompts proposal for the authoritative spec.