Event stream and OSC 7501 / OSC 133 interop
| Field | Value |
|---|---|
| Status | Accepted |
| Accepted | 2026-11-06, approved by the maintainer |
| Authors | commixon (commixon), with Codex |
| Created | 2026-11-06 |
| Linear | COM-202 |
| Supersedes | None |
| Superseded by | None |
History
- 2026-11-11 (venom-org/venom-spec#155, venom-org/venomx#179; compatible;
explicitly accepted by the maintainer
commixonon 2026-11-11): §8 also accepts kitty’s rawcmdline=form instead of ignoring it. libghostty-vt decodes both forms into one string and doesn’t say which one arrived. Both are untrusted display text, sanitized the same way. Shells should still sendcmdline_url. §9’s case covers the raw form. - 2026-11-11 (venom-org/venom-spec#151, venom-org/venomx#178; compatible
addition; explicitly accepted by the maintainer
commixonon 2026-11-11): §8’s C marker may carry kitty’scmdline_urlextension. Its decoded text becomes an optionalcmdlineincommand.starteddata and thecommandentity (§6). It is untrusted display text that the shell reports, so no command identity or trusted process data comes from it. §9 adds verification cases. Older readers ignore the field.
Summary
Define the shared events verb: a scoped NDJSON stream with ordered events,
reconnection cursors, bounded retention and consistent snapshot recovery.
venom-std implements the event log (COM-208); venom-term parses terminal
observations and venomx publishes them. OSC 7501 and OSC 133 observations
remain distinct from trusted agent requests and command execution results.
The maintainer accepted this design and all four Open questions on 2026-11-06.
Motivation
An agent reconnecting after a lost socket needs to recover state without silently missing changes. A pane’s reported permission prompt must be visible without screen scraping, while never authorizing an operation. Every consumer needs the same meaning for event order, filters, resets and shell markers.
This completes the event surface reserved by RFC-0001, using RFC-0002 transport and RFC-0004 declarations. Raw PTY bytes, terminal snapshots and pane-stream offsets belong to RFC-0006 (COM-221). They are not event cursors or the state snapshots defined here.
Design
1. Examples first
After hello, subscribe to a pane’s command lifecycle (UUIDs illustrative):
{"id":7,"verb":"events","params":{"types":["command.*"],"resources":["pane:p3"],"after":"venomx/01234567-89ab-4cde-8fab-0123456789ab:40","follow":true}}
{"id":7,"item":{"seq":41,"ts":"2026-11-06T12:00:00.000Z","source":"venomx/01234567-89ab-4cde-8fab-0123456789ab","type":"command.started","data":{"pane":"p3","command":"c9"}}}
{"id":7,"item":{"seq":42,"ts":"2026-11-06T12:00:01.000Z","source":"venomx/01234567-89ab-4cde-8fab-0123456789ab","type":"command.finished","data":{"pane":"p3","command":"c9","exit_code":0,"reason":"osc133"}}}
{"id":7,"item":{"seq":42,"ts":"2026-11-06T12:00:01.000Z","source":"venomx/01234567-89ab-4cde-8fab-0123456789ab","type":"stream.checkpoint","data":{}}}
The CLI unwraps each item into one compact JSON line, with no final success
line. Arrays are JSON flag values, not repeated flags or comma lists:
venomx events --types '["program.*","command.*"]' --resources '["pane:p3"]' --json
venomx events --after 'venomx/01234567-89ab-4cde-8fab-0123456789ab:42' --follow=false --json
Omitting after requests current state followed by live changes. A human
renderer MAY abbreviate records; it MUST visibly distinguish snapshots,
checkpoints and observed command/status events.
2. Envelope, ordering and identity
Every item MUST have exactly the following required members. Additional members introduced by future compatible revisions MUST be ignored by readers.
| Member | Type | Meaning |
|---|---|---|
seq |
Integer, 0–9007199254740991 | Log position, or snapshot/checkpoint watermark |
ts |
String | UTC RFC 3339 timestamp with milliseconds, assigned by the daemon |
source |
String | <tool>/<epoch>; tool per RFC-0002, epoch a lowercase UUID v4 |
type |
String | Dotted event name, using the RFC-0002 verb-name grammar |
data |
Object | Typed payload from the catalog below |
A daemon MUST generate a new epoch whenever it starts, changes event-log
identity, or would exhaust the safe integer range. No cursor survives such
an epoch change; sequence numbers alone MUST NOT be used across restarts.
A daemon has one ordered log across all its resources, starting at seq=1.
Committed state transitions and their event append MUST be serialized as
one operation, visible to snapshots together. Failure before commit MUST
publish neither. This does not require a persistent database in v1.
Log events have strictly increasing, contiguous sequence numbers before
retention. Wall time can move backwards; consumers MUST order by seq, not
ts. Events from different sources have no total order. A forwarding daemon
MUST NOT pretend to extend another daemon’s sequence. Cross-daemon aggregation
is outside v1; clients can maintain one cursor per source.
A cursor is the literal concatenation <source>:<seq> using unsigned decimal
without leading zeros except 0. The source has no colon. Consumers save
the cursor only after applying the item. Delivery across reconnects is at
least once; consumers MUST tolerate duplicate log events identified by
(source, seq). Snapshots and checkpoints are control items, not log events;
their watermarks can equal earlier items and MUST NOT be deduplicated as
ordinary events. Watermarks MUST never decrease within a subscription.
3. Subscription and filters
The shared bundle declares events with grant=read, streams=true,
result an empty object, the envelope as item, standard exit policy and
these parameters:
| Parameter | RFC-0004 type | Default / semantics |
|---|---|---|
after |
String | "": snapshot; otherwise exclusive cursor |
types |
Array of strings | []: all supported log types |
resources |
Array of strings | []: every resource in the caller’s read scope |
follow |
Boolean | true: continue after initial recovery; false: bounded catch-up |
Each type selector MUST be an exact dotted name or a dotted prefix followed
by .*; pane.* matches pane.created and pane.title_changed, not
panes.created or pane. A syntactically valid unknown selector matches
nothing. Invalid selectors fail with invalid_params.event_filter and
data.param naming types or resources. Duplicate selectors are harmless.
Resource selectors are exact <kind>:<id> strings; kind follows
[a-z][a-z0-9_]*, id is a nonempty resource identifier with no colon or
control characters. There are no resource globs. Resource IDs MUST NOT be
reused within an epoch. Changing filters or caller scope requires a new
snapshot (after=""), not reusing a cursor from the old projection.
Selectors within an array are ORed; the two arrays and authorization are
ANDed. The server MUST apply filtering before delivery, without renumbering
seq. Each catalog entry defines its resource. A resource selector does not
implicitly include descendants. A client wanting all panes in a session
must enumerate them or subscribe to its entire authorized scope.
A nonempty explicit resource list MUST be authorized in full before any
items are sent, otherwise denied.event_scope (exit 4, empty data). Do not
reveal whether an unauthorized resource exists. An authorized absent resource
matches nothing. Empty resources mean the authorized subset, never global
access. Filters cannot broaden a grant. The server MUST recheck scope for
replay, snapshots and live delivery, redact secrets before logging, and end
an affected subscription with denied.event_scope on scope change or grant
expiry/revocation. RFC-0005 (COM-204) defines how identities and scopes are
obtained; OSC fields MUST NOT supply them.
4. Replay, retention and checkpoints
On subscription the server MUST atomically capture high watermark H and
register live delivery after H. With a valid cursor C, replay matching,
authorized events with C < seq <= H, then send stream.checkpoint at H,
then live events above H. Appends during replay MUST be queued or read
from the log without a race; there MUST be no replay/live gap. If the
required history is lost during replay, end with unavailable.event_gap
(exit 6, empty data); the client restarts with a snapshot.
Let L be the oldest retained log position, or H+1 for an empty log.
A same-epoch cursor in [L-1,H] is usable. C>H fails with
invalid_params.event_cursor (exit 2, data.param="after"), as does malformed
cursor syntax. An older cursor, or any well-formed cursor from a different
source/epoch, MUST invoke the snapshot fallback in section 5 rather than
silently starting at L. No-hello clients still use RFC-0002’s implicit
version 1; no additional protocol feature capability is needed for events.
Default retention limits: retain a contiguous suffix, evicting oldest events when
any limit is exceeded: 10 minutes by monotonic age, 10,000 events, or 16 MiB
of compact envelope bytes. These are upper bounds, not a promised duration.
The product MAY configure lower or higher bounds and MUST expose effective
limits and current L, H, source and byte use through doctor. Trimming
MUST NOT change current state. A single event exceeding the log byte budget
forces eviction through its position; a future replay crosses a gap and
falls back to a snapshot. Durability across process restarts is not required.
stream.checkpoint has empty data. It certifies that every matching event
through its seq has been delivered, including when filters matched none.
The server MUST send it at the replay/live boundary and at least every five
seconds while following, using the processed high watermark. Control items
bypass type filters. They contain no resource data, although global sequence
numbers reveal aggregate activity. This metadata is part of the read grant.
With follow=false, complete immediately after the checkpoint with
{"id":7,"ok":{}} (using the actual request id). An idle follow stream stays
open. Cancellation, disconnect and slow-reader limits follow RFC-0002;
Ctrl-C exits 8. No new acknowledgement verb, binary frame or credit protocol
is introduced. A server MUST never silently skip a matching live event under
backpressure: close the connection or return unavailable.event_gap.
5. Snapshot fallback
A state snapshot replaces the consumer’s entire selected projection; it is
not a reconstruction of discarded historical commands or notifications.
The server MUST capture a consistent read view at H and send one or more
state.snapshot items, all at seq=H, before events above H. Their ts
is the capture time. data has:
| Field | Type | Meaning |
|---|---|---|
reason |
String | initial, expired or source_changed |
entities |
Array of objects | Each has required string resource, entity_type, content |
complete |
Boolean | True only on the last chunk |
content contains a compact JSON document for one entity. This is the same
string-container technique as RFC-0001’s config schema: format 1 of RFC-0004
has no arbitrary maps or discriminated unions. Products MUST document and
validate the JSON document’s shape. The snapshot MUST include current
entities associated with selected event types, within selected resources
and scope, even when those entities have no recently retained events.
Historical-only events contribute no entities. Each entity occurs once;
empty projections still send one chunk with entities=[], complete=true.
Clients MUST stage chunks, replace state and save the cursor only when
complete=true; a failed/incomplete snapshot MUST be discarded.
Chunks MUST fit the negotiated RFC-0002 max_frame, including the enclosing
item or CONTROL message. If one entity cannot fit, fail with
unsupported.event_size (exit 10, empty data). Products SHOULD keep entity
projections small; bulk terminal state is RFC-0006. Snapshot read views and
live queues MUST be bounded (recommended combined budget: 8 MiB per request);
exhaustion ends with unavailable.event_gap, never a partial success. Retry
with narrower resources or a larger negotiated frame limit where applicable.
After the final chunk, send a checkpoint at H, then either complete or
follow. A snapshot at H=0 is valid. For example, an expired cursor and an
empty selected projection produce these wire items before live delivery:
{"id":7,"item":{"seq":90,"ts":"2026-11-06T12:05:00.000Z","source":"venomx/01234567-89ab-4cde-8fab-0123456789ab","type":"state.snapshot","data":{"reason":"expired","entities":[],"complete":true}}}
{"id":7,"item":{"seq":90,"ts":"2026-11-06T12:05:00.000Z","source":"venomx/01234567-89ab-4cde-8fab-0123456789ab","type":"stream.checkpoint","data":{}}}
6. v1 event catalog and schema representation
All fields listed below are required unless marked optional. Payload fields not applicable to an event MUST be absent. Log events are emitted after the named transition commits; repeated equivalent changes produce no event. Each product MUST declare which applicable types it implements. The two control types are mandatory even for a daemon with no product events.
| Type | Resource | data fields |
Snapshot entity |
|---|---|---|---|
stream.checkpoint |
Subscription | Empty | None; section 4 |
state.snapshot |
Subscription | reason, entities, complete |
Section 5 |
config.changed |
config:root |
restart_required boolean |
config: redacted persisted ZON in string content |
config.reloaded |
config:root |
restart_required boolean |
config: same entity, also active redacted ZON in string active_content |
pane.created |
pane:<pane> |
pane string, session string |
pane: pane, session, title, exited boolean, optional exit_code |
pane.title_changed |
pane:<pane> |
pane, title strings |
pane |
pane.exited |
pane:<pane> |
pane, optional integer exit_code |
pane (retained until removal) |
pane.removed |
pane:<pane> |
pane |
pane disappears |
program.status_changed |
pane:<pane> |
pane, reason, records array |
program_status: pane, records |
command.started |
pane:<pane> |
pane, command strings, optional cmdline string |
command: active pane, command, optional cmdline |
command.finished |
pane:<pane> |
pane, command, reason, optional exit_code |
command disappears; no historical snapshot |
Snapshot resource is the catalog resource. entity_type is the name above;
content is its JSON object. Config snapshots always include both persisted
and active content plus restart_required; selecting either config event
selects that entity. No config secrets or mutation values appear in events.
Exit codes, when known, are integers 0–255; absence means unknown and MUST
NOT be treated as zero. Pane exit status comes from the child wait status,
not OSC. Products MUST document signal-to-status conversion.
The shared schema MUST describe the envelope as a closed object with required
seq, ts, source, type, data. Its data descriptor is a closed object
containing the union of the catalog’s field names, each optional with its
single fixed type. For example pane is always a string and records always
an array of the record object below. This is expressible with RFC-0004 format
1, without adding a union type. type is a string without choices, allowing
future event names; the publisher MUST additionally validate the per-type
required/forbidden fields from its catalog. The generated documentation MUST
include that catalog, not imply every combination is meaningful.
If a log item cannot fit the negotiated frame limit, terminate that
subscription with unsupported.event_size; never truncate or skip it.
Readers validate transport framing but MUST NOT reject future extra fields
merely because their compiled catalog is older. The closed schema describes
what the current publisher emits, not a ban on compatible future additions.
Product additions MUST extend that product’s item descriptor and catalog at build time with nonconflicting field types and document snapshot behavior. Consumers MUST ignore unknown event types and fields while advancing their cursor. Renaming/removing a field or changing its meaning requires a protocol major revision; compatible additions do not. New product event semantics must be specified before implementation; this catalog does not invent turn, inbox, grant or pane-stream events for future RFCs.
7. OSC 7501 ingestion and event mapping
The interoperability baseline is the Program Status Protocol revision 0.2 (2026-10-06), published in Rex’s “Program Status Protocol” documentation; tuios’s “Program Status” documentation identifies the same revision. The parser and record store MUST implement that revision, including validation, limits, inheritance, replacement, subtree clearing and lifetime rules. The upstream document is incorporated by reference; later revisions require explicit review here. Do not substitute window-title heuristics.
Wire example (POSIX shell, prints bytes to stdout for a PTY fixture):
printf '\033]7501;state=blocked:kind=permission:app=build:msg=QXBwcm92ZT8=\033\\'
printf '\033]7501;state=working:app=build:progress=40\007'
printf '\033]7501;state=clear\033\\'
Venom’s records is the full current normalized set, sorted by id; the root
is id="". A record has required string id, string state (idle, working,
done, blocked, error), and optional string kind, app, title, msg, and
optional integer progress (0–100). Store the explicitly reported app;
consumers compute inherited display app from ancestors. Decoded text is plain
text. Absence MUST remain absence, not an empty string or zero. A clear report
is a removal, never a record with state clear.
Publish exactly one program.status_changed per effective record-set
transition, including clearing, eviction and lifecycle cleanup. reason is
report, clear, evicted, prompt, process_exit, pane_removed or reset; a report
that also evicts uses evicted. The event contains the resulting whole set,
so consumers replace it atomically, including records=[]. Identical reports
may refresh store recency but do not emit an unchanged projection.
The first fixture, applied to an empty pane, produces this projection (sequence and command ids are assigned by the daemon):
{"seq":43,"ts":"2026-11-06T12:00:02.000Z","source":"venomx/01234567-89ab-4cde-8fab-0123456789ab","type":"program.status_changed","data":{"pane":"p3","reason":"report","records":[{"id":"","state":"blocked","kind":"permission","app":"build","msg":"Approve?"}]}}
For presentation, the summary priority is blocked > error > done >
working > idle, then lexical id. This
follows tuios’s urgency order; the event preserves all records so consumers
can choose another presentation. Venom retains idle records on prompt/process
exit and done/error until explicit clear, reset or pane removal; no visibility
or keyboard acknowledgement policy is imposed. Reset is RIS, not DECSTR.
Before pane.removed, clear remaining records with reason pane_removed.
Pane removal MUST follow supervised exit and the events in section 8.
OSC 133 A triggers upstream prompt cleanup. Observable exit of the process
attached to the PTY triggers exit cleanup; do not guess exits from silence.
Queries (7501;?) MUST produce only the upstream feature-detection reply
on the PTY input path, using the query’s terminator; they emit no event.
The single authoritative parser runs before raw-byte fan-out, so multiple
attached clients MUST NOT each inject replies or duplicate events. Parsing
MUST tolerate every byte split, bounded incomplete sequences and recovery
after malformed input. Invalid reports produce no state change or event.
Diagnostic counters MAY increase, without logging raw messages or secrets.
A blocked permission/question/auth record is an observation. It MUST NOT
create an approval token, grant rights, answer a prompt, invoke a verb or
prove the identity named by app. Any later inbox integration needs a trusted
adapter and RFC-0005 authorization; auth text MUST NOT elicit stored secrets.
Other clients’ PTY bytes and terminal rendering remain governed by RFC-0006.
8. OSC 133 command lifecycle
Baseline marker meanings are those documented by Microsoft VS Code’s “Terminal Shell Integration” and kitty’s “Shell integration”: A begins a prompt, B ends the prompt, C begins execution/output, D ends execution with an optional decimal exit code. Accept BEL and ESC-backslash terminators. The mapping to Venom events is defined here, independently of shell tooling.
Maintain at most one observed active command per pane:
| Input | Venom transition |
|---|---|
| A | Finish an active command with reason prompt, unknown status; perform OSC 7501 prompt cleanup |
| B | Mark input region only; no command event |
C, optional cmdline_url= |
If none active, allocate epoch-unique command id and emit command.started, with cmdline when given (below); duplicate C while active is ignored |
D, optional ;0–;255 |
If active, emit command.finished with reason osc133 and optional exit_code; clear active command |
| Pane exit | Finish active command with reason pane_exit, unknown command status, before pane.exited |
| RIS | Finish active command with reason reset, unknown status, then reset observation state |
D without an active command and repeated A/B/D produce no command event.
Malformed or out-of-range D status discards the marker and leaves state
unchanged. D with no status finishes with unknown status. A/B/C accept
semicolon extension fields, ignored in v1 except C’s cmdline_url; D accepts one optional status and
subsequent extension fields. Unknown marker letters are ignored. DECSTR and
alternate-screen switches MUST NOT invent command completions.
A’s synthetic command finish precedes its program-status cleanup event.
On pane exit, command finish precedes program cleanup, which precedes
pane.exited. Command ids are generated by the daemon, never taken from PTY
text. OSC 133 supplies no cwd, trusted process identity or authoritative
wait result, and command text only as the untrusted cmdline below. In particular, an observed D with status 0
MUST NOT complete a trusted run --wait; that operation uses its own child
supervision. OSC 7501 reports do not synthesize command events, and command
markers do not synthesize program done/error reports.
cmdline. C MAY carry kitty’s cmdline_url=<text> extension field: the
command line the shell is about to run, percent-encoded. It MAY instead
carry kitty’s raw cmdline=<text> form, which kitty’s shell integration
quotes with backslashes. The daemon decodes either one (%XX escapes for
cmdline_url, kitty’s unquoting for cmdline), then replaces each C0 or C1 control and DEL with U+FFFD, and cuts
the result to at most 1024 bytes on a UTF-8 code-point boundary. If the
decoded text is not valid UTF-8 or is empty, there is no cmdline. A
malformed escape makes only cmdline absent; the C marker still starts the
command. Shells SHOULD send cmdline_url, which carries any byte safely.
cmdline is what the shell
says, not what runs: an alias, a function or a lie are all possible. So it
is display text only. It is never a command id, a trusted process identity
or input to a grant, and clients render it as untrusted text. It is set
once, at C, and command.finished doesn’t repeat it.
printf '\033]133;C;cmdline_url=ping%%20google.com\033\\'
That starts a command whose cmdline is ping google.com.
A complete successful command fixture is:
printf '\033]133;A\033\\prompt> \033]133;B\033\\true\r\n\033]133;C\033\\\033]133;D;0\033\\'
It emits one command.started and one command.finished with the same
allocated command id, exit code 0 and reason osc133. Partial command
history from before parser startup is not invented.
9. Verification cases for downstream conformance
COM-208 and the OSC-consuming product MUST exercise these cases; this RFC supplies fixtures and expected semantics, not a claimed implementation test:
- Append while replay/snapshot capture is occurring; verify exactly the captured projection then every later matching event, in sequence order.
- Replay at
L-1,L,H, beforeL-1, ahead ofH, and from another epoch. Verify snapshot reasons, empty logs and multi-chunk commit behavior. - Filter out every event while advancing H; save a checkpoint and reconnect without replaying already processed unrelated history. Change filters only after resetting from a snapshot.
- Revoke read scope during replay and snapshot; disclose no subsequent items. Verify denied explicit selectors and redacted snapshot content.
- Exhaust retention during replay and overflow a live queue; verify explicit failure/disconnect and snapshot recovery, never a silent gap.
- Feed each OSC fixture one byte at a time and at every split boundary; BEL and ESC-backslash variants MUST agree. Verify no raw controls enter NDJSON.
- Try unknown states/keys, repeated keys, invalid base64, decoded controls, oversize sequences, bad ids, nested clear, full reset, soft reset and record-cap eviction against the pinned upstream OSC 7501 rules.
- Query OSC 7501 with two clients attached; observe one reply and zero events.
- Exercise all three blocked kinds, missing kind, duplicate reports and a working child under an idle root. Verify prompt/exit lifetimes and that no grant or approval is created.
- Exercise duplicate C, orphan D, D without status, malformed D, A during an active command and pane exit during a command. Check the ordering above.
- Send C with
cmdline_urlthat is plain, percent-encoded with multi-byte UTF-8, holds encoded controls, has a malformed escape, decodes to invalid UTF-8, or is over 1024 bytes. Also send kitty’s rawcmdline=form, plain and with backslash-quoted spaces. Check thecmdlinethat results (or its absence) and that the command starts every time. - Cancel the CLI stream and overrun MCP’s bounded buffer; verify RFC-0002
exit 8 and RFC-0004
unsupported.stream_limit, respectively.
Agent-contract impact
- Verbs/schema: fixes
eventssignature and fixed-type payload field superset; shared handlers validate the per-event catalog. No extra action or alternate privileged TUI route. - JSON/exits: ordinary RFC-0002 stream mapping and error classes; successful bounded catch-up exits 0 without an extra stdout record.
- Events: v1 catalog above; terminal observations are explicitly untrusted.
- Skill/doctor/config: generated skill MUST explain cursor resets, filters and checkpoints. Doctor reports retention limits and watermarks. Retention overrides, if offered, use existing ZON config verbs; this RFC does not add product-specific config keys. Other shared signatures are unchanged.
- Grants:
readplus resource scope throughout the subscription. No write, approval, auth or secret access inferred from terminal bytes. - Headless/OSC: subscription needs no TTY. PTY consumers implement the pinned OSC profile; non-PTY daemons need only the event surface.
- MCP: use RFC-0004 bounded buffering unchanged; recommend
follow=falsefor catch-up. Large snapshots may exceed its 1024-item/1-MiB limit and MUST fail rather than truncate. Continuous subscriptions use the CLI/wire.
Alternatives
- Only live delivery / do nothing: reconnect silently loses state changes.
- Sequence reset without an epoch: a cursor can accidentally reference a different daemon incarnation. Epoch-qualified source avoids that ambiguity.
- Replay forever: unnecessary storage and secret-retention cost; current state plus bounded history supports read-model recovery.
- Error only for old cursors: every client would reinvent snapshot/race handling. A typed snapshot makes recovery part of the subscription.
- Arbitrary JSON payload type in RFC-0004: would change the accepted format. A fixed field superset and JSON-string snapshot documents fit format 1; richer schema types can be proposed separately if this becomes cumbersome.
- Screen scraping or OSC as approval authority: unstable and forgeable. Observe protocol records; authorize trusted verbs separately.
Open questions
All four questions were resolved on 2026-11-06: the maintainer accepted the proposed answers and explicitly accepted this RFC.
- Recovery policy — resolved: automatic chunked snapshots and synthetic checkpoints, with a fresh epoch on every daemon start. Scope or filter changes require a fresh snapshot. Cursor durability across restart is outside v1.
- Retention and resource bounds — resolved: defaults are 10 minutes / 10,000 events / 16 MiB log, five-second checkpoints and an 8-MiB snapshot/queue budget, as specified in sections 4 and 5.
- Schema representation — resolved: a fixed-type field superset for
dataand string-contained JSON snapshot documents fit RFC-0004 format 1. This RFC does not extend that format’s type system. - OSC lifecycle/presentation — resolved: pin upstream revision 0.2, retain idle records, clear done/error only through the explicit lifecycle rules in section 7, and use the specified urgency summary and incomplete OSC 133 recovery policy. Foreground-process-group attribution beyond the attached PTY process remains outside v1.