Skip to content

docs: every --json run prints exactly one JSON object - #714

Merged
eseidel merged 7 commits into
mainfrom
docs/json-envelope-every-command
Oct 16, 2026
Merged

eseidel merged 7 commits into
mainfrom
docs/json-envelope-every-command

Conversation

@eseidel

@eseidel eseidel commented Oct 11, 2026 •

Copy link
Copy Markdown
Contributor

Updates the scripting docs for shorebirdtech/shorebird#4055, under which every --json run prints exactly one JSON envelope on stdout.

  • scripting.mdx: commands without structured output now print {"status": "success", "data": {}, ...} on success, with their logs (and --help usage) on stderr. That replaces "still print human-readable logs, check the exit code". shorebird release and shorebird patch move into the JSON commands table, since they already emit JSON. The caution no longer says some failures print plain text. Pre-run check failures now report precondition_failed, which is added to the error-code table.
  • agent-instructions.txt: the same change to the one-line summary, noting that shorebird api is the one command without --json.

shorebirdtech/shorebird#4055 shipped in Shorebird 1.6.129, so this can land. On 1.6.128 and earlier, commands without JSON output still leave stdout empty on success, and the page says the empty success object needs 1.6.129 or newer.

@eseidel

eseidel commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

Independent review

No blocking issues. The page matches shorebirdtech/shorebird#4055: there's a {} success envelope when nothing else wrote one, --help usage goes to stderr, and release/patch emit their own envelopes (release_command.dart, patch_command.dart). The rest of the table matches the commands that call emitJsonSuccess. precondition_failed exists (JsonErrorCode.preconditionFailed).

Should fix

  • scripting.mdx caution: "including failures in the checks that run before a command starts, which report precondition_failed" overstates it. Only checks that go through validatePreconditions / PreconditionFailedExit report precondition_failed. Ad-hoc pre-run checks return an exit code and get process_exit from the runner. For example, shorebird init without a pubspec.yaml returns ExitCode.noInput (init_command.dart:69-74). The one-envelope guarantee still holds. Suggested wording: "...including failures in the checks that run before a command starts. Most of those, such as not being logged in, report precondition_failed."

Nits

  • agent-instructions.txt:27: "to get one JSON object on stdout" is followed by "prints exactly one JSON object on stdout" in the same bullet. Drop one of them.
  • The hidden shorebird completion writes no envelope (see the CLI review). It doesn't need a mention in the docs, but "every command" is very slightly too strong.

@eseidel

eseidel commented Oct 11, 2026

Copy link
Copy Markdown
Contributor Author

lgtm

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked against shorebird origin/main (#4055 merge commit f3dae09). No changes needed.

  • Empty success envelope: the runner writes {"status":"success","data":{},...} when a --json run exits 0 or with no exit code and nothing else wrote an envelope (shorebird_cli_command_runner.dart). That covers init, cache clean, and bare shorebird --json.
  • --help on stderr: both ShorebirdCommand.printUsage and the runner's printUsage go through logger.info, so this holds for subcommand help and top-level help.
  • Table: every row matches a command that calls emitJsonSuccess. release and patch already do in v1.6.128, so moving them into the table is right. --version goes through the runner's own JsonResult.success.
  • precondition_failed: JsonErrorCode.preconditionFailed exists. Its doc comment lists "not logged in, not in a Shorebird project", which matches the table row. The caution's "Most of those" covers the ad-hoc checks that fall through to process_exit.
  • Earlier review: both points from the independent review are fixed. The caution is reworded and the agent-instructions.txt sentence no longer repeats itself.
  • CI is green.

Merge timing: #4055 merged after v1.6.128 was tagged and isn't in any release yet (13 commits on main since v1.6.128). Merging this now would document the data: {} envelope before users can get it, so this should wait for the next CLI release, as the description says.

@eseidel

eseidel commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Heads-up from #728's review: the JSON command table here should gain releases delete and a metrics row (both emit one JSON object with --json), and agent-instructions.txt should keep #728's --yes wording rather than --confirm-name.

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at 5c4f0fe.

Verdict: changes requested. One finding: on current shorebird main, two more commands return structured JSON. The table leaves them out, and the new paragraph wrongly says they print an empty data.

Checked

  • Empty success envelope: shorebird_cli_command_runner.dart on shorebird origin/main (0049cec1) still writes JsonResult.success(data: const {}, ...) when a --json run exits 0 or null and nothing else wrote an envelope. This still holds after #4097 and #4100. --help (null exit code) is covered by the same check. completion is still fast-tracked and writes no envelope; that was already accepted in the earlier review.
  • Existing table rows: each one matches an emitJsonSuccess call on origin/main:
    • account/{apps,orgs,whoami}_command.dart
    • apps/{delete,rename,transfer}, plus apps list through AppsListCommand extends AccountAppsCommand
    • channels/{list,create,delete}
    • patches/{list,info,set_track,patch_rollback_state}
    • releases/{list,info}
    • release_command.dart:202,490 and patch_command.dart:256,795
    • doctor_command.dart:199 and flutter_versions_list_command.dart:54
    • --version through the runner's own JsonResult.success
  • Other commands: init and cache clean have no emitJsonSuccess, so they get the empty envelope, as the new paragraph says.
  • Error codes: json_output.dart defines exactly process_exit, usage_error, software_error, fetch_failed, precondition_failed and interactive_prompt_required. The table now lists all six. The preconditionFailed doc comment says "not logged in, not in a Shorebird project, ...", which matches the new row. checkShorebirdInitialized in shorebird_validator.dart covers the shorebird.yaml case.
  • Caution wording: the runner maps PreconditionFailedExit to precondition_failed and a plain non-zero return to process_exit, so "Most of those" is accurate.
  • Release status: v1.6.128 is still the latest CLI tag, so the "land with the next CLI release" note in the description still applies.
  • Agent entry points:
    • agent-instructions.txt is updated.
    • The starlightLlmsTxt details in astro.config.mjs and agent-skills/index.json only say "--json for machine-readable output". Neither contradicts the change, so they need no edit.
  • Other pages: account/cli.mdx, code-push/tracks.mdx and code-push/rollback.mdx don't contradict the change.
  • Merges and lint:
    • git merge-tree shows the branch merging cleanly with docs main (beddc0b, which adds #727) and with #728's head. Taken together, the merged scripting.mdx and agent-instructions.txt read consistently.
    • Prettier passes, cspell finds no issues in scripting.mdx, and vale reports 0 errors, 0 warnings and 0 suggestions using main's .vale.ini.
    • No em-dashes in the added text.
    • All internal links in the table resolve on main.
  • Earlier reviews: both points from the first independent review are already addressed and are not raised again here.

Findings

  1. src/content/docs/code-push/ci/scripting.mdx:54-67: the JSON command table is missing shorebird releases delete and the shorebird metrics subcommands, so the new paragraph below it gives the wrong shape for them.

    Problem. The paragraph says every other command "prints a success object whose data is empty ({})". On shorebird main, two commands that ship in the same next CLI release return real data:

    • releases delete: releases_delete_command.dart:162 emits app_id, release_id, release_version, release_deleted, platforms and deleted.
    • Every metrics subcommand: metrics_subcommand.dart:180 emits emitJsonSuccess(toJson(response)).

    A script that follows this page would expect {} from both. The 2026-10-16 heads-up from #728's review is correct per source.

    Evidence.

    • releases_command.dart:11 registers ReleasesDeleteCommand.
    • shorebird_cli_command_runner.dart:100 registers MetricsCommand.
    • metrics_command.dart adds eight subcommands: active-hours, adoption, downloads, heatmap, installs, new-devices, users and versions.
    • All eight inherit run() from MetricsSubcommand. downloads and installs do this through the abstract MetricsPatchCountCommand, which has no name and is not registered.
    • Neither releases delete nor metrics exists at the v1.6.128 tag, so both are next-release features, like the rest of this PR.

    Fix. Replace the table with the version below (already run through Prettier; the column widths are unchanged).

    The metrics row has no link for now. The metrics section (/account/cli#metrics-commands) is added by #728. If #728 lands first, link the group cell as [`shorebird metrics`](/account/cli#metrics-commands) and re-run Prettier.

    | Group                                                                  | Commands                                                                                                             |
    | ---------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
    | [`shorebird account`](/account/cli#account-management-commands)        | `whoami`, `apps`, `orgs`                                                                                             |
    | [`shorebird apps`](/account/cli#app-management-commands)               | `list`, `rename`, `delete`, `transfer`                                                                               |
    | [`shorebird channels`](/code-push/tracks#managing-tracks-from-the-cli) | `list`, `create`, `delete`                                                                                           |
    | [`shorebird patches`](/code-push/patch#manage-patches)                 | `list`, `info`, `set-track`, `rollback`, `rollforward`                                                               |
    | [`shorebird releases`](/code-push/release)                             | `list`, `info`, `delete`                                                                                             |
    | `shorebird metrics`                                                    | `active-hours`, `adoption`, `downloads`, `heatmap`, `installs`, `new-devices`, `users`, `versions`                   |
    | Other                                                                  | `shorebird release`, `shorebird patch`, `shorebird doctor`, `shorebird flutter versions list`, `shorebird --version` |

    Not affected. eseidel's other note, to keep #728's --yes wording in agent-instructions.txt, needs no change in this PR. This PR does not touch the delete-confirmation line, and the two PRs merge cleanly.

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at a5f2154.

Verdict: no findings, nits included. The finding from the last round is fixed. releases delete and the metrics subcommands are now in the JSON command table.

Checked

  • The table matches the source. On shorebird origin/main (0049cec1), every command that calls emitJsonSuccess has a row, and every row has one:
    • account/{apps,orgs,whoami}, apps/{delete,rename,transfer} (apps list through AccountAppsCommand), channels/{list,create,delete}, patches/{list,info,set_track,patch_rollback_state}
    • releases/{list,info,delete} (releases_delete_command.dart:162)
    • metrics_subcommand.dart:180
    • release_command.dart:202,490, patch_command.dart:256,795, doctor_command.dart:199, flutter_versions_list_command.dart:54
    • --version through the runner's own JsonResult.success
  • Metrics row. metrics_command.dart:11-18 registers exactly active-hours, adoption, downloads, heatmap, installs, new-devices, users and versions, and all of them emit the API response through MetricsSubcommand.run(). The row is unlinked until #728, which adds the docs section, merges.
  • Empty success object. shorebird_cli_command_runner.dart:390-393 writes JsonResult.success(data: const {}) when a JSON-mode run has written no envelope and exits with null or 0. That covers init, cache clean and --help.
  • Logs go to stderr. In JSON mode the runner sends human and subprocess output to stderr and binds the JSON sink to the real stdout.
  • Error codes. JsonErrorCode in json_output.dart defines exactly the six codes the table lists, and the preconditionFailed doc comment matches the new row.
  • Exceptions. shorebird api is the only command that reserves stdout (api_command.dart:89); #726 documents it.
  • Agent entry points. agent-instructions.txt matches the page. The starlightLlmsTxt details and agent-skills/index.json don't contradict it.
  • Consistency with main. The branch merges cleanly with docs main. The changelog entries json-precondition-failed.md and release-patch-json.md agree with the page.
  • Lint. Prettier, cspell and vale are clean on the changed text, there are no em-dashes, and the table links resolve.
  • Release timing. v1.6.128 is still the latest CLI release and does not contain #4055, releases delete or metrics, so this lands with the next CLI release.

Findings

None.

@eseidel
eseidel enabled auto-merge (squash) October 16, 2026 16:30
@eseidel
eseidel merged commit d843948 into main Oct 16, 2026
4 checks passed
@eseidel
eseidel deleted the docs/json-envelope-every-command branch October 16, 2026 16:33
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