Flitzdocs
CLI

CLI overview

Install the flitz CLI and learn the conventions every command shares: global options, output streams, --json, and exit codes.

flitz is the one tool you install. It signs you in, downloads and pins the Flitz SDK for a project, builds a bundle from that project, publishes it, and tells you what is set up and what is not. There are no archive URLs to copy and no PATH juggling required to build a bundle.

The CLI itself is free to obtain and needs no license. Only the actions behind it are gated: downloading an SDK, reading the loader-plugin credentials, and publishing a bundle each check your organization's license when they run.

Supported hosts

The CLI ships for linux-x64 and macos-arm64 (Apple Silicon). Any other host is rejected with a clear error naming the supported set.

Install

The one-line installer detects your platform, downloads the matching pre-compiled binary, verifies its SHA-256, and installs flitz into ${XDG_BIN_HOME:-$HOME/.local/bin}:

curl -fsSL https://download.flitz.dev/install.sh | sh

Make sure that directory is on your PATH, then confirm the install:

export PATH="$HOME/.local/bin:$PATH"
flitz --version

The binary is self-contained. It needs no Dart or Flutter SDK on the machine — it is the bootstrap that installs one.

Prefer to install by hand? The download page at download.flitz.dev lists each host's binary with its SHA-256 and a copy-pasteable verify command (sha256sum -c on Linux, shasum -a 256 -c on macOS). Download, verify, chmod +x, and move it onto your PATH as flitz.

Update

Re-run the install script. It always installs the newest published CLI.

When a newer CLI exists, the CLI tells you once a day, after your command has finished, and never in CI or under --json. flitz status reports the same fact on demand. See Configuration → Update notices for how to silence it.

The happy path

flitz login              # once per machine
cd /path/to/your/flutter/app
flitz sdk use latest     # pin an SDK for this project and download it
flitz publish            # build a bundle and get a link + QR code

flitz --help prints the same three steps. Run flitz status at any point to see what is set up and what to do next. For the full walkthrough, including embedding the loader in your app, see Getting started.

Global options

Every option is accepted before or after the subcommand.

OptionEffect
--versionPrint the CLI's own version and exit 0. Prints nothing else.
-v, --verboseAdd stack traces to errors and stream build-tool output live. One level only; -vv is a usage error. See Verbose output.
-y, --yesAnswer yes to every confirmation prompt without showing it. See Prompts and --yes.
--jsonEmit the result as one JSON document on stdout. Accepted by seven commands; a usage error elsewhere. See Machine-readable output.
--no-colorForce plain output, overriding terminal detection, FORCE_COLOR, and config.yaml.
-h, --helpHelp for the CLI or the named command.

Output conventions

Two streams

stdout carries results; stderr carries everything else. A result is the thing you ran the command to obtain: an SDK path, a plugin version, a JSON document, the published URLs, a completion script, the version string. Progress, timings, spinners, warnings, prompts, errors, and hints all go to stderr.

So every command works in a pipeline. flitz publish > urls.txt captures the three result lines and nothing else while the terminal still shows the progress; flitz sdk path, flitz plugins configure --version-only, and flitz completions zsh each emit exactly their result.

Rich and plain output

There is one switch, rich versus plain, and it governs color, glyphs, and animation together. Rich output uses color, the Unicode verdict glyphs (✓ ⚠ ✗ ?), and in-place spinners. Plain output uses no escape sequences at all: ASCII verdict words ([ok] [warn] [fail] [unknown]) and one appended line per state change, so a CI log reads as a clean chronological record.

The mode is resolved once per stream, in this order:

  1. --no-color → plain.
  2. NO_COLOR set and non-empty → plain (it beats FORCE_COLOR).
  3. FORCE_COLOR set and non-empty → rich.
  4. config.yaml color: always → rich; color: never → plain.
  5. Otherwise rich when the stream is a terminal and TERM is neither unset nor dumb; plain otherwise.

Because it is per stream, redirecting stdout does not flatten the progress on stderr.

Verdict markers

Four markers are the CLI's whole visual vocabulary. They prefix status rows, errors, and warnings alike.

VerdictRichPlainMeaning
ok[ok]Satisfied.
advisory[warn]Works today; worth attention. Never blocks.
blocking[fail]Prevents building or publishing.
unknown?[unknown]Could not be determined — offline, or no credential to ask with.

Errors and hints

Every failure is one lowercase sentence saying what went wrong, then one indented line per next action, naming the command that fixes it:

✗ the pinned SDK <tag> is not installed
  → run `flitz sdk use <tag>`
  → or pass --yes

Warnings use and never change the exit code. Compiler output is passed through verbatim, never reformatted. The full contract, the six exit codes, and the bug-report capture are on Exit codes and messages.

Prompts and --yes

A prompt is asked only when stdin and stderr are both terminals. --yes (or assume_yes: true in config.yaml) answers every prompt affirmatively without displaying it. There are exactly three prompts:

PromptDefaultNon-interactive without --yes
publish: download the pinned SDK now?yesUsage error (exit 1); the hint names flitz sdk use and --yes.
sdk use: download the SDK just pinned?yesDownloads — you asked for it.
apikey revoke: revoke the organization key?noUsage error (exit 1); the hint names --yes.

There is no setup wizard. Onboarding is flitz status: it reports what is missing and each finding names the command that fixes it.

Machine-readable output (--json)

--json makes a command emit its result as a single JSON object on stdout and nothing else. Exactly these commands accept it:

CommandDocument
statuscli_version, host, checks[] keyed by stable identifiers, blocking, advisory.
sdk list{ "sdks": [ { "tag", "installed", "pinned" } ] }
sdk releases{ "releases": [ { "tag", "installed", "pinned" } ] }
sdk path{ "tag", "path", "installed" }
plugins configure{ "version", "target_sdk_tag", "repositories": { "maven", "swift", "cocoapods" } }
apikey status{ "present", "name", "obfuscated_value", "created_at", "last_used_at" }
publish{ "page_url", "deeplink", "bundle_url" }

Passing --json to any other command is a usage error (exit 1). The contract:

  • stdout carries exactly one document — no progress, no warnings, no banner. Everything human-facing goes to stderr or is suppressed, including the ambient update notice.
  • On failure the command emits no JSON. It reports the error on stderr and exits non-zero. Check the exit status first; parse stdout only on 0.
  • Documents are objects, never bare arrays, and schemas grow additively: fields are added, never removed or repurposed. status keys its checks on identifiers, not prose.
  • No document ever contains a plaintext API key, a token, or a signed upload URL. apikey status --json carries the obfuscated value only.

sdk path and plugins configure --version-only also print a bare string without --json: the bare form is what a shell substitution wants, the JSON form is what a tool wants.

Commands

CommandLicensePurpose
flitz loginSign in from a browser; stores a credential on this machine.
flitz logoutRemove the stored credential.
flitz statusRead-only health check of your account, project, plugins, and CLI. Always exits 0.
flitz sdk install / use / releasesrequiredDownload, pin, and list Flitz SDK releases.
flitz sdk list / path / removePurely local cache reads and deletes; never touch the network.
flitz publishrequiredBuild a .flitz bundle from the project and publish it.
flitz plugins configure / credentials / skillrequiredResolve the loader-plugin version, store the repository credentials, print the wiring prompt.
flitz apikey create / rotate / revoke / statusrequiredManage the organization's single CI API key.
flitz completions <shell>Print a static completion script for bash, zsh, or fish.

"Required" means the command needs a credential — an interactive session from flitz login or the FLITZ_APIKEY environment variable — and the organization's license must be active. There is no separate license pre-flight: a licensed command goes straight to the endpoint that does its work and reports what that endpoint answered. The apikey mutations (create/rotate/revoke) are the one exception: they require an interactive session and refuse an API key.

Where the CLI keeps things

PathContents
~/.config/flitz/credentials.jsonYour sign-in credential, mode 0600. Written by login, deleted by logout.
~/.config/flitz/config.yamlOptional preferences you author; the CLI never writes it. See Configuration.
~/.cache/flitz/sdk/<tag>/The SDK cache, one directory per release tag.
~/.cache/flitz/update-check.jsonThrottle state for the update notice.
<project>/flitz.yamlThe project's SDK pin, committed to your repository. See sdk use.

~/.config and ~/.cache follow XDG_CONFIG_HOME and XDG_CACHE_HOME when those are set. There is no log file: diagnostics are produced on demand by -v and by the bug-report capture.

On this page