agent-device 0.9.0 → 0.10.1

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 (82) hide show
  1. package/README.md +37 -559
  2. package/dist/src/224.js +1 -1
  3. package/dist/src/bin.js +10 -10
  4. package/dist/src/core/capabilities.d.ts +1 -1
  5. package/dist/src/core/click-button.d.ts +20 -0
  6. package/dist/src/core/dispatch-resolve.d.ts +7 -6
  7. package/dist/src/core/dispatch.d.ts +1 -0
  8. package/dist/src/daemon/android-system-dialog.d.ts +11 -0
  9. package/dist/src/daemon/context.d.ts +1 -0
  10. package/dist/src/daemon/handlers/interaction-common.d.ts +12 -0
  11. package/dist/src/daemon/handlers/interaction-fill.d.ts +3 -0
  12. package/dist/src/daemon/handlers/interaction-flags.d.ts +4 -0
  13. package/dist/src/daemon/handlers/interaction-get.d.ts +3 -0
  14. package/dist/src/daemon/handlers/interaction-is.d.ts +3 -0
  15. package/dist/src/daemon/handlers/interaction-press.d.ts +3 -0
  16. package/dist/src/daemon/handlers/interaction-scroll.d.ts +3 -0
  17. package/dist/src/daemon/handlers/interaction-selector.d.ts +27 -0
  18. package/dist/src/daemon/handlers/interaction-snapshot.d.ts +8 -0
  19. package/dist/src/daemon/handlers/interaction-targeting.d.ts +28 -0
  20. package/dist/src/daemon/handlers/interaction-touch.d.ts +46 -0
  21. package/dist/src/daemon/handlers/interaction.d.ts +2 -0
  22. package/dist/src/daemon/handlers/record-trace-android.d.ts +18 -0
  23. package/dist/src/daemon/handlers/record-trace-ios.d.ts +52 -0
  24. package/dist/src/daemon/handlers/record-trace-recording.d.ts +32 -0
  25. package/dist/src/daemon/handlers/record-trace.d.ts +2 -7
  26. package/dist/src/daemon/handlers/session-device-utils.d.ts +1 -0
  27. package/dist/src/daemon/handlers/session-runtime.d.ts +3 -1
  28. package/dist/src/daemon/handlers/session.d.ts +8 -0
  29. package/dist/src/daemon/handlers/snapshot-alert.d.ts +13 -0
  30. package/dist/src/daemon/handlers/snapshot-capture.d.ts +27 -0
  31. package/dist/src/daemon/handlers/snapshot-session.d.ts +15 -0
  32. package/dist/src/daemon/handlers/snapshot-settings.d.ts +24 -0
  33. package/dist/src/daemon/handlers/snapshot-wait.d.ts +37 -0
  34. package/dist/src/daemon/handlers/snapshot.d.ts +4 -20
  35. package/dist/src/daemon/is-predicates.d.ts +2 -1
  36. package/dist/src/daemon/record-trace-errors.d.ts +6 -0
  37. package/dist/src/daemon/recording-gestures.d.ts +3 -0
  38. package/dist/src/daemon/recording-telemetry.d.ts +20 -0
  39. package/dist/src/daemon/recording-timing.d.ts +24 -0
  40. package/dist/src/daemon/request-router.d.ts +6 -0
  41. package/dist/src/daemon/script-utils.d.ts +1 -0
  42. package/dist/src/daemon/selectors-build.d.ts +2 -1
  43. package/dist/src/daemon/selectors-match.d.ts +3 -2
  44. package/dist/src/daemon/selectors-resolve.d.ts +3 -2
  45. package/dist/src/daemon/snapshot-processing.d.ts +2 -1
  46. package/dist/src/daemon/touch-reference-frame.d.ts +7 -0
  47. package/dist/src/daemon/types.d.ts +64 -12
  48. package/dist/src/daemon.js +62 -35
  49. package/dist/src/platforms/android/devices.d.ts +4 -0
  50. package/dist/src/platforms/android/index.d.ts +1 -1
  51. package/dist/src/platforms/android/input-actions.d.ts +4 -0
  52. package/dist/src/platforms/android/sdk.d.ts +2 -0
  53. package/dist/src/platforms/ios/app-filter.d.ts +2 -0
  54. package/dist/src/platforms/ios/devices.d.ts +2 -1
  55. package/dist/src/platforms/ios/macos-apps.d.ts +12 -0
  56. package/dist/src/platforms/ios/runner-client.d.ts +4 -2
  57. package/dist/src/platforms/ios/runner-macos-products.d.ts +3 -0
  58. package/dist/src/platforms/ios/runner-session.d.ts +5 -0
  59. package/dist/src/platforms/ios/runner-xctestrun-products.d.ts +2 -0
  60. package/dist/src/platforms/ios/runner-xctestrun.d.ts +22 -2
  61. package/dist/src/recording/overlay.d.ts +10 -0
  62. package/dist/src/utils/command-schema.d.ts +4 -2
  63. package/dist/src/utils/device.d.ts +13 -5
  64. package/dist/src/utils/interactors.d.ts +7 -7
  65. package/dist/src/utils/video.d.ts +9 -0
  66. package/ios-runner/AgentDeviceRunner/AgentDeviceRunner.xcodeproj/project.pbxproj +58 -50
  67. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/AgentDeviceRunnerUITests.entitlements +10 -0
  68. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+CommandExecution.swift +201 -30
  69. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Interaction.swift +156 -9
  70. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Lifecycle.swift +39 -7
  71. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Models.swift +31 -1
  72. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+ScreenRecorder.swift +9 -12
  73. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+Snapshot.swift +132 -112
  74. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests+SystemModal.swift +4 -0
  75. package/ios-runner/AgentDeviceRunner/AgentDeviceRunnerUITests/RunnerTests.swift +23 -5
  76. package/ios-runner/AgentDeviceRunner/RecordingScripts/recording-overlay.swift +571 -0
  77. package/ios-runner/AgentDeviceRunner/RecordingScripts/recording-trim.swift +140 -0
  78. package/package.json +3 -2
  79. package/skills/agent-device/SKILL.md +25 -5
  80. package/skills/agent-device/references/macos-desktop.md +89 -0
  81. package/skills/agent-device/references/snapshot-refs.md +11 -2
  82. package/skills/agent-device/references/video-recording.md +9 -1
package/README.md CHANGED
@@ -8,590 +8,68 @@
8
8
 
9
9
  # agent-device
10
10
 
11
- CLI to control iOS and Android devices for AI agents influenced by Vercel’s [agent-browser](https://github.com/vercel-labs/agent-browser).
11
+ `agent-device` is a CLI for UI automation on iOS, tvOS, macOS, Android, and AndroidTV. It is designed for agent-driven workflows: inspect the UI, act on it deterministically, and keep that work session-aware and replayable.
12
12
 
13
- The project is in early development and considered experimental. Pull requests are welcome!
13
+ If you know Vercel's [agent-browser](https://github.com/vercel-labs/agent-browser), this project applies the same broad idea to mobile apps and devices.
14
14
 
15
- ## Features
16
- - Platforms: iOS/tvOS (simulator + physical device core automation) and Android/AndroidTV (emulator + device).
17
- - Core commands: `open`, `back`, `home`, `app-switcher`, `press`, `long-press`, `focus`, `type`, `fill`, `scroll`, `scrollintoview`, `wait`, `alert`, `screenshot`, `close`, `install`, `install-from-source`, `reinstall`, `push`, `trigger-app-event`.
18
- - Inspection commands: `snapshot` (accessibility tree), `diff snapshot` (structural baseline diff), `appstate`, `apps`, `devices`.
19
- - Clipboard commands: `clipboard read`, `clipboard write <text>`.
20
- - Keyboard commands: `keyboard status|get|dismiss` (Android).
21
- - Performance command: `perf` (alias: `metrics`) returns a metrics JSON blob for the active session; startup timing is currently sampled.
22
- - App logs and traffic inspection: `logs path` returns session log metadata; `logs start` / `logs stop` stream app output; `logs clear` truncates session app logs; `logs clear --restart` resets and restarts stream in one step; `logs doctor` checks readiness; `logs mark` writes timeline markers; `network dump` parses recent HTTP(s) entries from session logs.
23
- - Device tooling: `adb` (Android), `simctl`/`devicectl` (iOS via Xcode).
24
- - Minimal dependencies; TypeScript executed directly on Node 22+ (no build step).
15
+ <video src="https://github.com/user-attachments/assets/db81d164-c179-4e68-97fa-53f06e467211" controls muted playsinline></video>
25
16
 
26
- ## Install
27
-
28
- ```bash
29
- npm install -g agent-device
30
- ```
31
-
32
- Or use it without installing:
17
+ ## Project Goals
33
18
 
34
- ```bash
35
- npx agent-device open SampleApp
36
- ```
19
+ - Give agents a practical way to understand mobile UI state through structured snapshots.
20
+ - Keep automation flows token-efficient enough for real agent loops.
21
+ - Make common interactions reliable enough for repeated automation runs.
22
+ - Keep automation grounded in sessions, selectors, and replayable flows instead of one-off scripts.
37
23
 
38
- For the typed daemon client and `installFromSource` behavior, see [website/docs/docs/client-api.md](website/docs/docs/client-api.md).
24
+ ## Core Ideas
39
25
 
40
- The skill is also accessible on [ClawHub](https://clawhub.ai/okwasniewski/agent-device).
41
- For structured exploratory QA workflows, use the dogfood skill at [skills/dogfood/SKILL.md](skills/dogfood/SKILL.md).
26
+ - Sessions: open a target once, interact within that session, then close it cleanly.
27
+ - Snapshots: inspect the current accessibility tree in a compact form and get stable refs for exploration.
28
+ - Refs vs selectors: use refs for discovery, use selectors for durable replay and assertions.
29
+ - Human docs vs agent skills: docs explain the system for people; skills provide compact operating guidance for agents.
42
30
 
43
- ## Quick Start
31
+ ## Command Flow
44
32
 
45
- Use refs for agent-driven exploration and normal automation flows.
46
- Use `press` as the canonical tap command; `click` is an equivalent alias.
33
+ The canonical loop is:
47
34
 
48
35
  ```bash
49
- agent-device open Contacts --platform ios # creates session on iOS Simulator
50
- agent-device snapshot
51
- agent-device press @e5
52
- agent-device diff snapshot # subsequent runs compare against previous baseline
53
- agent-device fill @e6 "John"
54
- agent-device fill @e7 "Doe"
36
+ agent-device open SampleApp --platform ios
37
+ agent-device snapshot -i
55
38
  agent-device press @e3
39
+ agent-device diff snapshot -i
40
+ agent-device fill @e5 "test"
56
41
  agent-device close
57
42
  ```
58
43
 
59
- ## Fast batching (JSON steps)
60
-
61
- Use `batch` to execute multiple commands in a single daemon request.
62
-
63
- CLI examples:
64
-
65
- ```bash
66
- agent-device batch \
67
- --session sim \
68
- --platform ios \
69
- --udid 00008150-001849640CF8401C \
70
- --steps-file /tmp/batch-steps.json \
71
- --json
72
- ```
73
-
74
- Small inline payloads are also supported:
75
-
76
- ```bash
77
- agent-device batch --steps '[{"command":"open","positionals":["settings"]},{"command":"wait","positionals":["100"]}]'
78
- ```
79
-
80
- Batch payload format:
81
-
82
- ```json
83
- [
84
- { "command": "open", "positionals": ["settings"], "flags": {} },
85
- { "command": "wait", "positionals": ["label=\"Privacy & Security\"", "3000"], "flags": {} },
86
- { "command": "click", "positionals": ["label=\"Privacy & Security\""], "flags": {} },
87
- { "command": "get", "positionals": ["text", "label=\"Tracking\""], "flags": {} }
88
- ]
89
- ```
90
-
91
- Batch response includes:
92
-
93
- - `total`, `executed`, `totalDurationMs`
94
- - per-step `results[]` with `durationMs`
95
- - failure context with failing `step` and `partialResults`
96
-
97
- Agent usage guidelines:
98
-
99
- - Keep each batch to one screen-local workflow.
100
- - Add sync guards (`wait`, `is exists`) after mutating steps (`open`, `click`, `fill`, `swipe`).
101
- - Treat refs/snapshot assumptions as stale after UI mutations.
102
- - Prefer `--steps-file` over inline JSON for reliability.
103
- - Keep batches moderate (about 5-20 steps) and stop on first error.
104
-
105
- ## CLI Usage
106
-
107
- ```bash
108
- agent-device <command> [args] [--json]
109
- ```
110
-
111
- ## Configuration
112
-
113
- Create an `agent-device.json` file to set persistent CLI defaults instead of repeating flags.
114
-
115
- Config file lookup order:
116
- - `~/.agent-device/config.json`
117
- - `./agent-device.json`
118
- - `AGENT_DEVICE_*` environment variables
119
- - CLI flags
120
-
121
- Later sources override earlier ones. Use `--config <path>` or `AGENT_DEVICE_CONFIG` to load one explicit config file instead of the default locations.
122
-
123
- Example:
124
-
125
- ```json
126
- {
127
- "platform": "ios",
128
- "device": "iPhone 16",
129
- "session": "qa-ios",
130
- "snapshotDepth": 3,
131
- "daemonBaseUrl": "http://mac-host.example:4310/agent-device"
132
- }
133
- ```
134
-
135
- Notes:
136
- - Config keys use the existing camelCase flag names, for example `stateDir`, `daemonAuthToken`, `iosSimulatorDeviceSet`, and `androidDeviceAllowlist`.
137
- - Environment overrides use `AGENT_DEVICE_*` uppercase snake case names, for example `AGENT_DEVICE_SESSION`, `AGENT_DEVICE_DAEMON_BASE_URL`, and `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET`.
138
- - Bound-session routing defaults also work through config or env, for example `sessionLock` / `AGENT_DEVICE_SESSION_LOCK`.
139
- - For options that have CLI aliases, config/env use the canonical value rather than the alias flag. Example: use `"appsFilter": "user-installed"` or `AGENT_DEVICE_APPS_FILTER=user-installed`, not `--user-installed`.
140
- - Command-specific defaults are applied only when that command supports them, so a `snapshotDepth` default does not break `open` or `devices`.
141
-
142
- Basic flow:
143
-
144
- ```bash
145
- agent-device open SampleApp
146
- agent-device snapshot
147
- agent-device press @e7
148
- agent-device fill @e8 "hello"
149
- agent-device close SampleApp
150
- ```
151
-
152
- Debug flow:
153
-
154
- ```bash
155
- agent-device trace start
156
- agent-device snapshot -s "Sample App"
157
- agent-device find label "Wi-Fi" click
158
- agent-device trace stop ./trace.log
159
- ```
160
-
161
- Coordinates:
162
- - All coordinate-based commands (`press`, `longpress`, `swipe`, `focus`, `fill`) use device coordinates with origin at top-left.
163
- - X increases to the right, Y increases downward.
164
- - `press` is the canonical tap command.
165
- - `click` is an equivalent alias and accepts the same targets (`x y`, `@ref`, selector) and flags.
166
-
167
- Gesture series examples:
168
-
169
- ```bash
170
- agent-device press 300 500 --count 12 --interval-ms 45
171
- agent-device press 300 500 --count 6 --hold-ms 120 --interval-ms 30 --jitter-px 2
172
- agent-device press @e5 --count 5 --double-tap
173
- agent-device swipe 540 1500 540 500 120 --count 8 --pause-ms 30 --pattern ping-pong
174
- agent-device scrollintoview "Sign in"
175
- agent-device scrollintoview @e42
176
- ```
177
-
178
- ## Command Index
179
- - `boot`, `open`, `close`, `install`, `reinstall`, `home`, `back`, `app-switcher`
180
- - `push`
181
- - `batch`
182
- - `snapshot`, `diff snapshot`, `find`, `get`
183
- - `press` (alias: `click`), `focus`, `type`, `fill`, `long-press`, `swipe`, `scroll`, `scrollintoview`, `pinch`, `is`
184
- - `alert`, `wait`, `screenshot`
185
- - `trigger-app-event <event> [payloadJson]`
186
- - `trace start`, `trace stop`
187
- - `logs path`, `logs start`, `logs stop`, `logs clear`, `logs clear --restart`, `logs doctor`, `logs mark` (session app log file for grep; iOS simulator + iOS device + Android)
188
- - `clipboard read`, `clipboard write <text>` (iOS simulator + Android)
189
- - `keyboard [status|get|dismiss]` (Android emulator/device)
190
- - `network dump [limit] [summary|headers|body|all]`, `network log ...` (best-effort HTTP(s) parsing from session app log)
191
- - `settings wifi|airplane|location on|off`
192
- - `settings appearance light|dark|toggle`
193
- - `settings faceid match|nonmatch|enroll|unenroll` (iOS simulator only)
194
- - `settings touchid match|nonmatch|enroll|unenroll` (iOS simulator only)
195
- - `settings fingerprint match|nonmatch` (Android emulator/device where supported)
196
- - `settings permission grant|deny|reset camera|microphone|photos|contacts|notifications [full|limited]`
197
- - `appstate`, `apps`, `devices`, `session list`
198
- - `perf` (alias: `metrics`)
199
-
200
- Push notification simulation:
201
-
202
- ```bash
203
- # iOS simulator: app bundle + payload file
204
- agent-device push com.example.app ./payload.apns --platform ios --device "iPhone 16"
205
-
206
- # iOS simulator: inline JSON payload
207
- agent-device push com.example.app '{"aps":{"alert":"Welcome","badge":1}}' --platform ios
208
-
209
- # Android: package + payload (action/extras map)
210
- agent-device push com.example.app '{"action":"com.example.app.PUSH","extras":{"title":"Welcome","unread":3,"promo":true}}' --platform android
211
- ```
212
-
213
- Payload notes:
214
- - iOS uses `xcrun simctl push <device> <bundle> <payload>` and requires APNs-style JSON object (for example `{"aps":{"alert":"..."}}`).
215
- - Android uses `adb shell am broadcast` with payload JSON shape:
216
- `{"action":"<intent-action>","receiver":"<optional component>","extras":{"key":"value","flag":true,"count":3}}`.
217
- - Android extras support string/boolean/number values.
218
- - `push` works with session context (uses session device) or explicit device selectors.
219
-
220
- App event triggers (app hook):
221
-
222
- ```bash
223
- agent-device trigger-app-event screenshot_taken '{"source":"qa"}'
224
- ```
225
-
226
- - `trigger-app-event` dispatches an app event via deep link and requires an app-side test/debug hook.
227
- - `trigger-app-event` requires either an active session or explicit device selectors (`--platform`, `--device`, `--udid`, `--serial`).
228
- - On iOS physical devices, custom-scheme deep links require active app context (open the app in-session first).
229
- - Configure one of:
230
- - `AGENT_DEVICE_APP_EVENT_URL_TEMPLATE`
231
- - `AGENT_DEVICE_IOS_APP_EVENT_URL_TEMPLATE`
232
- - `AGENT_DEVICE_ANDROID_APP_EVENT_URL_TEMPLATE`
233
- - Template placeholders: `{event}`, `{payload}`, `{platform}`.
234
- - Example template: `myapp://agent-device/event?name={event}&payload={payload}`.
235
- - `payloadJson` must be a JSON object.
236
- - This is app-hook-based simulation, not an OS-global notification injector.
237
- - Canonical trigger contract lives in [`website/docs/docs/commands.md`](website/docs/docs/commands.md) under **App event triggers**.
238
-
239
- ## iOS Snapshots
240
-
241
- Notes:
242
- - iOS snapshots use XCTest on simulators and physical devices.
243
- - Scope snapshots with `-s "<label>"` or `-s @ref`.
244
- - If XCTest returns 0 nodes (e.g., foreground app changed), agent-device fails explicitly.
245
- - `diff snapshot` uses the same snapshot flags and compares the current capture with the previous session baseline, then updates baseline.
246
-
247
- Diff snapshots:
248
- - Run `diff snapshot` once to initialize baseline for the current session.
249
- - Run `diff snapshot` again after UI changes to get unified-style output (`-` removed, `+` added, unchanged context).
250
- - Use `--json` to get `{ mode, baselineInitialized, summary, lines }`.
251
-
252
- Efficient snapshot usage:
253
- - Default to `snapshot -i` for iterative agent loops.
254
- - Add `-s "<label>"` (or `-s @ref`) for screen-local work to reduce payload size.
255
- - Add `-d <depth>` when lower tree levels are not needed.
256
- - Re-snapshot after UI mutations before reusing refs.
257
- - Use `diff snapshot` for low-noise structural change verification between adjacent states.
258
- - Reserve `--raw` for troubleshooting and parser/debug investigations.
259
-
260
- Flags:
261
- - `--version, -V` print version and exit
262
- - `--platform ios|android|apple` (`apple` aliases the iOS/tvOS backend)
263
- - `--target mobile|tv` select device class within platform (requires `--platform`; for example AndroidTV/tvOS)
264
- - `--device <name>`
265
- - `--udid <udid>` (iOS)
266
- - `--serial <serial>` (Android)
267
- - `--ios-simulator-device-set <path>` constrain iOS simulator discovery/commands to one simulator set (`xcrun simctl --set`)
268
- - `--android-device-allowlist <serials>` constrain Android discovery/selection to comma/space-separated serials
269
- - `--activity <component>` (Android app launch only; package/Activity or package/.Activity; not for URL opens)
270
- - `--session <name>`
271
- - `--state-dir <path>` daemon state directory override (default: `~/.agent-device`)
272
- - `--daemon-base-url <url>` explicit remote HTTP daemon base URL; skips local daemon discovery/startup
273
- - `--daemon-auth-token <token>` remote HTTP daemon auth token; sent in both the JSON-RPC request token and HTTP auth headers (`Authorization: Bearer` and `x-agent-device-token`)
274
- - `--daemon-transport auto|socket|http` daemon client transport preference
275
- - `--daemon-server-mode socket|http|dual` daemon server mode (`http` and `dual` expose JSON-RPC over HTTP at `/rpc`)
276
- - `--tenant <id>` tenant identifier used with session isolation
277
- - `--session-isolation none|tenant` explicit session isolation mode (`tenant` scopes session namespace as `<tenant>:<session>`)
278
- - `--run-id <id>` run identifier used with tenant-scoped lease admission
279
- - `--lease-id <id>` active lease identifier used with tenant-scoped lease admission
280
- - `--count <n>` repeat count for `press`/`swipe`
281
- - `--interval-ms <ms>` delay between `press` iterations
282
- - `--hold-ms <ms>` hold duration per `press` iteration
283
- - `--jitter-px <n>` deterministic coordinate jitter for `press`
284
- - `--double-tap` use a double-tap gesture per `press`/`click` iteration (cannot be combined with `--hold-ms` or `--jitter-px`)
285
- - `--pause-ms <ms>` delay between `swipe` iterations
286
- - `--pattern one-way|ping-pong` repeat pattern for `swipe`
287
- - `--debug` (alias: `--verbose`) for debug diagnostics + daemon/runner logs
288
- - `--json` for structured output
289
- - `--steps <json>` batch: JSON array of steps
290
- - `--steps-file <path>` batch: read step JSON from file
291
- - `--on-error stop` batch: stop when a step fails
292
- - `--max-steps <n>` batch: max allowed steps per request
293
-
294
- Isolation precedence:
295
- - Discovery scope (`--ios-simulator-device-set`, `--android-device-allowlist`) is applied before selector matching (`--device`, `--udid`, `--serial`).
296
- - If a selector points outside the scoped set/allowlist, command resolution fails with `DEVICE_NOT_FOUND` (no host-global fallback).
297
- - When `--ios-simulator-device-set` is set (or its env equivalent), iOS discovery is simulator-set only (physical iOS devices are not enumerated).
298
-
299
- TV targets:
300
- - Use `--target tv` together with `--platform ios|android|apple`.
301
- - TV target selection supports both simulator/emulator and connected physical devices (AppleTV + AndroidTV).
302
- - AndroidTV app launch/app listing use TV launcher discovery (`LEANBACK_LAUNCHER`) and fallback component resolution when needed.
303
- - tvOS uses the same runner-driven interaction/snapshot flow as iOS (`snapshot`, `wait`, `press`, `fill`, `get`, `scroll`, `back`, `home`, `app-switcher`, `record`, and related selector flows).
304
- - tvOS back/home/app-switcher use Siri Remote semantics in the runner (`menu`, `home`, double-home).
305
- - tvOS follows iOS simulator-only command semantics for helpers like `pinch`, `settings`, and `push`.
306
-
307
- Examples:
308
- - `agent-device open YouTube --platform android --target tv`
309
- - `agent-device apps --platform android --target tv`
310
- - `agent-device open Settings --platform ios --target tv`
311
- - `agent-device screenshot ./apple-tv.png --platform ios --target tv`
312
-
313
- Pinch:
314
- - `pinch` is supported on iOS simulators (including tvOS simulator targets).
315
- - On Android, `pinch` currently returns `UNSUPPORTED_OPERATION` in the adb backend.
316
-
317
- Swipe timing:
318
- - `swipe` accepts optional `durationMs` (default `250`, range `16..10000`).
319
- - Android uses requested swipe duration directly.
320
- - iOS clamps swipe duration to a safe range (`16..60ms`) to avoid longpress side effects.
321
- - `scrollintoview` accepts either plain text or a snapshot ref (`@eN`); ref mode uses best-effort geometry-based scrolling without post-scroll verification. Run `snapshot` again before follow-up `@ref` commands.
322
-
323
- ## Skills
324
- Install the automation skills listed in [SKILL.md](skills/agent-device/SKILL.md).
325
-
326
- ```bash
327
- npx skills add https://github.com/callstackincubator/agent-device --skill agent-device
328
- ```
329
-
330
- Sessions:
331
- - `open` starts a session. Without args boots/activates the target device/simulator without launching an app.
332
- - All interaction commands require an open session.
333
- - If a session is already open, `open <app|url>` switches the active app or opens a deep link URL.
334
- - `close` stops the session and releases device resources. Pass an app to close it explicitly, or omit to just close the session.
335
- - Use `--session <name>` to manage multiple sessions.
336
- - Session scripts are written to `<state-dir>/sessions/<session>-<timestamp>.ad` when recording is enabled with `--save-script`.
337
- - `--save-script` accepts an optional path: `--save-script ./workflows/my-flow.ad`.
338
- - For ambiguous bare values, use an explicit form: `--save-script=workflow.ad` or a path-like value such as `./workflow.ad`.
339
- - Deterministic replay is `.ad`-based; use `replay --update` (`-u`) to update selector drift and rewrite the replay file in place.
340
- - On iOS, `appstate` is session-scoped and requires an active session on the target device.
341
-
342
- Navigation helpers:
343
- - `boot --platform ios|android|apple` ensures the target is ready without launching an app.
344
- - Use `boot` mainly when starting a new session and `open` fails because no booted simulator/emulator is available.
345
- - `open [app|url] [url]` already boots/activates the selected target when needed.
346
- - `install <app> <path>` installs app binary without uninstalling first (Android + iOS simulator/device).
347
- - `install-from-source <url>` installs from a URL source through the normal daemon artifact flow; repeat `--header name:value` for authenticated downloads.
348
- - `reinstall <app> <path>` uninstalls and installs the app binary in one command (Android + iOS simulator/device).
349
- - `install`/`reinstall` accept package/bundle id style app names and support `~` in paths.
350
- - `install-from-source` supports `--retain-paths` and `--retention-ms <ms>` when callers need retained materialized artifact paths after the install.
351
- - When `AGENT_DEVICE_DAEMON_BASE_URL` targets a remote daemon, local `.apk`/`.aab`/`.ipa` files and `.app` bundles are uploaded automatically before `install`/`reinstall`.
352
- - `open <app> --remote-config <path> --relaunch` is the canonical remote Metro-backed launch flow for sandbox agents. The remote profile supplies host + Metro settings, `open` prepares Metro locally when needed, derives platform runtime hints, and forwards them inline to the remote daemon before launch.
353
- - `metro prepare --remote-config <path>` remains available for inspection and debugging. It prints JSON runtime hints to stdout, `--json` wraps them in the standard `{ success, data }` envelope, and `--runtime-file <path>` persists the same payload when callers need an artifact.
354
- - Remote daemon screenshots and recordings are materialized back to the caller path instead of returning host-local daemon paths.
355
- - To force a daemon-side path instead of uploading a local file, prefix it with `remote:`, for example `remote:/srv/builds/MyApp.app`.
356
- - Supported binary formats for `install`/`reinstall`: Android `.apk` and `.aab`, iOS `.app` and `.ipa`.
357
- - `.aab` requires `bundletool` in `PATH`, or `AGENT_DEVICE_BUNDLETOOL_JAR=<path-to-bundletool-all.jar>` (with `java` in `PATH`).
358
- - For Android `.aab`, set `AGENT_DEVICE_ANDROID_BUNDLETOOL_MODE=<mode>` to override bundletool `--mode` (default: `universal`).
359
- - `.ipa` install extracts `Payload/*.app`; when an IPA contains multiple app bundles, `<app>` is used as a bundle id/name hint to select the target bundle.
360
-
361
- Deep links:
362
- - `open <url>` supports deep links with `scheme://...`.
363
- - `open <app> <url>` opens a deep link on iOS.
364
- - Android opens deep links via `VIEW` intent.
365
- - iOS simulator opens deep links via `simctl openurl`.
366
- - iOS device opens deep links via `devicectl --payload-url`.
367
- - On iOS devices, `http(s)://` URLs open in Safari when no app is active. Custom scheme URLs (`myapp://`) require an active app in the session.
368
- - `--activity` cannot be combined with URL opens.
369
-
370
- ```bash
371
- agent-device open "myapp://home" --platform android
372
- agent-device open "https://example.com" --platform ios # open link in web browser
373
- agent-device open MyApp "myapp://screen/to" --platform ios # open deep link to MyApp
374
- ```
375
-
376
- Find (semantic):
377
- - `find <text> <action> [value]` finds by any text (label/value/identifier) using a scoped snapshot.
378
- - `find text|label|value|role|id <value> <action> [value]` for specific locators.
379
- - Actions: `click` (default), `fill`, `type`, `focus`, `get text`, `get attrs`, `wait [timeout]`, `exists`.
380
-
381
- Assertions:
382
- - `is` predicates: `visible`, `hidden`, `exists`, `editable`, `selected`, `text`.
383
- - `is text` uses exact equality.
384
-
385
- Performance metrics:
386
- - `perf` (or `metrics`) requires an active session and returns a JSON metrics blob.
387
- - Current metric: `startup` sampled from the elapsed wall-clock time around each session `open` command dispatch (`open-command-roundtrip`), unit `ms`.
388
- - Startup samples are session-scoped and include sample history from recent `open` actions.
389
- - Platform support for current sampling: iOS simulator, iOS physical device, Android emulator/device.
390
- - `fps`, `memory`, and `cpu` are reported as not yet implemented in this release.
391
- - Quick usage:
392
-
393
- ```bash
394
- agent-device open Settings --platform ios
395
- agent-device perf --json
396
- ```
397
-
398
- - How to read it:
399
- - `metrics.startup.lastDurationMs`: most recent startup sample in milliseconds.
400
- - `metrics.startup.samples[]`: recent startup history for this session.
401
- - `sampling.startup.method`: currently `open-command-roundtrip`.
402
- - Caveat: startup here is command-to-launch round-trip timing, not true app TTI/first-interactive telemetry.
403
-
404
- Replay update:
405
- - `replay <path>` runs deterministic replay from `.ad` scripts.
406
- - `replay -u <path>` attempts selector updates on failures and atomically rewrites the same file.
407
- - Refs are the default/core mechanism for interactive agent flows.
408
- - Update targets: `click`, `fill`, `get`, `is`, `wait`.
409
- - Selector matching is a replay-update internal: replay parses `.ad` lines into actions, tries them, snapshots on failure, resolves a better selector, then rewrites that failing line.
410
-
411
- Update examples:
412
-
413
- ```sh
414
- # Before (stale selector)
415
- click "id=\"old_continue\" || label=\"Continue\""
416
-
417
- # After replay -u (rewritten in place)
418
- click "id=\"auth_continue\" || label=\"Continue\""
419
- ```
420
-
421
- ```sh
422
- # Before (ref-based action from discovery)
423
- snapshot -i -c -s "Continue"
424
- click @e13 "Continue"
425
-
426
- # After replay -u (upgraded to selector-based action)
427
- snapshot -i -c -s "Continue"
428
- click "id=\"auth_continue\" || label=\"Continue\""
429
- ```
430
-
431
- Android fill reliability:
432
- - `fill` clears the current value, then enters text.
433
- - `type` enters text into the focused field without clearing.
434
- - `fill` now verifies the entered value on Android.
435
- - If value does not match, agent-device clears the field and retries once with slower typing.
436
- - This reduces IME-related character swaps on long strings (e.g. emails and IDs).
437
- - Some Android system images cannot inject non-ASCII text (for example Chinese or emoji) through shell input.
438
- - If this occurs, install an ADB keyboard IME from a trusted source, verify checksum/signature, and enable it only for test sessions:
439
- - Trusted sources: https://github.com/senzhk/ADBKeyBoard or https://f-droid.org/packages/com.android.adbkeyboard/
440
- - `adb -s <serial> install <path-to-adbkeyboard.apk>`
441
- - `adb -s <serial> shell ime enable com.android.adbkeyboard/.AdbIME`
442
- - `adb -s <serial> shell ime set com.android.adbkeyboard/.AdbIME`
443
- - `adb -s <serial> shell ime list -s` (verify current/default IME)
444
-
445
- Settings helpers:
446
- - `settings wifi on|off`
447
- - `settings airplane on|off`
448
- - `settings location on|off` (iOS uses per-app permission for the current session app)
449
- - `settings appearance light|dark|toggle` (iOS simulator appearance + Android night mode)
450
- - `settings faceid|touchid match|nonmatch|enroll|unenroll` (iOS simulator only)
451
- - `settings fingerprint match|nonmatch` (Android emulator/device where supported)
452
- On physical Android devices, fingerprint simulation depends on `cmd fingerprint` support.
453
- - `settings permission grant|deny|reset <camera|microphone|photos|contacts|notifications> [full|limited]` (session app required)
454
- Note: iOS supports these only on simulators. iOS wifi/airplane toggles status bar indicators, not actual network state. Airplane off clears status bar overrides.
455
- - iOS permission targets map to `simctl privacy`: `camera`, `microphone`, `photos` (`full` => `photos`, `limited` => `photos-add`), `contacts`, `notifications`.
456
- - Android permission targets: `camera`, `microphone`, `photos`, `contacts` use `pm grant|revoke` (`reset` maps to `pm revoke`); `notifications` uses `appops set POST_NOTIFICATION allow|deny|default`.
457
- - `full|limited` mode is valid only for iOS `photos`; other targets reject mode.
458
-
459
- App state:
460
- - `appstate` shows the foreground app/activity (Android).
461
- - On iOS, `appstate` returns the currently tracked session app (`source: session`) and requires an active session on the selected device.
462
- - `apps` includes default/system apps by default (use `--user-installed` to filter).
463
-
464
- Clipboard:
465
- - `clipboard read` returns current clipboard text.
466
- - `clipboard write <text>` sets clipboard text (`clipboard write ""` clears it).
467
- - Supported on Android emulator/device and iOS simulator.
468
- - iOS physical devices currently return `UNSUPPORTED_OPERATION` for clipboard commands.
469
-
470
- Keyboard:
471
- - `keyboard status` (or `keyboard get`) reports Android keyboard visibility and best-effort input type classification (`text`, `number`, `email`, `phone`, `password`, `datetime`).
472
- - `keyboard dismiss` issues Android back keyevent only when keyboard is visible, then verifies hidden state.
473
- - Works with an active session device or explicit selectors (`--platform`, `--device`, `--udid`, `--serial`).
474
- - Supported on Android emulator/device.
44
+ In practice, most work follows the same pattern:
475
45
 
476
- ## Debug
46
+ 1. `open` a target app or URL.
47
+ 2. `snapshot -i` to inspect the current screen.
48
+ 3. `press`, `fill`, `scroll`, `get`, or `wait` using refs or selectors.
49
+ 4. `diff snapshot` or re-snapshot after UI changes.
50
+ 5. `close` when the session is finished.
477
51
 
478
- - **App logs (token-efficient):** Logging is off by default in normal flows. Enable it on demand when debugging. With an active session, run `logs path` to get path + state metadata (e.g. `<state-dir>/sessions/<session>/app.log`). Run `logs start` to stream app output to that file; use `logs stop` to stop. Run `logs clear` to truncate `app.log` (and remove rotated `app.log.N` files) before a new repro window. Run `logs doctor` for tool/runtime checks and `logs mark "step"` to insert timeline markers. Grep the file when you need to inspect errors (e.g. `grep -n "Error\|Exception" <path>`) instead of pulling full logs into context. Supported on iOS simulator, iOS physical device, and Android.
479
- - Use `logs clear --restart` when you want one command to stop an active stream, clear current logs, and immediately resume streaming.
480
- - `logs start` appends to `app.log` and rotates to `app.log.1` when the file exceeds 5 MB.
481
- - **Network dump (best-effort):** `network dump [limit] [summary|headers|body|all]` parses recent HTTP(s) lines from the same session app log file and returns method/url/status with optional headers/bodies. `network log ...` is an alias. Current limits: scans up to 4000 recent log lines, returns up to 200 entries, truncates payload/header fields at 2048 characters.
482
- - Android log streaming automatically rebinds to the app PID after process restarts.
483
- - Detailed playbook: `skills/agent-device/references/logs-and-debug.md`
484
- - iOS log capture relies on Unified Logging signals (for example `os_log`); plain stdout/stderr output may be limited depending on app/runtime.
485
- - Retention knobs: set `AGENT_DEVICE_APP_LOG_MAX_BYTES` and `AGENT_DEVICE_APP_LOG_MAX_FILES` to override rotation limits.
486
- - Optional write-time redaction patterns: set `AGENT_DEVICE_APP_LOG_REDACT_PATTERNS` to a comma-separated regex list.
487
- - `agent-device trace start`
488
- - `agent-device trace stop ./trace.log`
489
- - The trace log includes snapshot logs and XCTest runner logs for the session.
490
- - Built-in retries cover transient runner connection failures and Android UI dumps.
491
- - For snapshot issues (missing elements), compare with `--raw` flag for unaltered output and scope with `-s "<label>"`.
492
- - If startup fails with stale metadata hints, remove stale `<state-dir>/daemon.json` / `<state-dir>/daemon.lock` and retry (state dir defaults to `~/.agent-device` unless overridden).
52
+ ## Where To Go Next
493
53
 
494
- Boot diagnostics:
495
- - Boot failures include normalized reason codes in `error.details.reason` (JSON mode) and verbose logs.
496
- - Reason codes: `IOS_BOOT_TIMEOUT`, `IOS_RUNNER_CONNECT_TIMEOUT`, `ANDROID_BOOT_TIMEOUT`, `ADB_TRANSPORT_UNAVAILABLE`, `CI_RESOURCE_STARVATION_SUSPECTED`, `BOOT_COMMAND_FAILED`, `UNKNOWN`.
497
- - Android boot waits fail fast for permission/tooling issues and do not always collapse into timeout errors.
498
- - Use `agent-device boot --platform ios|android|apple` when starting a new session only if `open` cannot find/connect to an available target.
499
- - Android emulator boot by AVD name (GUI): `agent-device boot --platform android --device Pixel_9_Pro_XL`.
500
- - Android headless emulator boot: `agent-device boot --platform android --device Pixel_9_Pro_XL --headless`.
501
- - `--debug` captures retry telemetry in diagnostics logs.
502
- - Set `AGENT_DEVICE_RETRY_LOGS=1` to also print retry telemetry directly to stderr (ad-hoc troubleshooting).
54
+ For people:
55
+ - [Website](https://agent-device.dev/)
56
+ - [Docs](https://incubator.callstack.com/agent-device/docs/introduction)
503
57
 
504
- Diagnostics files:
505
- - Failed commands persist diagnostics in `~/.agent-device/logs/<session>/<date>/<timestamp>-<diagnosticId>.ndjson`.
506
- - `--debug` persists diagnostics for successful commands too and streams live diagnostic events.
507
- - JSON failures include `error.hint`, `error.diagnosticId`, and `error.logPath`.
58
+ For agents:
508
59
 
509
- ## App resolution
510
- - Bundle/package identifiers are accepted directly (e.g., `com.apple.Preferences`).
511
- - Human-readable names are resolved when possible (e.g., `Settings`).
512
- - Built-in aliases include `Settings` for both platforms.
60
+ - [agent-device skill](skills/agent-device/SKILL.md)
61
+ - [dogfood skill](skills/dogfood/SKILL.md)
62
+ - [agent-device skill on ClawHub](https://clawhub.ai/okwasniewski/agent-device)
513
63
 
514
- ## iOS notes
515
- - Core runner commands: `snapshot`, `wait`, `click`, `fill`, `get`, `is`, `find`, `press`, `longpress`, `focus`, `type`, `scroll`, `scrollintoview`, `back`, `home`, `app-switcher`.
516
- - Simulator-only commands: `alert`, `pinch`, `settings`.
517
- - tvOS targets are selectable (`--platform ios --target tv` or `--platform apple --target tv`) and support runner-driven interaction/snapshot commands.
518
- - `record` supports iOS simulators and physical iOS devices.
519
- - iOS simulator recording uses native `simctl io ... recordVideo`.
520
- - Physical iOS device recording is runner-based and built from repeated `XCUIScreen.main.screenshot()` frames (no native video stream/audio capture).
521
- - Physical iOS device recording requires an active app session context (`open <app>` first) so capture targets your app instead of the runner host app.
522
- - Physical iOS device capture is best-effort: dropped frames are expected and true 60 FPS is not guaranteed even with `--fps 60`.
523
- - Physical iOS device recording defaults to uncapped (max available) FPS.
524
- - Use `agent-device record start [path] --fps <n>` (1-120) to set an explicit FPS cap on physical iOS devices.
525
- - iOS device runs require valid signing/provisioning (Automatic Signing recommended). Optional overrides: `AGENT_DEVICE_IOS_TEAM_ID`, `AGENT_DEVICE_IOS_SIGNING_IDENTITY`, `AGENT_DEVICE_IOS_PROVISIONING_PROFILE`, `AGENT_DEVICE_IOS_BUNDLE_ID`.
526
- - Free Apple Developer (Personal Team) accounts may need a unique runner bundle id; set `AGENT_DEVICE_IOS_BUNDLE_ID` to a reverse-DNS identifier unique to your team (for example `com.yourname.agentdevice.runner`).
527
-
528
- ## Testing
529
-
530
- ```bash
531
- pnpm test
532
- ```
533
-
534
- Useful local checks:
535
-
536
- ```bash
537
- pnpm typecheck
538
- pnpm test:unit
539
- pnpm test:smoke
540
- ```
541
-
542
- ## Build
64
+ ## Install
543
65
 
544
66
  ```bash
545
- pnpm build
67
+ npm install -g agent-device
546
68
  ```
547
69
 
548
- Environment selectors:
549
- - `ANDROID_DEVICE=Pixel_9_Pro_XL` or `ANDROID_SERIAL=emulator-5554`
550
- - `IOS_DEVICE="iPhone 17 Pro"` or `IOS_UDID=<udid>`
551
- - `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET=<path>` (or `IOS_SIMULATOR_DEVICE_SET=<path>`) to scope all iOS simulator discovery/commands to one simulator set.
552
- - `AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST=<serials>` (or `ANDROID_DEVICE_ALLOWLIST=<serials>`) to scope Android discovery to allowlisted serials.
553
- - `AGENT_DEVICE_SESSION=<name>` sets the default CLI session when `--session` is omitted.
554
- - `AGENT_DEVICE_PLATFORM=ios|android|apple` sets the default CLI platform when `--platform` is omitted.
555
- - When `AGENT_DEVICE_SESSION` is set, the CLI treats the run as session-bound by default and sends a shared daemon lock policy with the request.
556
- - `--session-lock reject|strip` sets the lock policy for the current CLI invocation and nested batch steps.
557
- - `AGENT_DEVICE_SESSION_LOCK=reject|strip` sets the default lock policy for bound-session automation runs. `strip` ignores `--target`, `--device`, `--udid`, `--serial`, `--ios-simulator-device-set`, and `--android-device-allowlist`, and restores the configured platform.
558
- - The daemon is the source of truth for lock-policy enforcement across CLI requests, typed client calls, and direct RPC.
559
- - Direct RPC callers can pass `meta.lockPolicy` and optional `meta.lockPlatform` on `agent_device.command` requests to use the same daemon-enforced session lock concept.
560
- - `--session-locked`, `--session-lock-conflicts`, `AGENT_DEVICE_SESSION_LOCKED`, and `AGENT_DEVICE_SESSION_LOCK_CONFLICTS` remain supported as compatibility aliases.
561
- - For `batch`, steps that omit `platform` continue to inherit the parent batch `--platform` even when session-bound defaults are configured.
562
- - `AGENT_DEVICE_BUNDLETOOL_JAR=<path-to-bundletool-all.jar>` optional bundletool jar path used for Android `.aab` installs when `bundletool` is not in `PATH`.
563
- - `AGENT_DEVICE_ANDROID_BUNDLETOOL_MODE=<mode>` optional bundletool `build-apks --mode` override for Android `.aab` installs (default: `universal`).
564
- - CLI flags `--ios-simulator-device-set` / `--android-device-allowlist` override environment values.
565
- - `AGENT_DEVICE_IOS_BOOT_TIMEOUT_MS=<ms>` to adjust iOS simulator boot timeout (default: `120000`, minimum: `5000`).
566
- - `AGENT_DEVICE_DAEMON_TIMEOUT_MS=<ms>` to override daemon request timeout (default `90000`). Increase for slow physical-device setup (for example `120000`).
567
- - `AGENT_DEVICE_STATE_DIR=<path>` override daemon state directory (metadata, logs, session artifacts).
568
- - `AGENT_DEVICE_DAEMON_BASE_URL=http(s)://host:port[/base-path]` connect directly to a remote HTTP daemon and skip local daemon metadata/startup.
569
- - Remote daemon installs upload local artifacts through `POST /upload`; use a `remote:` path prefix when you need the daemon to read an existing server-side artifact path as-is.
570
- - `AGENT_DEVICE_DAEMON_AUTH_TOKEN=<token>` auth token for remote HTTP daemon mode; sent in both the JSON-RPC request token and HTTP auth headers (`Authorization: Bearer` and `x-agent-device-token`).
571
- - `AGENT_DEVICE_PROXY_TOKEN=<token>` preferred bearer token for `metro prepare --proxy-base-url <url>` so the host-bridge secret does not need to be passed on the command line. `AGENT_DEVICE_METRO_BEARER_TOKEN` is also supported.
572
- - `AGENT_DEVICE_DAEMON_SERVER_MODE=socket|http|dual` daemon server mode. `http` and `dual` expose JSON-RPC 2.0 at `POST /rpc` (`GET /health` available for liveness).
573
- - `AGENT_DEVICE_DAEMON_TRANSPORT=auto|socket|http` client preference when connecting to daemon metadata.
574
- - `AGENT_DEVICE_HTTP_AUTH_HOOK=<module-path>` optional HTTP auth hook module path for JSON-RPC server mode.
575
- - `AGENT_DEVICE_HTTP_AUTH_EXPORT=<export-name>` optional export name from auth hook module (default: `default`).
576
- - `AGENT_DEVICE_SOURCE_DOWNLOAD_TIMEOUT_MS=<ms>` timeout for `installFromSource` URL downloads (default: `120000`).
577
- - `AGENT_DEVICE_ALLOW_PRIVATE_SOURCE_URLS=1` opt out of the default SSRF guard that blocks loopback/private-network artifact URLs for `installFromSource`.
578
- - `AGENT_DEVICE_MAX_SIMULATOR_LEASES=<n>` optional max concurrent simulator leases for HTTP lease allocation (default: unlimited).
579
- - `AGENT_DEVICE_LEASE_TTL_MS=<ms>` default lease TTL used by `agent_device.lease.allocate` and `agent_device.lease.heartbeat` (default: `60000`).
580
- - `AGENT_DEVICE_LEASE_MIN_TTL_MS=<ms>` minimum accepted lease TTL (default: `5000`).
581
- - `AGENT_DEVICE_LEASE_MAX_TTL_MS=<ms>` maximum accepted lease TTL (default: `600000`).
582
- - `AGENT_DEVICE_IOS_TEAM_ID=<team-id>` optional Team ID override for iOS device runner signing.
583
- - `AGENT_DEVICE_IOS_SIGNING_IDENTITY=<identity>` optional signing identity override.
584
- - `AGENT_DEVICE_IOS_PROVISIONING_PROFILE=<profile>` optional provisioning profile specifier for iOS device runner signing.
585
- - `AGENT_DEVICE_IOS_BUNDLE_ID=<reverse-dns-id>` optional iOS runner app bundle id base. Tests derive from this as `<id>.uitests`.
586
- - `AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH=<path>` optional override for iOS runner derived data root. By default, simulator uses `~/.agent-device/ios-runner/derived` and physical device uses `~/.agent-device/ios-runner/derived/device`. If you set this override, use separate paths per kind to avoid simulator/device artifact collisions.
587
- - `AGENT_DEVICE_IOS_CLEAN_DERIVED=1` rebuild iOS runner artifacts from scratch for runtime daemon-triggered builds (`pnpm ad ...`) on the selected path. `pnpm build:xcuitest` (alias of `pnpm build:xcuitest:ios`), `pnpm build:xcuitest:tvos`, and `pnpm build:all` already clear their default derived paths and do not require this variable. When `AGENT_DEVICE_IOS_RUNNER_DERIVED_PATH` is set, cleanup is blocked by default; set `AGENT_DEVICE_IOS_ALLOW_OVERRIDE_DERIVED_CLEAN=1` only for trusted custom paths.
588
-
589
- Test screenshots are written to:
590
- - `test/screenshots/android-settings.png`
591
- - `test/screenshots/ios-settings.png`
592
-
593
70
  ## Contributing
594
- See `CONTRIBUTING.md`.
71
+
72
+ See [CONTRIBUTING.md](CONTRIBUTING.md).
595
73
 
596
74
  ## Made at Callstack
597
75