grantiva, with the current version reported by grantiva --version.
Commands fall into three families:
- Local automation —
build,run,hierarchy,record,simulator,runner,diff,ci - Your dashboard —
console, covered in Console commands - Setup —
init,doctor,auth,mcp
Global flags
Every command exceptgrantiva 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:
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.
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:
- Boots the simulator
- Builds via
xcodebuild(unless--app-fileor--no-build) - Installs via
simctl - 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:
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:
- Boots the simulator.
- Builds and installs the app (unless
--app-fileor--no-build). - 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.
- If
--logsis set, teesxcrun simctl spawn log streamoutput inline with the flow output. - Runs all configured
screens:first, then each file inflows:(or the single--flowfile), reporting step pass/fail. - On failure, captures a
simctlscreenshot of the simulator’s current state. - If
--keep-alive, writes a session file to~/.grantiva/runner/sessions/<udid>.jsonand blocks waiting for Ctrl-C so external tools can inspect the final state. Otherwise the session is torn down. - Saves screenshots to
.grantiva/captures/, or to<report-dir>/captureswhen--report-diris given.
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:
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.
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.
grantiva ci run
Run the full visual regression pipeline: build, capture, compare, upload.
- Boots the simulator
- Builds the app (unless
--app-fileor--no-build) - Installs the app and starts GrantivaAgent
- Captures screenshots for every screen in
screens: - Compares against baselines (pixel + perceptual)
- Uploads results to Grantiva
- Posts a GitHub Check Run when the GitHub App is configured
--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:
grantiva console vrt.
grantiva diff capture
Navigate to the configured screens and capture screenshots, without comparing.
.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.
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.
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.
GRANTIVA_API_KEY first, then ~/.grantiva/auth.json. The JSON result reports source as env or file.
grantiva auth logout
Remove the stored credentials.
~/.grantiva/auth.json. It does not affect GRANTIVA_API_KEY in your environment.