@houwert/conductor 0.12.2 → 0.13.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.
@@ -1,825 +0,0 @@
1
- ---
2
- name: conductor
3
- version: 0.12.2
4
- description: "Token-efficient CLI for mobile UI testing (iOS simulator + Android emulator), designed for AI agents"
5
- metadata.openclaw:
6
- category: service
7
- requires:
8
- bins: [conductor]
9
- ---
10
-
11
- # conductor
12
-
13
- A token-efficient CLI for Conductor mobile UI testing, designed for AI agents.
14
-
15
- ## Usage
16
-
17
- ```
18
- conductor <command> [args] [options]
19
- ```
20
-
21
- Global options:
22
- - `--device <id>` — target device ID; also keys the session and daemon (auto-detected if omitted)
23
- - `--device-name <name>` — target a booted device by its human-readable name (resolved to ID from booted devices); mutually exclusive with `--device`
24
- - `--help` — show help
25
- - `--json` — machine-readable JSON output (avoid unless you need structured parsing)
26
- - `--verbose / -v` — log daemon calls, driver fallbacks, and raw output
27
-
28
- ---
29
-
30
- ## Commands
31
-
32
- ### `list-devices`
33
-
34
- List connected Android emulators and iOS simulators. Shows both booted (running) devices and available (shutdown) simulators/emulators that can be started with `start-device`.
35
-
36
- ```bash
37
- conductor list-devices
38
- ```
39
-
40
- Output:
41
- ```
42
- Booted devices:
43
- android device emulator-5554 Pixel_6_API_33
44
- ios booted ABC123-DEF456 iPhone 15
45
-
46
- Available devices:
47
- ios shutdown DEF789-ABC012 iPhone 16 Pro
48
- android available Pixel_7_API_34 Pixel_7_API_34
49
- ```
50
-
51
- Exits with code 0 if any booted or available devices exist, 1 only if both lists are empty.
52
-
53
- ---
54
-
55
- ### `foreground-app`
56
-
57
- Print the bundle ID (iOS) or package name (Android) of the currently open app.
58
-
59
- ```bash
60
- conductor foreground-app
61
- conductor foreground-app --device C59D3241-FB6A-4E3B-AE7B-A82D3C933889
62
- ```
63
-
64
- ---
65
-
66
- ### `list-apps`
67
-
68
- List all installed app IDs (bundle IDs on iOS, package names on Android), sorted alphabetically. Does not require the driver to be running.
69
-
70
- ```bash
71
- conductor list-apps
72
- conductor list-apps --device emulator-5554
73
- ```
74
-
75
- ---
76
-
77
- ### `copy-app <bundleId>`
78
-
79
- Copy an installed app from one iOS simulator to another. Useful when you have a compiled `.app` bundle on one simulator and want to install it on others without recompiling.
80
-
81
- ```bash
82
- conductor copy-app com.example.myapp --from C59D3241-FB6A-4E3B-AE7B-A82D3C933889 --to 86B1BC33-7D83-47FF-AAFE-1BD70FC53038
83
- ```
84
-
85
- Flags:
86
- - `--from <id>` — source device ID (must be an iOS simulator)
87
- - `--to <id>` — target device ID (must be an iOS simulator)
88
-
89
- Both flags are required. The command reads the `.app` bundle path from the source simulator and installs it on the target.
90
-
91
- ---
92
-
93
- ### `install-app <path>`
94
-
95
- Install an app from a local `.app` bundle, `.ipa`, or `.apk` file onto the device.
96
-
97
- ```bash
98
- conductor install-app ./build/MyApp.app
99
- conductor install-app ./build/app-debug.apk --device emulator-5554
100
- ```
101
-
102
- ---
103
-
104
- ### `launch-app <appId>`
105
-
106
- Launch an app by bundle ID and save it to the session.
107
-
108
- ```bash
109
- conductor launch-app com.example.myapp
110
- conductor launch-app com.example.myapp --device emulator-5554
111
- conductor launch-app com.example.myapp --clear-state # wipe app data first
112
- conductor launch-app com.example.myapp --clear-keychain # wipe keychain first
113
- conductor launch-app com.example.myapp --no-stop-app # resume instead of restart
114
- conductor launch-app com.example.myapp --argument env=staging --argument debug=true
115
- ```
116
-
117
- Flags:
118
- - `--clear-state` — clear app data/state before launching
119
- - `--clear-keychain` — clear keychain before launching (iOS: full keychain; Android: account credentials)
120
- - `--no-stop-app` — do not stop the app before launching; brings it to the foreground instead of restarting it (default: app is stopped first)
121
- - `--argument key=value` — set a launch argument; repeatable for multiple arguments
122
-
123
- The `appId` and `deviceId` are persisted to `~/.conductor/sessions/<deviceId>.json` and reused by subsequent commands.
124
-
125
- ---
126
-
127
- ### `stop-app [<appId>]`
128
-
129
- Stop the running app. Uses session `appId` if not specified.
130
-
131
- ```bash
132
- conductor stop-app
133
- conductor stop-app com.example.myapp
134
- ```
135
-
136
- ---
137
-
138
- ### `clear-state [<appId>]`
139
-
140
- Clear app data/state without relaunching. Uses the session `appId` if not specified. On iOS this terminates the app, preserves the .app bundle, uninstalls, and reinstalls (clearing all user data). On Android this runs `pm clear`.
141
-
142
- ```bash
143
- conductor clear-state
144
- conductor clear-state com.example.myapp
145
- ```
146
-
147
- ---
148
-
149
- ### `uninstall-app <appId>`
150
-
151
- Uninstall an app from the device. The app ID is required.
152
-
153
- ```bash
154
- conductor uninstall-app com.example.myapp
155
- conductor uninstall-app com.example.myapp --device emulator-5554
156
- ```
157
-
158
- ---
159
-
160
- ### `tap-on <element>`
161
-
162
- Tap a UI element by its text label or accessibility ID. **Try the most obvious text label or ID first** — e.g. `"Sign In"`, `"Submit"`, `"btn_login"`. Only run `inspect` to look up the exact identifier if your first attempt fails. **For icon-only buttons (no visible text label), always run `inspect` first** to find the accessibility ID before tapping.
163
-
164
- ```bash
165
- conductor tap-on "Sign In"
166
- conductor tap-on --id "btn_login" # match by accessibility ID instead of text
167
- conductor tap-on --text "Edit" # match by text only (not id)
168
- conductor tap-on "Next" --index 1 # pick the 2nd match (0-based)
169
- conductor tap-on "Add to cart" --long-press
170
- conductor tap-on "Like" --double-tap
171
- conductor tap-on "Delete" --optional # do not fail if not found
172
- conductor tap-on "Edit" --below "Username" # tap "Edit" that is below the "Username" element
173
- conductor tap-on "Submit" --above "Footer"
174
- conductor tap-on ">" --right-of "Email"
175
- ```
176
-
177
- Flags:
178
- - `--id <id>` — match by accessibility ID / resourceId instead of text
179
- - `--text <text>` — match by text only (not id); bare positional arg matches text OR id
180
- - `--index <n>` — pick the nth match when multiple elements share the same text/id (0-based)
181
- - `--long-press` — hold instead of tap
182
- - `--double-tap` — double-tap the element
183
- - `--optional` — do not fail if element is not found
184
- - `--focused` — match only focused elements
185
- - `--enabled` / `--no-enabled` — match by enabled state
186
- - `--checked` / `--no-checked` — match by checked state
187
- - `--selected` / `--no-selected` — match by selected state
188
- - `--below <text>` — match element below the given reference element
189
- - `--above <text>` — match element above the given reference element
190
- - `--left-of <text>` — match element left of the given reference element
191
- - `--right-of <text>` — match element right of the given reference element
192
-
193
- ---
194
-
195
- ### `input-text <text>`
196
-
197
- Type text into the currently focused input field.
198
-
199
- ```bash
200
- conductor input-text "hello@example.com"
201
- conductor input-text "my password"
202
- ```
203
-
204
- ---
205
-
206
- ### `erase-text [n]`
207
-
208
- Erase characters from the currently focused input field. Defaults to 50 characters.
209
-
210
- ```bash
211
- conductor erase-text # erase 50 characters
212
- conductor erase-text 10 # erase 10 characters
213
- ```
214
-
215
- ---
216
-
217
- ### `back`
218
-
219
- Press the Android back button. **Android only** — iOS has no back button. On iOS, always run `inspect` first to find the exact label or accessibility ID of the in-app back button, then use `tap-on` to press it.
220
-
221
- ```bash
222
- conductor back
223
- ```
224
-
225
- ---
226
-
227
- ### `press-key <key>`
228
-
229
- Press a hardware or keyboard key. Valid keys: `Enter`, `Backspace`, `Home`, `End`, `Tab`, `Delete`, `Escape`, `VolumeUp`, `VolumeDown`, `Power`, `Lock`, `Back`, `Camera`, `Search`, `Remote Dpad Up`, `Remote Dpad Down`, `Remote Dpad Left`, `Remote Dpad Right`, `Remote Dpad Center`.
230
-
231
- Not all keys are supported on all platforms — unsupported keys are silently ignored (e.g. `Back` on iOS). The `Remote Dpad *` keys are Android TV only.
232
-
233
- ```bash
234
- conductor press-key Enter
235
- conductor press-key Backspace
236
- conductor press-key VolumeUp
237
- ```
238
-
239
- ---
240
-
241
- ### `hide-keyboard`
242
-
243
- Dismiss the on-screen keyboard. On iOS, sends the return key; on Android, sends KEYCODE_ESCAPE.
244
-
245
- ```bash
246
- conductor hide-keyboard
247
- ```
248
-
249
- ---
250
-
251
- ### `scroll`
252
-
253
- Scroll the screen. Default direction is `down`.
254
-
255
- ```bash
256
- conductor scroll
257
- conductor scroll --direction up
258
- conductor scroll --direction left
259
- conductor scroll --direction right
260
- ```
261
-
262
- Directions: `down` | `up` | `left` | `right`
263
-
264
- ---
265
-
266
- ### `swipe`
267
-
268
- Perform a swipe gesture.
269
-
270
- ```bash
271
- conductor swipe --direction UP
272
- conductor swipe --direction DOWN
273
- conductor swipe --direction LEFT
274
- conductor swipe --direction RIGHT
275
- conductor swipe --start 0.5,0.8 --end 0.5,0.2 # normalised coords (0–1)
276
- conductor swipe --start 540,1600 --end 540,400 # absolute px
277
- conductor swipe --direction UP --duration 1000 # slower swipe
278
- ```
279
-
280
- Flags:
281
- - `--direction <UP|DOWN|LEFT|RIGHT>` — directional swipe (case-insensitive)
282
- - `--start <x,y>` — start coordinate; values ≤1 are treated as normalised (0–1), larger as absolute px
283
- - `--end <x,y>` — end coordinate (same normalisation rule)
284
- - `--duration <ms>` — swipe duration in milliseconds (default: 500); use `--start`/`--end` or `--direction`
285
-
286
- ---
287
-
288
- ### `scroll-until-visible <element>`
289
-
290
- Scroll in a direction until an element is visible. Useful for long lists.
291
-
292
- ```bash
293
- conductor scroll-until-visible "Checkout"
294
- conductor scroll-until-visible --id "btn_submit"
295
- conductor scroll-until-visible "Terms" --direction up
296
- conductor scroll-until-visible "Privacy" --timeout 60000
297
- ```
298
-
299
- Flags:
300
- - `--id <id>` — match by accessibility ID / resourceId instead of text
301
- - `--text <text>` — match by text only (not id)
302
- - `--direction <down|up|left|right>` — scroll direction (default: `down`)
303
- - `--timeout <ms>` — max time in milliseconds (default: 30 000)
304
-
305
- ---
306
-
307
- ### `assert-visible <element>`
308
-
309
- Assert that a UI element is visible on screen. Exits with code 1 if not found. Try the expected text or ID directly — only use `inspect` if it fails and you need to find the exact identifier.
310
-
311
- ```bash
312
- conductor assert-visible "Welcome"
313
- conductor assert-visible --id "dashboard_title"
314
- conductor assert-visible --text "Submit" # text-only match
315
- conductor assert-visible "Loading..." --optional # do not fail if absent
316
- conductor assert-visible "Dashboard" --timeout 30000 # wait up to 30 s
317
- conductor assert-visible "Edit" --below "Username" # relative position
318
- conductor assert-visible "Item" --index 2 # third match (0-based)
319
- ```
320
-
321
- Flags:
322
- - `--id <id>` — match by accessibility ID / resourceId instead of text
323
- - `--text <text>` — match by text only (not id); bare positional arg matches text OR id
324
- - `--index <n>` — pick the nth match (0-based)
325
- - `--timeout <ms>` — max wait time in milliseconds (default: 17 000)
326
- - `--optional` — succeed even if the element is not found (useful for conditional checks)
327
- - `--focused` — match only focused elements
328
- - `--enabled` / `--no-enabled` — match by enabled state
329
- - `--checked` / `--no-checked` — match by checked state
330
- - `--selected` / `--no-selected` — match by selected state
331
- - `--below <text>` — match element below the given reference element
332
- - `--above <text>` — match element above the given reference element
333
- - `--left-of <text>` — match element left of the given reference element
334
- - `--right-of <text>` — match element right of the given reference element
335
-
336
- ---
337
-
338
- ### `assert-not-visible <element>`
339
-
340
- Assert that a UI element is **not** visible on screen. Fails (exit code 1) if the element is found. Use for verifying elements have been dismissed or hidden.
341
-
342
- ```bash
343
- conductor assert-not-visible "Loading..."
344
- conductor assert-not-visible --id "error_banner"
345
- conductor assert-not-visible "Error" --timeout 5000 # wait up to 5 s for it to disappear
346
- ```
347
-
348
- Flags:
349
- - `--id <id>` — match by accessibility ID / resourceId instead of text
350
- - `--text <text>` — match by text only (not id)
351
- - `--index <n>` — pick the nth match (0-based)
352
- - `--timeout <ms>` — max time to wait for element to disappear (default: 1 000)
353
-
354
- ---
355
-
356
- ### `open-link <url>`
357
-
358
- Open a URL or deep link on the device. Works for both HTTP URLs and custom scheme deep links.
359
-
360
- ```bash
361
- conductor open-link "https://example.com/reset-password"
362
- conductor open-link "myapp://onboarding"
363
- ```
364
-
365
- ---
366
-
367
- ### `set-location --lat <n> --lng <n>`
368
-
369
- Set the device's simulated GPS location.
370
-
371
- ```bash
372
- conductor set-location --lat 52.3676 --lng 4.9041
373
- conductor set-location --lat 37.7749 --lng -122.4194
374
- ```
375
-
376
- ---
377
-
378
- ### `set-orientation <portrait|landscape>`
379
-
380
- Set the device orientation.
381
-
382
- ```bash
383
- conductor set-orientation portrait
384
- conductor set-orientation landscape
385
- ```
386
-
387
- ---
388
-
389
- ### `take-screenshot`
390
-
391
- Take a screenshot of the current screen. **Prefer `inspect` over `take-screenshot`** when you need to understand what is on screen — the view hierarchy tells you element text, IDs, and structure without consuming a vision token. Use `take-screenshot` only for visual evidence, debugging rendering issues, or when a human needs to see the screen.
392
-
393
- ```bash
394
- conductor take-screenshot
395
- conductor take-screenshot --output /tmp/screen.png
396
- conductor take-screenshot --output ./screenshots/login.png
397
- ```
398
-
399
- Default output: `./screenshot-<timestamp>.png`
400
-
401
- **Screenshot path guidance:** Always write to `/tmp/<agent-name>/` (e.g. `/tmp/tester-ios-iphone-16/screen.png`). This keeps files off the working directory, is unique per agent, and is the same folder used for YAML flows. Create it with `mkdir -p` before first use.
402
-
403
- ---
404
-
405
- ### `inspect`
406
-
407
- Print the UI element hierarchy of the current screen. Use this when a `tap-on` or `assert-visible` fails and you need to discover the exact element text or accessibility ID.
408
-
409
- The hierarchy shows each element's type, text, and accessibility ID (resourceId / accessibilityIdentifier). Use the `text` value or `id` value as the argument to `tap-on` / `assert-visible`.
410
-
411
- ```bash
412
- conductor inspect
413
- conductor inspect --dump # full hierarchy as JSON with a11y fields
414
- ```
415
-
416
- `--dump` emits a11y-enriched JSON on all platforms. Each node carries
417
- `accessibilityOrder` (0-based screen-reader nav index, or `null`), `traits` / `role`,
418
- `nodeId` (stable per-capture path), and platform-specific fields:
419
- `isAccessibilityElement` + `accessibilityLabel/Hint/Value` on iOS,
420
- `contentDescription` + `screenReaderFocusable` + `importantForAccessibility` on Android,
421
- `accessibleName` + `focusable` on web. Existing fields (`label`, `frame`, `identifier`,
422
- `text`, `resource-id`, `bounds`, ...) are preserved.
423
-
424
- ---
425
-
426
- ### `capture-ui`
427
-
428
- Bundle everything Argus needs for a single UI inspection: screenshot (PNG base64) +
429
- full UI hierarchy (with a11y fields) + flat accessibility-order snapshot in one JSON
430
- document. Intended primarily for programmatic consumers (Argus UI panel); humans
431
- should prefer `inspect` + `take-screenshot`.
432
-
433
- ```bash
434
- conductor capture-ui # prints bundle as JSON to stdout
435
- conductor capture-ui --output /tmp/capture.json # writes bundle to file
436
- ```
437
-
438
- Output shape:
439
-
440
- ```json
441
- {
442
- "version": 1,
443
- "capturedAt": "2026-04-22T12:34:56.000Z",
444
- "device": { "platform": "ios", "deviceId": "...", "width": 390, "height": 844 },
445
- "screenshot": { "kind": "composite", "encoding": "png", "data": "<base64>" },
446
- "hierarchy": { /* platform-native hierarchy with a11y fields on each node */ },
447
- "a11ySnapshot": [
448
- { "nodeId": "0.2.1", "order": 0, "frame": {"x":0,"y":0,"w":80,"h":44},
449
- "label": "Sign in", "hint": "", "role": "button", "traits": ["button"],
450
- "announcement": "Sign in, button", "value": "",
451
- "state": {"enabled": true, "selected": false, "focused": false} }
452
- ],
453
- "capabilities": { "perViewPixels": false, "depthData": false }
454
- }
455
- ```
456
-
457
- `nodeId` is a stable per-capture path (dot-joined child indices) so Argus can
458
- correlate flat snapshot entries back to hierarchy nodes. `capabilities.perViewPixels`
459
- is `false` in v1; per-view pixel rendering is a future phase.
460
-
461
- ---
462
-
463
- ### `logs`
464
-
465
- Stream app console/log output in real time. Auto-detects the best log source based on the platform:
466
-
467
- - **Web** — captures Playwright browser console events
468
- - **React Native (iOS/Android)** — connects to the Metro dev server via Chrome DevTools Protocol
469
- - **Native iOS** — streams from the simulator via `simctl log stream`
470
- - **Native Android** — streams from the device via `adb logcat`
471
-
472
- ```bash
473
- conductor logs # auto-detect source and stream
474
- conductor logs --source metro # force Metro CDP (for React Native JS logs)
475
- conductor logs --source device # force platform-native logs (simctl/logcat)
476
- conductor logs --level warn # only show warnings and errors
477
- conductor logs --level error # only show errors
478
- conductor logs --metro-port 8082 # custom Metro dev server port (default: 8081)
479
- conductor logs --target 1 # connect to a specific Metro debugger target (0-based)
480
- conductor logs --list # list available Metro debugger targets and exit
481
- conductor logs --list --json # list targets as JSON (includes appId, logicalDeviceId)
482
- conductor logs --json # NDJSON output (one JSON object per line)
483
- ```
484
-
485
- For iOS/Android, auto-detection tries Metro first (2s timeout), then falls back to device logs. When multiple devices share one Metro instance, use `--list` to see available targets, then `--target <n>` to connect to a specific one. `--list` and `--source metro` don't require a running device session.
486
-
487
- Exits on Ctrl+C. Each line in `--json` mode is a complete JSON object:
488
- ```json
489
- {"timestamp":"...","level":"log","message":"User tapped sign-in","stackTrace":null,"source":"metro"}
490
- ```
491
-
492
- ---
493
-
494
- ### `run-flow <file>`
495
-
496
- Execute a Maestro YAML flow file.
497
-
498
- ```bash
499
- conductor run-flow ./flows/login.yaml
500
- conductor run-flow ./flows/checkout.yaml --device emulator-5554
501
- ```
502
-
503
- ---
504
-
505
- ### `run-flow-inline <yaml>`
506
-
507
- Execute inline Maestro YAML commands directly.
508
-
509
- ```bash
510
- conductor run-flow-inline "- tapOn: \"Submit\"\n- assertVisible: \"Success\""
511
- ```
512
-
513
- ---
514
-
515
- ### `session`
516
-
517
- Show, clear, or list device sessions.
518
-
519
- ```bash
520
- conductor session # show session for auto-detected device
521
- conductor session --device <id> # show session for a specific device
522
- conductor session --clear --device <id> # clear a device's session
523
- conductor session --list # list all device sessions
524
- ```
525
-
526
- Sessions are stored in `~/.conductor/sessions/<deviceId>.json`.
527
-
528
- ---
529
-
530
- ### `cheat-sheet`
531
-
532
- Print this command reference inline.
533
-
534
- ```bash
535
- conductor cheat-sheet
536
- ```
537
-
538
- ---
539
-
540
- ### `install-skills`
541
-
542
- Copy the conductor skill files into the current project's `.claude/skills/conductor/` directory, so AI agents in that project can use the `cheat-sheet` command locally.
543
-
544
- ```bash
545
- conductor install-skills
546
- ```
547
-
548
- ---
549
-
550
- ### `daemon-start`
551
-
552
- Start the background daemon for the current device session. The daemon keeps the driver process alive between commands, reducing startup overhead. Commands auto-start the driver directly if no daemon is running — this is optional.
553
-
554
- ```bash
555
- conductor daemon-start
556
- conductor daemon-start --device emulator-5554
557
- ```
558
-
559
- ---
560
-
561
- ### `daemon-stop`
562
-
563
- Stop the daemon for a device session.
564
-
565
- ```bash
566
- conductor daemon-stop
567
- conductor daemon-stop --device emulator-5554
568
- conductor daemon-stop --all # stop all running daemons
569
- ```
570
-
571
- ---
572
-
573
- ### `daemon-status`
574
-
575
- Show whether the daemon is running for a device session.
576
-
577
- ```bash
578
- conductor daemon-status
579
- conductor daemon-status --device emulator-5554
580
- ```
581
-
582
- ---
583
-
584
- ### `device-pool`
585
-
586
- Manage a shared pool of devices for concurrent multi-agent use. Pool state is stored in `~/.conductor/device-pool.json` with file-based locking so multiple agents can safely acquire/release devices without colliding.
587
-
588
- ```bash
589
- conductor device-pool --list # list all devices and their pool status
590
- conductor device-pool --acquire # claim a free device; prints its ID
591
- conductor device-pool --release <id> # release a device back to the pool
592
- ```
593
-
594
- Typical multi-agent workflow:
595
- ```bash
596
- # Each agent acquires its own device before starting
597
- DEVICE=$(conductor device-pool --acquire)
598
- conductor launch-app com.example.myapp --device "$DEVICE"
599
- # ... run tests ...
600
- conductor device-pool --release "$DEVICE"
601
- ```
602
-
603
- Stale acquisitions (whose process is no longer running) are automatically pruned on the next `--acquire`.
604
-
605
- ---
606
-
607
- ### `run-parallel`
608
-
609
- Distribute a directory of Maestro YAML flow files across all booted devices, running them in parallel. Flows are assigned round-robin; results are aggregated and printed at the end.
610
-
611
- ```bash
612
- conductor run-parallel --flows-dir ./tests
613
- ```
614
-
615
- Exits with code 0 if all flows pass, 1 if any fail.
616
-
617
- ---
618
-
619
- ## Typical Agent Workflow
620
-
621
- **Prefer individual CLI commands over `run-flow` / `run-flow-inline`.** Use `tap-on`, `input-text`, `scroll`, `swipe`, `assert-visible`, etc. directly — they are faster, give immediate feedback per step, and make failures easier to diagnose. Only reach for `run-flow` or `run-flow-inline` when you need Maestro-specific YAML features (conditional logic, `runScript`, retryTapIfNoChange`, etc.) that have no CLI equivalent.
622
-
623
- **Always `launch-app` before interacting.** Never attempt to `tap-on`, `input-text`, `scroll`, or navigate before the app is launched and the session is set. `launch-app` both opens the app and saves the `appId`/`deviceId` to the session so all subsequent commands know which device and app to target.
624
-
625
- **To understand what is on screen, run `inspect` first** — it gives you element text, IDs, and structure. Only take a `take-screenshot` when you need visual evidence or are debugging a rendering issue.
626
-
627
- **Try obvious text labels and IDs first. Only run `inspect` when a `tap-on` or `assert-visible` fails and you need to discover the exact identifier.**
628
-
629
- Single-agent (default session, no flag needed):
630
- ```bash
631
- # 1. Check what devices are available
632
- conductor list-devices
633
-
634
- # 2. Launch the app — ALWAYS do this first (sets session, opens app)
635
- conductor launch-app com.example.myapp --device emulator-5554
636
-
637
- # 3. Interact using the most likely text labels or IDs
638
- conductor tap-on "Sign In" # try the obvious label first
639
- conductor tap-on "username_field" # or a guessed test ID
640
- conductor input-text "user@example.com"
641
- conductor tap-on "password_field"
642
- conductor input-text "secret123"
643
- conductor tap-on "Login"
644
-
645
- # → If a tap fails, run inspect to find the real identifier:
646
- conductor inspect
647
- # → hierarchy shows text="Log in", id="btn_login" — retry with correct value
648
- conductor tap-on "Log in"
649
-
650
- # 4. Assert — try expected text directly
651
- conductor assert-visible "Dashboard"
652
-
653
- # 5. Inspect to understand what is on screen (prefer over screenshot)
654
- conductor inspect
655
-
656
- # 6. Screenshot only for visual evidence or rendering checks
657
- conductor take-screenshot --output /tmp/tester-ios-iphone-16/post-login.png
658
-
659
- # 7. Run a full flow only when CLI commands aren't sufficient
660
- # Write the YAML to /tmp/<agent-name>/ first — never pass YAML inline, it doesn't work
661
- mkdir -p /tmp/tester-ios-iphone-16
662
- cat > /tmp/tester-ios-iphone-16/checkout.yaml << 'EOF'
663
- appId: com.example.myapp
664
- ---
665
- - tapOn: "Checkout"
666
- - assertVisible: "Order confirmed"
667
- EOF
668
- conductor run-flow /tmp/tester-ios-iphone-16/checkout.yaml
669
- ```
670
-
671
- ---
672
-
673
- ## Session State
674
-
675
- Each session is stored in `~/.conductor/sessions/<name>.json`:
676
-
677
- ```json
678
- {
679
- "appId": "com.example.myapp",
680
- "deviceId": "emulator-5554"
681
- }
682
- ```
683
-
684
- - Set automatically by `launch-app`
685
- - Cleared by `session --clear`
686
- - Used by all interaction commands when `--device` is not specified
687
-
688
- ---
689
-
690
- ## Multi-Agent Parallel Testing
691
-
692
- Pass `--device <id>` on every command. The device ID is the natural key — each device gets its own session file and its own daemon process (with a persistent direct driver connection). Two agents targeting different devices never share state or a daemon.
693
-
694
- ### Device assignment — do this first, before spawning agents
695
-
696
- **CRITICAL: each device must be assigned to exactly one agent. Never give two agents the same device.**
697
-
698
- Before spawning any agents, check how many devices are already booted with `list-devices`. If there are not enough for the number of agents you need, boot more with `start-device` — one call per additional device needed. Only then assign and spawn agents.
699
-
700
- ```bash
701
- # 1. Check what's already booted
702
- conductor list-devices
703
- # ios booted C59D3241-... iPhone 16
704
- # (only 1 device, but we need 2)
705
-
706
- # 2. Boot another if needed
707
- conductor start-device --platform ios
708
-
709
- # 3. Re-check to get the new device's ID
710
- conductor list-devices
711
- # ios booted C59D3241-... iPhone 16
712
- # ios booted 86B1BC33-... iPhone 15
713
- ```
714
-
715
- Assign explicitly — one device per agent, no sharing.
716
-
717
- ```bash
718
- conductor list-devices
719
- # ios booted C59D3241-FB6A-4E3B-AE7B-A82D3C933889 iPhone 16
720
- # ios booted 86B1BC33-7D83-47FF-AAFE-1BD70FC53038 iPhone 15
721
- # android device emulator-5554 Pixel_6_API_33
722
- ```
723
-
724
- Assign explicitly — one device per agent, no sharing:
725
- ```
726
- Agent tester-ios-iphone-16 → --device C59D3241-FB6A-4E3B-AE7B-A82D3C933889
727
- Agent tester-ios-iphone-15 → --device 86B1BC33-7D83-47FF-AAFE-1BD70FC53038
728
- Agent tester-android-pixel-6 → --device emulator-5554
729
- ```
730
-
731
- ### Agent naming
732
-
733
- Name each agent after the platform under test and the device it controls: `tester-${platform}-${device_name}` (lowercased, spaces replaced with hyphens). The platform prefix reflects what is being tested — it is not always `ios`. Examples:
734
- - `tester-ios-iphone-16` — testing an iOS app on an iPhone 16 simulator
735
- - `tester-android-pixel-6` — testing an Android app on a Pixel 6 emulator
736
- - `tester-web-iphone-15` — testing a mobile web app on an iPhone 15 simulator
737
- - `tester-payments-pixel-7` — testing a payments flow on a Pixel 7 emulator
738
-
739
- This makes it immediately obvious which agent controls which device and prevents accidental reassignment.
740
-
741
- ### Setup — one `launch-app` per device
742
-
743
- ```bash
744
- # Agent tester-ios-iphone-16
745
- conductor launch-app com.example.myapp --device C59D3241-FB6A-4E3B-AE7B-A82D3C933889
746
-
747
- # Agent tester-android-pixel-6
748
- conductor launch-app com.example.myapp --device emulator-5554
749
- ```
750
-
751
- **Every subsequent command carries `--device`:**
752
- ```bash
753
- # Agent tester-ios-iphone-16
754
- conductor tap-on "Sign In" --device C59D3241-FB6A-4E3B-AE7B-A82D3C933889
755
- conductor input-text "user@a.com" --device C59D3241-FB6A-4E3B-AE7B-A82D3C933889
756
- conductor inspect --device C59D3241-FB6A-4E3B-AE7B-A82D3C933889
757
-
758
- # Agent tester-android-pixel-6 (runs fully in parallel)
759
- conductor tap-on "Sign In" --device emulator-5554
760
- conductor input-text "user@b.com" --device emulator-5554
761
- conductor inspect --device emulator-5554
762
- ```
763
-
764
- **Inspect all device sessions:**
765
- ```bash
766
- conductor session --list
767
- # Sessions:
768
- # C59D3241-... appId=com.example.myapp deviceId=C59D3241-...
769
- # emulator-5554 appId=com.example.myapp deviceId=emulator-5554
770
- ```
771
-
772
- **Rules for multi-agent use:**
773
- - Run `list-devices` first and assign devices before spawning agents — never let agents pick their own
774
- - Each agent owns exactly one device; no two agents share a device
775
- - Name agents `tester-ios-${device_name}` / `tester-android-${device_name}` so ownership is obvious
776
- - Always pass `--device` on every command — this is how agents stay isolated
777
- - Each device gets its own daemon (`~/.conductor/daemons/<deviceId>/`), keeping the driver process alive for the lifetime of the daemon
778
- - Screenshot paths must be unique per device; use the device name in the path
779
-
780
- ---
781
-
782
- ## Output Modes
783
-
784
- Output is human-readable by default:
785
- ```
786
- ✓ tap "Submit" — done
787
- ✗ assert-visible "Welcome" — element not found
788
- ```
789
-
790
- Use `--json` only when you need structured output for parsing:
791
- ```json
792
- {"status": "ok", "message": "tap \"Submit\" — done"}
793
- {"status": "error", "message": "assert-visible \"Welcome\" — element not found"}
794
- ```
795
-
796
- ---
797
-
798
- ### `start-device`
799
-
800
- Boot an iOS simulator or Android emulator. Creates the Simulator window and waits until the device is fully ready.
801
-
802
- ```bash
803
- conductor start-device --platform ios
804
- conductor start-device --platform android
805
- conductor start-device --platform ios --os-version 18
806
- conductor start-device --platform ios --device-type "iPhone 16 Pro"
807
- conductor start-device --platform ios --name "Test Device"
808
- conductor start-device --platform android --avd Pixel_6_API_33
809
- ```
810
-
811
- Flags:
812
- - `--platform <ios|android>` — required
813
- - `--os-version <n>` — filter by OS version (iOS: e.g. `18`; Android: API level e.g. `33`)
814
- - `--avd <name>` — Android AVD name to launch (default: first available AVD)
815
- - `--name <name>` — set a custom name on the simulator after boot (iOS only)
816
- - `--device-type <name>` — iOS device type to boot (e.g. `"iPhone 16 Pro"`); if no existing simulator matches, one is created automatically
817
-
818
- iOS picks the first available iPhone simulator matching the OS version and device type filters (or any if unfiltered). Android launches the named AVD, or the first AVD found.
819
-
820
- ---
821
-
822
- ## Related Documentation
823
-
824
- - [Conductor Flow Syntax](./references/flow-syntax.md)
825
-