^[control-codes live in libghostty-vt

Proposals

OSC 88 Terminal Resume Protocol

A proposal for a program to tell its terminal how to relaunch it when the terminal itself is restarted.

OSC 88 ; op ; key=value … ST
Specification
Terminal Resume Protocol (TRP), OSC 88 Specification, v1

The Terminal Resume Protocol lets a long-running program, an editor, a multiplexer, an SSH session, tell its terminal how to start it again after the terminal itself restarts, whether it crashed, the machine rebooted, or the terminal was upgraded. The terminal keeps that declaration for the pane and, when it restores the pane, runs the command. The program announces; the terminal acts on its own schedule. Apart from an optional query, nothing is sent back.

This summarizes version 1 of the specification as it stood at commit aabe19c, where its status is Proposal. Its authors name Otty as the reference implementation and say the protocol is not specific to it.

The sequence

OSC 88 ; op [ ; key=value ]… ST

The first field after 88 is the operation. Fields after it are key=value pairs separated by ;, and a receiver splits each on its first = only. Every value is the base64 of a UTF-8 string, which keeps a ; from ever appearing inside one, except the two numeric fields, v and self_repaint, which are written as plain digits. Either ST or BEL may end the sequence; the specification prefers ST and requires a receiver to accept both.

OperationSent byMeaning
armthe programSet this pane’s resume command, replacing any set before. It must have a cmd; one without is ignored.
clearthe programWithdraw it, as on a clean exit. Any fields are ignored.
querythe programOptional. Asks whether the terminal implements the protocol.
supportedthe terminalThe answer to query: OSC 88 ; supported ; v=N ST, with N the highest version it implements.

A program may send arm and clear without asking first: a terminal that does not implement the protocol must ignore the whole sequence. One that does should answer query, but no answer means only that support is unknown, and the program must not wait for one indefinitely.

The fields of arm

FieldValueMeaning
cmdbase64, requiredThe program to run, and what the terminal verifies before trusting the rest
argsbase64The rest of the command line, appended after cmd
self_repaint0 or 11: the program redraws its own screen, so the terminal should not restore the pane’s old contents as well. Default 0
cwdbase64The directory to run in; otherwise the pane’s last known working directory
titlebase64A title for the restored pane, below OSC 0 and 2 in priority
vdigitsThe protocol version, 1 by default

A receiver ignores keys it does not know, so that later versions can add fields; a change that is not backward compatible must raise v. args is a single string, and the specification does not say how it is split into separate arguments.

For example, to have htop -d 10 started again in /home/alice, with cmd the base64 of htop, args of -d 10, cwd of /home/alice, and self_repaint=1 because htop draws its whole screen itself:

ESC ] 88 ; arm ; cmd=aHRvcA== ; args=LWQgMTA= ; cwd=L2hvbWUvYWxpY2U= ; self_repaint=1 ESC \

without the spaces, which are there only to make it readable, and ESC ] 88 ; clear ESC \ when it exits normally.

Security

The terminal will later run what was armed, so the specification is mostly about keeping text that merely passes through the terminal, a file being catted, a log, a page of man, from arming a command. That kind of escape-sequence injection is the threat it sets out to stop; a program that can already run code in the pane is out of scope, since it can do worse than arm a command. A terminal must:

  • not run a resumed command without a check that defeats injection. The recommended check is to confirm, before keeping an arm, that a live process in the pane has an argv[0] whose basename is the basename of cmd; a cat printing forged bytes cannot claim another program’s name. Another check is allowed if it proves the same thing.
  • run only cmd as the program, with args strictly as its arguments, so that the unverified args can never change which program runs.
  • show the resume to the user, and let them undo it.
  • and should let the user turn resuming off, for every program or for particular ones.

Open questions

The specification lists what may still change before version 1 is final:

  • whether to add a patch operation that updates single fields, such as cwd as the program changes directory, instead of arm replacing everything;
  • whether a program should be able to fix cwd so that the terminal may not substitute its own, more recent idea of it;
  • whether query should be answered in the style of DECRQM instead of with an OSC.

The number 88 itself is proposed, not settled: the specification found no terminal using OSC 88, and asks for the number to be coordinated through the community registry at terminfo.dev.

Every example on these pages runs in your browser, in libghostty-vt compiled to WebAssembly.