zeno-mobile-runner 0.2.15 → 0.2.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/CONTRIBUTING.md +20 -7
  3. package/FEATURES.md +29 -20
  4. package/README.md +73 -57
  5. package/SECURITY.md +11 -6
  6. package/clients/README.md +8 -7
  7. package/clients/go/README.md +2 -2
  8. package/clients/kotlin/README.md +2 -2
  9. package/clients/kotlin/build.gradle.kts +1 -1
  10. package/clients/python/README.md +2 -1
  11. package/clients/python/pyproject.toml +1 -1
  12. package/clients/rust/Cargo.lock +1 -1
  13. package/clients/rust/Cargo.toml +1 -1
  14. package/clients/rust/README.md +2 -2
  15. package/clients/swift/README.md +2 -2
  16. package/clients/typescript/README.md +2 -1
  17. package/clients/typescript/package.json +1 -1
  18. package/docs/adr/0001-agent-native-runner-boundary.md +1 -1
  19. package/docs/adr/README.md +7 -5
  20. package/docs/agent-discovery.md +15 -15
  21. package/docs/ai-agents.md +30 -20
  22. package/docs/app-integration.md +59 -27
  23. package/docs/benchmarking.md +16 -8
  24. package/docs/benchmarks/README.md +3 -1
  25. package/docs/benchmarks/benchmark-lab-v1.md +1 -1
  26. package/docs/client-installation.md +18 -9
  27. package/docs/clients.md +7 -6
  28. package/docs/config.md +29 -15
  29. package/docs/demo.md +14 -9
  30. package/docs/expo-smoke.md +12 -18
  31. package/docs/frameworks.md +30 -21
  32. package/docs/install.md +63 -13
  33. package/docs/npm.md +45 -27
  34. package/docs/production-readiness.md +32 -17
  35. package/docs/protocol-fixtures/core-session.responses.jsonl +1 -1
  36. package/docs/protocol-versioning.md +5 -3
  37. package/docs/protocol.md +33 -18
  38. package/docs/scenario-authoring.md +15 -8
  39. package/docs/support-matrix.md +38 -0
  40. package/docs/trace-privacy.md +5 -3
  41. package/docs/troubleshooting.md +17 -14
  42. package/npm/app-config.mjs +2 -0
  43. package/npm/commands.mjs +4 -4
  44. package/npm/scaffold.mjs +2 -2
  45. package/package.json +2 -2
  46. package/prebuilds/darwin-arm64/zmr +0 -0
  47. package/prebuilds/darwin-x64/zmr +0 -0
  48. package/prebuilds/linux-arm64/zmr +0 -0
  49. package/prebuilds/linux-x64/zmr +0 -0
  50. package/schemas/README.md +6 -3
  51. package/schemas/import-output.schema.json +1 -1
  52. package/schemas/scenario.schema.json +2 -0
  53. package/schemas/zmr-config.schema.json +2 -1
  54. package/scripts/install-ios-shim.sh +39 -4
  55. package/scripts/public-metadata-guard.sh +101 -0
  56. package/shims/android/README.md +4 -3
  57. package/shims/android/protocol.md +3 -2
  58. package/shims/ios/README.md +8 -7
  59. package/shims/ios/ZMRShimUITestCase.swift +58 -17
  60. package/shims/ios/protocol.md +2 -1
  61. package/skills/zmr-mobile-testing/SKILL.md +9 -8
  62. package/src/android_emulator.zig +54 -5
  63. package/src/cli_import.zig +15 -2
  64. package/src/cli_output.zig +2 -0
  65. package/src/cli_run.zig +8 -0
  66. package/src/config.zig +3 -0
  67. package/src/errors.zig +3 -0
  68. package/src/ios_devices.zig +100 -0
  69. package/src/main.zig +1 -1
  70. package/src/mcp_protocol.zig +12 -9
  71. package/src/run_options.zig +4 -0
  72. package/src/scaffold.zig +10 -8
  73. package/src/scenario.zig +43 -0
  74. package/src/selector.zig +53 -9
  75. package/src/trace_json.zig +4 -0
  76. package/src/validation.zig +5 -0
  77. package/src/version.zig +1 -1
package/docs/config.md CHANGED
@@ -1,16 +1,18 @@
1
1
  # App-Local Config
2
2
 
3
- ZMR uses `.zmr/config.json` as the app-local source of truth for default app ids,
4
- devices, scenario paths, and trace directories.
3
+ Use `.zmr/config.json` to keep app-specific defaults in the app repository:
4
+ app ids, device targets, scenario paths, trace directories, artifact settings,
5
+ redaction rules, and shim command paths.
5
6
 
6
- The schema is published at `schemas/zmr-config.schema.json`.
7
- Runtime parsing follows the schema for primitive field types. For example,
7
+ The schema is published at `schemas/zmr-config.schema.json`. Runtime parsing
8
+ follows the schema for primitive field types. For example,
8
9
  boolean fields such as `artifacts.screenRecording`, `artifacts.screenshots`,
9
- `android.resetBeforeRun`, and `android.waitReady` must be JSON booleans, not
10
- strings. Path, id, redaction-list, and script command string fields must be
11
- non-empty. `zmr doctor --json --config .zmr/config.json` reports those type/value mistakes as
12
- structured `config` warnings. Unknown fields are rejected too, so typos in
13
- app-local config do not silently fall back to defaults.
10
+ `android.resetBeforeRun`, `android.waitReady`, and `ios.ensureDevice` must be
11
+ JSON booleans, not strings. Path, id, redaction-list, and script command string
12
+ fields must be non-empty. `zmr doctor --json --config .zmr/config.json`
13
+ reports those type/value mistakes as structured `config` warnings. Unknown
14
+ fields are rejected too, so typos in app-local config do not silently fall back
15
+ to defaults.
14
16
 
15
17
  Example:
16
18
 
@@ -29,13 +31,15 @@ Example:
29
31
  "avdSystemImage": "system-images;android-35;google_apis;arm64-v8a",
30
32
  "avdDeviceProfile": "pixel_6",
31
33
  "resetBeforeRun": false,
32
- "waitReady": true
34
+ "waitReady": true,
35
+ "ensureDevice": true
33
36
  },
34
37
  "ios": {
35
38
  "enabled": true,
36
39
  "defaultDevice": "booted",
37
40
  "smokeScenario": ".zmr/ios-smoke.json",
38
- "traceDir": "traces/zmr-ios"
41
+ "traceDir": "traces/zmr-ios",
42
+ "ensureDevice": true
39
43
  },
40
44
  "artifacts": {
41
45
  "screenshots": true,
@@ -68,12 +72,13 @@ invoked from another checkout. Relative optional tool commands such as
68
72
  `tools.adbPath` are resolved the same way when they look like paths; bare
69
73
  commands such as `adb`, `xcrun`, or `zig` stay as PATH lookups.
70
74
 
71
- Explicit CLI flags always win:
75
+ Explicit CLI flags always win. Use config for stable app defaults and CLI flags
76
+ for one-off local or CI overrides:
72
77
 
73
78
  - `--app-id` overrides `appId`
74
79
  - `--device` overrides platform `defaultDevice`
75
80
  - `--trace-dir` overrides platform `traceDir`
76
- - `--android-avd`, `--create-avd-if-missing`, `--avd-system-image`, `--avd-device`, `--restore-snapshot`, `--reset-emulator`, and `--wait-emulator` override Android emulator lifecycle defaults
81
+ - `--android-avd`, `--create-avd-if-missing`, `--avd-system-image`, `--avd-device`, `--restore-snapshot`, `--reset-emulator`, `--wait-emulator`, `--ensure-device`, and `--no-ensure-device` override device lifecycle defaults
77
82
  - `--screen-record` and `--no-screen-record` override `artifacts.screenRecording`
78
83
  - a positional scenario path overrides platform `smokeScenario`
79
84
  - `--adb`, `--emulator`, `--avdmanager`, `--android-shim`, `--xcrun`, `--ios-shim`, and `--zig` override optional tool paths
@@ -83,6 +88,9 @@ Explicit CLI flags always win:
83
88
  The Android platform config can boot and wait for an emulator before a traced
84
89
  `zmr run` starts:
85
90
 
91
+ - `ensureDevice`: when the requested Android device is not ready, boot the
92
+ configured `avdName`; if no `avdName` is configured, boot the first local AVD
93
+ from `emulator -list-avds`, then wait for `sys.boot_completed=1`.
86
94
  - `avdName`: AVD name passed to the Android emulator.
87
95
  - `createAvdIfMissing`: check `emulator -list-avds` and create the AVD when absent.
88
96
  - `avdSystemImage`: installed Android system image package for `avdmanager create avd`.
@@ -91,12 +99,18 @@ The Android platform config can boot and wait for an emulator before a traced
91
99
  - `resetBeforeRun`: best-effort `adb emu kill` before booting the configured AVD.
92
100
  - `waitReady`: wait for `adb wait-for-device` and `sys.boot_completed=1`.
93
101
 
94
- The equivalent CLI flags are `--android-avd <name>`,
102
+ The equivalent CLI flags are `--ensure-device`, `--no-ensure-device`,
103
+ `--android-avd <name>`,
95
104
  `--create-avd-if-missing`, `--avd-system-image <package>`,
96
105
  `--avd-device <profile>`, `--restore-snapshot <name>`, `--reset-emulator`,
97
106
  and `--wait-emulator`. AVD creation, snapshot restore, and reset require an AVD
98
107
  name. AVD creation also requires an installed system image package.
99
108
 
109
+ For iOS simulator runs, `ensureDevice` or `--ensure-device` reuses an already
110
+ booted simulator when one exists. If the target is `booted` and none are
111
+ running, ZMR boots the first available shutdown simulator and waits for
112
+ `simctl bootstatus -b`. Physical iOS devices are never auto-booted.
113
+
100
114
  ## Android Shim
101
115
 
102
116
  Set `tools.androidShimPath` when an app repo has built or installed an Android
@@ -127,7 +141,7 @@ CLI `--ios-shim <path>` takes precedence over the config value for `zmr run`,
127
141
  ## Artifact Capture
128
142
 
129
143
  The `artifacts` object controls what raw trace artifacts are persisted during
130
- `zmr run`.
144
+ `zmr run`. Turn off raw artifacts when traces might leave a trusted machine.
131
145
 
132
146
  - `screenshots`: write PNG screenshot artifacts.
133
147
  - `hierarchy`: write raw Android UI hierarchy XML artifacts.
package/docs/demo.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Demo
2
2
 
3
- Run the local demo with no emulator, simulator, app, or credentials:
3
+ Run the local demo when you want a fast proof of the CLI, schemas, fake-device
4
+ flows, reference clients, trace output, and diagnostics without an emulator,
5
+ simulator, app build, or credentials:
4
6
 
5
7
  ```bash
6
8
  ./scripts/demo.sh
@@ -94,14 +96,15 @@ snapshot handling.
94
96
  Load any generated `.zmrtrace` in `viewer/index.html` to inspect the replay
95
97
  timeline, payloads, screenshot, UI tree, selected node details, and raw
96
98
  artifacts side-by-side. When the viewer and the bundle are served over HTTP,
97
- link straight to a loaded trace with `viewer/index.html?bundle=<url>` useful
98
- for CI artifact links and shared triage.
99
+ link straight to a loaded trace with `viewer/index.html?bundle=<url>`, which is
100
+ useful for CI artifact links and shared triage.
99
101
 
100
102
  ![ZMR trace viewer with a loaded Android demo trace showing the timeline, device screenshot, and UI tree](assets/viewer-android.png)
101
103
 
102
104
  ## Real Android Pilot Demo
103
105
 
104
- Run the Android pilot against a sample app test build:
106
+ Run the Android pilot against a sample app test build when you want real
107
+ emulator/device evidence:
105
108
 
106
109
  ```bash
107
110
  ./scripts/run-android-pilot.sh \
@@ -109,11 +112,13 @@ Run the Android pilot against a sample app test build:
109
112
  --device emulator-5554
110
113
  ```
111
114
 
112
- To force a known emulator state, direct `zmr run` supports `--android-avd`,
113
- `--create-avd-if-missing`, `--avd-system-image`, `--avd-device`,
114
- `--restore-snapshot`, `--reset-emulator`, and `--wait-emulator`. The pilot
115
- wrapper accepts the same state controls while also building/installing the app.
116
- Add `--screen-record` to keep a pilot-level MP4 under the trace root:
115
+ Direct `zmr run --ensure-device` can boot an Android emulator or iOS simulator
116
+ before the scenario starts. To force a known Android emulator state, direct
117
+ `zmr run` also supports `--android-avd`, `--create-avd-if-missing`,
118
+ `--avd-system-image`, `--avd-device`, `--restore-snapshot`,
119
+ `--reset-emulator`, and `--wait-emulator`. The pilot wrapper accepts the same
120
+ state controls while also building/installing the app. Add `--screen-record` to
121
+ keep a pilot-level MP4 under the trace root:
117
122
 
118
123
  ```bash
119
124
  ./scripts/run-android-pilot.sh \
@@ -1,9 +1,9 @@
1
1
  # Expo Smoke Test
2
2
 
3
- This is the quickest public smoke path for an Expo app. It proves that the npm
4
- package installs, the wizard scaffolds a scenario, ZMR can launch an iOS app,
5
- and the runner can produce screenshots, traces, HTML reports, JUnit XML, and
6
- redacted trace bundles.
3
+ This is the quickest public smoke path for an Expo app. It proves the
4
+ framework-neutral ZMR binary install, app-local scaffold, iOS app launch,
5
+ screenshot capture, trace collection, HTML reporting, JUnit XML, and redacted
6
+ export.
7
7
 
8
8
  Run the flow below on a local iOS simulator before treating a specific app build
9
9
  as validated.
@@ -11,12 +11,11 @@ as validated.
11
11
  ```bash
12
12
  npx create-expo-app@latest /tmp/zmr-expo-smoke --template blank --yes
13
13
  cd /tmp/zmr-expo-smoke
14
- npm install --save-dev zeno-mobile-runner
14
+ curl -fsSL https://raw.githubusercontent.com/johnmikel/zeno-mobile-runner/main/install.sh | sh
15
+ export PATH="$HOME/.local/bin:$PATH"
15
16
 
16
- npx zmr-wizard --yes --dir . \
17
- --app-id com.example.zenoexposmoke \
18
- --ios \
19
- --package-json
17
+ zmr init --app --dir . \
18
+ --app-id com.example.zenoexposmoke
20
19
  ```
21
20
 
22
21
  Boot a simulator, then build and launch the app:
@@ -29,14 +28,14 @@ npx expo run:ios --device <simulator-name>
29
28
  Run the generated ZMR scenario:
30
29
 
31
30
  ```bash
32
- npx zmr run .zmr/ios-smoke.json \
31
+ zmr run .zmr/ios-smoke.json \
33
32
  --platform ios \
34
33
  --device booted \
35
34
  --trace-dir traces/zmr-ios \
36
35
  --json
37
36
 
38
- npx zmr report traces/zmr-ios --out traces/zmr-ios/report.html --junit traces/zmr-ios/junit.xml
39
- npx zmr export traces/zmr-ios --out traces/zmr-ios-redacted.zmrtrace --redact
37
+ zmr report traces/zmr-ios --out traces/zmr-ios/report.html --junit traces/zmr-ios/junit.xml
38
+ zmr export traces/zmr-ios --out traces/zmr-ios-redacted.zmrtrace --redact
40
39
  ```
41
40
 
42
41
  Expected result shape:
@@ -62,12 +61,7 @@ the XCTest shim described in [app integration](app-integration.md).
62
61
  Android follows the same pattern with a connected emulator or device:
63
62
 
64
63
  ```bash
65
- npx zmr-wizard --yes --dir . \
66
- --app-id com.example.zenoexposmoke \
67
- --android \
68
- --package-json
69
-
70
- npx zmr run .zmr/android-smoke.json \
64
+ zmr run .zmr/android-smoke.json \
71
65
  --platform android \
72
66
  --device emulator-5554 \
73
67
  --trace-dir traces/zmr-android \
@@ -2,25 +2,31 @@
2
2
 
3
3
  ZMR drives the installed mobile app through Android and iOS automation surfaces.
4
4
  It does not require a React Native, Expo, Flutter, Swift, Kotlin, or Java test
5
- SDK inside the app. The app only needs stable selectors and a predictable way to
6
- reach the screens you want to test.
5
+ SDK inside the app. The app only needs stable selectors, predictable navigation,
6
+ and build artifacts that ZMR can install or launch.
7
7
 
8
8
  ## React Native
9
9
 
10
- Use app-owned selectors for controls that agents need to find:
10
+ Use app-owned selectors for controls that agents need to find repeatedly:
11
11
 
12
12
  - `testID` for Android resource ids and iOS accessibility identifiers.
13
- - `accessibilityLabel` for user-facing controls that should be visible to assistive technology.
14
- - Stable visible text for headings, tabs, and actions that are not localized or data-driven.
13
+ - `accessibilityLabel` for user-facing controls that should be visible to
14
+ assistive technology.
15
+ - Stable visible text for headings, tabs, and actions that are not localized or
16
+ data-driven.
15
17
  - Deep links for jumping directly to logged-in, onboarding, or error states.
16
18
 
17
- Keep generated ZMR files under `.zmr/` and run the wizard from the app repo:
19
+ Keep generated ZMR files under `.zmr/` and initialize ZMR from the app repo:
18
20
 
19
21
  ```bash
20
- npx zmr-wizard --app-id com.example.mobiletest --package-json
22
+ zmr init --app --app-id com.example.mobiletest
21
23
  ```
22
24
 
23
- To inspect a generated public fixture with a longer workflow:
25
+ JavaScript teams that want generated package scripts can use
26
+ `npx zmr-wizard --app-id com.example.mobiletest --package-json` instead.
27
+
28
+ To inspect a generated public fixture with a longer workflow, use the npm
29
+ helper from a JavaScript toolchain:
24
30
 
25
31
  ```bash
26
32
  npx zmr-create-react-native-expo-demo-app --out /tmp/zmr-rn-expo-demo
@@ -32,9 +38,11 @@ values, accessibility labels, and Android/iOS ZMR workflow scenarios under
32
38
 
33
39
  ## Expo
34
40
 
35
- Expo development builds work like React Native apps once they are installed on a
36
- simulator, emulator, or device. For dev-client flows, give ZMR the scheme that
37
- opens your development build:
41
+ Expo development builds work like React Native apps once they are installed on
42
+ an emulator, simulator, or device. `zmr init --app` creates baseline Android
43
+ and iOS smoke scenarios. For dev-client flows that need generated open-link
44
+ scenarios, use the JavaScript wizard and give ZMR the scheme that opens the
45
+ development build:
38
46
 
39
47
  ```bash
40
48
  npx zmr-wizard \
@@ -43,15 +51,15 @@ npx zmr-wizard \
43
51
  --package-json
44
52
  ```
45
53
 
46
- The wizard adds Android and iOS dev-client scenarios that open Metro before
47
- selector assertions run.
54
+ The wizard adds Android and iOS dev-client scenarios that open Metro
55
+ before selector assertions run. For CI, prefer a known Metro command, stable
56
+ deep link, and a prebuilt development client.
48
57
 
49
58
  ## Flutter
50
59
 
51
- ZMR supports Flutter apps at the platform level. It can launch the Android or
52
- iOS app, open deep links, wait for accessibility semantics, tap visible
53
- controls, type text, take screenshots, collect traces, and export redacted
54
- artifacts.
60
+ ZMR supports Flutter apps at the Android/iOS app level. It can launch the app,
61
+ open deep links, wait for accessibility semantics, tap visible controls, type
62
+ text, take screenshots, collect traces, and export redacted artifacts.
55
63
 
56
64
  ZMR does not inspect Flutter widget trees, read Dart state, or replace Flutter's
57
65
  own widget/integration test APIs. For reliable ZMR scenarios, expose stable
@@ -66,8 +74,9 @@ Semantics(
66
74
  ```
67
75
 
68
76
  Prefer app-owned semantics labels for form fields, primary buttons, tabs, and
69
- important states. Deep links are the cleanest way to skip setup screens and reach
70
- the state an agent needs to inspect.
77
+ important states. Deep links are the cleanest way to skip setup screens and
78
+ reach the state an agent needs to inspect. Do not describe ZMR as a Flutter
79
+ widget-tree driver.
71
80
 
72
81
  ## Native Android And iOS
73
82
 
@@ -76,7 +85,7 @@ Native apps should expose:
76
85
  - Android `resourceId` values or content descriptions for important controls.
77
86
  - iOS accessibility identifiers or labels for important controls.
78
87
  - Deep links for direct navigation into test states.
79
- - Optional Android and iOS shims when native selector actions and bounded
80
- hierarchy snapshots are needed.
88
+ - Optional Android and iOS/iPadOS shims when native selector actions and
89
+ bounded hierarchy snapshots are needed.
81
90
 
82
91
  See [app-integration.md](app-integration.md) for the shim setup commands.
package/docs/install.md CHANGED
@@ -1,10 +1,52 @@
1
1
  # Install
2
2
 
3
- Most mobile app teams should install ZMR from npm inside the app repository.
4
- That keeps `.zmr/` config, scenarios, generated package scripts, and traces with
5
- the app they belong to.
3
+ Install ZMR where the mobile app lives. That keeps `.zmr/` config, scenarios,
4
+ generated package scripts, and trace output next to the app they verify.
6
5
 
7
- ## npm Install
6
+ Use the curl installer for the framework-neutral path. It installs the native
7
+ `zmr` binary from the GitHub release archive for your OS and CPU, verifies the
8
+ archive against `SHA256SUMS`, and leaves app setup to `zmr init --app`. npm
9
+ remains the convenience path for JavaScript teams that want package scripts and
10
+ helper bins in `node_modules/.bin`.
11
+
12
+ ## Curl Install
13
+
14
+ Recommended path for native Android, native iOS, Flutter, React Native, Expo,
15
+ and mixed mobile repositories:
16
+
17
+ ```bash
18
+ curl -fsSL https://raw.githubusercontent.com/johnmikel/zeno-mobile-runner/main/install.sh | sh
19
+ export PATH="$HOME/.local/bin:$PATH"
20
+ zmr init --app --app-id com.example.mobiletest
21
+ zmr doctor --strict --json --config .zmr/config.json
22
+ ```
23
+
24
+ The installer defaults to the latest GitHub release. It downloads
25
+ `zmr-<version>-<target>.tar.gz` plus `SHA256SUMS` from the release, and refuses
26
+ to install when the archive checksum entry is missing or mismatched:
27
+
28
+ ```bash
29
+ ./install.sh --version 0.2.17 --dry-run
30
+ ```
31
+
32
+ Dry-run output includes `checksum-verification: required`, the selected
33
+ platform target, the archive URL, and the checksum URL. Use
34
+ `--install-dir <dir>` to install somewhere other than `~/.local/bin`, or
35
+ `--base-url <url>` when testing release candidates from a staging bucket.
36
+
37
+ The native binary works the same way regardless of app framework:
38
+
39
+ ```bash
40
+ zmr validate .zmr/android-smoke.json
41
+ zmr run .zmr/android-smoke.json --device emulator-5554 --trace-dir traces/zmr-android --ensure-device
42
+ zmr mcp --config .zmr/config.json --trace-dir traces/zmr-agent
43
+ ```
44
+
45
+ ## JavaScript Teams
46
+
47
+ Use npm when the app repo wants ZMR pinned as a dev dependency, generated npm
48
+ scripts, and the helper commands such as `zmr-wizard`,
49
+ `zmr-install-android-shim`, `zmr-install-ios-shim`, and `zmr-device-matrix`:
8
50
 
9
51
  ```bash
10
52
  npm install --save-dev zeno-mobile-runner
@@ -13,8 +55,8 @@ npx zmr doctor --strict --json --config .zmr/config.json
13
55
  ```
14
56
 
15
57
  The wizard creates `.zmr/config.json`, Android and iOS smoke scenarios,
16
- `.zmr/device-matrix.json`, and `.zmr/AGENTS.md`. Run the generated validation
17
- before touching a device:
58
+ `.zmr/device-matrix.json`, `.zmr/AGENTS.md`, and optional package scripts. Run
59
+ the generated validation before touching a device:
18
60
 
19
61
  ```bash
20
62
  npm run zmr:validate
@@ -36,14 +78,17 @@ app-local `.zmr/` setup.
36
78
 
37
79
  ## Homebrew Or Existing Binary
38
80
 
39
- Teams that do not use JavaScript can install or build the `zmr` executable once
40
- and point any language client or script at it:
81
+ Homebrew remains a native install option once you have a generated formula from
82
+ the release artifacts:
41
83
 
42
84
  ```bash
43
85
  brew install --build-from-source ./dist/homebrew/zmr.rb
44
86
  zmr version
45
87
  ```
46
88
 
89
+ Any existing `zmr` binary can also be used by language clients, MCP configs, or
90
+ scripts as long as it matches the protocol version expected by the app repo.
91
+
47
92
  ## Build From Source
48
93
 
49
94
  ```bash
@@ -60,6 +105,9 @@ verification path used by CI and release gates.
60
105
 
61
106
  ## First Run Without A Device
62
107
 
108
+ These commands prove the binary, schemas, and fake-device demo before device
109
+ or simulator setup enters the loop:
110
+
63
111
  ```bash
64
112
  zmr version --json
65
113
  zmr schemas --json
@@ -71,8 +119,8 @@ zmr validate examples/demo-fake.json
71
119
 
72
120
  ## App Codebase Integration
73
121
 
74
- ZMR runs outside the app process and points at app build artifacts. For real app
75
- pilots, pass the app root, app id, target device, and optional shim paths:
122
+ ZMR runs outside the app process and points at app build artifacts. For a real
123
+ app pilot, pass the app root, app id, target device, and optional shim paths:
76
124
 
77
125
  ```bash
78
126
  npx zmr-pilot-gate \
@@ -91,6 +139,8 @@ npx zmr-pilot-gate \
91
139
  --evidence-out traces/zmr-pilots/evidence.jsonl
92
140
  ```
93
141
 
94
- See [app-integration.md](app-integration.md), [frameworks.md](frameworks.md),
95
- and [config.md](config.md) for framework guidance, shim setup, `.zmr/config.json`
96
- defaults, and CLI override precedence.
142
+ Next:
143
+
144
+ - [app-integration.md](app-integration.md): app-side test surface and shims
145
+ - [frameworks.md](frameworks.md): React Native, Expo, Flutter, and native apps
146
+ - [config.md](config.md): `.zmr/config.json` defaults and CLI precedence
package/docs/npm.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # npm Package
2
2
 
3
- ZMR can be installed in a mobile app codebase as a dev dependency:
3
+ Install the npm package inside a mobile app repo when you want the `zmr` binary,
4
+ setup wizard, app-local scripts, schemas, examples, clients, and agent skill to
5
+ version with the app:
4
6
 
5
7
  ```bash
6
8
  npm install --save-dev zeno-mobile-runner
7
9
  ```
8
10
 
9
- The package exposes:
11
+ The package exposes these command surfaces:
10
12
 
11
13
  - `zmr`: CLI binary wrapper.
12
14
  - `zmr-init`: app-local scenario scaffolder.
@@ -44,8 +46,8 @@ The package exposes:
44
46
  - packaged docs, schemas, examples, reference clients, and the reusable
45
47
  `skills/zmr-mobile-testing` agent skill.
46
48
 
47
- Most app teams can start with `zmr-wizard`, generated smoke scenarios, and
48
- redacted traces. Use the pilot and readiness helpers when you want repeated
49
+ JavaScript app teams should start with `zmr-wizard`, generated smoke scenarios,
50
+ and redacted traces. Use pilot and readiness helpers when you need repeated
49
51
  local evidence for your own app and devices.
50
52
 
51
53
  ## App Setup
@@ -67,25 +69,39 @@ This creates:
67
69
  AGENTS.md
68
70
  ```
69
71
 
70
- `.zmr/config.json` is the app-local source of truth for default devices, trace directories, smoke scenario paths, and suggested script commands. `.zmr/device-matrix.json` gives CI a ready Android/iOS matrix starting point. ZMR auto-discovers config from the app repo, and explicit CLI flags override it. The wizard does not inspect or depend on any other mobile test runner configuration.
71
- `.zmr/AGENTS.md` gives AI agents an app-local operating note with strict
72
- doctor/validate commands, schema discovery, direct `zmr run` smoke commands,
73
- JSON-RPC and MCP startup commands, selector guidance, the exact
74
- `zmr discover --from-trace traces/zmr-agent --out .zmr/discovered/replay-smoke.json --include-actions --validate --json`
75
- trace-to-test command,
76
- `zmr explain traces/zmr-agent --json` failure-triage command, the exact
77
- `zmr export traces/zmr-agent --out traces/zmr-agent-redacted.zmrtrace --redact`
78
- redacted trace export command.
79
- `zmr-init` and wizard runs without `--package-json` write direct commands in `.zmr/AGENTS.md` so agents can execute the generated guidance immediately.
80
- `zmr-init` accepts the same platform, shim, and Expo dev-client scaffold flags as the wizard, plus `--package-json` for non-interactive app templates that do not need dependency checks.
81
- `zmr-init` prints direct `Next steps` commands before the package-script snippet so humans and agents can run the generated smoke, reliability, matrix, pilot, JSON-RPC, MCP, failure-triage, and redacted-export commands without editing `package.json`.
72
+ `.zmr/config.json` is the app-local source of truth for default devices, trace
73
+ directories, smoke scenario paths, and suggested script commands.
74
+ `.zmr/device-matrix.json` gives CI a ready Android/iOS matrix starting point.
75
+ ZMR auto-discovers config from the app repo, and explicit CLI flags override it.
76
+ The wizard does not inspect or depend on any other mobile test runner
77
+ configuration.
78
+
79
+ `.zmr/AGENTS.md` gives AI agents an app-local operating note with:
80
+
81
+ - strict doctor and validation commands
82
+ - schema discovery
83
+ - direct `zmr run` smoke commands
84
+ - JSON-RPC and MCP startup commands
85
+ - selector guidance
86
+ - trace-to-test discovery commands
87
+ - failure-triage commands
88
+ - redacted trace export commands
89
+
90
+ `zmr-init` and wizard runs without `--package-json` write direct commands in
91
+ `.zmr/AGENTS.md` so agents can execute the generated guidance immediately.
92
+ `zmr-init` accepts the same platform, shim, and Expo dev-client scaffold flags
93
+ as the wizard, plus `--package-json` for non-interactive app templates that do
94
+ not need dependency checks.
82
95
  For setup scripts and AI agents that need a machine-readable handoff, use
83
96
  `npx zmr-init --json --dir . --app-id com.example.mobiletest` or
84
97
  `npx zmr-wizard --json --dir . --app-id com.example.mobiletest --android --ios`.
85
- The JSON form is covered by `schemas/init-output.schema.json` and includes
86
- the generated config, scenario, Expo dev-client scenario, device matrix, and
98
+ The JSON form is covered by `schemas/init-output.schema.json` and includes the
99
+ generated config, scenario, Expo dev-client scenario, device matrix, and
87
100
  `AGENTS.md` paths plus `nextCommands`, `scriptCount`, and `scriptNames`.
88
- Wizard runs with `--package-json` write npm script commands in `.zmr/AGENTS.md` because the wizard installs those scripts into `package.json`. Run `npm run zmr:validate` after editing generated scenarios and before starting longer smoke, matrix, or pilot runs.
101
+ Wizard runs with `--package-json` write npm script commands in `.zmr/AGENTS.md`
102
+ because the wizard installs those scripts into `package.json`. Run
103
+ `npm run zmr:validate` after editing generated scenarios and before starting
104
+ longer smoke, matrix, or pilot runs.
89
105
 
90
106
  Add app-local scripts:
91
107
 
@@ -95,11 +111,11 @@ Add app-local scripts:
95
111
  "zmr:doctor": "zmr doctor --strict --json --config .zmr/config.json",
96
112
  "zmr:schemas": "zmr schemas --json",
97
113
  "zmr:validate": "zmr validate --json .zmr/android-smoke.json && zmr validate --json .zmr/ios-smoke.json",
98
- "zmr:android": "zmr run .zmr/android-smoke.json --device emulator-5554 --trace-dir traces/zmr-android",
114
+ "zmr:android": "zmr run .zmr/android-smoke.json --device emulator-5554 --trace-dir traces/zmr-android --ensure-device",
99
115
  "zmr:android:report": "zmr report traces/zmr-android --out traces/zmr-android/report.html --junit traces/zmr-android/junit.xml",
100
116
  "zmr:android:reliability": "export ZMR_BIN=\"${ZMR_BIN:-zmr}\"; zmr-benchmark --zmr .zmr/android-smoke.json --device emulator-5554 --app-id com.example.mobiletest --runs 20 --trace-root traces/zmr-android-reliability --min-pass-rate 100 --max-failures 0 --max-p95-ms 30000 && \"$ZMR_BIN\" report traces/zmr-android-reliability --out traces/zmr-android-reliability/report.html --junit traces/zmr-android-reliability/junit.xml",
101
117
  "zmr:matrix": "ZMR_BIN=${ZMR_BIN:-zmr} zmr-device-matrix --matrix .zmr/device-matrix.json --trace-root traces/zmr-matrix --min-pass-rate 100 --max-failures 0",
102
- "zmr:ios": "zmr run .zmr/ios-smoke.json --platform ios --device booted --trace-dir traces/zmr-ios",
118
+ "zmr:ios": "zmr run .zmr/ios-smoke.json --platform ios --device booted --trace-dir traces/zmr-ios --ensure-device",
103
119
  "zmr:ios:report": "zmr report traces/zmr-ios --out traces/zmr-ios/report.html --junit traces/zmr-ios/junit.xml",
104
120
  "zmr:ios:reliability": "export ZMR_BIN=\"${ZMR_BIN:-zmr}\"; zmr-benchmark --zmr .zmr/ios-smoke.json --platform ios --device booted --app-id com.example.mobiletest --xcrun xcrun --runs 20 --trace-root traces/zmr-ios-reliability --min-pass-rate 100 --max-failures 0 --max-p95-ms 45000 && \"$ZMR_BIN\" report traces/zmr-ios-reliability --out traces/zmr-ios-reliability/report.html --junit traces/zmr-ios-reliability/junit.xml",
105
121
  "zmr:pilot": "zmr-pilot-gate --android --ios --android-app-root . --android-app-id com.example.mobiletest --android-device emulator-5554 --ios-app-root . --ios-app-path ./build/Debug-iphonesimulator/Sample.app --ios-app-id com.example.mobiletest --ios-device booted --runs 20 --min-pass-rate 100 --max-failures 0 --evidence-out traces/zmr-pilots/evidence.jsonl",
@@ -130,8 +146,9 @@ npx zmr-wizard \
130
146
  --package-json
131
147
  ```
132
148
 
133
- The wizard checks Node, ZMR, ADB, `xcrun`, and Zig when applicable. It scaffolds `.zmr` scenarios and can patch `package.json` scripts.
134
- It also ensures `traces/` is ignored in the app repo.
149
+ The wizard checks Node, ZMR, ADB, `xcrun`, and Zig when applicable. It
150
+ scaffolds `.zmr` scenarios, can patch `package.json` scripts, and ensures
151
+ `traces/` is ignored in the app repo.
135
152
  When `--expo-dev-client-scheme` is set, it also writes
136
153
  `.zmr/android-dev-client-smoke.json` and `.zmr/ios-dev-client-open-link.json`.
137
154
  Package-script setup also adds `zmr:android:dev-client`,
@@ -165,8 +182,9 @@ Rerunning `zmr init --app` refreshes generated `.zmr/config.json`,
165
182
  `.zmr/device-matrix.json`, and `.zmr/AGENTS.md` the same way, while preserving
166
183
  existing scenario files. Pass `--force` only when you intentionally want to
167
184
  replace the generated smoke scenarios too.
168
- The reliability scripts use `zmr-benchmark` with `100%` pass-rate and zero-failure
169
- defaults; tune p95 thresholds only after capturing stable local baseline runs.
185
+ The reliability scripts use `zmr-benchmark` with `100%` pass-rate and
186
+ zero-failure defaults. Tune p95 thresholds only after capturing stable local
187
+ baseline runs.
170
188
  The wizard only adds `zmr:readiness` for Android+iOS setups because the
171
189
  production readiness target requires Android, iOS simulator, and physical iOS
172
190
  evidence; single-platform setups should use `zmr:pilot` and the platform
@@ -179,8 +197,8 @@ explicit runner binary instead of relying on `PATH` or `ZMR_BIN`. Add
179
197
  `--evidence-out traces/zmr-pilots/evidence.jsonl` so production-readiness rows
180
198
  can be evaluated with `zmr-release-readiness`.
181
199
 
182
- The standalone CLI has the same non-interactive app-local bootstrap for
183
- source or release-archive installs:
200
+ The standalone CLI has the same non-interactive app-local bootstrap for source
201
+ or native-binary installs:
184
202
 
185
203
  ```bash
186
204
  zmr init --app --json --dir . --app-id com.example.mobiletest