Writing flows
Writing flows
A flow is a test written as numbered steps in plain language. Your agent records it once on a phone; after that it replays on any phone without AI.
Where flows live
Each flow is two files in e2e/proofsheet/flows/, committed with the app:
checkout.md: the steps, written by a person.checkout.steps.yaml: the recorded steps, written by the agent. Don't edit it by hand.
The flow file
---
app: { ios: com.example.shop, android: com.example.shop }
env: [SHOPPER_PASSWORD]
permissions: allow
---
# Checkout with a saved card
1. Open the app signed in as the test shopper
2. Add the first product to the cart
3. Pay with the saved card
4. Expect the receipt with the order total
| Key | What it does |
|---|---|
app | The iOS bundle id and Android package, or one string for both. |
env | The names of the secrets the flow types. Steps type ${SHOPPER_PASSWORD}, never the value; the value comes from the environment, then the project's .env in the folder proofsheet e2e where prints, outside the repo. |
permissions | allow or deny: how system popups (notifications, camera, location and the like) are answered. allow when unset. |
actors | For a flow on several phones at once, such as [alice, bob]. Start each item with its actor: 2. bob: expect a notification "hi". |
Write one thing a user does or sees per item. Items that start with "Expect" become checks: exact ones where the screen allows it, otherwise a visual check that waits for a review.
Record it
Ask your agent, for example:
Author the checkout flow on my iPhone
It walks through the items on the phone and records each step. When an element has no id, it asks you to add one in the app: accessibilityIdentifier on iOS, a resource-id on Android, testID in React Native, Semantics(identifier:) in Flutter.
Replay it
proofsheet e2e run checkout --device ios
proofsheet e2e run checkout --all
proofsheet e2e run flows --all --max 2
--device: a phone by id or part of its name or model, or a pool:android,iosorany.--all: every connected phone the flow has an app for.--maxcaps how many run at once.--shard: each flow once, on the first free phone that fits.- A folder runs its flows in name order. A busy phone is waited for, up to
--wait(10 minutes).
| Exit code | Meaning |
|---|---|
0 | Passed. |
1 | A step failed, or visual checks are pending with --strict. |
2 | Bad arguments, or a flow that is not recorded or changed since it was recorded. |
3 | Hub or phone trouble, or an aborted run. |
When the app changes
When a run fails, ask your agent to look at it. It tells test drift (the app changed on purpose) from a real regression, patches the flow for drift, and reports the regression to you. A flow whose .md changed after recording needs recording again from the changed step.
Uploads
Every finished run uploads to your workspace on its own. proofsheet e2e upload uploads any finished runs the portal is missing. Recording runs, and runs that hit hub trouble or were aborted, are not uploaded.