You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(cli): structured JSON/YAML error and warning output for --output mode #2040
When --output json or --output yaml is active, successful command output is properly structured, but errors still flow through miette's human-readable diagnostic formatter. An automation consumer parsing stdout gets an unexpected non-JSON/YAML blob when a command fails.
--output json/yaml was introduced in PR #1989 (still pending) to enable automation and MCP tool wrappers to consume structured data instead of parsing ANSI-colored human output. This issue addresses the error path that PR #1989 intentionally deferred to be solved at the framework level.
Current behavior (--output json, gateway unreachable):
Error: openshell::gateway_connection
× failed to connect to gateway 'openshell' at localhost:5173.
Start the gateway service with the installed package manager,
or register a different endpoint with `openshell gateway add <endpoint>`.
╰─▶ error sending request for url (https://localhost:5173/)
Exit code: 1, stdout: miette-formatted text (not JSON).
Expected behavior:
{"error": "failed to connect to gateway 'openshell' at localhost:5173", "code": "gateway_unreachable"}
Exit code: 1, stdout: valid JSON.
Motivation
During review of PR #1989, @johntmyers identified that the error output path was not fully addressed (#1989 (comment)). The current PR handles per-command error labels correctly for human output, but structured error output affects all commands and should be solved once at the framework level rather than per-command.
Primary consumers: MCP tool wrappers, CI scripts, and agent harnesses that parse CLI output programmatically. These tools currently have to detect and handle miette-formatted error text as a special case.
Design Sketch
Error Output (exit code ≠ 0)
When --output json or --output yaml is active and a command fails, emit a structured error on stdout with a non-zero exit code. The exit code is the authoritative error signal; the JSON payload provides the message and optional machine-parseable category.
Why stdout, not stderr: The purpose of --output json is "give me one parseable stream." Splitting success to stdout and errors to stderr forces automation to merge two streams. stderr in structured mode stays reserved for debug/trace logging only.
Warnings (exit code = 0)
When a command succeeds but has warnings, include them as a warnings array alongside the data in the JSON output. The array is omitted when empty. Consumers who don't care about warnings ignore the field.
Scope
All commands that accept --output (current and future)
Centralized error handling (one code path, not per-command)
Non-goal: changing the default human-readable error format
The single parseable stdout stream is useful for MCP and CI consumers. It would help to define a stable top-level envelope shared by success and failure, for example data, error, and warnings, so adding warnings does not change the success payload’s type. A regression test could also assert that debug logging remains exclusively on stderr while stdout parses as exactly one JSON or YAML document.
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.
This issue has had no activity for 14 days and is now marked stale. It may be closed in 14 days if there is no further activity. Comment or remove the state:stale label to keep it open.
Activity
hiSandog commentedon Jul 11, 2026
The single parseable stdout stream is useful for MCP and CI consumers. It would help to define a stable top-level envelope shared by success and failure, for example
data,error, andwarnings, so adding warnings does not change the success payload’s type. A regression test could also assert that debug logging remains exclusively on stderr while stdout parses as exactly one JSON or YAML document.github-actions commentedon Aug 30, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 7 days if there is no further activity. Comment or remove the state:stale label to keep it open.
github-actions commentedon Oct 15, 2026
This issue has had no activity for 14 days and is now marked stale. It may be closed in 14 days if there is no further activity. Comment or remove the state:stale label to keep it open.
rhuss commentedon Oct 15, 2026
I think this issue is still worth to implement.