docs: restructure agent-device skill docs (#260)

* docs: restructure agent-device skill docs

* docs: keep agent-device references grouped

* docs: clarify batch use in verification

* docs: restore skill operational detail

* docs: add qa loop for acceptance criteria

* docs: clarify qa modes in skill router

* docs: improve skill mental model wording

* docs: simplify skill router labels

* docs: add accessibility audit guidance

* docs: update iOS simulator example device

* docs: clarify follow-up routing after session open

* docs: tighten session follow-up rule
This commit is contained in:
Michał Pierzchała
2026-03-25 16:01:03 +01:00
committed by GitHub
parent 7100fc5920
commit bb8d9ddeb8
16 changed files with 733 additions and 820 deletions
+5
View File
@@ -116,6 +116,11 @@ Minimal operating guide for AI coding agents in this repo.
- For behavior/CLI surface changes, evaluate docs/skills updates.
- Update `README.md` and relevant `website/docs/**` pages for command behavior/flags/aliases/workflows.
- Update relevant `skills/**/SKILL.md` when usage examples/workflow recommendations change.
- Keep skill docs task-first:
- top-level `SKILL.md` should stay a thin router, not a full manual.
- keep detailed workflows/troubleshooting in a `references/` folder instead of growing the router.
- isolate true platform/infra exceptions (for example macOS-only or remote-tenancy-only guidance) in dedicated files.
- do not delete high-value operational guidance during refactors; move or condense it unless the behavior is obsolete.
- In final summaries, state whether docs/skills were updated; if not, explain why.
## When Blocked
+24 -107
View File
@@ -3,120 +3,37 @@ name: agent-device
description: Automates interactions for Apple-platform apps (iOS, tvOS, macOS) and Android devices. Use when navigating apps, taking snapshots/screenshots, tapping, typing, scrolling, or extracting UI info across mobile, TV, and desktop targets.
---
# Apple and Android Automation with agent-device
# agent-device
Use this skill as a router.
Core rule:
## QA modes
- explore with `snapshot -i` and `@ref`
- stabilize with selectors
- use plain `snapshot` when you need to verify whether text is visible
- re-snapshot after every meaningful UI change
- Open-ended bug hunt with reporting: use [../dogfood/SKILL.md](../dogfood/SKILL.md).
- Pass/fail QA from acceptance criteria: stay in this skill, start with [references/bootstrap-install.md](references/bootstrap-install.md), then use the QA loop in [references/exploration.md](references/exploration.md).
For exploratory QA bug hunts and reporting, use [../dogfood/SKILL.md](../dogfood/SKILL.md).
## Mental model
## Quick route
- First choose the correct target and open the app or session you want to work on.
- Then inspect the current UI with `snapshot -i` and pick targets from the actual UI state.
- Act with `press`, `fill`, `get`, `is`, `wait`, or `find`.
- Re-snapshot after meaningful UI changes instead of reusing stale refs.
- End by capturing proof if needed, then `close`.
- Normal UI task: `open` -> `snapshot -i` -> `click/fill/press` -> `close`
- Debug task: `open` -> `logs clear --restart` -> reproduce -> `network dump` -> `logs path`
- Replay drift: `replay -u <path>`
- No target context yet: `devices` -> pick target -> `open`
## Decision rules
## Target rules
- Use plain `snapshot` when you need to verify whether text is visible.
- Use `snapshot -i` mainly for interactive exploration and choosing refs.
- Use `fill` to replace text.
- Use `type` to append text.
- Prefer `@ref` or selector targeting over raw coordinates.
- Keep the default loop short: `open` -> explore/act -> optional debug or verify -> `close`.
- iOS local QA: prefer simulators
- Android binary flow: `install` or `reinstall` first, then `open <package> --relaunch`
- In mixed-device labs, always pin the target with `--device`, `--udid`, `--serial`, or an isolation scope
- For session-bound automation, prefer `AGENT_DEVICE_SESSION` + `AGENT_DEVICE_PLATFORM`
## Choose a reference
## macOS rules
- Use `open <app> --platform macos` for normal Mac app automation
- Use `open --platform macos --surface frontmost-app|desktop|menubar` when you need desktop-global inspection first
- Use `app` sessions for `click`, `fill`, `press`, `scroll`, `screenshot`, and `record`
- Use `frontmost-app`, `desktop`, and `menubar` mainly for `snapshot`, `get`, `is`, and `wait`
- If you inspect with `desktop` or `menubar` and then need to act inside one app, open that app in a normal `app` session
- Prefer `@ref` or selectors over raw `x y` on macOS
- Use `click --button secondary` for context menus, then run `snapshot -i` again
## Canonical flows
### Normal flow
```bash
agent-device open Settings --platform ios
agent-device snapshot -i
agent-device press @e3
agent-device fill @e5 "test"
agent-device close
```
### macOS app flow
```bash
agent-device open TextEdit --platform macos
agent-device snapshot -i
agent-device fill @e3 "desktop smoke test"
agent-device screenshot /tmp/macos-textedit.png
agent-device close
```
### macOS desktop-global inspect flow
```bash
agent-device open --platform macos --surface desktop
agent-device snapshot -i
agent-device get attrs @e4
agent-device is visible 'role="window" label="Notes"'
agent-device wait text "Notes"
agent-device close
```
### Android relaunch flow
```bash
agent-device reinstall MyApp /path/to/app-debug.apk --platform android --serial emulator-5554
agent-device open com.example.myapp --remote-config ./agent-device.remote.json --relaunch
agent-device snapshot -i
agent-device close
```
### Debug flow
```bash
agent-device open MyApp --platform ios
agent-device logs clear --restart
agent-device network dump 25
agent-device logs path
```
### Replay maintenance
```bash
agent-device replay -u ./session.ad
```
## High-value guardrails
- Prefer `snapshot -i`; use `--raw` only for structure debugging
- Use plain `snapshot` to verify text visibility; use `snapshot -i` mainly for interactive exploration and choosing refs
- Use refs for discovery, selectors for replay/assertions
- `fill` clears then types; `type` only types into the focused field
- `network dump` is best-effort and reads from the session app log
- `logs clear --restart` requires an active app session
- On macOS, helper-backed flows cover permissions, alerts, and desktop-global snapshot surfaces
- On macOS, do not assume `desktop` or `menubar` are the best surface for real interactions yet
## References
- [references/macos-desktop.md](references/macos-desktop.md)
- [references/snapshot-refs.md](references/snapshot-refs.md)
- [references/logs-and-debug.md](references/logs-and-debug.md)
- [references/session-management.md](references/session-management.md)
- [references/permissions.md](references/permissions.md)
- [references/video-recording.md](references/video-recording.md)
- [references/coordinate-system.md](references/coordinate-system.md)
- [references/batching.md](references/batching.md)
- [references/perf-metrics.md](references/perf-metrics.md)
- [references/remote-tenancy.md](references/remote-tenancy.md)
- Pick target device, install, open, or manage sessions: [references/bootstrap-install.md](references/bootstrap-install.md)
- Need to discover UI, pick refs, wait, query, or interact: [references/exploration.md](references/exploration.md)
- Need logs, network, alerts, permissions, or failure triage: [references/debugging.md](references/debugging.md)
- Need screenshots, diff, recording, replay maintenance, or perf data: [references/verification.md](references/verification.md)
- Need desktop surfaces, menu bar behavior, or macOS-specific interaction rules: [references/macos-desktop.md](references/macos-desktop.md)
- Need to connect to a remote `agent-device` daemon over HTTP or use tenant leases: [references/remote-tenancy.md](references/remote-tenancy.md)
@@ -1,79 +0,0 @@
# Batching
## When to use batch
- The agent already knows a short sequence of commands.
- Steps belong to one logical screen flow.
- You want one result object with per-step timing and failure context.
## When not to use batch
- Flows are unrelated and should be retried independently.
- The workflow is highly dynamic and requires replanning after each step.
- You need human approvals between steps.
## CLI patterns
From file:
```bash
agent-device batch --session sim --platform ios --steps-file /tmp/batch-steps.json --json
```
Inline (small payloads only):
```bash
agent-device batch --steps '[{"command":"open","positionals":["settings"]}]'
```
## Step payload contract
```json
[
{ "command": "open", "positionals": ["settings"], "flags": {} },
{ "command": "wait", "positionals": ["label=\"Privacy & Security\"", "3000"], "flags": {} },
{ "command": "click", "positionals": ["label=\"Privacy & Security\""], "flags": {} },
{ "command": "get", "positionals": ["text", "label=\"Tracking\""], "flags": {} }
]
```
Rules:
- `positionals` optional, defaults to `[]`.
- `flags` optional, defaults to `{}`.
- nested `batch` and `replay` are rejected.
- stop-on-first-error is the supported mode (`--on-error stop`).
## Response handling
Success includes:
- `total`, `executed`, `totalDurationMs`
- `results[]` entries with `step`, `command`, `durationMs`, and optional `data`
Failure includes:
- `details.step`
- `details.command`
- `details.executed`
- `details.partialResults`
Use these fields to replan from the first failing step.
## Common error categories and agent actions
- `INVALID_ARGS`: payload/step shape issue; fix payload and retry.
- `SESSION_NOT_FOUND`: open or select the correct session, then retry.
- `UNSUPPORTED_OPERATION`: switch command/target to supported operation.
- `AMBIGUOUS_MATCH`: refine selector/locator, then retry failed step.
- `COMMAND_FAILED`: add sync guard (`wait`, `is exists`) and retry from failed step.
## Reliability guardrails
- Add sync guards after mutating steps.
- Assume snapshot/ref drift after navigation.
- Keep batch size moderate (about 5-20 steps).
- Split long workflows into phases:
1. navigate
2. verify/extract
3. cleanup
@@ -0,0 +1,167 @@
# Bootstrap and Install
## When to open this file
Open this file when you still need to choose the right target, start the right session, install or relaunch the app, or pin automation to one device before interacting.
## Main commands to reach for first
- `devices`
- `ensure-simulator`
- `open`
- `install` or `reinstall`
- `close`
- `session list`
## Most common mistake to avoid
Do not start acting before you have pinned the correct target and opened an `app` session. In mixed-device environments, always pass `--device`, `--udid`, or `--serial`.
## Canonical loop
```bash
agent-device ensure-simulator --platform ios --device "iPhone 17 Pro" --boot
agent-device open MyApp --platform ios --device "iPhone 17 Pro" --relaunch
agent-device snapshot -i
agent-device close
```
## Choose the right starting point
- iOS local QA: prefer simulators unless the task explicitly requires physical hardware.
- iOS in mixed simulator and device environments: run `ensure-simulator` first, then keep using `--device` or `--udid`.
- TV targets: use `--target tv` together with `--platform` when the task is for tvOS or Android TV rather than phone or tablet surfaces.
- Android binary flow: use `install` or `reinstall` for `.apk` or `.aab`, then open by installed package name.
- Android React Native plus Metro flow: `reinstall <app> <apk>` first, then `open <package> --remote-config <path> --relaunch`.
- macOS desktop app flow: use `open <app> --platform macos`. Only load [macos-desktop.md](macos-desktop.md) if a desktop surface or macOS-specific behavior matters.
TV example:
```bash
agent-device open MyTvApp --platform ios --target tv
agent-device open com.example.androidtv --platform android --target tv
```
## Session rules
- Use `--session <name>` when you need a named session:
```bash
agent-device --session auth open Settings --platform ios
agent-device --session auth snapshot -i
```
- Use `open <app>` before interactions.
- Use `close` when done. Add `--shutdown` when you want simulators or emulators torn down with the session.
- Use semantic session names when you need multiple concurrent runs.
- Use `--save-script=<path>` on `close` when you want to keep a replay script.
- For dev loops where state can linger, prefer `open <app> --relaunch`.
- In iOS sessions, use `open <app>` for the app itself. Use `open <url>` for deep links, and `open <app> <url>` when you need to launch the app and deep link in one step.
- On iOS, `appstate` is session-scoped and requires the matching active session on the target device.
## After a session is established
Once you have opened the correct session on the correct target, default to the conservative rule: keep the session binding on follow-up commands, and stop repeating device-routing flags unless you are intentionally retargeting.
- Prefer `--session <name>` on follow-up commands, or use sandboxed `AGENT_DEVICE_SESSION`.
- Do not keep repeating `--platform`, `--target`, `--device`, `--udid`, `--serial`, or similar target-selection flags on normal follow-up commands.
- Only omit follow-up session flags when the environment explicitly guarantees isolation.
Good shared-host pattern:
```bash
agent-device --session auth open Settings --platform ios --device "iPhone 17 Pro"
agent-device --session auth snapshot -i
agent-device --session auth press @e3
agent-device --session auth close
```
Bad shared-host pattern:
```bash
agent-device --session auth open Settings --platform ios --device "iPhone 17 Pro"
agent-device --session auth snapshot -i --platform ios --device "iPhone 17 Pro"
```
Use target-selection flags again only when you are choosing the target before opening a session, or when you explicitly mean to retarget.
## Session-bound automation
Use this when an orchestrator must keep plain CLI calls on one session and device.
```bash
export AGENT_DEVICE_SESSION=qa-ios
export AGENT_DEVICE_PLATFORM=ios
export AGENT_DEVICE_SESSION_LOCK=strip
agent-device open MyApp --relaunch
agent-device snapshot -i
agent-device close
```
- `AGENT_DEVICE_SESSION` plus `AGENT_DEVICE_PLATFORM` provides the default binding.
- `--session-lock reject|strip` controls whether conflicting per-call routing flags fail or are ignored.
- Conflicts include explicit retargeting flags such as `--platform`, `--target`, `--device`, `--udid`, `--serial`, `--ios-simulator-device-set`, and `--android-device-allowlist`.
- Lock policy applies to nested `batch` steps too.
- Compatibility aliases remain supported: `--session-locked`, `--session-lock-conflicts`, `AGENT_DEVICE_SESSION_LOCKED`, and `AGENT_DEVICE_SESSION_LOCK_CONFLICTS`.
Android emulator variant:
```bash
export AGENT_DEVICE_SESSION=qa-android
export AGENT_DEVICE_PLATFORM=android
agent-device reinstall MyApp /path/to/app-debug.apk --serial emulator-5554
agent-device --session-lock reject open com.example.myapp --relaunch
agent-device snapshot -i
agent-device close --shutdown
```
## Scoped discovery
Use scoped discovery when one run must not see host-global device lists.
```bash
agent-device devices --platform ios --ios-simulator-device-set /tmp/tenant-a/simulators
agent-device devices --platform android --android-device-allowlist emulator-5554,device-1234
```
- Scope is applied before `--device`, `--udid`, and `--serial`.
- Out-of-scope selectors fail with `DEVICE_NOT_FOUND`.
- With iOS simulator-set scope enabled, iOS physical devices are not enumerated.
- If the scoped iOS simulator set is empty, the error should point at the set path and suggest creating a simulator in that set.
- Environment equivalents:
- `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET`
- `AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST`
## Session inspection and replay
```bash
agent-device session list
agent-device replay ./session.ad --session auth
agent-device replay -u ./session.ad --session auth
```
- iOS session entries include `device_udid` and `ios_simulator_device_set`. Use them to confirm routing in concurrent runs.
- Prefer selector-based actions and assertions in saved replay scripts.
- Tenant isolation namespaces sessions as `<tenant>:<session>` during tenant-scoped runs.
## When to leave this file
- Once the correct target and session are pinned, move to [exploration.md](exploration.md).
- If opening, startup, permissions, or logs become the blocker, switch to [debugging.md](debugging.md).
## Install and open examples
```bash
agent-device reinstall MyApp /path/to/app-debug.apk --platform android --serial emulator-5554
agent-device open com.example.myapp --remote-config ./agent-device.remote.json --relaunch
```
Do not use `open <apk|aab> --relaunch` on Android.
## Security and trust notes
- Treat signing, provisioning, and daemon auth values as host secrets. Do not paste them into shared logs or commit them to source control.
- Prefer Xcode Automatic Signing over manual overrides when a physical iOS device is involved.
- Keep persistent host-specific defaults in environment variables rather than checked-in project config.
@@ -1,8 +1,28 @@
# Coordinate System
All coordinate-based actions use device screen coordinates:
## When to open this file
- Origin: top-left of the device screen
- Units: device points for iOS, pixels for Android
Open this file only when you must use raw coordinates instead of selectors or `@ref` targeting.
Use screenshots to reason about coordinates.
## Main commands to reach for first
- `screenshot`
- coordinate-based `click` or `swipe`
## Most common mistake to avoid
Do not assume coordinates mean the same thing across platforms or runs. Prefer selectors and refs first.
## Canonical loop
```bash
agent-device screenshot /tmp/current-screen.png
agent-device click 120 240
```
## Rules
- Origin is the top-left of the device screen.
- iOS uses device points.
- Android uses pixels.
- Use screenshots to reason about coordinates before acting.
+115
View File
@@ -0,0 +1,115 @@
# Debugging
## When to open this file
Open this file when the task turns into failure triage, logs, network inspection, permission prompts, setup trouble, or unstable session behavior.
## Main commands to reach for first
- `logs clear --restart`
- `network dump`
- `logs path`
- `logs doctor`
- `alert wait`
- `alert accept` or `alert dismiss`
## Most common mistake to avoid
Do not leave logging on for normal flows or dump full log files into context. Keep debug windows short and inspect logs with `grep` or `tail`.
## Canonical loop
```bash
agent-device open MyApp --platform ios
agent-device logs clear --restart
agent-device network dump 25
agent-device logs path
agent-device close
```
## Log and network flow
Logging is off by default. Enable it only when you need a debugging window.
- Default app logs live under `~/.agent-device/sessions/<session>/app.log`.
- `logs clear --restart` is the fastest clean repro loop.
- `network dump [limit] [summary|headers|body|all]` parses recent HTTP(s) entries from the same session app log.
- `logs doctor` checks backend and runtime readiness for the current session and device.
- `logs mark "before tap"` inserts a timestamped marker into the app log.
- Session app logs can contain runtime data, headers, or payload fragments. Review them before sharing.
- `logs start` requires an active app session and appends to `app.log`.
- `logs stop` stops streaming. `close` also stops logging.
- `logs clear` truncates `app.log` and removes rotated `app.log.N` files, and requires logging to be stopped first.
- `logs path` returns the log path plus metadata about the active backend and file state.
- `network log` is an alias for `network dump`.
Operational limits:
- `app.log` rotates to `app.log.1` after 5 MB by default.
- `network dump` scans the last 4000 app-log lines, returns up to 200 entries, and truncates header or payload fields at 2048 characters.
- Retention knobs:
- `AGENT_DEVICE_APP_LOG_MAX_BYTES`
- `AGENT_DEVICE_APP_LOG_MAX_FILES`
- Redaction hook:
- `AGENT_DEVICE_APP_LOG_REDACT_PATTERNS`
Useful shell follow-up after `logs path`:
```bash
grep -n -E "Error|Exception|Fatal|crash" <path>
tail -50 <path>
```
## Alerts and permissions
Use `alert` for iOS simulator permission dialogs instead of tapping coordinates.
```bash
agent-device alert wait 5000
agent-device alert accept
```
- `alert` is only supported on iOS simulators.
- `alert accept` and `alert dismiss` retry internally for a short window, so you usually do not need manual sleeps.
- iOS 16+ "Allow Paste" prompts are suppressed under XCUITest. Use `xcrun simctl pbcopy booted` when you need to seed simulator clipboard content directly.
## Setup problems worth recognizing early
- iOS snapshots do not require macOS Accessibility permissions.
- iOS physical-device XCTest setup does require valid signing and provisioning.
- If physical-device runner setup fails, prefer Xcode Automatic Signing first.
- Optional overrides are:
- `AGENT_DEVICE_IOS_TEAM_ID`
- `AGENT_DEVICE_IOS_SIGNING_IDENTITY`
- `AGENT_DEVICE_IOS_PROVISIONING_PROFILE`
- `AGENT_DEVICE_IOS_BUNDLE_ID`
- If daemon startup is timing out during setup, increase `AGENT_DEVICE_DAEMON_TIMEOUT_MS`.
- If daemon startup fails with stale metadata hints, clean `~/.agent-device/daemon.json` and `~/.agent-device/daemon.lock`, then retry.
- Free Apple Developer personal-team accounts may reject generic bundle IDs. Use a unique reverse-DNS value for `AGENT_DEVICE_IOS_BUNDLE_ID` when that happens.
## Common failure patterns
- `snapshot` returns 0 nodes: the app may no longer be foregrounded or the UI is not stable yet. Re-open the app or retry when state settles.
- Logs are empty: confirm you opened an app session before `logs clear --restart`.
- Android logs look stale after relaunch: retry the repro window after the process rebinds.
- Permission prompts block the flow: wait for the alert and handle it explicitly.
- If snapshots keep returning 0 nodes on an iOS simulator, restart Simulator and re-open the app.
- If a macOS snapshot looks incomplete, compare with `snapshot --raw --platform macos` to separate collector filtering from missing AX content.
## Crash triage fast path
Always start from the session app log, then branch by platform.
```bash
agent-device logs path
grep -n -E "SIGABRT|SIGSEGV|EXC_|fatal|exception|terminated|killed|jetsam|memorystatus|FATAL EXCEPTION|Abort message" <path>
```
- iOS: if the log suggests `ReportCrash`, `SIGABRT`, or `EXC_*`, inspect `~/Library/Logs/DiagnosticReports`.
- Android: if the app log is not enough, use `adb logcat` for `FATAL EXCEPTION`, `Abort message`, or `signal` lines around process death.
- If no crash signature appears in app logs, stop collecting broad logs and switch to the platform-native crash source.
## When to leave this file
- Return to [exploration.md](exploration.md) once the app is stable again.
- Load [verification.md](verification.md) if you need evidence artifacts after reproducing the issue.
@@ -0,0 +1,192 @@
# Exploration
## When to open this file
Open this file when the app or screen is already running and you need to discover the UI, choose targets, read state, wait for conditions, or perform normal interactions.
## Main commands to reach for first
- `snapshot`
- `snapshot -i`
- `press`
- `fill`
- `get`
- `is`
- `wait`
- `find`
## Most common mistake to avoid
Do not treat `@ref` values as durable after navigation or dynamic updates. Re-snapshot after the UI changes, and switch to selectors when the flow must stay stable.
## Canonical loop
```bash
agent-device open Settings --platform ios
agent-device snapshot -i
agent-device press @e3
agent-device wait visible 'label="Privacy & Security"' 3000
agent-device get text 'label="Privacy & Security"'
agent-device close
```
## Snapshot choices
- Use plain `snapshot` when you only need to verify whether visible text or structure is on screen.
- Use `snapshot -i` when you need refs such as `@e3` for interactive exploration.
- Use `snapshot -i -s "Camera"` or `snapshot -i -s @e3` when you want a smaller, scoped result.
Example:
```bash
agent-device snapshot -i
```
Sample output:
```text
Page: com.apple.Preferences
App: com.apple.Preferences
@e1 [ioscontentgroup]
@e2 [button] "Camera"
@e3 [button] "Privacy & Security"
```
## Refs vs selectors
- Use refs for discovery, debugging, and short local loops.
- Use selectors for deterministic scripts, assertions, and replay-friendly actions.
- Prefer selector or `@ref` targeting over raw coordinates.
- For tap interactions, `press` is canonical and `click` is an equivalent alias.
Examples:
```bash
agent-device press @e2
agent-device fill @e5 "test"
agent-device press 'id="camera_row" || label="Camera" role=button'
agent-device is visible 'id="camera_settings_anchor"'
```
## Text entry rules
- Use `fill` to replace text in an editable field.
- Use `type` to append text to the current insertion point.
## Query and sync rules
- Use `get` to read text, attrs, or state from a known target.
- Use `is` for assertions.
- Use `wait` when the UI needs time to settle after a mutation.
- Use `find "<query>" click --json` when you need search-driven targeting plus matched-target metadata.
- If you are forced onto raw coordinates, open [coordinate-system.md](coordinate-system.md) first.
Example:
```bash
agent-device find "Increment" click --json
```
Returned metadata comes from the matched snapshot node and can be used for observability or replay maintenance.
## QA from acceptance criteria
Use this loop when the task starts from acceptance criteria and you need to turn them into concrete checks.
Preferred mapping:
- visibility or presence claim: `is visible` or plain `snapshot`
- exact text, label, or value claim: `get text`
- post-action state change: act, then `wait`, then `is` or `get`
- nearby structural UI change: `diff snapshot`
- proof artifact for the final result: `screenshot` or `record`
Anti-hallucination rules:
- Do not invent app names, device ids, session names, refs, selectors, or package names.
- Discover them first with `devices`, `open`, `snapshot -i`, `find`, or `session list`.
- If refs drift after navigation, re-snapshot or switch to selectors instead of guessing.
Canonical QA loop:
```bash
agent-device open MyApp --platform ios
agent-device snapshot -i
agent-device press @e3
agent-device wait visible 'label="Success"' 3000
agent-device is visible 'label="Success"'
agent-device screenshot /tmp/qa-proof.png
agent-device close
```
## Accessibility audit
Use this pattern when you need to find UI that is visible to a user but missing from the accessibility tree.
Audit loop:
1. Capture a `screenshot` to see what is visually rendered.
2. Capture a `snapshot` or `snapshot -i` to see what the accessibility tree exposes.
3. Compare the two:
- visible in screenshot and present in snapshot: exposed to accessibility
- visible in screenshot and missing from snapshot: likely accessibility gap
4. If you suspect the node exists in AX but is filtered from interactive output, retry with `snapshot --raw`.
Example:
```bash
agent-device screenshot /tmp/accessibility-screen.png
agent-device snapshot -i
```
Use `screenshot` as the visual source of truth and `snapshot` as the accessibility source of truth for this audit.
## Batch only when the sequence is already known
Use `batch` when a short command sequence is already planned and belongs to one logical screen flow.
```bash
agent-device batch --session sim --platform ios --steps-file /tmp/batch-steps.json --json
```
- Keep batch size moderate, roughly 5 to 20 steps.
- Add `wait` or `is exists` guards after mutating steps.
- Do not use `batch` for highly dynamic flows that need replanning after each step.
Step payload contract:
```json
[
{ "command": "open", "positionals": ["Settings"], "flags": { "platform": "ios" } },
{ "command": "wait", "positionals": ["label=\"Privacy & Security\"", "3000"], "flags": {} },
{ "command": "click", "positionals": ["label=\"Privacy & Security\""], "flags": {} },
{ "command": "get", "positionals": ["text", "label=\"Tracking\""], "flags": {} }
]
```
- `positionals` is optional and defaults to `[]`.
- `flags` is optional and defaults to `{}`.
- Nested `batch` and `replay` are rejected.
- Supported error mode is stop-on-first-error.
Response handling:
- Success returns fields such as `total`, `executed`, `totalDurationMs`, and `results[]`.
- Failed runs include `details.step`, `details.command`, `details.executed`, and `details.partialResults`.
- Replan from the first failing step instead of rerunning the whole flow blindly.
Common batch error categories:
- `INVALID_ARGS`: fix the payload shape and retry.
- `SESSION_NOT_FOUND`: open or select the correct session, then retry.
- `UNSUPPORTED_OPERATION`: switch to a supported command or surface.
- `AMBIGUOUS_MATCH`: refine the selector or locator, then retry the failed step.
- `COMMAND_FAILED`: add sync guards and retry from the failing step.
## Stop conditions
- If refs drift after transitions, switch to selectors.
- If a desktop surface or context menu is involved on macOS, load [macos-desktop.md](macos-desktop.md).
- If logs, network, alerts, or setup failures become the blocker, switch to [debugging.md](debugging.md).
- If the flow is stable and you need proof or replay maintenance, switch to [verification.md](verification.md).
@@ -1,114 +0,0 @@
# Logs (Token-Efficient Debugging)
Logging is off by default in normal flows. Enable it on demand for debugging windows. App output is written to a session-scoped file so agents can grep it instead of loading full logs into context.
`network dump` parses recent HTTP(s) entries from this same session app log file.
## Data Handling
- Default app logs are stored under `~/.agent-device/sessions/<session>/app.log`.
- Replay scripts saved with `--save-script` are written to the explicit path you provide.
- Log files may contain sensitive runtime data; review before sharing and clean up when finished.
- Use `AGENT_DEVICE_APP_LOG_REDACT_PATTERNS` to redact sensitive patterns at write time when needed.
## Retention and Cleanup
- Keep logging scoped to active debug windows (`logs clear --restart` before repro, `logs stop` after repro).
- Prefer bounded inspection (`grep -n`, `tail -50`) instead of reading full logs into context.
- Clear session logs when finished:
`agent-device logs clear`
- Close session to stop background logging state:
`agent-device close`
## Quick Flow
```bash
agent-device open MyApp --platform ios # or --platform android
agent-device logs clear --restart # Preferred: stop stream, clear logs, and start streaming again
agent-device network dump 25 # Parse latest HTTP(s) requests (method/url/status) from app.log
agent-device logs path # Print path, e.g. ~/.agent-device/sessions/default/app.log
agent-device logs doctor # Check tool/runtime readiness for current session/device
agent-device logs mark "before tap" # Insert a timeline marker into app.log
# ... run flows; on failure, grep the path (see below)
agent-device logs stop # Stop streaming (optional; close also stops)
```
Precondition: `logs clear --restart` requires an active app session (`open <app>` first).
## Command Notes
- `logs path`: returns log file path and metadata (`active`, `state`, `backend`, size, timestamps).
- `logs start`: starts streaming; requires an active app session (`open` first). Supported on iOS simulator, iOS device, Android, and macOS app sessions.
- `logs stop`: stops streaming. Session `close` also stops logging.
- `logs clear`: truncates `app.log` and removes rotated `app.log.N` files. Requires logging to be stopped first.
- `logs clear --restart`: convenience reset for repro loops (stop stream, clear files, restart stream).
- `logs doctor`: reports backend/tool checks and readiness notes for troubleshooting.
- `logs mark`: writes a timestamped marker line to the session log.
- `network dump [limit] [summary|headers|body|all]`: parses recent HTTP(s) lines from the session app log and returns request summaries.
- `network log ...`: alias for `network dump`.
- On macOS, logs/network are still app-scoped. They rely on Unified Logging output associated with the active session app rather than packet capture.
## Behavior and Limits
- `logs start` appends to `app.log` and rotates to `app.log.1` when `app.log` exceeds 5 MB.
- `network dump` scans the last 4000 app-log lines, returns up to 200 entries, and truncates payload/header fields at 2048 characters.
- Android log streaming automatically rebinds to the app PID after process restarts.
- iOS log capture relies on Unified Logging signals (for example `os_log`); plain stdout/stderr output may be limited depending on app/runtime.
- Retention knobs:
- `AGENT_DEVICE_APP_LOG_MAX_BYTES`
- `AGENT_DEVICE_APP_LOG_MAX_FILES`
- Optional write-time redaction patterns:
- `AGENT_DEVICE_APP_LOG_REDACT_PATTERNS` (comma-separated regex)
## Grep Patterns
After getting the path from `logs path`, run `grep` (or `grep -E`) so only matching lines enter context.
```bash
# Get path first, then grep it; -n adds line numbers
grep -n "Error\|Exception\|Fatal" <path>
grep -n -E "Error|Exception|Fatal|crash" <path>
# Bounded context: last N lines only
tail -50 <path>
```
- Use `-n` for line numbers.
- Use `-E` for extended regex so `|` in the pattern does not need escaping.
- Prefer targeted patterns (e.g. `Error`, `Exception`, or app-specific tags) over reading the full file.
## Crash Triage Fast Path
Always start from the session app log, then branch by platform.
```bash
agent-device logs path
grep -n -E "SIGABRT|SIGSEGV|EXC_|fatal|exception|terminated|killed|jetsam|memorystatus|FATAL EXCEPTION|Abort message" <path>
nl -ba <path> | sed -n '<start>,<end>p'
```
### iOS
```bash
# If log shows ReportCrash / SIGABRT / EXC_*, inspect simulator DiagnosticReports:
ls -lt ~/Library/Logs/DiagnosticReports | grep -E "<AppName>|<BundleId>" | head
```
- `SIGABRT`: app/runtime abort; inspect `.ips` triggered thread and top frames.
- `SIGKILL` + jetsam/memorystatus markers: memory-pressure kill.
- `EXC_BAD_ACCESS`/`SIGSEGV`: native memory access issue.
### Android
```bash
# Capture fatal crash lines around app process death:
adb -s <serial> logcat -d | grep -n -E "FATAL EXCEPTION|Process: <package>|Abort message|signal [0-9]+ \\(SIG"
```
- `FATAL EXCEPTION` with Java stack: uncaught Java/Kotlin exception.
- `signal 6 (SIGABRT)` or `signal 11 (SIGSEGV)` with tombstone refs: native crash path (NDK/JNI/runtime).
- `Low memory killer` / `Killing <pid>` entries: OS memory-pressure/process reclaim.
## Stop Conditions
- If no crash signature appears in app log, switch to platform-native crash sources (`.ips` on iOS, logcat/tombstone flow on Android).
- If signatures are present and root cause class is identified (abort, native fault, memory pressure), stop collecting broad logs and focus on reproducing the specific path.
+47 -89
View File
@@ -1,129 +1,87 @@
# macOS Desktop Automation
# macOS Desktop
Use this reference for host Mac apps such as Finder, TextEdit, System Settings, Preview, or browser apps running as normal desktop windows.
## When to open this file
## Start here
Open this file only when `--platform macos` is involved or the task needs `frontmost-app`, `desktop`, or `menubar` surfaces.
- Use `open <app> --platform macos` when you need to act inside one app.
- Use `open --platform macos --surface frontmost-app|desktop|menubar` when you need to inspect desktop-global UI first.
- Use `app` sessions for `click`, `fill`, `press`, `scroll`, `screenshot`, and `record`.
- Use `frontmost-app`, `desktop`, and `menubar` mainly for `snapshot`, `get`, `is`, and `wait`.
- Prefer `@ref` or selectors. Avoid raw coordinates unless there is no better target.
## Main commands to reach for first
## Mental model
- `open <app> --platform macos`
- `open --platform macos --surface frontmost-app|desktop|menubar`
- `snapshot -i`
- `get`
- `is`
- `click --button secondary`
- `snapshot -i` should describe UI visible to a human.
- Context menus are not ambient UI. Open them explicitly with `click --button secondary`, then re-snapshot.
- Prefer refs for exploration and selectors for deterministic replay/assertions.
- If you inspect with `desktop` or `menubar` and then need to act on one app, switch to a normal `app` session.
## Most common mistake to avoid
## Canonical app flow
Do not treat every macOS surface the same. Use the normal `app` surface when you want to act inside one app. Use `frontmost-app`, `desktop`, or `menubar` mainly to inspect what is visible before switching back to `app` for most interactions.
## Canonical loop
```bash
agent-device open Finder --platform macos
agent-device snapshot -i
agent-device click @e66 --button secondary --platform macos
agent-device open TextEdit --platform macos
agent-device snapshot -i
agent-device fill @e3 "desktop smoke test"
agent-device close
```
## Canonical desktop-global flow
## Surface rules
```bash
agent-device open --platform macos --surface desktop
agent-device snapshot -i
agent-device get attrs @e4
agent-device is visible 'role="window" label="Finder"'
agent-device close
```
Surface variants:
```bash
agent-device open --platform macos --surface frontmost-app
agent-device open --platform macos --surface desktop
agent-device open --platform macos --surface menubar
```
- `app`: default session surface; use this for most real interaction work.
- `app`: default surface and the normal choice for `click`, `fill`, `press`, `scroll`, `screenshot`, and `record`.
- `frontmost-app`: inspect the currently focused app without naming it first.
- `desktop`: inspect visible desktop windows across apps.
- `menubar`: inspect the active app menu bar and system menu extras.
Use `frontmost-app`, `desktop`, and `menubar` for read/inspect flows first. If the next step is a click/fill/press/scroll in one app, switch back to `app`.
Use inspect-first surfaces to understand desktop-global UI, then switch back to `app` when you need to act in one app.
## What to expect from snapshots
## Snapshot expectations
- `app` snapshots should focus on the chosen app window.
- `desktop` snapshots can contain multiple windows from multiple apps.
- `menubar` snapshots can contain both app-menu items and system menu extras.
- File rows, sidebar items, toolbar controls, search fields, and visible context menus should appear.
- Finder and other native apps may expose duplicate-looking structures such as row wrapper nodes, `cell` nodes, and child `text` or `text-field` nodes.
- Treat those as distinct AX nodes unless you have a stronger selector anchor.
- `snapshot -i` should describe UI visible to a human.
- `desktop` snapshots can include multiple windows from multiple apps.
- `menubar` snapshots can include both app-menu items and system menu extras.
- Finder-style rows, sidebar items, toolbar controls, search fields, and opened context menus should appear when visible.
- Finder and other native apps may expose duplicate-looking row, cell, and child text nodes. Treat them as distinct AX nodes unless you have a stronger selector anchor.
## Context menus
Use secondary click when the app exposes actions only through the contextual menu.
Context menus are not ambient UI. Open them explicitly, then re-snapshot.
```bash
agent-device click @e66 --button secondary --platform macos
agent-device snapshot -i
```
Expected pattern:
Expected loop:
1. Snapshot visible content.
2. Secondary-click the target row/item.
2. Secondary-click the target item.
3. Snapshot again.
4. Interact with newly visible `menu-item` nodes.
4. Interact with the new `menu-item` nodes.
Do not expect context-menu items to appear before the menu is opened.
## Targeting rules
Do not use `longpress` as a substitute for right-click on macOS.
- Prefer selectors or `@ref` values over raw coordinates.
- On macOS, window position can vary across runs, so coordinate-only flows are fragile.
- If the task only needs shared exploration rules, return to [exploration.md](exploration.md).
## Finder-specific guidance
Selector guidance:
- `snapshot -i` should still expose visible folder rows even when nothing is selected.
- Unselected folder contents should still be visible in `snapshot -i` through list/table rows.
- A file row may expose multiple nodes with the same label, including a row container, name cell, and child text/text-field.
- For opening a context menu, prefer the outer visible row/cell ref over a nested text child if both exist.
- After secondary click, expect actions such as `Rename`, `Quick Look`, `Copy`, `Compress`, and tag-related items in the next snapshot.
- Good selectors usually anchor on stable labels or app-owned identifiers such as `label="Downloads"` or `role=menu-item label="Rename"`.
- Avoid relying on framework-generated `_NS:*` identifiers as stable selectors.
## Raw snapshots
Use `snapshot --raw --platform macos` only when debugging AX structure or collector filtering. Do not make raw snapshots the default agent loop.
Use `snapshot --raw` only when debugging AX structure or collector issues.
Things not to rely on:
```bash
agent-device snapshot --raw --platform macos
```
- Mobile-only helpers such as `install`, `reinstall`, or `push`.
- Desktop-global click or fill parity from `desktop` or `menubar` sessions.
- Raw coordinate assumptions across runs.
- Raw output is larger and less token-efficient.
- It is useful for verifying whether missing UI is absent from the AX tree or only filtered from interactive output.
- Do not use raw output as the default agent loop when `snapshot -i` already shows the visible window content you need.
Troubleshooting:
## Selector guidance
Good macOS selectors usually anchor on one of:
- `label="Downloads"`
- `label="failed-step.json"`
- `role=button label="Search"`
- `role=menu-item label="Rename"`
- `role=window label="Notes"`
Prefer exact labels when the desktop UI is stable. Use `id=...` when the AX identifier is clearly app-owned and not a framework-generated `_NS:*` value.
## Things not to rely on
- Mobile-only helpers like `install`, `reinstall`, and `push`
- Desktop-global click/fill parity from `desktop` or `menubar` sessions
- Raw coordinate assumptions across runs; macOS windows can move
- Framework-generated `_NS:*` identifiers as stable selectors
## Troubleshooting
- If visible window content is missing from `snapshot -i`, re-snapshot once after the UI settles.
- If `desktop` is too broad, retry with `frontmost-app` to narrow the inspect surface.
- If `menubar` is missing the menu you expect, make the target app frontmost first, then re-open the `menubar` surface and snapshot again.
- If the wrong menu opened or no menu appeared, retry secondary-clicking the row/cell wrapper instead of the nested text node.
- If the app has multiple windows, ensure the correct one is frontmost before relying on refs.
- If visible content is missing from `snapshot -i`, re-snapshot after the UI settles.
- If `desktop` is too broad, retry with `frontmost-app`.
- If `menubar` is missing the expected menu, make the app frontmost first and retry.
- If the wrong menu opened, retry secondary-clicking the row or cell wrapper rather than the nested text node.
- If the app has multiple windows, make the correct window frontmost before relying on refs.
@@ -1,53 +0,0 @@
# Performance Metrics (`perf` / `metrics`)
Use this reference when you need to measure launch performance in agent workflows.
## Quick flow
```bash
agent-device open Settings --platform ios
agent-device perf --json
```
Alias:
```bash
agent-device metrics --json
```
## What is measured today
- Session-scoped `startup` timing only.
- Sampling method: `open-command-roundtrip`.
- Unit: milliseconds (`ms`).
- Source: elapsed wall-clock time around each session `open` command dispatch for the active app target.
## Output fields to use
- `metrics.startup.lastDurationMs`: most recent startup sample.
- `metrics.startup.lastMeasuredAt`: ISO timestamp of most recent sample.
- `metrics.startup.sampleCount`: number of retained samples.
- `metrics.startup.samples[]`: recent startup history for the current session.
- `sampling.startup.method`: current sampling method identifier.
## Platform support (current)
- iOS simulator: supported for startup sampling.
- iOS physical device: supported for startup sampling.
- Android emulator/device: supported for startup sampling.
- `fps`, `memory`, and `cpu`: currently placeholders (`available: false`).
## Interpretation guidance
- Treat startup values as command round-trip timing, not true app first-frame or first-interactive telemetry.
- Compare like-for-like runs:
- same device target
- same app build
- same workflow/session steps
- Use multiple runs and compare trend/median, not one-off samples.
## Common pitfalls
- Running `perf` before any `open` in the session yields no startup sample yet.
- Comparing values across different devices/runtimes introduces large noise.
- Interpreting current `startup` as CPU/FPS/memory would be incorrect.
@@ -1,70 +0,0 @@
# Permissions and Setup
## iOS snapshots
iOS snapshots use XCTest and do not require macOS Accessibility permissions.
## iOS physical device runner
For iOS physical devices, XCTest runner setup requires valid signing/provisioning.
Use Automatic Signing in Xcode, or provide optional overrides:
- `AGENT_DEVICE_IOS_TEAM_ID`
- `AGENT_DEVICE_IOS_SIGNING_IDENTITY`
- `AGENT_DEVICE_IOS_PROVISIONING_PROFILE`
- `AGENT_DEVICE_IOS_BUNDLE_ID` (optional runner bundle-id base override)
Free Apple Developer (Personal Team) accounts may reject generic bundle IDs as unavailable.
Set `AGENT_DEVICE_IOS_BUNDLE_ID` to a unique reverse-DNS identifier when that happens.
Security guidance for these overrides:
- These variables are optional and only needed for physical-device XCTest setup.
- Treat values as sensitive host configuration; do not share in chat logs or commit to source control.
- Do not provide private keys or unrelated secrets; use the minimum values required for signing.
- Prefer Xcode Automatic Signing when possible to reduce manual secret/config handling.
- For autonomous/CI runs, keep these unset by default and require explicit opt-in for physical-device workflows.
If setup/build takes long, increase:
- `AGENT_DEVICE_DAEMON_TIMEOUT_MS` (default `90000`, for example `120000`)
If daemon startup fails with stale metadata hints, clean stale files and retry:
- `~/.agent-device/daemon.json`
- `~/.agent-device/daemon.lock`
## iOS permission alerts (simulator only)
iOS apps trigger system permission dialogs (camera, location, notifications, etc.) on first use.
Use `alert` to handle them without tapping coordinates:
```bash
agent-device alert wait # block until an alert appears (default 10 s timeout)
agent-device alert accept # accept the frontmost alert
agent-device alert dismiss # dismiss the frontmost alert
agent-device alert get # read alert title/message without acting
```
**Timing note:** `alert accept` and `alert dismiss` include a built-in 2 s retry window.
If the alert is present in the UI hierarchy but not yet interactive, the command retries every 300 ms
rather than failing immediately. You do not need to add manual sleeps between triggering the alert
and accepting it.
**Preferred pattern for clean simulator sessions:**
```bash
agent-device open MyApp --platform ios
agent-device alert wait 5000 # wait up to 5 s for the permission prompt
agent-device alert accept # accept; retries internally if not yet actionable
```
`alert` is only supported on iOS simulators; iOS physical devices are not supported.
## iOS: "Allow Paste" dialog
iOS 16+ shows an "Allow Paste" prompt when an app reads the system pasteboard. Under XCUITest (which `agent-device` uses), this prompt is suppressed by the testing runtime. Use `xcrun simctl pbcopy booted` to set clipboard content directly on the simulator instead.
## Simulator troubleshooting
- If snapshots return 0 nodes, restart Simulator and re-open the app.
@@ -1,56 +1,56 @@
# Remote Tenancy and Lease Admission
# Remote Tenancy
Use this reference for remote daemon HTTP flows that require explicit
tenant/run admission control.
## When to open this file
## Transport prerequisites
Open this file only for remote daemon HTTP flows that require explicit daemon URL setup, authentication, lease allocation, or tenant-scoped command admission.
- Start daemon in HTTP mode (`AGENT_DEVICE_DAEMON_SERVER_MODE=http|dual`).
- Point remote clients at the host with `AGENT_DEVICE_DAEMON_BASE_URL=http(s)://host:port[/base-path]`
or `--daemon-base-url <url>` so the CLI skips local daemon discovery/startup.
- Use `AGENT_DEVICE_DAEMON_AUTH_TOKEN` / `--daemon-auth-token` when the client should send the
shared daemon token automatically.
- Direct JSON-RPC callers can use a token in params, `Authorization: Bearer <token>`, or
`x-agent-device-token`.
- Prefer an auth hook (`AGENT_DEVICE_HTTP_AUTH_HOOK`) for caller validation and
tenant injection.
## Main commands to reach for first
## Lease lifecycle (JSON-RPC)
- `AGENT_DEVICE_DAEMON_BASE_URL=...`
- `AGENT_DEVICE_DAEMON_AUTH_TOKEN=...`
- `curl ... agent_device.lease.allocate`
- `curl ... agent_device.lease.heartbeat`
- `curl ... agent_device.lease.release`
- `agent-device --tenant ... --session-isolation tenant --run-id ... --lease-id ...`
Use `POST /rpc` with JSON-RPC 2.0 methods:
## Most common mistake to avoid
- `agent_device.lease.allocate`
- `agent_device.lease.heartbeat`
- `agent_device.lease.release`
Do not run a tenant-isolated command without matching `tenant`, `run`, and `lease` scope. Admission checks require all three to line up.
Example allocate:
## Canonical loop
```bash
export AGENT_DEVICE_DAEMON_BASE_URL=http://mac-host.example:4310
export AGENT_DEVICE_DAEMON_AUTH_TOKEN=<token>
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
-H "content-type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"jsonrpc":"2.0","id":"alloc-1","method":"agent_device.lease.allocate","params":{"tenantId":"acme","runId":"run-123","ttlMs":60000}}'
agent-device \
--tenant acme \
--session-isolation tenant \
--run-id run-123 \
--lease-id <lease-id> \
session list --json
```
Example heartbeat:
Heartbeat and release example:
```bash
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
-H "content-type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"jsonrpc":"2.0","id":"hb-1","method":"agent_device.lease.heartbeat","params":{"leaseId":"<lease-id>","ttlMs":60000}}'
```
Example release:
```bash
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
-H "content-type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{"jsonrpc":"2.0","id":"rel-1","method":"agent_device.lease.release","params":{"leaseId":"<lease-id>"}}'
```
Example session-locked command request:
Session-locked RPC command example:
```bash
curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
@@ -59,11 +59,34 @@ curl -sS "${AGENT_DEVICE_DAEMON_BASE_URL}/rpc" \
-d '{"jsonrpc":"2.0","id":"cmd-1","method":"agent_device.command","params":{"session":"qa-ios","command":"snapshot","positionals":[],"meta":{"lockPolicy":"reject","lockPlatform":"ios","tenantId":"acme","runId":"run-123","leaseId":"<lease-id>"}}}'
```
Direct RPC callers can send the same session lock concept as the CLI and typed client through `meta.lockPolicy` and optional `meta.lockPlatform`.
## Transport prerequisites
- Start the daemon in HTTP mode with `AGENT_DEVICE_DAEMON_SERVER_MODE=http|dual`.
- Point the client at the remote host with `AGENT_DEVICE_DAEMON_BASE_URL=http(s)://host:port[/base-path]`.
- Use `AGENT_DEVICE_DAEMON_AUTH_TOKEN` or `--daemon-auth-token` when the client should send the shared daemon token automatically.
- Direct JSON-RPC callers can authenticate with request params, `Authorization: Bearer <token>`, or `x-agent-device-token`.
- Prefer an auth hook such as `AGENT_DEVICE_HTTP_AUTH_HOOK` when the host needs caller validation or tenant injection.
## Lease lifecycle
Use JSON-RPC methods on `POST /rpc`:
- `agent_device.lease.allocate`
- `agent_device.lease.heartbeat`
- `agent_device.lease.release`
Keep the lease alive for the duration of the run and release it when the tenant-scoped work is complete.
Host-level lease knobs:
- `AGENT_DEVICE_MAX_SIMULATOR_LEASES`
- `AGENT_DEVICE_LEASE_TTL_MS`
- `AGENT_DEVICE_LEASE_MIN_TTL_MS`
- `AGENT_DEVICE_LEASE_MAX_TTL_MS`
## Command admission contract
For tenant-isolated command execution, pass all four flags:
For tenant-isolated command execution, pass all four CLI flags together:
```bash
agent-device \
@@ -74,25 +97,11 @@ agent-device \
session list --json
```
Admission checks require tenant/run/lease scope alignment.
The CLI sends `AGENT_DEVICE_DAEMON_AUTH_TOKEN` in both the JSON-RPC request token field and HTTP auth headers so existing daemon auth paths continue to work.
The CLI sends `AGENT_DEVICE_DAEMON_AUTH_TOKEN` in both the JSON-RPC request token field and HTTP
auth headers so existing daemon auth paths continue to work.
## Failure semantics and trust notes
## Failure semantics
- Missing tenant/run/lease fields in tenant isolation mode: `INVALID_ARGS`
- Lease not active or wrong scope: `UNAUTHORIZED`
- Method mismatch: JSON-RPC `-32601` (HTTP 404)
## Operational guidance
- Keep TTL short and heartbeat only while a run is active.
- Release lease immediately on run completion/error paths.
- For remote debug sessions, inspect logs on the remote host; client-side `--debug` no longer tails
a local daemon log when `AGENT_DEVICE_DAEMON_BASE_URL` is set.
- For bounded hosts, configure:
- `AGENT_DEVICE_MAX_SIMULATOR_LEASES`
- `AGENT_DEVICE_LEASE_TTL_MS`
- `AGENT_DEVICE_LEASE_MIN_TTL_MS`
- `AGENT_DEVICE_LEASE_MAX_TTL_MS`
- Missing tenant, run, or lease fields in tenant-isolation mode should fail as `INVALID_ARGS`.
- Inactive or scope-mismatched leases should fail as `UNAUTHORIZED`.
- Inspect logs on the remote host during remote debugging. Client-side `--debug` does not tail a local daemon log once `AGENT_DEVICE_DAEMON_BASE_URL` is set.
- Treat daemon auth tokens and lease identifiers as sensitive operational data.
@@ -1,101 +0,0 @@
# Session Management
## Named sessions
```bash
agent-device --session auth open Settings --platform ios
agent-device --session auth snapshot -i
```
Sessions isolate device context. A device can only be held by one session at a time.
## Best practices
- Name sessions semantically.
- Close sessions when done.
- Use separate sessions for parallel work.
- For orchestrated QA runs, prefer a pre-bound session/platform over repeating per-command selectors.
- For remote tenant-scoped automation, run commands with:
`--tenant <id> --session-isolation tenant --run-id <id> --lease-id <id>`
- In iOS sessions, use `open <app>`. `open <url>` opens deep links; on devices `http(s)://` opens Safari when no app is active, and custom schemes require an active app in the session.
- In iOS sessions, `open <app> <url>` opens a deep link.
- On iOS, `appstate` is session-scoped and requires a matching active session on the target device.
- For dev loops where runtime state can persist (for example React Native Fast Refresh), use `open <app> --relaunch` to restart the app process in the same session.
- Use `--save-script [path]` to record replay scripts on `close`; path is a file path and parent directories are created automatically.
- Use `close --shutdown` on iOS simulators or Android emulators to shut down the target as part of session teardown, preventing resource leakage in multi-tenant or CI workloads.
- For ambiguous bare `--save-script` values, prefer `--save-script=workflow.ad` or `./workflow.ad`.
- For deterministic replay scripts, prefer selector-based actions and assertions.
- Use `replay -u` to update selector drift during maintenance.
## Session-bound automation
Use this when an external orchestrator must keep every CLI call on the same session/device without a wrapper script.
```bash
export AGENT_DEVICE_SESSION=qa-ios
export AGENT_DEVICE_PLATFORM=ios
export AGENT_DEVICE_SESSION_LOCK=strip
agent-device open MyApp --relaunch
agent-device snapshot -i
agent-device press @e3
agent-device close
```
- `AGENT_DEVICE_SESSION` and `AGENT_DEVICE_PLATFORM` provide the default binding when `--session` and `--platform` are omitted.
- A configured `AGENT_DEVICE_SESSION` enables lock policy enforcement by convention. The default mode is `reject`.
- `--session-lock reject|strip` or `AGENT_DEVICE_SESSION_LOCK=reject|strip` controls whether conflicting selectors fail or are ignored.
- The daemon enforces the same lock policy for CLI requests, typed client calls, and direct RPC commands.
- Conflicts include explicit retargeting selectors such as `--platform`, `--target`, `--device`, `--udid`, `--serial`, `--ios-simulator-device-set`, and `--android-device-allowlist`.
- `--session-locked`, `--session-lock-conflicts`, `AGENT_DEVICE_SESSION_LOCKED`, and `AGENT_DEVICE_SESSION_LOCK_CONFLICTS` remain supported as compatibility aliases.
- Lock policy applies to nested `batch` steps too. If a step omits `platform`, it still inherits the parent batch `--platform` instead of being silently replaced by an environment default.
Android emulator variant:
```bash
export AGENT_DEVICE_SESSION=qa-android
export AGENT_DEVICE_PLATFORM=android
agent-device reinstall MyApp /path/to/app-debug.apk --serial emulator-5554
agent-device --session-lock reject open com.example.myapp --relaunch
agent-device snapshot -i
agent-device close --shutdown
```
## Scoped device isolation
Use scoped discovery when sessions must not see host-global device lists.
```bash
agent-device devices --platform ios --ios-simulator-device-set /tmp/tenant-a/simulators
agent-device devices --platform android --android-device-allowlist emulator-5554,device-1234
```
- Scope is applied before selectors (`--device`, `--udid`, `--serial`).
- If selector target is outside scope, resolution fails with `DEVICE_NOT_FOUND`.
- If the scoped iOS simulator set is empty (first-run), the error includes the set path and a suggested `xcrun simctl --set <path> create ...` command.
- With iOS simulator-set scope enabled, iOS physical devices are not enumerated.
- Environment equivalents:
- `AGENT_DEVICE_IOS_SIMULATOR_DEVICE_SET` (compat: `IOS_SIMULATOR_DEVICE_SET`)
- `AGENT_DEVICE_ANDROID_DEVICE_ALLOWLIST` (compat: `ANDROID_DEVICE_ALLOWLIST`)
## Listing sessions
```bash
agent-device session list
```
iOS session entries include `device_udid` and `ios_simulator_device_set` (null when using the default set). Use these fields to confirm device routing in concurrent multi-session runs without additional `simctl` calls.
## Replay within sessions
```bash
agent-device replay ./session.ad --session auth
agent-device replay -u ./session.ad --session auth
```
## Tenant isolation note
When session isolation is set to tenant mode, session namespace is scoped as
`<tenant>:<session>`. For remote runs, allocate and maintain an active lease
for the same tenant/run scope before executing tenant-isolated commands.
@@ -1,105 +0,0 @@
# Snapshot Refs and Selectors
## Purpose
Refs are useful for discovery/debugging. For deterministic scripts, use selectors.
For tap interactions, `press` is canonical; `click` is an equivalent alias.
For host Mac desktop apps, pair this reference with [macos-desktop.md](macos-desktop.md) because context menus and native list/table structures need desktop-specific handling.
## Snapshot
```bash
agent-device snapshot -i
```
Use plain `snapshot` when you need to verify whether text is visible on screen.
Use `snapshot -i` mainly for interactive exploration and choosing refs.
Output:
```
Page: com.apple.Preferences
App: com.apple.Preferences
@e1 [ioscontentgroup]
@e2 [button] "Camera"
@e3 [button] "Privacy & Security"
```
## Using refs (discovery/debug)
```bash
agent-device press @e2
agent-device fill @e5 "test"
```
On macOS, if actions live in a context menu, use:
```bash
agent-device click @e5 --button secondary --platform macos
agent-device snapshot -i
```
## Using selectors (deterministic)
```bash
agent-device press 'id="camera_row" || label="Camera" role=button'
agent-device fill 'id="search_input" editable=true' "test"
agent-device is visible 'id="camera_settings_anchor"'
```
## Ref lifecycle
Refs can become invalid when UI changes (navigation, modal, dynamic list updates).
Re-snapshot after transitions if you keep using refs.
## Scope snapshots
Use `-s` to scope to labels/identifiers. This reduces size and speeds up results:
```bash
agent-device snapshot -i -s "Camera"
agent-device snapshot -i -s @e3
```
## Diff snapshots (structural)
Use `diff snapshot` when you need compact state-change visibility between nearby UI states:
```bash
agent-device snapshot -i # First snapshot initializes baseline
agent-device press @e5
agent-device diff snapshot -i # Shows +/− structural lines vs prior snapshot
```
Efficient pattern:
- Initialize once at a stable point.
- Mutate UI (`press`, `fill`, `swipe`).
- Run `diff snapshot` after interactions to confirm expected change shape with bounded output.
- Re-run full/scoped `snapshot` only when you need fresh refs for next step selection.
## Troubleshooting
- Ref not found: re-snapshot.
- If `snapshot` returns 0 nodes, foreground app state or accessibility state may have changed. Re-open the app or retry after state is stable.
- On macOS, use `snapshot --raw --platform macos` to distinguish collector filtering from truly missing AX content.
## Stop Conditions
- If refs are unstable after UI transitions, switch to selector-based targeting and stop investing in ref-only flows.
## find click response
`find "<query>" click --json` returns deterministic matched-target metadata:
```json
{ "ref": "@e3", "locator": "any", "query": "Increment", "x": 195, "y": 422 }
```
Fields come from the matched snapshot node, not the platform runner. Use these for observability and replay quality — they are stable across runs for the same UI state.
## Replay note
- Prefer selector-based actions in recorded `.ad` replays.
- Use `agent-device replay -u <path>` to update selector drift and rewrite replay scripts in place.
@@ -0,0 +1,103 @@
# Verification
## When to open this file
Open this file when the task needs evidence, regression checks, replay maintenance, or startup performance measurements after the main interaction flow is already working.
## Main commands to reach for first
- `screenshot`
- `diff snapshot`
- `record`
- `replay -u`
- `perf`
## Most common mistake to avoid
Do not use verification tools as the first exploration step. First get the app into the correct state with the normal interaction flow, then capture proof or maintain replay assets.
## Canonical loop
```bash
agent-device open Settings --platform ios
agent-device snapshot -i
agent-device press @e5
agent-device diff snapshot -i
agent-device screenshot /tmp/settings-proof.png
agent-device close
```
## Structural verification with diff snapshot
Use `diff snapshot` when you need a compact view of how the UI changed between nearby states.
```bash
agent-device snapshot -i
agent-device press @e5
agent-device diff snapshot -i
```
- Initialize the baseline at a stable point.
- Perform the mutation.
- Run `diff snapshot` to confirm the expected structural change.
- Re-run full `snapshot` only when you need fresh refs.
## Visual artifacts
Use `screenshot` when the proof needs a rendered image instead of a structural tree.
## Session recording
Use `record` for debugging, documentation, or shareable verification artifacts.
```bash
agent-device record start ./recordings/ios.mov
agent-device open App
agent-device snapshot -i
agent-device press @e3
agent-device close
agent-device record stop
```
- `record` supports iOS simulators, iOS devices, and Android.
- On iOS, recording is a wrapper around `simctl` for simulators and the corresponding device capture path for physical devices.
- On Android, recording is a wrapper around `adb`.
- Recording writes a video artifact and a gesture-telemetry sidecar JSON.
- On macOS hosts, touch overlay burn-in is available for supported recordings.
- On non-macOS hosts, recording still succeeds but the video stays raw and `record stop` can return an `overlayWarning`.
- If the agent already knows the interaction sequence and wants a more lifelike, uninterrupted recording, drive the flow with `batch` while recording instead of replanning between each step.
Example:
```bash
agent-device record start ./recordings/smoke.mov
agent-device batch --session sim --platform ios --steps-file /tmp/smoke-steps.json --json
agent-device record stop
```
- Use this only after exploration has stabilized the flow.
- Keep the batch short and add `wait` or `is exists` guards after mutating steps so the recorded flow still tracks realistic UI timing.
## Replay maintenance
Use replay updates when selectors drift but the recorded scenario is still correct.
```bash
agent-device replay -u ./session.ad
```
- Prefer selector-based actions in recorded `.ad` replays.
- Use update mode for maintenance, not as a substitute for fixing a broken interaction strategy.
## Performance checks
Use `perf --json` or `metrics --json` when you need startup timing for the active session.
```bash
agent-device open Settings --platform ios
agent-device perf --json
```
- Current startup data is command round-trip timing around `open`.
- It is not true first-frame or first-interactive telemetry.
- `fps`, `memory`, and `cpu` are currently placeholders.
@@ -1,51 +0,0 @@
# Video Recording
Capture device automation sessions as video for debugging, documentation, or verification
## iOS Simulator
Use `agent-device record` commands (wrapper around simctl):
```bash
# Start recording
agent-device record start ./recordings/ios.mov
# Perform actions
agent-device open App
agent-device snapshot -i
agent-device click @e3
agent-device close
# Stop recording
agent-device record stop
```
`record` supports iOS simulators, physical iOS devices, and Android.
Recording outputs:
- a video artifact
- a gesture-telemetry sidecar JSON next to the video
Touch overlay support:
- macOS host: telemetry can be burned into the video as visible touch overlays
- non-macOS host: recording still succeeds, but the video stays raw and `record stop` returns an `overlayWarning`
## Android Emulator/Device
Use `agent-device record` commands (wrapper around adb):
```bash
# Start recording
agent-device record start ./recordings/android.mp4
# Perform actions
agent-device open App
agent-device snapshot -i
agent-device click @e3
agent-device close
# Stop recording
agent-device record stop
```