NVIDIA / NVIDIA/OpenShell

feat(cli): structured JSON/YAML error and warning output for --output mode

Open
#2,040 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

area:cli feature request state:stale
Dominant language
Rust
Stars
8.7k
Forks
1.3k
Avg merge
2d 11h
Merged PRs (30d)
253

Description

Problem

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 (https://github.com/NVIDIA/OpenShell/pull/1989#discussion_r3469577953). 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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing PR #1989 and tracing the centralized CLI output and error-handling path used by commands accepting --output. Exercise successful and failing commands with --output json and --output yaml, including the gateway-unreachable case. Done means failures emit valid structured output on stdout with a non-zero exit code, while successful commands include warnings only when present.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.