Skip to content

feat: add structured output to report and status built-ins - #306

Open
Agnik47 wants to merge 1 commit into
agentrhq:mainfrom
Agnik47:feat/175-structured-output-builtins
Open

feat: add structured output to report and status built-ins#306
Agnik47 wants to merge 1 commit into
agentrhq:mainfrom
Agnik47:feat/175-structured-output-builtins

Conversation

@Agnik47

@Agnik47 Agnik47 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Part of #175 (tracking: #171). This is the first of the two PRs I proposed in #175 (comment) — the non-browser built-ins. Browser reads follow separately.

What

validate, verify, doctor, bare skills, daemon status, and profile list all returned stable data internally but rejected -f/--format and printed hand-written text only. Each now routes through the shared resolveOutputFormat + render path from #190.

webcmd validate -f json
webcmd verify -f yaml
webcmd doctor -f json
webcmd daemon status -f json
webcmd profile list -f json
webcmd skills -f json

adapter status is on the issue's list but already gained -f in #190, so it needed no change here.

Behavior

Each command keeps its human-readable report as the table rendering, which stays the default. Any other format returns the underlying result object.

I followed the convention-audit precedent from #190 and branch on the raw format rather than the TTY-resolved one. I first tried resolving through the implicit non-TTY rule, but that moves profile list's prose onto the structured path whenever stdout is a pipe, which breaks the guidance contract two existing tests encode (reports stale daemon instead of no profiles…, uses runtime profile wording…). Branching on the raw format means no existing implicit behavior changes and nothing here is breaking — the issue asks for these commands to stop rejecting -f, not to change what an unflagged invocation prints.

Two commands needed a real data model rather than a straight serialization:

  • daemon status gains a projection mirroring the text rendering: running, stale, pid, version, cliVersion, uptimeMs, runtimeConnected, runtimeName, runtimeVersion, profileRequired, profileDisconnected, profiles, memoryMB, port. It returns { "running": false } when no daemon is reachable.
  • profile list returns one row per profile — contextId, alias, default, connected, runtimeVersion — covering both connected profiles and saved aliases that are not currently connected, which the prose surfaced but no caller could parse. That aligns it with the hosted profile-list row set.

For those two, daemon guidance ("Daemon is not running…", stale-daemon hints) goes to stderr under structured formats so stdout stays parseable. It stays on stdout for table.

Bare skills and skills list now share one renderer instead of duplicating the row set with a hardcoded format, which is the de-duplicating half of the issue's "or make it a true alias" option.

Still open from my issue comment

Neither of these blocks review, and I'm happy to adjust:

  1. Bare skills — I shared the renderer rather than restructuring the Commander wiring into a literal alias. Say the word if you'd prefer the true alias.
  2. profile list — I kept the local field set (alias, default marker, runtime version) and matched hosted's format handling rather than adopting hosted's column set, since the local fields have no hosted equivalent.

Testing

  • npm run typecheck, npm run build — clean
  • npm run check:hosted-contract — contract bytes unchanged
  • npm run check:plugin-parity, check:package-bin, check:codex-plugin — pass
  • 14 new tests in src/cli.test.ts covering JSON/YAML per command family, the stdout/stderr split, bare-skills/skills list equivalence, and -f xml rejection (exit 2, before any side effects)
  • Verified against the built CLI, including that profile list -f json 2>/dev/null emits clean []

On the full suite I get 122 pre-existing failures on this Windows machine (symlink EPERM and a build-test timeout). I confirmed that count is identical on a clean main — same 12 files — and that passing tests go 5450 → 5464, exactly the 14 added. No regressions; CI should be a cleaner signal than my local box.

@github-actions

Copy link
Copy Markdown
Contributor

🟠 Maintainer review suggested — low confidence

The automated review could not reach a fully supported conclusion.

This review is advisory and does not block merging.

@Agnik47

Agnik47 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

The two red jobs — Unit tests (ubuntu-latest, shard 1/2) and Plugin tests (ubuntu-latest) — are a runner infrastructure failure, not a test failure. Both died in the Set up job step after 3–4s:

##[error]An action could not be found at the URI
'https://codeload.github.com/actions/checkout/tar.gz/d23441a48e516b6c34aea4fa41551a30e30af803'
##[error]Failed to download archive '...' after 1 attempts.

That is codeload failing to serve actions/checkout@v6; the job never reached a test. Unit tests (ubuntu-latest, shard 2/2) ran on the same image and passed, and every other job is green — builds on all three OSes, both macOS and Windows unit shards, macOS/Windows plugin tests, Bun, audit, and docs sync.

I can't re-run them myself (needs admin on this repo), and I'd rather not push an empty commit and re-trigger the whole matrix for a CDN blip. A re-run of just those two should clear it whenever someone gets a chance.

Part of agentrhq#175. `validate`, `verify`, `doctor`, bare `skills`, `daemon status`,
and `profile list` returned stable data internally but rejected `-f/--format`
and printed hand-written text only. Each now routes through the shared
`resolveOutputFormat` + `render` path introduced in agentrhq#190.

`adapter status` already gained `-f` in agentrhq#190, so it needed no change here.

Each command keeps its human-readable report as the `table` rendering, which
remains the default, and returns the underlying result object under any other
format. Following the `convention-audit` precedent, the human text is chosen on
the raw format rather than the TTY-resolved one, so no existing implicit
behavior changes.

`daemon status` gains a machine-readable projection that mirrors the text
rendering, reporting `{ running: false }` when no daemon is reachable.
`profile list` returns one row per profile covering both connected profiles and
saved-but-disconnected aliases, aligning it with the hosted profile-list row
set. Daemon guidance for those two goes to stderr under structured formats so
stdout stays parseable.

Bare `skills` and `skills list` now share one renderer instead of duplicating
the row set with a hardcoded format.

Browser read commands are intentionally left for a follow-up: they go through
the session/bridge layer and need separate care around the streaming and
JSONL-follow exclusions the issue calls out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVuD882dJuEwWKWBLaf7bs
@Agnik47
Agnik47 force-pushed the feat/175-structured-output-builtins branch from 228982c to af84f96 Compare August 14, 2026 07:30
@Agnik47

Agnik47 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Resolved — no re-run needed after all. I amended the commit (identical tree, git diff 228982c af84f96 is empty) to pick up fresh runners, and both ubuntu jobs now pass: unit shard 1/2 in 43s and plugin tests in 1m12s. All checks green.

That confirms it was the transient codeload fetch of actions/checkout@v6 rather than anything in the diff. Sorry for the noise on your notifications.

@Agnik47

Agnik47 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review! Quick check before this goes further — I'd left a scoping comment on #175 proposing to split this into two PRs (builtins here, browser reads separately), but it seems to have disappeared. Also saw an older comment on #175 mentioning it might already be spoken for via #190 — that one actually closed #172, a sibling issue, so I want to make sure #175 itself is still open for me to work on before I start phase 2.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants