kane-cli testrun run --remote dispatches a suite of _test.md files to HyperExecute instead of running it on your machine. The grid provisions the runtime, runs every member, and streams the job back to your terminal: one job, one exit code, one sealed evidence pack, and the same recordings and evidence you get from a run on your own machine.
Remote runs cover both kinds of test:
- Web suites run on Chrome on a HyperExecute macOS runner, with no Chrome on your machine or CI runner, headless by construction, and
--parallel Nspreads the members across N grid runners. - Mobile suites (
target: emulatorortarget: simulator) run on a virtual Android emulator or iOS simulator on a HyperExecute macOS host, so you can author and run mobile tests from any machine: Linux, Windows, Intel Macs, or a Mac without Xcode or Android Studio. The macOS Apple Silicon requirement applies only to mobile runs on your own machine.
--remote is not the same as --ws-endpoint or --cdp-endpoint. Those attach a remote browser to a run that still executes on your machine (kane-cli run, kane-cli testmd run). --remote moves the whole suite to the grid: kane-cli itself runs there, and nothing but Node and the plugin is needed locally.Prerequisites
The project and folder the run uploads to are the ones configured on your profile (
kane-cli config project and kane-cli config folder); they are passed to the grid’s login.
How a remote run works
- Preflight, then remote preflight. The normal
testrunplan is built (one organisation, one project, see Preflight); then kane-cli checks the selection can be one grid job (What one job can hold) and, for mobile, resolves the device against the grid catalog. Anything wrong stops here, nothing is dispatched, exit2. - Payload. The current directory is zipped (respecting
.gitignore) and uploaded with a generated job definition. The dispatch leaves.hyperexecute/,hyperexecute-cli.logand.updatedhyperexecute.yamlin that directory: add them to.gitignore, they are not inputs. - On the grid (a macOS runner): a pre-step installs kane-cli and logs in with your credentials and project; for mobile it installs the device tooling and boots the device. Then each member runs as its own
kane-cli testmd run, headless, exactly as it would on your machine. A member with recordings replays them, a member without authors on the grid. - Back to you. The job streams progress and the dashboard link to your terminal. When it ends, the members’
output-<stem>/recordings and the sealed evidence pack are downloaded into your project, the pack is published to Test Manager, and the suite summary and exit code are the same as a localtestrun.
Dispatching a run
--remote takes the normal testrun selection (paths, --match, --tags).
--dry-run runs both preflights and resolves any device without creating a job. Use it before every new selection; it costs nothing.
A real run prints the job id and dashboard link, then tracks the job until it completes:
Web suites on the grid
A web suite needs nothing beyond the prerequisites: the grid runner has Chrome, kane-cli finds it and runs each member headless. Use it when the runner cannot have Chrome, when you want the suite off your laptop, or when you want more parallelism than one machine gives you.testrun summary; the only extra lines are the dispatch and the job link. A member that authors on the grid comes back with its output-<stem>/ recordings, so the next run, on the grid or on your machine, replays them. Commit those recordings as you would after a local run.
A web selection cannot share a job with device members (mobile_remote_mixed). Run the two suites separately.
Choosing a grid device
Remote devices come from the grid catalog, not from the AVDs or simulators on your machine. List what the grid can provision:
If you pass neither, kane-cli picks a catalog default for the platform and prints it on the device line. Read it before relying on it.
The two platforms bind the device differently:
- Emulator: the job allocates one device for all its members, so they must agree on one Android version (
mobile_os_version_splitotherwise, or force one with--os-version). An AVD name from your own machine is ignored in a member (you get adevice_name_ignorednote), because a remote job’s device is named by the catalog. - Simulator: each task boots a simulator inside its own VM, so each member binds its own
device_name:andos_version:(validated against the catalog).--device-nameand--os-version, when passed, apply to every member. Members may ask for different iOS versions as long as their iOS majors map to one HyperExecute pool, which the catalog decides (today 17 and 18 share one, 26 is another); otherwisemobile_pool_split.
The app under test on the grid
The grid machine has to obtain the app. A build never rides the payload, it reaches the grid by id:
Each member gets its own id, so a run may hold members that name different builds. A
.ipa is refused up front: it is a device build, and the emulator and simulator upload does not take it. Every upload is reported (app: <file> → APP… (uploaded), or the remote_app event for agents).
kane-cli apps list --target emulator|simulator shows the uploaded builds your account can use, and the APP ID column is what app: takes. There is no upload subcommand: any run with a local build, on the grid or on your machine, uploads it and prints the APP… id. Uploads belong to an organisation, so apps list for the current profile is the authority on which ids a run can use.
What one job can hold
One remote run is one HyperExecute job, which allocates one kind of runtime. The remote preflight refuses a selection that needs more than one, and tells you how to split it (--match or --tags):
Every reason arrives with the offending paths, both in the terminal and as a
remote_error event for agents.
What comes back
- Recordings: authored members’
output-<stem>/directories land in your project exactly as a run on your machine would leave them, so the next run replays from cache. - Evidence: one sealed pack for the suite in
.testmuai/evidence/, published to your project’s execution history in Test Manager. - Job logs: the per-member session logs under
~/.testmuai/kaneai/sessions/remote/<job-id>/, and the full stage logs on the HyperExecute dashboard at the printed job link. - Exit code: the same as a local
testrun.0all passed,1a member failed or broke,2preflight, auth or usage (nothing dispatched),3cancelled.
When a remote run fails
- A member failed or broke (exit
1): read it like any other failure.output-<stem>/Result.mdnames the failing step and reason, and the evidence pack has the screenshots and logs. See Debugging with a pack. - A member is
brokenwith no steps and nothing was published: the grid-side kane-cli refused before launching. Open the job link and read the scenario stage log. For mobile, the usual cause is anAPP…id that belongs to a different organisation than the account running the job. - Nothing was dispatched (exit
2): the printed reason is one of the preflight codes above, orkane-cli plugin doctor remote-executionshows what is missing (plugin, binary, login).
In CI
A remote run needs no Chrome, Xcode or Android Studio on the runner, only Node and the plugin:.testmuai/evidence/*.evidence as the build artifact. More pipeline shapes are in CI/CD.
For agents: NDJSON events
In agent or non-TTY mode a remote run adds typed events around the normaltestrun_* stream (see For agents):
testrun_summary also carries a remote object (backend, jobId, jobUrl, sessionsPath).
Next Steps
- Batch Runs (testrun) for selection, preflight, flags and exit codes
- Mobile Testing for setup on your own machine, or skip it with
--remote - Writing test.md files for
target:,app:,device_name:andos_version: - Evidence Packs for what comes back and how to view it
- CI/CD for pipeline patterns, including runners with no Chrome