Documentation Index
Fetch the complete documentation index at: https://docs.grantiva.io/llms.txt
Use this file to discover all available pages before exploring further.
Generate a config file
This creates grantiva.yml in your project root. The CLI auto-detects your Xcode scheme and workspace.
grantiva init --scheme MyApp --bundle-id com.example.myapp
Configuration reference
# Required (unless using --app-file)
scheme: MyApp
simulator: iPhone 16
# Optional
workspace: MyApp.xcworkspace # If using a workspace
project: MyApp.xcodeproj # If not using a workspace
bundle_id: com.example.myapp # Derived from binary if --app-file is used
# Screens to capture (VRT)
screens:
- name: Home
path: launch
- name: Profile
path:
- tap: "Profile"
- wait: 1
- name: Settings
path:
- swipe: up
- tap: "Settings"
- assert_visible: "Advanced"
- tap: "Advanced"
# Standalone Maestro flow files to run (functional tests)
flows:
- grantiva-flows/tasks.yaml
- grantiva-flows/shopping.yaml
# Diff thresholds
diff:
threshold: 0.02 # Max pixel diff % (0–1.0)
perceptual_threshold: 5.0 # Max CIE76 color distance
When using --app-file to provide a pre-built binary, scheme is not required. The bundle ID is derived from the binary’s Info.plist if not specified.
Screens
Each screen has a name and a path that describes how to navigate to it.
Simple launch screenshot
- name: Home
path: launch
Navigation steps
- name: Settings
path:
- tap: "Settings" # Tap by accessibility label
- type: "search query" # Type into focused field
- wait: 2 # Wait N seconds
- swipe: up # up, down, left, right
- assert_visible: "Advanced" # Fail if element not visible
- tap: "Advanced"
| Action | Description |
|---|
launch | Screenshot immediately after app launch |
tap: "Label" | Tap element by accessibility label |
type: "text" | Type text into the focused field |
swipe: direction | Swipe up, down, left, or right |
wait: N | Wait N seconds |
assert_visible: "Label" | Verify element is visible (fails the screen if not) |
assert_not_visible: "Label" | Verify element is not visible |
run_flow: "path.yaml" | Include steps from another YAML file |
A screenshot is automatically taken at the end of each screen’s path.
Flows
The flows: key lists paths to existing Maestro YAML files that grantiva run executes as standalone functional tests, in addition to any screens: entries.
flows:
- grantiva-flows/tasks.yaml
- grantiva-flows/shopping.yaml
- grantiva-flows/calendar.yaml
How it differs from screens:
| screens: | flows: |
|---|
| Format | Grantiva DSL | Native Maestro YAML |
| Purpose | VRT capture targets | Functional / smoke tests |
| Screenshot | Taken automatically at the end | Wherever takeScreenshot appears in the file |
| Baselines | Compared against stored baselines by grantiva ci run | Not compared — pass/fail only |
Paths are resolved relative to the directory containing grantiva.yml. Any screenshots taken inside a flow file are saved to .grantiva/captures/ named <flowname>-<screenshot>.png.
grantiva run runs all screens: first, then each flow in flows: order. A runner failure in any flow captures a simctl screenshot of the current simulator state for debugging.
flows: is only used by grantiva run. The grantiva ci run pipeline (VRT) only processes screens:.
Maestro compatibility
Grantiva can read Maestro flow files as a drop-in replacement. If you have existing Maestro flows, there’s no need to rewrite them.
Auto-detection
Grantiva auto-detects the format when loading configuration:
- Looks for
grantiva.yml — parses as Grantiva or Maestro format (auto-detected)
- If no
grantiva.yml, looks for a .maestro/ directory and loads all flow files
Using Maestro flows
Write grantiva.yml in Maestro format, or place flows in .maestro/:
appId: com.example.myapp
---
- launchApp
- tapOn: "Sign In"
- inputText: "user@example.com"
- takeScreenshot: "Login"
- tapOn: "Submit"
- assertVisible: "Welcome"
- takeScreenshot: "Welcome"
Each takeScreenshot becomes a named screen capture point. Commands between screenshots become navigation steps.
Supported Maestro commands
| Maestro command | Grantiva mapping |
|---|
tapOn / doubleTapOn / longPressOn | tap (supports text: and id: selectors) |
inputText | type |
assertVisible | assert_visible |
assertNotVisible | assert_not_visible |
scroll: {direction: down} | swipe: up (direction inverted) |
swipe: {start: ..., end: ...} | swipe (direction derived from coordinates) |
runFlow / runFlow: {file: ...} | run_flow |
extendedWaitUntil: {text: ...} | assert_visible |
waitForAnimationToEnd | wait (timeout converted to seconds) |
takeScreenshot: "name" | Screen capture boundary |
launchApp / stopApp | Skipped (Grantiva handles app lifecycle) |
Unsupported commands (pressKey, setPermissions, evalScript, repeat, etc.) are silently skipped.
Sub-flows
Maestro sub-flows referenced via runFlow are also parsed in Maestro format when auto-detected. You can mix Grantiva and Maestro flow files.
Diff thresholds
| Setting | Default | Description |
|---|
threshold | 0.02 | Maximum pixel difference percentage (2%) |
perceptual_threshold | 5.0 | Maximum CIE76 perceptual color distance |
A screen fails if either threshold is exceeded.
Build settings
Pass extra flags directly to xcodebuild:
build_settings:
- "OTHER_SWIFT_FLAGS=-DDEBUG_MODE"
- "SWIFT_OPTIMIZATION_LEVEL=-Onone"
Each entry is appended verbatim to the xcodebuild invocation.
Accessibility checks
a11y:
fail_on_new_violations: true # Fail the run on new violations (default: true)
rules:
- missing_label # Elements with no accessibility label
- small_tap_target # Tap targets smaller than 44×44pt
| Setting | Default | Description |
|---|
fail_on_new_violations | true | Fail CI when new violations are detected |
rules | [missing_label, small_tap_target] | Which a11y rules to enforce |
Size limits
Warn or fail when a screenshot exceeds a file size threshold:
size:
warn_mb: 0.5 # Warn if any capture exceeds 500 KB (default: 0.5)
fail_mb: 2.0 # Fail if any capture exceeds 2 MB (default: 2.0)
AI provider
ai:
provider: none # AI provider for smart assertions (default: none)
Reserved for future AI-powered visual assertion features.
Directory structure
After running commands, Grantiva creates:
.grantiva/
├── captures/ # Screenshots from capture runs
│ └── diffs/ # Diff images for failed comparisons
└── baselines/ # Local baseline images (if not using cloud)
Credentials are stored at ~/.grantiva/auth.json.