How record works
How Haiku watches a live session and turns it into a .haiku spec — for UI flows on iOS and for backend test runs.
haiku record is the other half of the authoring loop. Instead of writing
a spec by hand, you run your app or your tests the way you normally would,
and Haiku watches what happens and writes the matching .haiku spec.
Editable, replayable with haiku recite, and grounded in something that
actually ran.
Record routes by what you give it.
UI recording (iOS)
When the argument looks like a reverse-DNS bundle ID, Haiku takes the UI recording path.
Behind the scenes Haiku:
- Resolves the simulator — uses the device name you passed (before or after the bundle ID), or the currently-booted simulator. Boots it if needed.
- Launches the app and brings up the Haiku recording overlay alongside it.
- Watches the session — the overlay observes accessibility events (tap targets, text input, scroll/swipe gestures, view appearances) and captures screenshots at every meaningful moment so the vision model can later describe what was on screen.
- Translates events to English — the captured event stream and the screenshots are folded into a plain-English step sequence: "Tap the search bar. Type Statue of Liberty. Verify the result appears."
- Writes a
.ios.haikufile — frontmatter populated with the app's bundle ID and the simulator that captured it; body filled with the inferred steps. Default output filename is derived from the bundle ID if you don't pass-o.
The result is ready to hand to haiku recite for replay, or to edit if
you want to tighten the prose.
Backend recording
When the argument is a command (anything that isn't a reverse-DNS bundle ID), Haiku takes the backend recording path. The output filename's extension chooses the target language:
Behind the scenes Haiku:
- Detects the runtime from the command —
pytest/python→ Python,cargo→ Rust,go→ Go,npx/tsx/node→ TypeScript, and so on. - Runs the command and observes its output: assertion successes, function names that were called, exceptions raised, return values captured at the boundary.
- Walks the codebase for the function and module names that showed
up at runtime, so it knows which sources actually got exercised
(recorded as the
sources:frontmatter list, most-called first). - Translates observations to English assertions — "Calling
create_userwith an empty email raisesValueError. Looking up an unknown id returnsNone." - Writes the
.<lang>.haikufile at the path you passed to-o(or streams to stdout if you didn't). Frontmatter carries thesources:list; body is the assertion sequence.
The output runs through haiku recite, which re-generates the native
test file and executes it through your language's real test runner —
same pipeline a hand-written spec would take.
Trace logs
Every record invocation produces a forensic trace log, same as
recite. Default location is /tmp/haiku-record-<timestamp>.log and the
path is printed to stderr at the start. Pass --trace for a sticky path
in the current directory, or --trace=PATH for a custom location.
When to record vs. write
Recording is great when:
- The flow is easier to demonstrate than to describe (long UI sequences, multi-step checkouts).
- You want a spec grounded in the actual function names and assertions your test run produced.
- You're seeding a new spec from real behaviour and will edit it down.
Writing by hand is great when:
- You know exactly what you want to assert and the spec is short.
- You're describing intent that the current code doesn't yet satisfy — i.e. you're using the spec to drive new development.