Context
session_start is emitted only after validation, bootstrap, subscription, and session creation. Invalid files/directories, empty input, bootstrap failures, and stalled stdin can therefore leave JSON consumers with no stdout event.
A truthful session_start cannot be emitted before a real session ID exists.
Problem / Goal
Give accepted JSON run executions a structured lifecycle from invocation start through pre-session failure without inventing a session ID or changing the meaning of session_start.
Approach
Add a run-scoped invocation envelope owned by the parsed RunCommand handler:
invocation_start with schemaVersion and a generated invocationID;
invocation_error for known validation, stdin, bootstrap, and session-creation failures;
invocation_complete exactly once for the wrapped run;
invocationID on later session events once a real session exists.
The lifecycle uses the shared serialized stdout writer and does not add entrypoint hooks, argv sniffing, global singleton state, or a second writer.
Acceptance Criteria
Out of Scope
- Argument-parser failures before the run handler is accepted.
- Non-run commands.
- Process-global uncaught exceptions and unhandled rejections.
- Signal and timeout policy.
- Fabricating sessions solely to report validation failures.
Roadmap Alignment
- Pillar: EXEC
- Quarter: Q3 2026
- Priority: P1
- Theme fit: Execution telemetry and pilot-quality executor reliability.
- Decision gate impact: Indirect, by making failed automation diagnosable.
References
Upstream OpenCode References
- anomalyco/opencode#27559 — auto-closed after inactivity, not resolved; a missing session exits 0 with empty JSON stdout and the report explicitly requests a structured JSON failure event.
- anomalyco/opencode#30100 — open; a JSON command spawned from Node.js/Electron on Windows exits successfully with empty stdout.
These reports demonstrate pre-session and command-start failures that are invisible to JSON-only consumers. Neither defines a general invocation lifecycle independent of a real session ID.
Context
session_startis emitted only after validation, bootstrap, subscription, and session creation. Invalid files/directories, empty input, bootstrap failures, and stalled stdin can therefore leave JSON consumers with no stdout event.A truthful
session_startcannot be emitted before a real session ID exists.Problem / Goal
Give accepted JSON
runexecutions a structured lifecycle from invocation start through pre-session failure without inventing a session ID or changing the meaning ofsession_start.Approach
Add a run-scoped invocation envelope owned by the parsed
RunCommandhandler:invocation_startwithschemaVersionand a generatedinvocationID;invocation_errorfor known validation, stdin, bootstrap, and session-creation failures;invocation_completeexactly once for the wrapped run;invocationIDon later session events once a real session exists.The lifecycle uses the shared serialized stdout writer and does not add entrypoint hooks, argv sniffing, global singleton state, or a second writer.
Acceptance Criteria
RunCommandhandler creates the lifecycle whenargs.format === "json".invocation_startis emitted before reading piped stdin and before run validation/bootstrap.invocationID, not a fabricatedsessionID.invocationID.--dir, missing--file, empty input, invalid--fork, bootstrap failure, and session-create failure produce sanitized structured invocation errors.invocation_complete.session_startretains its current meaning and real session ID.invocation_startbefore piped stdin closes.Out of Scope
Roadmap Alignment
References
packages/cli/src/cli/cmd/run.tsUpstream OpenCode References
These reports demonstrate pre-session and command-start failures that are invisible to JSON-only consumers. Neither defines a general invocation lifecycle independent of a real session ID.