A terminal connects a user with programs. Control of the program side of
terminals is typically passed around to various different components while the
user is active: a shell might pass control to a process it invokes. If that
process is run0
then primary control is passed to the privileged session of
the target user. If systemd-nspawn
is invoked to start a container, primary
control is passed to that container, and so on.
A terminal emulator might be interested to know which component is currently in primary control of the program side of a terminal. OSC 3008 is a mechanism to inform it about such contexts. Each component taking over control can inform the terminal emulators that a new context begins now, and then use the terminal or pass control down to further apps, which can introduce contexts. Each context may carry various descriptive metadata fields.
This OSC sequence has been invented by the systemd project and is generated by systemd. Currently, no terminal application is known that consumes these sequences.
Terminal emulators can use hierarchical context information:
To introduce markers/bookmarks in the output that the user can jump between.
To visually identify output from different contexts. For example the background of the associated output can be tinted in a reddish tone when privileges are acquired, and similar.
Meta information on specific output can be shown in a tooltip or similar
Programs (and all subcontexts) can be killed via a right-click menu on the output they generate.
Similar, a right-click menu might offer an item to offer opening a new interactive shell in the same working directory that was current on the selected context.
Failed commands or aborted sessions can be marked requesting user attention.
There are various types of contexts defined by this specification:
boot
→ a booted system initiates this context early at boot. (systemd’s
PID 1 generates this on /dev/console
.)
container
→ a container manager initialized an interactive connection to a
container. (systemd-nspawn
generates this when interactively invoking a
container. machinectl login
, machinectl shell
do this too.)
vm
→ a VM manager initialized a terminal connection to a
VM. (systemd-vmspawn
generates this when interactively invoking a VM, as
one example.)
elevate
→ when the user interactively acquired higher privileges. (run0
initiates a context of this type whenever the user invokes it to acquire
root privileges.)
chpriv
→ similar, but when the user acquired different privileges, not
necessarily higher ones. (run0
initiates a context of this type whenever
the user invokes it to acquire non-root privileges of another user.)
subcontext
→ similar, but the source and target privileges where
identical. (run0
initiates a context of this type whenever the user
invokes it to acquire privileges of the user itself.)
remote
→ a user invoked a tool such as ssh
to connect to a remote
system.
shell
→ an interactive terminal shell initiates this context
command
→ a shell interactively invokes a new program.
app
→ an interactive program may initiate this context.
service
→ the service manager invokes an interactive service on the terminal
session
→ a login session of the user is initialized.
Contexts in the sense of OSC 3008 are hierarchical, and describe a tree structure: whenever a new context is opened it becomes the new active context, and the previously active context becomes its parent (if there is one). Only one context is currently active, but previously opened contexts remain valid in the background. Any other data written or read should be considered associated with the currently active context.
Each context carries an identifier, chosen by the component opening the context. The identifier can chosen freely, but must not be longer than 64 characters. The characters may be in the 32…126 byte range. Identifiers should be universally unique, for example randomly generated. A freshly generated UUID would work well for this, but this could also be something like the Linux boot ID combined with the 64bit inode number of Linux pidfds, or something hashed from it.
Fundamentally, there are two OSC 3008 commands defined:
OSC “3008;start=
” … (the start sequence) → this initiates, updates or
indicates a return to a context. It carries a context identifier, and
typically some metadata. This may be sent to first initiate a context. If
sent again for the same context ID that was initiated already this indicates
an update of the existing context. In this case, any previously set
metadata fields for the context are flushed out, reset to their defaults,
and then reinitialized from the newly supplied data. Also, in this case any
subcontexts of the contexts are implicitly terminated.
OSC “3008;end=
” … (the end sequence) → this terminates a context. It
carries a context identifier to close, initiated before with OSC
“3008;start=
”. It may also carry additional metadata.
This builds on ECMA-48, and reuses the OSC and ST concepts introduced there.
For sequences following this specification it is recommended to encode OSC as 0x1B 0x5D, and ST as 0x1B 0x5C.
ECMA-48 only allows characters from the range 0x20…0x7e (i.e. 32…126) inside
OSC sequences. However, most terminal emulators nowadays allow the ASCII byte
range > 0x7f in the OSC sequences they process, and so does this
specification. Control characters (< 0x20 and 0x7f) are not allowed. The
semicolon character (“;
”) – which is used as field separator by this
specification – shall be replaced by “\x3b
” and the backslash character
(“\
”) shall be replaced by “\x5c
”. All textual fields must be encoded in
UTF-8, and then escaped with these two replacements.
The start sequence begins with OSC, followed by the string 3008;start=
,
followed by the context ID. This is then followed by any number of metadata
fields, including none. Metadata fields begin with a semicolon (;
) followed
by in a string identifying the type of field, followed by an equal sign (=
),
and the field value. The sequence ends in ST.
The end sequence begins with OSC, followed by the string 3008;end=
, followed
by the context ID, and a series of metadata fields in the same syntax as for
the start sequence. The sequence ends in ST.
The following fields are currently defined for the start sequence:
Field | Context Types | Description |
---|---|---|
type= |
all | Declares the context type, one of the types described above |
user= |
all | UNIX user name the process issuing the sequence runs as |
hostname= |
all | UNIX host name of the system the process issuing the sequence runs on |
machineid= |
all | The machine ID (i.e. /etc/machine-id ) of the system the process issuing the sequence runs on |
bootid= |
all | The boot ID (i.e. /proc/sys/kernel/random/boot_id ) of the system the process issuing the sequence runs on |
pid= |
all | The numeric PID of the process issuing the sequence, in decimal notation |
pidfdid= |
all | The 64bit inode number of the pidfd of the process issuing the sequence, in decimal notation |
comm= |
all | The process name (i.e. /proc/$PID/comm , PR_GET_NAME ) of the process issuing the sequence |
cwd= |
shell , command |
The current working directory |
cmdline= |
command |
The full command line of the invoked command |
vm= |
vm |
The name of the VM being invoked |
container= |
container |
The name of the container being invoked |
targetuser= |
elevate , chpriv , vm , container , remote , session |
Target UNIX user name |
targethost= |
remote |
Target UNIX, DNS host name, or IP address |
sessionid= |
session |
New allocated session ID |
The following fields are currently defined for the end sequence:
Field | Context Types | Description |
---|---|---|
exit= |
command |
One of success , failure , crash , interrupt , indicating how the program terminated |
status= |
command |
The command’s numeric exit status, i.e. the 0…255 value a program returns |
signal= |
command |
The termination signal of the command, if it died abnormally. A symbolic signal name. (SIGKILL , …) |
All fields are optional, including the context type. However, it is generally recommended to always include the first 7 fields listed above, to make it easy to pinpoint the origin of a context in a race-free fashion, without any ambiguities.
The order of the metadata fields is undefined, they may appear in any order
(including that type=
is specified at the very end or in the middle!). Note
that start=
and end=
are not considered metadata fields but part of the
start sequence, and hence must always appear right after OSC.
All context information provided like this should be considered auxiliary and – to some degree – redundant information. Hence, it would be wise for a terminal to enforce limits on various resources, dropping additional data once these limits are hit. Most importantly, a maximum stacking depth should probably enforced: any attempts to initiate further contexts should be ignored once the stack limit is hit (i.e. the earlier contexts should be kept, the later contexts be discarded, not the opposite). Overly long fields should be discarded (or potentially truncated, depending on the field type). This specification does not recommend any specific stack or string limits for now.
The usual terminal reset sequences should not affect the stack of contexts
(this is a safety feature: a program down the stack should not be able to
affect the stack further up, possibly hiding relevant information). A temporary
TTY hangup (vhangup()
) should result in a full reset of the stack.
All provided data should be processed in a lenient, graceful fashion: if a sequence contains invalid fields, those fields should be ignored, but the rest of the fields should still be used. In particular, unknown fields should be ignored.
The fields provided in these sequences should not contain sensitive information. Context IDs should not be considered confidential, but it is strongly recommended to generate them in a fashion that guarantees their sufficient uniqueness and avoids accidental or intended clashes with other contents.
A new container foobar
has been invoked by user lennart
on host zeta
:
OSC "3008;start=bed86fab93af4328bbed0a1224af6d40;type=container;user=lennart;hostname=zeta;machineid=3deb5353d3ba43d08201c136a47ead7b;bootid=d4a3d0fdf2e24fdea6d971ce73f4fbf2;pid=1062862;pidfdid=1063162;comm=systemd-nspawn;container=foobar" ST
This context ends: OSC "3008;end=bed86fab93af4328bbed0a1224af6d40" ST
OSC = %x1B %x5D
ST = %x1B %x5C
DECIMAL = "0"-"9"
HEX = "0"-"9" / "A"-"F" / "a-f"
ID128 = 32*36(HEX / "-")
UINT64 = 1*20DECIMAL
ESCSEMICOLON = "\x3b"
ESCBACKSLASH = "\x5c"
SAFE = %x20-3a / %x3c-5b / %x5d-7e / ESCSEMICOLON / ESCBACKSLASH
CTXID = 1*64SAFE
TYPEENUM = "service" / "session" / "shell" / "command" / "vm" / "container" / "elevate" / "chpriv" / "subcontext" / "remote" / "boot" / "app"
TYPE = "type=" TYPEENUM
USER = "user=" 1*255SAFE
HOSTNAME = "hostname=" 1*255SAFE
MACHINEID = "machineid=" 1D128
BOOTID = "bootid=" ID128
PID = "pid=" UINT64
PIDFDID = "pidfdid=" UINT64
COMM = "comm=" 1*255SAFE
CWD = "cwd=" 1*255SAFE
CMDLINE = "cmdline=" *255SAFE
VM = "vm=" 1*255SAFE
CONTAINER = "container=" 1*255SAFE
TARGETUSER = "targetuser=" 1*255SAFE
TARGETHOST = "targethost=" 1*255SAFE
SESSIONID = "sessionid=" 1*255SAFE
STARTFIELD = TYPE / USER / HOSTNAME / MACHINEID / BOOTID / PID / PIDFDID / COMM / CWD / CMDLINE / VM / CONTAINER / TARGETUSER / TARGETHOST / SESSIONID
STARTSEQ = OSC "3008;start=" CTXID *(";" STARTFIELD) ST
EXITENUM = "success" / "failure" / "crash" / "interrupt"
SIGNALENUM = "SIGBUS" / "SIGTRAP" / "SIGABRT" / "SIGSEGV" / …
EXIT = "exit=" EXITENUM
STATUS = "status=" UINT64
SIGNAL = "signal=" SIGNALENUM
ENDFIELD = EXIT / STATUS / SIGNAL
ENDSEQ = OSC "3008;end=" CTXID *(";" ENDFIELD) ST
Here’s a list of OSC prefixes used by the various sequences currently in public use in various terminal emulators. It’s not going to be complete, but I tried to do some reasonably thorough research to avoid conflicts with the new OSC sequence defined above.
OSC Prefix | Purpose |
---|---|
OSC "0;…" |
Icon name + window title |
OSC "1;…" |
Icon name |
OSC "2;…" |
Window title |
OSC "3;…" |
X11 property |
OSC "4;…" |
Palette |
OSC "5;…" |
Special palette |
OSC "6;…" |
Disable special color |
OSC "7;…" |
Report cwd |
OSC "8;…" |
Hyperlink |
OSC "9;…" |
Progress bar (conemu) [conflict: also growl notifications] |
OSC "10;…" |
Change colors |
OSC "11;…" |
” |
OSC "12;…" |
” |
OSC "13;…" |
” |
OSC "14;…" |
” |
OSC "15;…" |
” |
OSC "16;…" |
” |
OSC "17;…" |
” |
OSC "18;…" |
” |
OSC "19;…" |
” |
OSC "21;…" |
Query colors (kitty) |
OSC "22;…" |
Cursor shape |
OSC "46;…" |
Log file |
OSC "50;…" |
Set font |
OSC "51;…" |
Emacs shell |
OSC "52;…" |
Manipulate selection data (aka clipboard) |
OSC "60;…" |
Query allowed |
OSC "61;…" |
Query disallowed |
OSC "99;…" |
Notifications (kitty) |
OSC "104;…" |
Reset color |
OSC "105;…" |
Enable/disable special color |
OSC "110;…" |
Reset colors |
OSC "111;…" |
” |
OSC "112;…" |
” |
OSC "113;…" |
” |
OSC "114;…" |
” |
OSC "115;…" |
” |
OSC "116;…" |
” |
OSC "117;…" |
” |
OSC "118;…" |
” |
OSC "119;…" |
” |
OSC "133;…" |
Prompt/command begin/command end (finalterm/iterm2) |
OSC "440;…" |
Audio (mintty) |
OSC "633;…" |
vscode action (Windows Terminal) |
OSC "666;…" |
“termprop” (vte) |
OSC "701;…" |
Locale (mintty) |
OSC "777;…" |
Notification (rxvt) |
OSC "3008;…" |
This specification |
OSC "7704;…" |
ANSI colors (mintty) |
OSC "7750;…" |
Emoji style (mintty) |
OSC "7770;…" |
Font size (mintty) |
OSC "7771;…" |
Glyph coverage (mintty) |
OSC "7721:…" |
Copy window title (mintty) |
OSC "7777;…" |
Window size (mintty) |
OSC "9001;…" |
Action (Windows Terminal) |
OSC "1337;…" |
iterm2 multiplex seeuqnece |
OSC "5522;…" |
Clipboard (kitty) |
OSC "30001;…" |
Push color onto stack (kitty) |
OSC "30101;…" |
Pop color from stack (kitty) |
OSC "77119;…" |
Wide chars (mintty) |