Recording mode
klera record is the CLI recorder. It connects to the bridge as a
driver, captures a live session against your simulator or device, and
on Ctrl-C compiles the captured timeline into a .flow.md draft +
paired .flow.json cache via the planner.
klera record --output flows/checkout.flow.md --name "Checkout"This is distinct from the in-app recorder (Cmd+Shift+R / dev-menu trigger; see recording a flow). Both feed the same compile pipeline; they differ in where the trigger lives and which screen the user is looking at.
When to use the CLI recorder
Reach for klera record when:
- You want the recording terminal in front of you with
--maskpatterns visible — easier to demo, easier to review. - You’re recording on a device the in-app dev menu doesn’t reach (a remote sim through SSH, a CI sandbox).
- You’re scripting an unattended capture as part of a fixture- generation pipeline.
Reach for the in-app recorder when:
- You’re a PM / designer driving the device by hand and want the recording trigger one tap away.
- The flow starts mid-app — already past launch, already authenticated — and the CLI’s “attach to a running bridge” timing is awkward.
What it captures
The recorder subscribes to a stream of recording_event frames the
runtime emits as you drive the app. Each frame carries:
| Event | What it captures |
|---|---|
| User taps | Coordinates plus the resolved element descriptor (testID, accessibilityLabel, role, text) |
| Text input | The typed value, redacted against any --mask patterns |
| Scroll / swipe | Direction + bounds |
| Network requests | URL, method, response status (skip with --no-network) |
| Screen transitions | Element-graph snapshots at the boundary |
When you Ctrl-C, the recorder hands the captured timeline to the
planner’s compileFromRecording, which compiles it to a Flow. The
planner uses the same prompt + retry loop as klera plan; see
planner transports for how
the LLM call is routed.
Output
Two files land alongside each other:
<name>.flow.md— prose draft, one sentence per step, with a privacy footer reminding you to review masked values before commit.<name>.flow.json— paired IR cache, ready to run.
flows/
checkout.flow.md ← review and clean up
checkout.flow.json ← runnable immediatelyThe prose is a draft. It will read like “Tap the Sign In button, then type redacted into the email field, then tap Continue.” Polish it the way you’d polish any generated text — fold small steps into one sentence, give the flow a real name, drop redundant assertions.
A typical session
Boot the device and start Metro
npx expo start --dev-clientOpen your app, drive it past whatever lazy-load / login gate you don’t want in the recording.
Start the bridge
In another terminal:
klera serve --port 7345The bridge accepts the runtime’s handshake. Leave it running.
Start recording
In a third terminal:
klera record \
--output flows/checkout.flow.md \
--name "Checkout" \
--mask 'email|card-number'The recorder attaches to the bridge, sends start_recording, and
streams events to stdout as you drive:
record: attached to ws://127.0.0.1:7345
record: capturing — Ctrl-C to stop
tap Sign In
type email = ********
tap Continue
scroll down 320px
tap Add to cartDrive the app
Tap, type, scroll. The recorder buffers events as long as it’s running.
Stop and compile
Ctrl-C in the recorder pane. The compile step runs in-process:
record: stopping; compiling 14 events…
record: planner returned 6 steps
wrote flows/checkout.flow.md
next: klera run flows/checkout.flow.mdReview and clean up
Open flows/checkout.flow.md in an editor. Read the prose aloud —
that’s the canonical review. Fix anything ambiguous. Commit both
.flow.md and .flow.json together.
Cleaning up the prose
The recorder’s prose is mechanical: one event per step. Adopters typically rewrite it into a 3–6 sentence narrative before commit. A typical pass:
- # Recording
+ # Add an item to the cart and check out
- Tap the Sign In button.
- Type "user@test.com" into the email field.
- Type the password into the password field.
- Tap the Continue button.
- Tap the "Add to cart" button.
- Tap the Checkout button.
- Assert that the text "Order placed" is visible.
+ Sign in with the seeded test user, add the first product on the
+ home screen to the cart, then check out and assert that the order
+ confirmation appears.The compile step preserves intent — the planner re-resolves the prose
against the element-graph snapshot, so the IR matches the screen even
when the prose tightens. Always run klera run flows/<name>.flow.md
after editing to verify the cache still passes.
Recording from a fresh launch vs. an attached session
Fresh launch. Start the recorder before the app boots. The
runtime registers as soon as <KleraRuntimeProvider> mounts; the
recorder picks up the first runtime_connected event and the
captured timeline starts from the welcome screen. This is what you
want for end-to-end smoke flows.
Attached session. Start the recorder after the app is past launch — already authenticated, already on a deep-linked screen. The recorder attaches mid-session via the bridge URL. This is what you want for partial flows that exercise one feature without the launch + login overhead.
The --app <bundle-id> flag scopes the capture to a specific
runtime when more than one app is connected to the bridge — useful
for multi-app sandboxes.
Flags
| Flag | Default | What it does |
|---|---|---|
--output <path> | flows/<slug>.flow.md | where to write the prose + sibling .flow.json |
--name "<title>" | recording | flow title used in the prose header |
--app <bundle-id> | any | restrict capture to one connected runtime |
--mask <regex> | — | mask values matching the pattern; comma-separated, repeatable |
--no-network | off | skip network event capture |
--append | off | extend an existing .flow.md instead of overwriting |
--bridge-url <url> | ws://127.0.0.1:7345 | bridge URL to attach to |
--mask patterns redact values in the timeline — they do not
redact values from the on-disk .flow.md after compile. Anything
the planner is told to type (a password, a credit card) lands in
prose unless you also use ${secret:KEY} references. Pair --mask
with the secret-handling flow described in
secret handling for end-to-end safety.
The privacy footer at the bottom of the generated .flow.md is a
reminder to review masked values before commit. It’s a comment line —
safe to delete once you’ve audited the file.