Scripting the Shorebird CLI
The Shorebird CLI can run without a person at the keyboard, in a CI job, a script, or a coding agent. This page covers how it behaves there, how to get machine-readable output, and how to run destructive commands safely.
Non-interactive mode
Section titled “Non-interactive mode”Shorebird stops asking questions when any of these is true:
- The global
--jsonflag is passed. - stdout or stdin isn’t a terminal, for example when output is piped to a file.
- A CI environment variable is set, such as
CI(with any value),BOT=true, or the variables set by GitHub Actions, Azure Pipelines, Travis, AppVeyor, Cirrus CI, AWS CodeBuild, or Jenkins.
In non-interactive mode, nothing waits for input:
- Some prompts use a default.
shorebird inituses your pubspec name as the app’s display name.shorebird patchwithout--release-versionbuilds the patch with the latest Flutter version to work out which release it belongs to, which can pick the wrong release or Flutter version. - Other prompts fail. When there’s no safe default, the command exits with
an error and a hint, usually naming the flag that provides the answer. For
example,
shorebird patchfails on native code changes unless you pass--allow-native-diffs, andshorebird initfails if you belong to several organizations and don’t pass--org-id. - Progress spinners become plain lines when stdout isn’t a terminal or
--jsonis passed. Each step printsStarting ...and thenDone ...orFailed ...to stderr.
To keep a job from failing or guessing, pass every input as a flag: the app with
--app-id or --flavor, and the release with --release-version. For
shorebird patch, --release-version=latest targets the most recently updated
release. Authenticate with an API key in the
SHOREBIRD_TOKEN environment variable, since shorebird login needs a browser.
In GitHub Actions, a job can
sign in with OIDC
instead, with Shorebird 1.6.129 or newer.
JSON output
Section titled “JSON output”Pass the global --json flag to get one JSON object on stdout instead of
human-readable text. --json also turns on non-interactive mode and removes
color codes.
These commands return structured JSON:
| Group | Commands |
|---|---|
shorebird account | whoami, update, notifications, orgs |
shorebird auth | status, token |
shorebird apps | list, rename, delete, transfer |
shorebird invitations | list, accept, decline |
shorebird channels | list, create, delete |
shorebird patches | list, info, set-track, promote, rollback, rollforward |
shorebird releases | 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 |
Every other command, such as shorebird init or shorebird cache clean, also
accepts --json and runs non-interactively. Its logs go to stderr, and when it
succeeds it prints a success object whose data is empty ({}), so stdout
always holds exactly one JSON object. --help with --json works the same way:
the usage text goes to stderr. This needs Shorebird 1.6.129 or newer; earlier
releases leave stdout empty when these commands succeed.
shorebird api is the exception: it prints the API response body as-is and
rejects --json. See
Calling the API from the command line.
Success
Section titled “Success”A successful command prints an object with status set to success. The
command’s result is in data, and meta says which CLI version and command
produced it:
The fields inside data depend on the command.
Errors
Section titled “Errors”A failed command prints an object with status set to error and exits with a
non-zero code:
error.code is one of:
| Code | Meaning |
|---|---|
usage_error | Invalid or missing arguments. Exit code 64. |
interactive_prompt_required | The command needed an answer to a prompt. Exit code 64. |
fetch_failed | Shorebird couldn’t retrieve something it needed, such as an app. |
precondition_failed | A check before the command ran failed, such as not being logged in or not finding shorebird.yaml. |
software_error | The command failed unexpectedly. |
process_exit | The command stopped with a non-zero exit code. |
When there’s a way to recover, error.hint says what to do, such as the flag to
add.
When the Shorebird API rejected the request, error.api_code holds the server’s
error code, such as shorebird_plan_insufficient_tier for a feature your plan
doesn’t include, and error.details holds any extra detail the server sent.
Branch on api_code rather than on the message text. These fields need
Shorebird 1.6.129 or newer.
Destructive commands
Section titled “Destructive commands”Commands that delete something ask for confirmation in a terminal. Without a
terminal, in CI, or with --json, they never prompt, so confirm with a flag or
the command fails with a usage error and nothing is deleted:
shorebird releases deleteandshorebird channels delete: pass--yes.shorebird apps delete: pass the app’s display name with--confirm-name. Deleting an app has no--yes.
This behavior needs Shorebird 1.6.129 or newer. Earlier releases confirmed every
delete with --confirm-name.
Retrying rollbacks
Section titled “Retrying rollbacks”shorebird patches rollback and shorebird patches rollforward succeed when
the patch is already in the requested state, so a retried job doesn’t fail. Pass
--require-change to make the command exit with a usage error when nothing
changed, if your script needs to know. With --json, the data.changed field
reports the same thing:
See Roll back from the CLI for the command’s options, and What happens when a patch is rolled back? for what it does on devices.