Skip to content

Commit 6fa3a55

Browse files
committed
Merge branch 'main' into feat/domain-members-move-single-user-between-groups
2 parents 6f9e127 + c71784d commit 6fa3a55

508 files changed

Lines changed: 580720 additions & 368823 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/agent-device/SKILL.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,23 @@ allowed-tools: Bash(agent-device *) Bash(npm root *)
88

99
## Pre-flight
1010

11-
`agent-device` CLI version: !`agent-device --version 2>&1 || echo "NOT_INSTALLED"`
11+
<!-- The line below compares the installed `agent-device --version` to the required minimum 0.13.0 -->
12+
13+
`agent-device` version check: !`R=0.13.0; V=$(agent-device --version 2>/dev/null); [ -n "$V" ] && [ "$(printf '%s\n%s\n' "$R" "$V" | sort -V | head -1)" = "$R" ] && echo "OK ($V)" || echo "FAIL (need v$R+, got: ${V:-not installed})"`
14+
15+
> If the version check above shows `FAIL`, **STOP** and instruct the developer: `npm install -g agent-device@latest`.
1216
1317
Canonical skill reference path (read these files directly for device automation guidance - bootstrap, exploration, verification, debugging): !`echo "$(npm root -g)/agent-device/skills/agent-device"`
1418

15-
> If the version line above shows `NOT_INSTALLED` or a command-not-found error, **STOP** and instruct the developer to install it: `npm install -g agent-device`. All device interaction depends on it.
19+
## Dev prerequisites
20+
21+
Default assumption: dev build from this repo. Before `open <app>`, both must be true:
22+
23+
1. **Metro dev server** running: `npm run start` (background).
24+
2. **Dev build installed** on target: `npm run ios` or `npm run android` from the repo root.
25+
26+
Skip these only when the developer explicitly targets a non-dev build (e.g., standalone/prod artifact, or a pre-installed release build).
27+
28+
## Flows
29+
30+
Repeatable steps (sign-in, onboarding, etc.) are captured as composable `.ad` snippets under [`flows/`](flows/README.md). Before manually tapping through a screen, follow the **Agent decision loop** in [`flows/README.md`](flows/README.md) - it covers discovery, `@pre` filtering, replay, and `@post` verification.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Flows
2+
3+
Composable `.ad` snippets - bounded units of work. A flow may span one or multiple screens as long as it represents a coherent, reusable action with clear start (`@pre`) and completion (`@post`) checkpoints. Each flow advertises machine-matchable metadata (`@pre`, `@post`, `@tag`) via `# @`-prefixed comment headers, so an agent can pick the right one from a snapshot.
4+
5+
## Agent decision loop
6+
7+
Before manually navigating, use this human-in-the-loop loop:
8+
9+
1. `agent-device snapshot -i` - see current state.
10+
2. `grep -H '^# @' .claude/skills/agent-device/flows/*.ad` - full catalog in one read.
11+
3. For each candidate flow, run `agent-device is exists "<selector>"` per `@pre`. Keep flows where every `@pre` passes.
12+
4. Rank survivors by goal closeness (`@post` overlap with the requested destination when present) and present top candidates to the user with a short "why this flow" note.
13+
5. Wait for user selection before replaying. **Auto-run is allowed only when there is exactly one survivor and it is an unambiguous match for an explicit user request.**
14+
6. `agent-device replay <path>`.
15+
7. If the flow declares `@post`, verify each `@post` with `is exists`. On success, re-enter the loop only if the user's stated goal is not complete; otherwise stop and report completion. On failure, propose peer flow/manual fallback options and ask before continuing. If no `@post` is declared (utility flow), rely on explicit user confirmation or the next snapshot before continuing.
16+
17+
## Metadata header spec
18+
19+
Each flow starts with `# @key value` comment lines. The `.ad` parser treats `#` lines as no-ops, so headers cost nothing at replay time.
20+
21+
| Field | Cardinality | Value |
22+
| -------- | ----------- | ------------------------------------------------------------------------------------------------ |
23+
| `@desc` | 1 | One-line human summary. |
24+
| `@pre` | 1..N | Selector that must resolve in the current snapshot. Multiple lines are ANDed. |
25+
| `@post` | 0..N | Selector expected after replay. Multiple lines are ANDed. Used for chaining + success. |
26+
| `@tag` | 0..N | Free-form category (`auth`, `onboarding`, ...) or scoped (`sentry-<spanName>`). |
27+
28+
Selector syntax matches the body: `id="..."`, `role="..." label="..."`, `text="..."`, `||` for fallbacks.
29+
30+
## Parametrization (`agent-device` v0.13.0+)
31+
32+
Lift body literals to named variables via `env` + `${VAR}` interpolation so values can be overridden at runtime without editing the file.
33+
34+
| Construct | Where | Purpose |
35+
| ------------------ | -------------------- | -------------------------------------------------------------------------------- |
36+
| `env KEY=VALUE` | Header (after `# @`) | File-level default. Quote values with spaces or `||` chains: `env KEY="a || b"`. |
37+
| `${KEY}` | Body | Interpolation point. Resolves at replay time. |
38+
| `${KEY:-fallback}` | Body | Use `fallback` if `KEY` is unset. |
39+
| `\${KEY}` | Body | Literal `${KEY}` (escape). |
40+
41+
Resolution precedence (high to low): CLI `-e KEY=VALUE` (repeatable) > shell `AD_KEY=...` (auto-imported, prefix stripped) > file `env` > built-ins (`AD_PLATFORM`, `AD_SESSION`, `AD_FILENAME`, `AD_DEVICE`, `AD_ARTIFACTS`). Unresolved `${X}` errors with `file:line`.
42+
43+
Override at runtime without editing the file:
44+
45+
```bash
46+
agent-device replay <flow>.ad -e EMAIL=other@example.com
47+
```
48+
49+
## Authoring rules
50+
51+
- **No `open`, no `close`, no `context` header.** Caller owns lifecycle.
52+
- **No fixed `wait` calls.** `fill`/`press` resolve selectors with retry. Only add `wait <selector>` for real post-action blocks.
53+
- **Durable selectors.** Prefer `id=...` first, then `role=... label=...`, with `||` fallbacks. Avoid `@eN` refs.
54+
- **Every flow declares `@desc` and `@pre`.** Add `@post` for outcome-bearing flows; utility flows (for example `go-back`) may omit it. Add `@tag` when applicable.
55+
- **Keep scope coherent, not artificially tiny.** Flows can span multiple screens when that sequence is the reusable intent (for example "create and submit manual expense").
56+
- **Peers share `@pre` and differ on `@post`.** One flow per narrow outcome is better than a mega-flow with conditional branches.
57+
- **Use `env` for substituted values.** If a literal is interpolated into the body, declare a matching `env` default and reference it as `${VAR}`.
58+
59+
## Recording a new flow
60+
61+
1. Drive the target screen manually.
62+
2. Start a session with `--save-script`:
63+
```bash
64+
agent-device open <app> --save-script .claude/skills/agent-device/flows/<name>.ad
65+
```
66+
3. Perform the steps.
67+
4. `agent-device close` - flushes the `.ad`.
68+
5. Edit the generated file:
69+
- Delete the `context` line, leading `open ... --relaunch`, trailing `close`, and eyeballing `wait`s.
70+
- Add `@desc`, `@pre`, optional `@post`, and `@tag` headers.
71+
6. Verify: pre-check from a matching state, replay, post-check.
72+
73+
## Maintenance
74+
75+
Heal selector drift in place:
76+
77+
```bash
78+
agent-device replay -u .claude/skills/agent-device/flows/<name>.ad
79+
```
80+
81+
Re-verify `@pre`/`@post` still hold, then commit. Note: `replay -u` is rejected when the script declares `env` directives (rewrite would drop them); strip the `env` block manually before healing, then re-add it.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# @desc Complete onboarding with minimal choices (skip work email, pick "Something else" purpose, enter generic name). Lands on Home.
2+
# @pre text="What’s your work email?"
3+
# @post text="Home"
4+
# @post role="button" label="Search"
5+
# @tag onboarding
6+
env FIRST_NAME=Agent
7+
env LAST_NAME=Device
8+
9+
press "id=\"onboardingPrivateEmailSkipButton\" || role=\"button\" label=\"Skip\" || label=\"Skip\""
10+
press "role=\"button\" label=\"Something else\" || label=\"Something else\""
11+
fill "role=\"textfield\" label=\"First name\" editable=true || label=\"First name\" editable=true" "${FIRST_NAME}"
12+
fill "role=\"textfield\" label=\"Last name\" editable=true || label=\"Last name\" editable=true" "${LAST_NAME}"
13+
press "role=\"button\" label=\"Continue\" || label=\"Continue\""
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# @desc Open Create Expense from the FAB, enter an amount on the Manual tab, fill the Merchant field, and submit. Supports configurable currency-aware submit button matching. Exercises the full submit-chain Sentry spans end-to-end. Assumes a workspace where Category is not required.
2+
# @pre role="button" label="Open actions menu"
3+
# @post text="Reports"
4+
# @post role="button" label="Expenses"
5+
# @tag iou
6+
# @tag navigation
7+
# @tag perf
8+
# @tag sentry-ManualCreateExpenseSubmit
9+
# @tag sentry-ManualSubmitToDestinationVisible
10+
# @tag sentry-ManualCreateExpenseServerResponse
11+
# @tag sentry-ManualConfirmationMount
12+
# @tag sentry-ManualConfirmationListReady
13+
# @tag sentry-ManualConfirmationReceiptLoad
14+
# @tag sentry-ManualGeolocationWait
15+
env AMOUNT=22
16+
env CURRENCY=PLN
17+
env MERCHANT="Test Coffee"
18+
19+
press "role=\"button\" label=\"Open actions menu\""
20+
press "role=\"button\" label=\"Create expense\" || label=\"Create expense\""
21+
press "label=\"Manual\""
22+
is exists "role=\"button\" label=\"Flip\""
23+
fill "editable=true" "${AMOUNT}"
24+
press "role=\"button\" label=\"Next\" || label=\"Next\""
25+
press "role=\"button\" label=\"Merchant\" || label=\"Merchant\""
26+
fill "role=\"text-field\" label=\"Merchant,\" editable=true || label=\"Merchant,\" editable=true" "${MERCHANT}"
27+
press "role=\"button\" label=\"Save\" || label=\"Save\""
28+
press "label=\"Create ${CURRENCY} ${AMOUNT}.00 expense\" || label=\"Create expense\""
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# @desc Generic back navigation via the HeaderWithBackButton chevron. Works on any screen that mounts HeaderWithBackButton (Create Expense, Search, Report details, settings pages, etc.).
2+
# @pre role="button" label="Back"
3+
# @tag navigation
4+
press "role=\"button\" label=\"Back\""
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# @desc From the Inbox tab, open the FAB actions menu and tap "Create expense". Triggers the ManualOpenCreateExpense Sentry span (startMoneyRequest -> IOURequestStart/Participants/Confirmation page). Assumes the user is signed in and the Inbox bottom nav with the floating action button is visible.
2+
# @pre text="Inbox"
3+
# @pre role="button" label="Open actions menu"
4+
# @post text="Manual"
5+
# @tag iou
6+
# @tag navigation
7+
# @tag perf
8+
# @tag sentry-ManualOpenCreateExpense
9+
find "Inbox" "click"
10+
press "role=\"button\" label=\"Open actions menu\""
11+
press "role=\"button\" label=\"Create expense\" || label=\"Create expense\""
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# @desc From the Inbox tab, open a chat/report matching TARGET_CHAT in the LHN, with fallback to the first available chat row. Triggers the ManualOpenReport Sentry span (LHN row press -> report screen mounted with composer visible). Assumes the user is signed in with at least one chat in the Inbox.
2+
# @pre text="Inbox"
3+
# @pre text="Navigates to a chat"
4+
# @post role="textview" label="Write something..."
5+
# @tag chat
6+
# @tag navigation
7+
# @tag perf
8+
# @tag sentry-ManualOpenReport
9+
env TARGET_CHAT="Navigates to a chat"
10+
11+
find "Inbox" "click"
12+
find "${TARGET_CHAT}" "click"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# @desc Open the SearchRouter from the Inbox tab. Triggers the ManualOpenSearchRouter Sentry span (Search button tap -> SearchRouterPage visible). Assumes the user is signed in.
2+
# @pre text="Inbox"
3+
# @pre role="button" label="Search"
4+
# @post label="Search for something..." editable=true
5+
# @tag navigation
6+
# @tag perf
7+
# @tag search
8+
# @tag sentry-ManualOpenSearchRouter
9+
press "label=\"Inbox\" || label=\"Inbox. Your review is required\""
10+
press "role=\"button\" label=\"Search\""
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# @desc From the Inbox tab, open the FAB -> Create expense -> switch to Scan tab. Triggers the ManualCameraInit Sentry span (Scan tab mount -> camera session ready). Assumes the user is signed in and camera permission is granted.
2+
# @pre text="Inbox"
3+
# @pre role="button" label="Open actions menu"
4+
# @post text="Take a photo"
5+
# @tag iou
6+
# @tag scan
7+
# @tag perf
8+
# @tag sentry-ManualCameraInit
9+
find "Inbox" "click"
10+
press "role=\"button\" label=\"Open actions menu\""
11+
press "role=\"button\" label=\"Create expense\" || label=\"Create expense\""
12+
press "label=\"Scan\""
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# @desc From the Inbox tab, open a chat matching TARGET_CHAT in the LHN, type a message and send it. Triggers the ManualSendMessage Sentry span (Send press -> optimistic message fragment rendered). Assumes the user is signed in with at least one chat in the Inbox.
2+
# @pre text="Inbox"
3+
# @pre text="Navigates to a chat"
4+
# @post label="Write something..." editable=true
5+
# @tag chat
6+
# @tag navigation
7+
# @tag perf
8+
# @tag sentry-ManualSendMessage
9+
env MESSAGE="Hello from agent-device ManualSendMessage flow"
10+
env TARGET_CHAT="Navigates to a chat"
11+
12+
find "Inbox" "click"
13+
find "${TARGET_CHAT}" "click"
14+
is exists "label=\"Write something...\" editable=true"
15+
fill "label=\"Write something...\" editable=true" "${MESSAGE}"
16+
press "role=\"button\" label=\"Send\""

0 commit comments

Comments
 (0)