visor --help, visor -h, or invoke the CLI with no command, visor prints a usage summary instead of a JSON response envelope. visor --version and visor -v print the package version instead of a JSON response envelope.
Global runtime inputs
These inputs are accepted globally and, where relevant, by individual commands.| Input | Meaning |
|---|---|
device | Device or simulator identifier |
timeout | Per-step timeout budget in milliseconds for scenario runs |
output | Base output directory for run artifacts and reports |
format | text or json |
server-url | Appium server URL |
app-id | Android app package or iOS bundle identifier; on iOS it must match an installed app on the selected target |
attach | Attach to an already running app process when possible |
no-map | Disable app-map reads and writes for this command |
repair | Allow opt-in exploratory app-map repair after a missing or stale route |
formatis currently informational only for normal commands; the implementation still returns JSON envelopesvisor --help,visor -h, and no-command invocation print plain-text usage instead of JSONvisor --versionandvisor -vprint the package version instead of JSONplatformis inferred from the selected device;--platformis not accepted
Mapped execution
Mapped execution is enabled by default for direct action commands and scenario runs. Visor observes lightweight UI source around target actions, stores a schema-versioned host-machine app map under.visor/maps, and can reuse confirmed navigation edges when a later command targets a known screen from a different current screen.
Use --no-map or VISOR_NO_MAP=true when you need raw Appium behavior. No-map mode disables both map reads and map writes.
Exploratory repair is off by default. Use --repair when you want Visor to try safe controls after a missing or stale route instead of failing fast.
Every mapped direct action returns data.map. Mapped target, coordinate, and scroll actions also return data.observation with before/after fingerprints, screen_changed, previous/current screen ids, and visible_text_count. Scenario runs return data.run.map and per-step map details under data.run.steps[].details.map when a step used routing, repair, or map observation.
Direct action commands
tap
Purpose: click an element or coordinate.
Inputs:
- target mode:
target - coordinate mode:
x,y - optional:
normalized - optional post-action wait:
--wait-for,--timeout, and--poll-msto wait for a selector after the tap
actionplatformargs
args contains either:
target, orx,y, andnormalized
x and y values are screen points by default. With normalized, they are fractions of the current screen width and height.
Coordinate taps work as direct commands and as scenario steps. Target taps report args.tap_method; when Visor can resolve an element rectangle, it taps the center coordinate and returns the resolved x and y.
Examples:
navigate
Purpose: move to a destination.
Required input:
to
actionplatformargs.to
- the destination is passed to WebdriverIO through
url(to)
act
Purpose: perform a helper action.
Supported variants:
name=typewithtargetandvaluename=typewithvalueonly, which types into the active fieldname=backname=homename=resetname=dragwithstart-x,start-y,end-x, andend-yname=sliderwithtarget,valuefrom0to1, and optionalstart-value
drag also accepts normalized so coordinates can be fractions of the viewport. reset requires app-id because Visor restarts the target app.
Optional post-action wait inputs:
--wait-for--timeout--poll-ms
--wait-for polls for a selector after the helper action completes. --timeout and --poll-ms control that post-action wait.
Returns action payload fields:
actionplatformargs
scroll
Purpose: perform a page-style vertical scroll.
Required input:
directionwith valueupordown
percent, default70- post-action wait:
--wait-for,--timeout, and--poll-ms
--wait-for polls for a selector after the scroll completes. --timeout and --poll-ms control that post-action wait.
Returns action payload fields:
actionplatformargs.directionargs.percent
- Android uses Appium scroll gestures within the current viewport
- iOS attempts the same gesture path and falls back to a touch swipe when needed
screenshot
Purpose: capture a PNG image.
Optional input:
labelpathsettleorsettle-ms
actionplatformargs.labelargs.fileargs.pathargs.widthargs.height
label is omitted, the runtime defaults it to capture.
If path is provided, Visor writes the PNG to that path. Otherwise it writes <label>.png in the current working directory for direct Appium actions, or under --output when that directory is supplied. Direct command responses include the screenshot path in both data.args.path and the top-level artifacts array. settle waits briefly before capture; settle-ms controls the wait duration.
Examples:
wait
Purpose: pause, wait for a selector, or wait for source stability.
Inputs:
msforwith optionaltimeoutandpoll-msstablewith optionaltimeoutandpoll-ms
actionplatformargs.ms, or selector/stability wait result fields
wait --for <selector> polls until the selector exists. wait --stable polls UI source until two consecutive captures match. If either predicate times out, the command or scenario step fails and preserves the wait payload with matched: false.
source
Purpose: capture current UI source as XML.
Optional inputs:
labelpathsettleorsettle-ms
actionplatformargs.labelargs.fileargs.pathargs.formatargs.bytes
visor start first.
For direct screenshot and source, a returned args.path is also surfaced as a top-level response artifact. --output <dir> writes the capture under that directory when path is not provided.
discover
Purpose: observe the current screen and update the shared app map without running a scenario action.
Optional runtime inputs:
deviceserver-urlapp-idattachno-mapcrawlcrawl-depthcrawl-limitcrawl-includecrawl-allow-risky
--crawl to explore safe controls from the current screen and record app-map edges. Crawling is bounded by --crawl-depth and --crawl-limit.
Use --crawl-include <text> and --crawl-allow-risky on sandbox/dev builds when you intentionally want the crawler to include otherwise risky controls such as delete, logout, purchase, or confirm surfaces.
Response data fields:
actionmapmap.summary, when the persisted map can be readscreencrawl, when--crawlis used
map.summary is a path-free inventory of the persisted app map for review: schema version, identity, app id, platform, screen count, variant count, edge count, authentication-required variant count, and last update time.
Persisted variants include source-derived items for review and replay tooling, plus exit_recipes for visible back/close/dismiss/done controls when coordinates are available.
record
Purpose: start or stop a named replay flow.
Required input:
name
stopforcerecord-values
visor record <name> creates .visor/flows/<name>.json and marks it active. Successful direct action commands append ordered steps to every active flow. visor record <name> --stop closes the flow so it can be replayed.
Recording is privacy-preserving by default: typed act --name type values are redacted from the flow, and map, observation, and screen metadata are not persisted into .visor/flows/*.json. Use --record-values only when you intentionally want typed values saved for replay. Starting a recording fails if a flow with the same name already exists; pass --force to overwrite it.
replay
Purpose: run a recorded flow through the normal scenario runner.
Required input:
name
devicetimeoutoutputserver-urlapp-idattachno-maprepairparamaskey=value
replay converts recorded steps into a generated scenario and runs it through the Appium-backed daemon path. --param query=shoes substitutes {{query}} placeholders in recorded args before execution. Replay responses list substituted names in data.param_keys and do not echo parameter values.
Scenario commands
validate
Purpose: parse a scenario and return validation issues.
Required input:
scenario
validissues
- returns success when the scenario is valid
- returns a non-zero exit code with
status: okwhen the scenario is syntactically valid JSON but fails schema validation - returns a failure envelope when parsing fails or the file cannot be read
run
Purpose: execute one scenario, evaluate assertions, and write reports.
Required input:
scenario
devicetimeoutoutputserver-urlapp-idattachruntime, with valuesappiumorlocalno-map
runwarnings
run object contains the full run result, including step results, assertion results, artifacts, determinism signature, and run-level error data.
For Appium-backed scenario runs, run visor start first.
For deterministic local development checks, pass --runtime local. This runs the scenario against Visor’s local fixture runtime, writes normal reports and artifacts, and does not require Appium, a daemon, an emulator, a simulator, or a real app.
When mapped execution is enabled, the run also includes map metadata and any hidden route or repair decisions in step details.
benchmark
Purpose: run one scenario repeatedly and compute a determinism score.
Required input:
scenario
runswith default20thresholdwith default95.0devicetimeoutoutputserver-urlapp-idattachcompare-map
runsthresholddeterminismScorepassfailuresrunIdswarningsvariantswhencompare-mapis enabled
--runtime local; use run with --runtime local for deterministic local harness checks.
Use --compare-map to run the same scenario twice per iteration group: once with app-map reads and writes disabled, and once with app-map enabled. Each entry in variants includes name, mapEnabled, runs, threshold, determinismScore, pass, failures, and runIds.
For benchmark runs, run visor start first.
report
Purpose: return guidance about where run reports are stored.
Optional input:
path, which defaults toartifacts
messagepathformat
Runtime lifecycle commands
start
Purpose: start the Visor daemon and ensure Appium is reachable.
Optional inputs:
server-urlappium-cmd
serverUrldaemonappium
daemon includes process and diagnostic metadata such as running, pid, socketPath, metadataPath, logPath, packageVersion, runtimeVersion, currentPackageVersion, and stale. When visor start finds an already-running daemon whose package version differs from the current CLI package version, or whose package version is unknown, daemon.stale is true and the response includes daemon.warning and daemon.nextAction.
status
Purpose: report Visor daemon state, Appium reachability, and warm sessions.
Optional inputs:
server-url
serverUrldaemonappium
daemon.packageVersion and daemon.runtimeVersion describe the running daemon process. daemon.currentPackageVersion describes the CLI process that produced the status response. If those package versions differ, or the daemon does not report a package version and is shown as unknown, daemon.stale is true, daemon.warning explains the mismatch, and daemon.nextAction is restart. Visor reports this state but does not automatically restart the daemon.
stop
Purpose: close warm sessions and stop the Visor daemon.
Optional inputs:
server-urlforce
serverUrlstoppeddaemonappium
Response envelope behavior
Every command returns the same top-level envelope fields:statuscommand_idstarted_atended_atartifactsnext_actionerrordata
next_action is a hint, not an execution chain. Examples include run, report, and none.
Help and version output are the exceptions: visor --help, visor -h, and no-command invocation print usage text instead of an envelope, while visor --version and visor -v print the package version.