Program Status Protocol

OSC 7501 lets a program report its current state to a terminal: working, waiting for input, finished, or failed. The terminal decides how to present that state.

This independent reference describes Mitchell Hashimoto's Program Status Protocol, revision 0.4 (2026-10-10). The linked specification is authoritative. Checked 2026-11-13.

# Sequence format

OSC 7501 ; pairs ST
OSC 7501 ; ? ST

pairs := pair (":" pair)*
pair  := key "=" value
key   := [a-z]+
value := [A-Za-z0-9_.,+/=-]*

OSC is ESC ] (1B 5D in hexadecimal). ST is either ESC \ (1B 5C) or BEL (07). The first form is a report, and the second is a feature query. Spaces shown around the syntax are explanatory, not part of the sequence. Whitespace around keys and values is stripped.

Pairs are separated by colons. The value alphabet excludes : and ;, so values do not need escaping. A pair without =, with an empty key, or with a byte outside the value character set is skipped and the rest of the report is processed. Unknown keys must be ignored. For repeated keys, the last value wins. msg and title contain standard base64 of UTF-8 text, with optional padding. Their decoded text must not contain control characters in U+0000–U+001F, U+007F, or U+0080–U+009F, including newline and tab. Both fields are single-line text. A report with invalid base64, a decoded control character, or a limit violation is discarded in full. Nothing from a discarded report is applied.

# Records

A terminal is one window, tab, split, or pane attached to one pseudo-terminal. Each terminal maintains records by id. An omitted id addresses the root record. An ID has this grammar:

id      := segment ("/" segment)*
segment := [A-Za-z0-9_.+-]{1,32}

A report replaces the addressed record entirely. Include app, title, and other fields again when they must remain present. An invalid ID causes the report to be ignored, not applied to the root.

Slash-separated IDs form a hierarchy. For example, build/test is a child of build, which is a child of the root. Parents need not exist. Terminals must use the hierarchy for clearing and app inheritance and may use it for grouping. The hierarchy has no other meaning. Root and child records can coexist.

Records belong to the terminal rather than either screen buffer. Switching between primary and alternate screens leaves them intact. A full reset (RIS) removes all records. A soft reset (DECSTR) does not.

# States

state is required. A missing or unrecognized state causes the report to be ignored.

On interruption or cancellation, a program reports idle. A program exiting after completion should report done or error immediately before exit.

No heartbeat is required. Terminals must not require repeated reports to keep records alive. When the attached process exits or a new shell prompt begins (OSC 133 A), terminals must remove working and blocked records and may remove idle records. done and error survive both events. The terminal chooses when to stop displaying them.

# Keys

# Feature detection

program  → OSC 7501 ; ? ST
terminal → OSC 7501 ; ?:states=idle,working,done,blocked,error:kinds=permission,question,auth ST

Detection is optional. Terminals must ignore unknown OSC sequences, so programs may send reports without a query. A terminal supporting the protocol must reply with ? and may include comma-separated states and kinds lists. clear is excluded from states. If states is omitted, its default is idle,working,done,blocked,error. If kinds is omitted, its default is permission,question,auth. These defaults are fixed and do not change in later revisions. Programs must ignore reply pairs they do not understand and should check the lists before using later additions, falling back to a supported value.

A program that receives no reply within a timeout of its choosing treats the protocol as unsupported. To avoid waiting, it can send primary device attributes (CSI c) immediately after the query. If the device-attributes response arrives first, the protocol is unsupported.

# Limits and security

Terminals may impose lower limits. They must check every pair before changing stored records and discard the entire report if a limit is exceeded.

Check encoded msg size before decoding. When a new record would exceed the terminal's record cap, remove the least recently updated record to make room.

Reports are untrusted. Terminals must reject decoded control characters and must not render msg or title as markup. When displaying text outside the terminal grid, they should neutralize direction overrides and other invisible formatting characters. Displays should identify the originating terminal. Effects outside the terminal, such as sounds or notifications, should be rate-limited.

Feature detection is the only response. It contains no report data. There is no record-reading operation.

OSC 9;4 reports busy, a percentage, or error, without a message or identity. A program may send both OSC 9;4 and OSC 7501. Terminals may map OSC 9;4 to the root record. Because a mapped report replaces the root record, terminals should stop mapping OSC 9;4 after receiving OSC 7501 until the next full reset. OSC 9, 99, and 777 are notifications rather than persistent state. A terminal may produce a notification when a record changes. OSC 133 marks shell boundaries, including the prompt event used for record lifetime.

# Example

Spaces in these examples are explanatory. This report uses ESC \ as the terminator and sets a root record with the message Building:

ESC ] 7501 ; state=working:app=build:msg=QnVpbGRpbmc= ESC \

To clear all records on the terminal, send ESC ] 7501 ; state=clear ESC \.

# Support directory

This directory is selective. Support and releases change, so check the linked project for current availability. Entries checked 2026-11-13.

# Reporters

# Receivers

# Multiplexers

# Developer libraries