Skip to main content
The CLI is one binary, grantiva, with the current version reported by grantiva --version. Commands fall into three families:
  • Local automationbuild, run, hierarchy, record, simulator, runner, diff, ci
  • Your dashboardconsole, covered in Console commands
  • Setupinit, doctor, auth, mcp

Global flags

Every command except grantiva init accepts --json. All commands accept --verbose and --quiet.

stdout is the result, stderr is the commentary

Anything you would capture or parse — a --json payload, the UDID from simulator ensure, a result table, a dumped hierarchy — goes to stdout, undecorated. Progress narration, warnings, and errors go to stderr. Both of these work, and neither sees the other’s output:
Colour is emitted only when stdout is a terminal, and NO_COLOR suppresses it.

Exit codes

0 on success. 1 when the command’s own verdict is a failure — a build error, a failing flow, a screen over threshold, a failing required doctor check, a webhook test the endpoint rejected — or when the command errored out. Invalid arguments exit non-zero before any work starts.

grantiva init

Generate grantiva.yml in the current directory.
This is the one command with no --json; it still takes --verbose and --quiet.

grantiva doctor

Check the environment and dependencies.
It reports on three sections: Only a required check failing exits 1 — the optional checks (no booted simulator, no grantiva.yml, not authenticated) report a warning and are advisory. That makes grantiva doctor || exit 1 a usable CI preflight.

grantiva build

Build the app for a simulator using xcodebuild.
Boots the simulator, runs xcodebuild, and prints a build summary. Exits 1 on build failure. --app-file and --no-build belong to the commands that install and drive the app — build install, run, ci run, and diff. grantiva build always builds.
--derived-data-path is available on every command that builds the app, accepts absolute or relative paths including paths with spaces, and overrides a -derivedDataPath value in build_settings when both are given.

grantiva build install

Build and install the app on a simulator, then optionally launch it.
What it does:
  1. Boots the simulator
  2. Builds via xcodebuild (unless --app-file or --no-build)
  3. Installs via simctl
  4. Launches, unless --no-launch

Seeding fixtures before first launch

--no-launch exists so a harness can seed the installed app’s data container or defaults before the app starts. With --json the result carries the container path:
The JSON result carries status (installed or launched), scheme, bundleId, appPath, dataContainerPath, and the selected simulator’s name and udid. dataContainerPath is only resolved under --json.

grantiva run

Run flows against a simulator. No visual regression — it reports step pass/fail and captures a screenshot on failure.
What it does:
  1. Boots the simulator.
  2. Builds and installs the app (unless --app-file or --no-build).
  3. Starts GrantivaAgent on the simulator. The flow drives the app — there is no pre-launch, because a CLI-side launch creates a process WDA cannot control.
  4. If --logs is set, tees xcrun simctl spawn log stream output inline with the flow output.
  5. Runs all configured screens: first, then each file in flows: (or the single --flow file), reporting step pass/fail.
  6. On failure, captures a simctl screenshot of the simulator’s current state.
  7. If --keep-alive, writes a session file to ~/.grantiva/runner/sessions/<udid>.json and blocks waiting for Ctrl-C so external tools can inspect the final state. Otherwise the session is torn down.
  8. Saves screenshots to .grantiva/captures/, or to <report-dir>/captures when --report-dir is given.
No authentication required. Exit code 0 if all steps pass, 1 if any fail.

Waiting on a run with --ready-file

With --keep-alive the session deliberately outlives the flows, so process exit is not a completion signal, and report.json is rewritten incrementally. Wait on the ready file instead:
Two guarantees make that loop safe. The file is deleted at startup, before any project, build, or simulator work, so a file left by a previous run can never be read as this run’s verdict — and an unwritable path is rejected immediately rather than at the end of a long suite. And it is always written: a failure before the runner starts (no project, bad scheme, build failure, no simulator) records failed rather than leaving that loop, which has no timeout, spinning until CI’s global limit.

grantiva hierarchy

Dump the UI hierarchy of a booted simulator without relaunching the app. Read-only — no launch, no stopApp, no clearState.
Requires grantiva run --keep-alive to be holding a session open in another shell or as a backgrounded CI process. If no keep-alive session is live, the command fails with an actionable error rather than spinning up a fresh session — which would relaunch the app and destroy the state you wanted to inspect.
The output is the accessibility tree of the currently foregrounded view — element types, labels, identifiers, bounds, traits.

grantiva record

Record a simulator and extract PNG frames at exact requested timestamps.
The command boots the simulator, records with simctl io recordVideo, then extracts one PNG per requested timestamp with zero tolerance — the frame you asked for, not the nearest keyframe. Frames land in a <output-basename>-frames/ directory next to the video, named 000150ms.png. A JSON report is written alongside the video at <output-basename>.json with the requested and actual millisecond offsets per frame.
Recording that ends before the last requested timestamp is an error, not a silent truncation.

grantiva ci run

Run the full visual regression pipeline: build, capture, compare, upload.
What it does:
  1. Boots the simulator
  2. Builds the app (unless --app-file or --no-build)
  3. Installs the app and starts GrantivaAgent
  4. Captures screenshots for every screen in screens:
  5. Compares against baselines (pixel + perceptual)
  6. Uploads results to Grantiva
  7. Posts a GitHub Check Run when the GitHub App is configured
When --app-file is provided, the binary is validated to be a simulator build, the bundle ID is derived from its Info.plist if not specified, and .ipa archives are extracted automatically. Requires authentication, and a git repository with an origin remote: the project slug is owner/repo parsed from git remote get-url origin, and the branch comes from GITHUB_HEAD_REF or GITHUB_REF_NAME when they are set, falling back to git rev-parse --abbrev-ref HEAD. That fallback is why the environment variables matter — GitHub Actions checks out in detached HEAD, where the git command returns HEAD. Exit code 0 if all screens pass, 1 if any fail — the results are uploaded either way. With --json the result is one object:
Review the run from the terminal with grantiva console vrt.

grantiva diff capture

Navigate to the configured screens and capture screenshots, without comparing.
Saves .png files to .grantiva/captures/.

grantiva diff compare

Diff current captures against baselines.
Baselines are loaded from the Grantiva server when you are authenticated, or from .grantiva/baselines/ locally. Diff images for failures are written to .grantiva/captures/diffs/.

grantiva diff approve

Promote current captures to baselines.
Pass screen names to approve selectively, or omit them to approve all.

grantiva simulator

Provision, inspect, and tear down managed simulators.
ensure prints only the UDID on stdout, so udid=$(grantiva simulator ensure --name "iPhone 17 Pro") works directly. See Simulator management for the capacity model, leases, and reclaiming a stranded device.

grantiva runner install

Extract or update the embedded UI automation runner binary.
Run once after installing or upgrading the CLI.

grantiva runner version

Show the embedded runner version.

grantiva runner start

Start the runner with WebDriverAgent and keep it alive for interactive use.
Boots the simulator, launches WDA, and writes a session file so other commands can auto-detect the port. If a session is already alive the command reports it and exits without starting a second one. The session holds the simulator lease for its whole life, so a concurrent grantiva run on the same simulator cannot tear it down. grantiva runner stop releases the lease.

grantiva runner stop

Stop the running runner session.

grantiva runner dump-hierarchy

Dump the view hierarchy from a running app, for agent inspection.
Requires a session started with grantiva runner start. To read the hierarchy of a grantiva run --keep-alive session instead, use grantiva hierarchy.

grantiva auth login

Authenticate with Grantiva.
Without --api-key, the CLI creates a login session, opens your browser, and polls for up to 5 minutes. Either way the credentials are written to ~/.grantiva/auth.json with mode 0600 — the file holds a plaintext API key.

grantiva auth status

Show the current authentication status.
Checks GRANTIVA_API_KEY first, then ~/.grantiva/auth.json. The JSON result reports source as env or file.

grantiva auth logout

Remove the stored credentials.
This deletes ~/.grantiva/auth.json. It does not affect GRANTIVA_API_KEY in your environment.

grantiva console

Manage your Grantiva dashboard from the terminal — feature flags, apps, claims, devices, analytics, VRT review, release notes, feedback, support, webhooks, alerts, API keys, team, audit log, and org settings.
See Console commands.

grantiva mcp

Start the Grantiva MCP server for AI agent integration.
Speaks MCP over stdio, so your MCP client normally launches it for you. See MCP server.