zig-mobile-runner 0.1.0

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 (225) hide show
  1. package/CHANGELOG.md +484 -0
  2. package/CONTRIBUTING.md +42 -0
  3. package/FEATURES.md +112 -0
  4. package/LICENSE +21 -0
  5. package/README.md +255 -0
  6. package/SECURITY.md +34 -0
  7. package/build.zig +38 -0
  8. package/build.zig.zon +7 -0
  9. package/clients/README.md +144 -0
  10. package/clients/go/README.md +24 -0
  11. package/clients/go/examples/fake-session/main.go +93 -0
  12. package/clients/go/go.mod +3 -0
  13. package/clients/go/zmr/client.go +432 -0
  14. package/clients/kotlin/README.md +35 -0
  15. package/clients/kotlin/build.gradle.kts +35 -0
  16. package/clients/kotlin/settings.gradle.kts +15 -0
  17. package/clients/kotlin/src/main/kotlin/dev/zmr/FakeSession.kt +86 -0
  18. package/clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt +67 -0
  19. package/clients/python/README.md +29 -0
  20. package/clients/python/examples/fake_session.py +48 -0
  21. package/clients/python/pyproject.toml +13 -0
  22. package/clients/python/zmr_client.py +202 -0
  23. package/clients/rust/Cargo.lock +107 -0
  24. package/clients/rust/Cargo.toml +10 -0
  25. package/clients/rust/README.md +19 -0
  26. package/clients/rust/examples/fake_session.rs +70 -0
  27. package/clients/rust/src/lib.rs +461 -0
  28. package/clients/swift/Package.swift +16 -0
  29. package/clients/swift/README.md +36 -0
  30. package/clients/swift/Sources/ZMRClient/ZMRClient.swift +114 -0
  31. package/clients/swift/Sources/ZMRFakeSession/main.swift +86 -0
  32. package/clients/typescript/README.md +34 -0
  33. package/clients/typescript/examples/fake-session.mjs +36 -0
  34. package/clients/typescript/index.d.ts +144 -0
  35. package/clients/typescript/index.mjs +192 -0
  36. package/clients/typescript/package.json +8 -0
  37. package/docs/adr/0001-agent-native-runner-boundary.md +31 -0
  38. package/docs/adr/0002-app-local-zmr-contract.md +39 -0
  39. package/docs/adr/0003-ios-simulator-xctest-shim.md +41 -0
  40. package/docs/adr/0004-benchmark-claims-and-baseline-collection.md +37 -0
  41. package/docs/adr/README.md +12 -0
  42. package/docs/ai-agents.md +156 -0
  43. package/docs/app-integration.md +316 -0
  44. package/docs/benchmarking.md +275 -0
  45. package/docs/client-installation.md +141 -0
  46. package/docs/clients.md +98 -0
  47. package/docs/config.md +175 -0
  48. package/docs/demo.md +259 -0
  49. package/docs/dsl.md +57 -0
  50. package/docs/install.md +233 -0
  51. package/docs/market-positioning.md +70 -0
  52. package/docs/npm.md +359 -0
  53. package/docs/protocol-fixtures/README.md +8 -0
  54. package/docs/protocol-fixtures/core-session.requests.jsonl +8 -0
  55. package/docs/protocol-fixtures/core-session.responses.jsonl +8 -0
  56. package/docs/protocol-versioning.md +65 -0
  57. package/docs/protocol.md +560 -0
  58. package/docs/publication.md +77 -0
  59. package/docs/release-audit.md +99 -0
  60. package/docs/release-candidate.md +111 -0
  61. package/docs/release-evidence.md +188 -0
  62. package/docs/release-notes-template.md +58 -0
  63. package/docs/roadmap.md +334 -0
  64. package/docs/scenario-authoring.md +88 -0
  65. package/docs/shipping.md +170 -0
  66. package/docs/trace-privacy.md +88 -0
  67. package/docs/troubleshooting.md +256 -0
  68. package/examples/android-app-auth-probe.json +89 -0
  69. package/examples/android-app-error-state.json +13 -0
  70. package/examples/android-app-login-smoke.json +192 -0
  71. package/examples/android-app-onboarding.json +12 -0
  72. package/examples/android-app-referral-deep-link.json +12 -0
  73. package/examples/android-shim-smoke.json +19 -0
  74. package/examples/demo-failure.json +12 -0
  75. package/examples/demo-fake.json +14 -0
  76. package/examples/ios-dev-client-open-link.json +26 -0
  77. package/examples/ios-dev-client-route-snapshot.json +24 -0
  78. package/examples/ios-shim-smoke.json +23 -0
  79. package/examples/ios-smoke.json +9 -0
  80. package/go.work +3 -0
  81. package/npm/agents.mjs +183 -0
  82. package/npm/app-config.mjs +95 -0
  83. package/npm/build-zmr.mjs +21 -0
  84. package/npm/commands.mjs +104 -0
  85. package/npm/generated-files.mjs +50 -0
  86. package/npm/index.mjs +75 -0
  87. package/npm/init-app.mjs +80 -0
  88. package/npm/package-scripts.mjs +72 -0
  89. package/npm/postinstall.mjs +21 -0
  90. package/npm/scaffold.mjs +179 -0
  91. package/npm/scenarios.mjs +93 -0
  92. package/npm/setup.mjs +69 -0
  93. package/npm/wizard.mjs +117 -0
  94. package/npm/zmr.mjs +23 -0
  95. package/package.json +114 -0
  96. package/prebuilds/darwin-arm64/zmr +0 -0
  97. package/prebuilds/darwin-x64/zmr +0 -0
  98. package/prebuilds/linux-arm64/zmr +0 -0
  99. package/prebuilds/linux-x64/zmr +0 -0
  100. package/schemas/README.md +26 -0
  101. package/schemas/action-result.schema.json +27 -0
  102. package/schemas/capabilities-output.schema.json +98 -0
  103. package/schemas/devices-output.schema.json +25 -0
  104. package/schemas/doctor-output.schema.json +51 -0
  105. package/schemas/explain-output.schema.json +51 -0
  106. package/schemas/import-output.schema.json +23 -0
  107. package/schemas/init-output.schema.json +71 -0
  108. package/schemas/json-rpc.schema.json +55 -0
  109. package/schemas/release-manifest.schema.json +43 -0
  110. package/schemas/release-readiness-output.schema.json +127 -0
  111. package/schemas/run-output.schema.json +43 -0
  112. package/schemas/scenario.schema.json +128 -0
  113. package/schemas/schemas-output.schema.json +26 -0
  114. package/schemas/semantic-snapshot.schema.json +116 -0
  115. package/schemas/snapshot.schema.json +60 -0
  116. package/schemas/trace-event.schema.json +14 -0
  117. package/schemas/trace-manifest.schema.json +59 -0
  118. package/schemas/validate-output.schema.json +42 -0
  119. package/schemas/version-output.schema.json +23 -0
  120. package/schemas/zmr-config.schema.json +75 -0
  121. package/scripts/android-emulator.sh +126 -0
  122. package/scripts/assert-ios-physical-ready.sh +213 -0
  123. package/scripts/benchmark-command.sh +307 -0
  124. package/scripts/benchmark.sh +359 -0
  125. package/scripts/benchmark_gate.py +117 -0
  126. package/scripts/benchmark_result_row.py +88 -0
  127. package/scripts/compare-benchmarks.py +288 -0
  128. package/scripts/create-android-demo-app.sh +342 -0
  129. package/scripts/create-ios-demo-app.sh +261 -0
  130. package/scripts/demo-android-real.sh +232 -0
  131. package/scripts/demo-ios-real.sh +270 -0
  132. package/scripts/demo.sh +464 -0
  133. package/scripts/device-matrix.sh +338 -0
  134. package/scripts/ensure-ios-shim-target.rb +237 -0
  135. package/scripts/install-android-shim.sh +281 -0
  136. package/scripts/install-ios-shim.sh +589 -0
  137. package/scripts/pilot-gate.sh +560 -0
  138. package/scripts/release-readiness.py +838 -0
  139. package/scripts/release-readiness.sh +91 -0
  140. package/scripts/run-android-pilot.sh +561 -0
  141. package/scripts/run-ios-pilot.sh +509 -0
  142. package/shims/android/README.md +21 -0
  143. package/shims/android/ZMRShimInstrumentedTest.java +152 -0
  144. package/shims/android/protocol.md +18 -0
  145. package/shims/ios/README.md +50 -0
  146. package/shims/ios/ZMRShim.swift +110 -0
  147. package/shims/ios/ZMRShimUITestCase.swift +475 -0
  148. package/shims/ios/protocol.md +74 -0
  149. package/skills/zmr-mobile-testing/SKILL.md +127 -0
  150. package/src/android.zig +344 -0
  151. package/src/android_device_info.zig +99 -0
  152. package/src/android_emulator.zig +154 -0
  153. package/src/android_screen_recording.zig +112 -0
  154. package/src/android_shell.zig +112 -0
  155. package/src/bundle.zig +124 -0
  156. package/src/bundle_redaction.zig +272 -0
  157. package/src/bundle_tar.zig +123 -0
  158. package/src/cli_devices.zig +97 -0
  159. package/src/cli_doctor.zig +114 -0
  160. package/src/cli_import.zig +70 -0
  161. package/src/cli_info.zig +39 -0
  162. package/src/cli_init.zig +72 -0
  163. package/src/cli_output.zig +467 -0
  164. package/src/cli_run.zig +259 -0
  165. package/src/cli_serve.zig +287 -0
  166. package/src/cli_trace.zig +111 -0
  167. package/src/cli_validate.zig +41 -0
  168. package/src/command.zig +211 -0
  169. package/src/config.zig +305 -0
  170. package/src/config_diagnostics.zig +212 -0
  171. package/src/config_paths.zig +49 -0
  172. package/src/device_registry.zig +37 -0
  173. package/src/doctor.zig +412 -0
  174. package/src/doctor_hints.zig +52 -0
  175. package/src/errors.zig +55 -0
  176. package/src/fake_device.zig +163 -0
  177. package/src/health.zig +28 -0
  178. package/src/importer.zig +343 -0
  179. package/src/importer_json.zig +100 -0
  180. package/src/importer_model.zig +103 -0
  181. package/src/ios.zig +399 -0
  182. package/src/ios_devices.zig +219 -0
  183. package/src/ios_lifecycle.zig +72 -0
  184. package/src/ios_shim.zig +242 -0
  185. package/src/ios_snapshot.zig +20 -0
  186. package/src/json_fields.zig +80 -0
  187. package/src/json_rpc.zig +150 -0
  188. package/src/json_rpc_methods.zig +318 -0
  189. package/src/json_rpc_observation.zig +31 -0
  190. package/src/json_rpc_params.zig +52 -0
  191. package/src/json_rpc_protocol.zig +110 -0
  192. package/src/json_rpc_trace.zig +73 -0
  193. package/src/main.zig +135 -0
  194. package/src/mcp.zig +234 -0
  195. package/src/mcp_protocol.zig +64 -0
  196. package/src/mcp_trace.zig +83 -0
  197. package/src/report.zig +346 -0
  198. package/src/report_html.zig +63 -0
  199. package/src/report_values.zig +27 -0
  200. package/src/run_options.zig +152 -0
  201. package/src/runner.zig +280 -0
  202. package/src/runner_actions.zig +109 -0
  203. package/src/runner_config.zig +6 -0
  204. package/src/runner_diagnostics.zig +268 -0
  205. package/src/runner_events.zig +170 -0
  206. package/src/runner_native.zig +88 -0
  207. package/src/runner_waits.zig +300 -0
  208. package/src/scaffold.zig +472 -0
  209. package/src/scenario.zig +346 -0
  210. package/src/scenario_fields.zig +50 -0
  211. package/src/schema_registry.zig +53 -0
  212. package/src/selector.zig +84 -0
  213. package/src/semantic.zig +171 -0
  214. package/src/trace.zig +315 -0
  215. package/src/trace_json.zig +340 -0
  216. package/src/trace_summary.zig +218 -0
  217. package/src/trace_summary_diagnostic.zig +202 -0
  218. package/src/types.zig +120 -0
  219. package/src/uiautomator.zig +164 -0
  220. package/src/validation.zig +187 -0
  221. package/src/version.zig +22 -0
  222. package/viewer/app.js +373 -0
  223. package/viewer/index.html +126 -0
  224. package/viewer/parser.js +233 -0
  225. package/viewer/styles.css +585 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 John Mikel Regida
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # Zig Mobile Runner
2
+
3
+ > Agent-native mobile UI automation for Android, iOS simulators, and physical iOS devices.
4
+
5
+ [![CI](https://github.com/johnmikel/zig-mobile-runner/actions/workflows/ci.yml/badge.svg)](https://github.com/johnmikel/zig-mobile-runner/actions/workflows/ci.yml)
6
+ [![Release](https://img.shields.io/github/v/release/johnmikel/zig-mobile-runner?include_prereleases)](https://github.com/johnmikel/zig-mobile-runner/releases)
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
8
+
9
+ ZMR gives AI agents and test harnesses a typed mobile control plane: observe the
10
+ app, choose an action, wait for the UI to settle, assert state, and export a
11
+ replayable trace. The runner does not embed an LLM. Agents stay outside and use
12
+ ZMR through JSON-RPC, CLI JSON, scenarios, and language clients.
13
+
14
+ ## Why ZMR
15
+
16
+ - **AI-native protocol:** structured snapshots, semantic mobile trees, actions,
17
+ waits, assertions, live trace events, and redacted trace export over
18
+ JSON-RPC or MCP.
19
+ - **Trace-first debugging:** every run can produce screenshots, UI trees, logs,
20
+ timings, action inputs, assertion results, and an HTML report.
21
+ - **Fast local core:** Zig owns orchestration, subprocess control, selectors,
22
+ waits, retries, scenario execution, and release artifacts.
23
+ - **App-local setup:** `.zmr/config.json`, smoke scenarios, shim commands, and
24
+ traces live in the app repo.
25
+ - **Android and iOS:** Android uses ADB/UI Automator plus an optional native
26
+ shim. iOS simulators use `simctl`; physical iOS devices use `devicectl`;
27
+ selector-grade iOS automation uses the XCTest/XCUIAutomation shim.
28
+
29
+ ## Install
30
+
31
+ Inside a mobile app repo:
32
+
33
+ ```bash
34
+ # Available after the npm registry package is published:
35
+ npm install --save-dev zig-mobile-runner
36
+ npx zmr-wizard --app-id com.example.mobiletest --package-json
37
+ npx zmr doctor --strict --json --config .zmr/config.json
38
+ ```
39
+
40
+ For Expo development builds, add `--expo-dev-client-scheme <scheme>` to the
41
+ wizard command.
42
+
43
+ Today, install the release tarball from GitHub:
44
+
45
+ ```bash
46
+ npm install --save-dev https://github.com/johnmikel/zig-mobile-runner/releases/download/v0.1.0/zig-mobile-runner-0.1.0.tgz
47
+ npx zmr-wizard --app-id com.example.mobiletest --package-json
48
+ npx zmr doctor --strict --json --config .zmr/config.json
49
+ ```
50
+
51
+ From source:
52
+
53
+ ```bash
54
+ git clone https://github.com/johnmikel/zig-mobile-runner.git
55
+ cd zig-mobile-runner
56
+ zig build-exe src/main.zig -target aarch64-macos.15.0 -O Debug -femit-bin=zig-out/bin/zmr
57
+ ./zig-out/bin/zmr version
58
+ ```
59
+
60
+ Release archives and npm tarballs are attached to GitHub releases. The npm
61
+ registry package is pending publish.
62
+
63
+ Homebrew is the preferred binary install for teams that do not use JavaScript:
64
+
65
+ ```bash
66
+ brew install --build-from-source ./dist/homebrew/zmr.rb
67
+ ```
68
+
69
+ ## Try It
70
+
71
+ No device required:
72
+
73
+ ```bash
74
+ ./scripts/demo.sh
75
+ ```
76
+
77
+ Real iOS simulator demo:
78
+
79
+ ```bash
80
+ npx zmr-demo-ios --out /tmp/zmr-ios-demo --device booted
81
+ ```
82
+
83
+ The demo command boots an available simulator when none is already running.
84
+
85
+ Android app-local pilot:
86
+
87
+ ```bash
88
+ zmr-pilot-gate \
89
+ --android \
90
+ --android-app-root /path/to/mobile-app \
91
+ --android-app-id com.example.mobiletest \
92
+ --android-device emulator-5554 \
93
+ --runs 20 \
94
+ --min-pass-rate 100 \
95
+ --max-failures 0 \
96
+ --evidence-out /path/to/mobile-app/traces/zmr-pilots/evidence.jsonl
97
+ ```
98
+
99
+ iOS app-local pilot:
100
+
101
+ ```bash
102
+ zmr-pilot-gate \
103
+ --ios \
104
+ --ios-app-root /path/to/mobile-app \
105
+ --ios-app-path /path/to/mobile-app/build/Debug-iphonesimulator/Sample.app \
106
+ --ios-app-id com.example.mobiletest \
107
+ --ios-device booted \
108
+ --ios-shim /path/to/mobile-app/.zmr/ios-shim \
109
+ --runs 20 \
110
+ --min-pass-rate 100 \
111
+ --max-failures 0 \
112
+ --evidence-out /path/to/mobile-app/traces/zmr-pilots/evidence.jsonl
113
+ ```
114
+
115
+ ## Scenario Example
116
+
117
+ ZMR scenarios are JSON today because JSON is strict, schema-validatable, and
118
+ easy for agents and code generators to emit.
119
+
120
+ ```json
121
+ {
122
+ "name": "Login smoke",
123
+ "appId": "com.example.mobiletest",
124
+ "steps": [
125
+ { "action": "launch" },
126
+ { "action": "assertHealthy", "timeoutMs": 5000 },
127
+ { "action": "tap", "selector": { "resourceId": "email" } },
128
+ { "action": "typeText", "text": "user@example.com" },
129
+ { "action": "tap", "selector": { "resourceId": "password" } },
130
+ { "action": "typeText", "text": "password" },
131
+ { "action": "tap", "selector": { "text": "Login" } },
132
+ { "action": "waitVisible", "selector": { "text": "Welcome" }, "timeoutMs": 30000 }
133
+ ]
134
+ }
135
+ ```
136
+
137
+ Validate before touching a device:
138
+
139
+ ```bash
140
+ zmr version --json
141
+ zmr schemas --json
142
+ zmr devices --json
143
+ zmr init --app --json --dir . --app-id com.example.mobiletest
144
+ zmr validate --json .zmr/login-smoke.json
145
+ zmr run .zmr/login-smoke.json --json --trace-dir traces/login-smoke
146
+ zmr explain --json traces/login-smoke
147
+ zmr import flow-yaml .zmr/legacy-flow.yaml --out .zmr/legacy-flow.json
148
+ zmr export traces/login-smoke --out traces/login-smoke-redacted.zmrtrace --redact
149
+ ```
150
+
151
+ Stable JSON outputs are documented with schemas:
152
+ `version-output.schema.json`, `schemas-output.schema.json`,
153
+ `capabilities-output.schema.json`, `init-output.schema.json`,
154
+ `devices-output.schema.json`, `validate-output.schema.json`,
155
+ `run-output.schema.json`, `explain-output.schema.json`,
156
+ `semantic-snapshot.schema.json`, `release-manifest.schema.json`,
157
+ `release-readiness-output.schema.json`, and `RELEASE_MANIFEST.json`.
158
+
159
+ See [docs/dsl.md](docs/dsl.md) for the DSL decision and roadmap.
160
+
161
+ ## Agent And Language Clients
162
+
163
+ Clients are thin wrappers around `zmr serve --transport stdio`. They do not
164
+ replace the runner; they make it easier for agents and test code to call the
165
+ same JSON-RPC protocol.
166
+
167
+ ```bash
168
+ zmr serve --transport stdio --config .zmr/config.json --trace-dir traces/zmr-agent
169
+ ```
170
+
171
+ Agents that support the Model Context Protocol can use the native MCP surface:
172
+
173
+ ```bash
174
+ zmr mcp --config .zmr/config.json --trace-dir traces/zmr-agent
175
+ ```
176
+
177
+ The MCP server exposes mobile-specific tools such as `semantic_snapshot`,
178
+ `tap`, `type`, `wait_visible`, `trace_events`, and `trace_export`.
179
+
180
+ | Language | Entry point | Example |
181
+ | --- | --- | --- |
182
+ | TypeScript | `clients/typescript/index.mjs` + `index.d.ts` | `node clients/typescript/examples/fake-session.mjs` |
183
+ | Python | `clients/python/zmr_client.py` + `pyproject.toml` | `python3 clients/python/examples/fake_session.py` |
184
+ | Go | `clients/go/zmr/client.go` | `go run ./clients/go/examples/fake-session` |
185
+ | Rust | `clients/rust/src/lib.rs` | `cargo run --manifest-path clients/rust/Cargo.toml --example fake_session` |
186
+ | Swift | `clients/swift/Sources/ZMRClient` | `swift build --package-path clients/swift` |
187
+ | Kotlin | `clients/kotlin/src/main/kotlin/dev/zmr` | `gradle -p clients/kotlin build` |
188
+
189
+ Rust uses `src/lib.rs` because that is the idiomatic crate layout. TypeScript
190
+ uses `index.mjs` plus declarations, Python uses a pip-installable module, Go
191
+ uses a package directory under `clients/go/zmr`, Swift uses SwiftPM, and Kotlin
192
+ uses Gradle.
193
+
194
+ See [clients/README.md](clients/README.md), [docs/client-installation.md](docs/client-installation.md),
195
+ and [docs/ai-agents.md](docs/ai-agents.md).
196
+
197
+ ## Platform Support
198
+
199
+ | Target | Status | Notes |
200
+ | --- | --- | --- |
201
+ | Android emulator | Supported | ADB/UI Automator, optional Android shim, emulator lifecycle helpers |
202
+ | Android physical device | Supported | Requires ADB connection and app build/install surface |
203
+ | iOS simulator | Supported | `simctl` plus app-local XCTest/XCUIAutomation shim for native selector actions, native waits, and bounded snapshots |
204
+ | iOS physical device | Supported, evidence-gated | `devicectl` lifecycle plus app-local XCTest/XCUIAutomation shim; run the physical pilot before claiming device reliability |
205
+ | Cloud device farms | Not yet | Planned after local matrix certification |
206
+
207
+ Current release: `0.1.0` developer preview. Protocol version:
208
+ `2026-04-28`. Latest local coverage run: `94.40%` line coverage.
209
+
210
+ ## Documentation
211
+
212
+ - [FEATURES.md](FEATURES.md): complete feature list and limitations
213
+ - [docs/install.md](docs/install.md): source, archive, npm, and app setup
214
+ - [docs/app-integration.md](docs/app-integration.md): app-side Android/iOS shims
215
+ - [docs/protocol.md](docs/protocol.md): JSON-RPC methods and schemas
216
+ - [docs/ai-agents.md](docs/ai-agents.md): JSON-RPC and MCP agent workflows
217
+ - [docs/dsl.md](docs/dsl.md): scenario DSL decision and roadmap
218
+ - [docs/clients.md](docs/clients.md): language client guide
219
+ - [docs/client-installation.md](docs/client-installation.md): npm, Homebrew, TS, Python, Go, Rust, Swift, and Kotlin setup
220
+ - [docs/market-positioning.md](docs/market-positioning.md): competitive positioning
221
+ - [docs/adr/](docs/adr/): architecture decision records
222
+ - [docs/shipping.md](docs/shipping.md): release gate and support matrix
223
+ - [docs/release-audit.md](docs/release-audit.md): prompt-to-artifact completion audit
224
+ - [docs/trace-privacy.md](docs/trace-privacy.md): safe trace export
225
+ - [skills/zmr-mobile-testing/SKILL.md](skills/zmr-mobile-testing/SKILL.md): reusable agent skill
226
+
227
+ ## Release Gate
228
+
229
+ Before publishing:
230
+
231
+ ```bash
232
+ ./scripts/release-gate.sh
233
+ ./scripts/build-release.sh
234
+ ./scripts/verify-release-artifacts.sh
235
+ npm pack --dry-run
236
+ ```
237
+
238
+ The release gate runs formatting, shell syntax checks, client tests, public
239
+ safety scans, Zig tests, the no-device demo, coverage, archive generation,
240
+ checksum/manifest verification, host archive smoke, and npm package dry-run.
241
+
242
+ Release-candidate evidence can be checked explicitly:
243
+
244
+ ```bash
245
+ zmr-release-readiness --evidence traces/release-candidate/<run>/evidence.jsonl \
246
+ --target dev-preview
247
+ ```
248
+
249
+ Use `--target production` only after repeated real app/device pilots exist, and
250
+ `--target market-claim` only after same-host/device benchmark comparison
251
+ evidence exists.
252
+
253
+ ## License
254
+
255
+ MIT
package/SECURITY.md ADDED
@@ -0,0 +1,34 @@
1
+ # Security Policy
2
+
3
+ ZMR is a local mobile automation runner. It can collect screenshots, UI trees,
4
+ logs, app ids, device metadata, and scenario inputs. Treat raw traces as
5
+ sensitive.
6
+
7
+ ## Supported Versions
8
+
9
+ The current supported line is `0.1.x` dev preview. Security fixes should target
10
+ the latest dev-preview branch until a stable release exists.
11
+
12
+ ## Reporting A Vulnerability
13
+
14
+ Open a private security advisory on GitHub when available. If private advisory
15
+ reporting is not enabled, contact the repository maintainer through the channel
16
+ listed in the project profile.
17
+
18
+ Include:
19
+
20
+ - ZMR version and platform.
21
+ - Reproduction steps.
22
+ - Whether the issue exposes screenshots, logs, trace data, credentials, or
23
+ device access.
24
+ - A minimal scenario or redacted trace bundle when possible.
25
+
26
+ Do not publish raw traces from private apps in public issues.
27
+
28
+ ## Trace Handling
29
+
30
+ - Use `zmr export --redact` before sharing trace bundles.
31
+ - Do not share raw screenshot artifacts from private apps.
32
+ - Do not paste logs that include tokens, emails, API keys, or device identifiers.
33
+ - Prefer fake-device reproductions for public bug reports.
34
+
package/build.zig ADDED
@@ -0,0 +1,38 @@
1
+ const std = @import("std");
2
+
3
+ pub fn build(b: *std.Build) void {
4
+ const target = b.standardTargetOptions(.{});
5
+ const optimize = b.standardOptimizeOption(.{});
6
+
7
+ const exe = b.addExecutable(.{
8
+ .name = "zmr",
9
+ .root_module = b.createModule(.{
10
+ .root_source_file = b.path("src/main.zig"),
11
+ .target = target,
12
+ .optimize = optimize,
13
+ }),
14
+ });
15
+
16
+ b.installArtifact(exe);
17
+
18
+ const run_cmd = b.addRunArtifact(exe);
19
+ run_cmd.step.dependOn(b.getInstallStep());
20
+ if (b.args) |args| {
21
+ run_cmd.addArgs(args);
22
+ }
23
+
24
+ const run_step = b.step("run", "Run zmr");
25
+ run_step.dependOn(&run_cmd.step);
26
+
27
+ const unit_tests = b.addTest(.{
28
+ .root_module = b.createModule(.{
29
+ .root_source_file = b.path("src/main.zig"),
30
+ .target = target,
31
+ .optimize = optimize,
32
+ }),
33
+ });
34
+ const run_unit_tests = b.addRunArtifact(unit_tests);
35
+
36
+ const test_step = b.step("test", "Run unit tests");
37
+ test_step.dependOn(&run_unit_tests.step);
38
+ }
package/build.zig.zon ADDED
@@ -0,0 +1,7 @@
1
+ .{
2
+ .name = .zig_mobile_runner,
3
+ .version = "0.0.1",
4
+ .minimum_zig_version = "0.15.2",
5
+ .paths = .{""},
6
+ .fingerprint = 0x5a9670ea13a33fab,
7
+ }
@@ -0,0 +1,144 @@
1
+ # ZMR Language Clients
2
+
3
+ ZMR clients are small wrappers around the same newline-delimited JSON-RPC
4
+ protocol exposed by:
5
+
6
+ ```bash
7
+ zmr serve --transport stdio --config .zmr/config.json --trace-dir traces/zmr-agent
8
+ ```
9
+
10
+ They are intended for AI agents, CI harnesses, and app teams that want typed
11
+ or idiomatic calls without reimplementing JSON-RPC framing.
12
+ Each client includes `devices()` for `device.list`, including the portable
13
+ `ready` boolean, and a semantic snapshot helper for `observe.semanticSnapshot`
14
+ so agents can work from normalized roles, selectors, bounds, and recommended
15
+ actions instead of raw platform hierarchy classes.
16
+ The TypeScript, Python, Go, and Rust clients expose the same core control
17
+ surface: session lifecycle, app launch/stop/link/state, snapshot and semantic
18
+ snapshot, tap/type/erase/hide-keyboard/swipe/back/scroll, waits, assertions,
19
+ trace event polling, and trace export.
20
+ Use the `assertHealthy`/`assert_healthy` helper after launches, links, and major
21
+ navigation steps to catch native crash overlays and development-client failures
22
+ without hand-maintaining negative selectors in every client.
23
+
24
+ For install commands across package managers, see
25
+ [docs/client-installation.md](../docs/client-installation.md).
26
+
27
+ ## TypeScript
28
+
29
+ Runtime: `clients/typescript/index.mjs`
30
+ Types: `clients/typescript/index.d.ts`
31
+
32
+ ```bash
33
+ node clients/typescript/examples/fake-session.mjs
34
+ ```
35
+
36
+ ```js
37
+ import { createZmrClient } from "./clients/typescript/index.mjs";
38
+
39
+ const zmr = createZmrClient({
40
+ command: "zmr",
41
+ args: ["serve", "--transport", "stdio", "--config", ".zmr/config.json"],
42
+ });
43
+ ```
44
+
45
+ ## Python
46
+
47
+ Runtime: `clients/python/zmr_client.py`
48
+
49
+ ```bash
50
+ python3 -m pip install "git+https://github.com/johnmikel/zig-mobile-runner.git#subdirectory=clients/python"
51
+ ```
52
+
53
+ ```bash
54
+ python3 clients/python/examples/fake_session.py
55
+ ```
56
+
57
+ ```python
58
+ from zmr_client import ZmrClient
59
+
60
+ with ZmrClient("zmr", ["serve", "--transport", "stdio", "--config", ".zmr/config.json"]) as zmr:
61
+ snapshot = zmr.snapshot()
62
+ ```
63
+
64
+ ## Go
65
+
66
+ Runtime: `clients/go/zmr/client.go`
67
+
68
+ ```bash
69
+ go get github.com/johnmikel/zig-mobile-runner/clients/go@main
70
+ ```
71
+
72
+ ```bash
73
+ go run ./clients/go/examples/fake-session \
74
+ --zmr ./zig-out/bin/zmr \
75
+ --adb ./tests/fake-adb.sh \
76
+ --trace-dir traces/demo-go-client
77
+ ```
78
+
79
+ ```go
80
+ client, err := zmr.Start(ctx, "zmr", "serve", "--transport", "stdio", "--config", ".zmr/config.json")
81
+ ```
82
+
83
+ ## Rust
84
+
85
+ Runtime: `clients/rust/src/lib.rs`
86
+
87
+ Cargo packages library code from `src/lib.rs` by convention. Because this repo
88
+ is not yet published as a Rust crate, consume the client from a local checkout:
89
+
90
+ ```bash
91
+ git submodule add https://github.com/johnmikel/zig-mobile-runner.git vendor/zig-mobile-runner
92
+ ```
93
+
94
+ ```toml
95
+ [dependencies]
96
+ zmr-client = { path = "vendor/zig-mobile-runner/clients/rust" }
97
+ ```
98
+
99
+ ```bash
100
+ cargo run --manifest-path clients/rust/Cargo.toml --example fake_session -- \
101
+ --zmr ./zig-out/bin/zmr \
102
+ --adb ./tests/fake-adb.sh \
103
+ --trace-dir traces/demo-rust-client
104
+ ```
105
+
106
+ ```rust
107
+ let mut client = zmr_client::Client::start("zmr", ["serve", "--transport", "stdio", "--config", ".zmr/config.json"])?;
108
+ let snapshot = client.snapshot()?;
109
+ ```
110
+
111
+ ## Swift
112
+
113
+ Runtime: `clients/swift/Sources/ZMRClient/ZMRClient.swift`
114
+
115
+ Use the Swift client from a local SwiftPM package path until it is published as
116
+ a standalone Swift package:
117
+
118
+ ```bash
119
+ git submodule add https://github.com/johnmikel/zig-mobile-runner.git vendor/zig-mobile-runner
120
+ ```
121
+
122
+ ```swift
123
+ .package(path: "vendor/zig-mobile-runner/clients/swift")
124
+ ```
125
+
126
+ Swift is useful for macOS host-side automation next to iOS app code. It is not
127
+ an SDK embedded in the app under test.
128
+
129
+ ## Kotlin
130
+
131
+ Runtime: `clients/kotlin/src/main/kotlin/dev/zmr/ZmrClient.kt`
132
+
133
+ ```bash
134
+ git submodule add https://github.com/johnmikel/zig-mobile-runner.git vendor/zig-mobile-runner
135
+ gradle -p vendor/zig-mobile-runner/clients/kotlin build
136
+ ```
137
+
138
+ Kotlin is useful for Android teams that want host-side orchestration in Kotlin.
139
+ It still drives the external `zmr` binary.
140
+
141
+ Rust has `src/lib.rs` because Cargo packages libraries from that path by
142
+ convention. The other clients use the equivalent idiomatic layout for their
143
+ ecosystem: ESM entry file for TypeScript, a pip-installable Python module, a Go
144
+ package directory, a SwiftPM package, and a Gradle/Kotlin source package.
@@ -0,0 +1,24 @@
1
+ # ZMR Go Client
2
+
3
+ Small standard-library JSON-RPC client for driving `zmr serve --transport stdio`
4
+ from Go agents and test harnesses.
5
+
6
+ ```go
7
+ client, err := zmr.Start(ctx, "zmr", "serve", "--transport", "stdio")
8
+ if err != nil {
9
+ panic(err)
10
+ }
11
+ defer client.Close()
12
+
13
+ snapshot, err := client.Snapshot(ctx)
14
+ healthy, err := client.AssertHealthy(ctx, 1000)
15
+ ```
16
+
17
+ Run the fake-session example from the repository root:
18
+
19
+ ```sh
20
+ go run ./clients/go/examples/fake-session \
21
+ --zmr ./zig-out/bin/zmr \
22
+ --adb ./tests/fake-adb.sh \
23
+ --trace-dir traces/demo-go-client
24
+ ```
@@ -0,0 +1,93 @@
1
+ package main
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+ "flag"
7
+ "fmt"
8
+ "os"
9
+ "time"
10
+
11
+ "github.com/johnmikel/zig-mobile-runner/clients/go/zmr"
12
+ )
13
+
14
+ func main() {
15
+ zmrBin := flag.String("zmr", "zig-out/bin/zmr", "zmr executable")
16
+ adb := flag.String("adb", "tests/fake-adb.sh", "adb executable or fake adb script")
17
+ device := flag.String("device", "fake-android-1", "device serial")
18
+ appID := flag.String("app-id", "com.example.mobiletest", "app id")
19
+ traceDir := flag.String("trace-dir", "traces/demo-go-client", "trace directory")
20
+ traceOut := flag.String("trace-out", "traces/demo-go-client-redacted.zmrtrace", "trace export path")
21
+ flag.Parse()
22
+
23
+ ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
24
+ defer cancel()
25
+
26
+ client, err := zmr.Start(ctx,
27
+ *zmrBin,
28
+ "serve",
29
+ "--transport", "stdio",
30
+ "--device", *device,
31
+ "--app-id", *appID,
32
+ "--adb", *adb,
33
+ "--trace-dir", *traceDir,
34
+ )
35
+ if err != nil {
36
+ fail(err)
37
+ }
38
+ defer client.Close()
39
+
40
+ capabilities, err := client.Capabilities(ctx)
41
+ if err != nil {
42
+ fail(err)
43
+ }
44
+ if _, err := client.CreateSession(ctx); err != nil {
45
+ fail(err)
46
+ }
47
+ if _, err := client.OpenLink(ctx, "exampleapp://go-client"); err != nil {
48
+ fail(err)
49
+ }
50
+ if _, err := client.WaitUntil(ctx, map[string]interface{}{"text": "Dashboard"}, 1000); err != nil {
51
+ fail(err)
52
+ }
53
+ if _, err := client.Tap(ctx, map[string]interface{}{"text": "Sign in"}); err != nil {
54
+ fail(err)
55
+ }
56
+ if _, err := client.TypeText(ctx, "agent@example.com", map[string]interface{}{"resourceId": "email-login-email-input"}); err != nil {
57
+ fail(err)
58
+ }
59
+ if _, err := client.AssertNotVisible(ctx, map[string]interface{}{"text": "Application has crashed"}, 100); err != nil {
60
+ fail(err)
61
+ }
62
+ if _, err := client.AssertHealthy(ctx, 100); err != nil {
63
+ fail(err)
64
+ }
65
+ snapshot, err := client.Snapshot(ctx)
66
+ if err != nil {
67
+ fail(err)
68
+ }
69
+ exported, err := client.ExportTrace(ctx, *traceOut, true, true)
70
+ if err != nil {
71
+ fail(err)
72
+ }
73
+ events, err := client.TraceEvents(ctx, 0, 10)
74
+ if err != nil {
75
+ fail(err)
76
+ }
77
+
78
+ summary := map[string]interface{}{
79
+ "protocolVersion": capabilities.ProtocolVersion,
80
+ "activePackage": snapshot.ActivePackage,
81
+ "nodes": len(snapshot.Nodes),
82
+ "events": events.NextSeq,
83
+ "traceDir": *traceDir,
84
+ "traceOut": exported.Out,
85
+ }
86
+ encoded, _ := json.Marshal(summary)
87
+ fmt.Println(string(encoded))
88
+ }
89
+
90
+ func fail(err error) {
91
+ fmt.Fprintln(os.Stderr, err)
92
+ os.Exit(1)
93
+ }
@@ -0,0 +1,3 @@
1
+ module github.com/johnmikel/zig-mobile-runner/clients/go
2
+
3
+ go 1.22