Skip to Content
DocsRunning flowsRecording mode

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 --mask patterns 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:

EventWhat it captures
User tapsCoordinates plus the resolved element descriptor (testID, accessibilityLabel, role, text)
Text inputThe typed value, redacted against any --mask patterns
Scroll / swipeDirection + bounds
Network requestsURL, method, response status (skip with --no-network)
Screen transitionsElement-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 immediately

The 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-client

Open 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 7345

The 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 cart

Drive 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.md

Review 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

FlagDefaultWhat it does
--output <path>flows/<slug>.flow.mdwhere to write the prose + sibling .flow.json
--name "<title>"recordingflow title used in the prose header
--app <bundle-id>anyrestrict capture to one connected runtime
--mask <regex>mask values matching the pattern; comma-separated, repeatable
--no-networkoffskip network event capture
--appendoffextend an existing .flow.md instead of overwriting
--bridge-url <url>ws://127.0.0.1:7345bridge 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.

Last updated on