Context
Headless JSON output is written through process.stdout.write(), while the CLI entry points finish with forced process.exit(). The writer does not observe backpressure or expose a terminal flush operation.
A local Bun 1.3.10 subprocess test preserved immediate piped writes through 64 KiB but truncated a 1 MiB write at 64 KiB. This confirms a durability defect for sufficiently buffered output, but does not establish that it causes the majority of empty production streams.
Problem / Goal
Ensure every NDJSON record accepted by the CLI's output writer is flushed before normal or controlled-error shutdown, without removing the hard-exit behavior used to terminate hanging subprocesses.
Proposed Approach
Introduce one serialized NDJSON writer that:
- owns JSON stdout writes;
- observes
process.stdout.write() backpressure;
- exposes an awaited
flush() operation;
- handles a closed downstream pipe without recursively entering the uncaught-exception handler.
Run instance/subprocess disposal first, flush stdout second, and force-exit last.
Reproduction
- Spawn a Bun child process that writes NDJSON exceeding the pipe buffer.
- Call
process.exit() immediately after writing.
- Observe that only the initial buffered portion reaches the reader.
- Expected: all accepted records, including the terminal record, reach the reader.
Environment
- Default branch:
main
- Verified against:
f78832517f64d69680e48bcb0199bf07e49f3d36
- Bun:
1.3.10
Acceptance Criteria
Out of Scope
- Claiming this defect explains the observed majority-null telemetry rate.
- SIGTERM/SIGINT cancellation policy.
- Pre-session lifecycle events.
- Token aggregation or usage semantics.
Roadmap Alignment
- Pillar: EXEC
- Quarter: Q3 2026
- Priority: P1
- Theme fit: Executor reliability and execution telemetry.
- Decision gate impact: Indirect support for pilot-quality automation.
References
Upstream OpenCode References
- anomalyco/opencode#30831 — open; truncated CLI completion output attributed to forced exit before stdout drains.
- anomalyco/opencode#29866 — closed as completed; near-exact report of
run --format json losing final events at process exit.
- anomalyco/opencode#31435 — open; same missing/empty JSON symptom caused by an independent event-ordering race where
session.status=idle arrives before pending part events.
- anomalyco/opencode#31482 — open; resumed sessions persist the assistant result but emit empty stdout.
- anomalyco/opencode#29340 — closed without merge; proposed a shared stdio flush helper while preserving forced exit.
The event-ordering reports are not evidence for the stdout-flush mechanism. Tests for this issue should isolate writer durability from event delivery and should not assume flushing alone resolves all empty streams.
Context
Headless JSON output is written through
process.stdout.write(), while the CLI entry points finish with forcedprocess.exit(). The writer does not observe backpressure or expose a terminal flush operation.A local Bun 1.3.10 subprocess test preserved immediate piped writes through 64 KiB but truncated a 1 MiB write at 64 KiB. This confirms a durability defect for sufficiently buffered output, but does not establish that it causes the majority of empty production streams.
Problem / Goal
Ensure every NDJSON record accepted by the CLI's output writer is flushed before normal or controlled-error shutdown, without removing the hard-exit behavior used to terminate hanging subprocesses.
Proposed Approach
Introduce one serialized NDJSON writer that:
process.stdout.write()backpressure;flush()operation;Run instance/subprocess disposal first, flush stdout second, and force-exit last.
Reproduction
process.exit()immediately after writing.Environment
mainf78832517f64d69680e48bcb0199bf07e49f3d361.3.10Acceptance Criteria
packages/cli, not the repository root.Out of Scope
Roadmap Alignment
References
packages/cli/src/cli/cmd/run.tspackages/cli/src/headless.tspackages/cli/src/index.tsUpstream OpenCode References
run --format jsonlosing final events at process exit.session.status=idlearrives before pending part events.The event-ordering reports are not evidence for the stdout-flush mechanism. Tests for this issue should isolate writer durability from event delivery and should not assume flushing alone resolves all empty streams.