Prepare the app state
A tutorial runs on the real app. Many screens need data in a specific state: a signed offer that hasn’t expired, a deal pending a condition, a client that doesn’t exist yet. Here are the ways to get there, simplest first.
1. Start from an existing record
Section titled “1. Start from an existing record”The demo account usually has records in every state. Open one directly:
steps: - id: review-offer start: /offers/OFF-1042 # a record of the demo dataIf the id changes, look it up first and save it:
setup: - goto: /offers?status=signed - remember: { name: offer, target: { id: offers-row }, attribute: data-offer-id }steps: - id: review-offer start: /offers/{offer}2. Dates that stay in the future
Section titled “2. Dates that stay in the future”{date+N} is the date N days after the shoot (in the browser’s time zone),
so {date+7} is always a week ahead. Use it wherever the app validates a
date (a deadline, an irrevocability date, a shift):
- say: { en-US: Set the deadline one week from now. } type: { target: { id: offer-deadline-input }, text: "{date+7}" }3. A value unique to each run
Section titled “3. A value unique to each run”Apps often reject duplicates (a client email, a name). {run} is a short
value that’s unique to each run and the same in every step of that run:
type: { target: { id: client-email-input }, text: "client-{run}@example.com" }The email must still match safeEmail in your settings.
4. Set up the data before filming
Section titled “4. Set up the data before filming”setup: runs off camera before the first step, with the same actions as a
shot (goto, click, type, select, attach). Use it to open the right
record, close a window the app might show, or change a date:
setup: - click: { id: welcome-close-button } ifPresent: 5000 # waits up to 5 s for it, skipped when it does not show - goto: /offers/{offer}/edit - type: { target: { id: offer-irrevocable-date }, text: "{date+3}" } - click: { id: offer-save-button }writes: - '/updateOffer$' # the save above is a write: list itA command from your repository can also prepare data off screen:
run: "node scripts/demo-offer.cjs signed". This works on your
infrastructure only, never on Ondaclip Cloud. It runs from the repository
root for 120 seconds at most, with TUTORIAL_ID, TUTORIAL_OUTPUT and
TUTORIAL_APP_URL.
5. Leave the app as you found it
Section titled “5. Leave the app as you found it”A tutorial that writes data needs one of these:
cleanup:actions that undo its changes (they always run, even after a failure);- or
demoData.resetinconfig.yaml: the command your team uses to reset the demo data, when cleaning up after each tutorial isn’t possible.
6. Responses that must stay the same
Section titled “6. Responses that must stay the same”When a screen calls an AI model or an outside service, record its responses once and replay them, so every video and every check shows the same thing:
frozenResponses: { url: "invokeLLM|/suggestCondition" }Checks never record, so a new tutorial with frozen responses needs one shoot first.
7. Learn a new tutorial’s requests
Section titled “7. Learn a new tutorial’s requests”In a Firebase app, the SDK reads data with POST requests, and every callable
is a POST. Instead of finding them one check at a time, run a learn check
(MCP check with learn: true). Every request your settings don’t allow is
logged with its step: reads go through, and anything else is blocked without
failing the run. run_status then suggests the allowedWrites for
config.yaml and the writes: for each tutorial. Review them, push, and
check again without learn.
8. When it fails
Section titled “8. When it fails”A problem report shows the step, the element, what covered it (a dialog, a banner) and any messages the app showed at that moment (a toast, an error), along with a screenshot of the failure. Read it before you change the tutorial: the cause is often in the data (a duplicate, an empty required field, a past date).
Is the data fine, but the screen is new and only exists on a branch? Film the branch on its preview. See film a branch on a preview.