Skip to content
Agentmart
Submit a tool

record-user-journey

Use when you need a recording or visual proof of a real user journey through a running app — a demo video for a PR, ticket or stakeholder, evidence that a fix…

Skill by LRNZ09

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/lrnz09-record-user-journey

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Use when you need a recording or visual proof of a real user journey through a running app — a demo video for a PR, ticket or stakeholder, evidence that a fix behaves correctly end to end, a walkthrough captured at a fixed device viewport (TV, tablet, kiosk), or the same journey re-recorded later after code changed. Also use when a recording came out cropped, juddering, or showing something that did not happen.

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Node.js package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/record-user-journey

What's inside

Skill name
record-user-journey
Description
Use when you need a recording or visual proof of a real user journey through a running app — a demo video for a PR, ticket or stakeholder, evidence that a fix behaves correctly end to end, a walkthrough captured at a fixed device viewport (TV, tablet, kiosk), or the same journey re-recorded later after code changed. Also use when a recording came out cropped, juddering, or showing something that did not happen.
License
MIT
Instructions
219 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (8)

  • SKILL.md
  • driver.mjs
  • instrument.js
  • standby-teardown.example.json · journeys/
  • overlay.js
  • reference.md
  • build-stack-filter.mjs · scripts/
  • side-by-side.sh · scripts/

SKILL.md (first lines)

# Record a User Journey

Drive a running app over the Chrome DevTools Protocol, capture the journey as video, and
annotate it with what actually happened. The journey is data; the harness in this directory
executes it.

**Core principle: the recording is evidence, so it has to be honest.** A frame that shows a
held video still while the screen was off, a caption that claims success the run did not
achieve, a viewport that is really a cropped window — each turns a demo into a false claim.
Every rule below exists to keep the recording faithful.

## Prerequisites

1. The app running locally, and a Chrome you control:
   ```sh
   /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome \
     --remote-debugging-port=9222 --user-data-dir=/tmp/journey-profile \
     --hide-crash-restore-bubble
   ```
   **Do not pass `--disable-backgrounding-occluded-windows` or
   `--disable-renderer-backgrounding`** — they stop the page ever being backgrounded, so any
   journey that hides the app silently tests nothing. Automation-launched browsers
   (including MCP-driven ones) commonly set them; launch your own instead.
   If you copy a real profile to inherit a login, delete `SingletonLock`, `SingletonCookie`
   and `SingletonSocket` from the copy first or Chrome hands off to the running instance and
   never opens the port.
2. Sign in manually once. The profile keeps the session.
3. **Confirm the server is serving the code you intend to demonstrate.** Check the branch,
   and check the code is reachable — an effect nobody subscribes to is dead code. Restart the
   dev server after switching branches. Skipping this produces recordings of the wrong build
   that look exactly like recordings of the right one.
4. **Start the dev server so it does not inherit your shell's file descriptors**, and load
   the route you are about to record before recording it. A server backgrounded from an
   agent's own shell (`nohup … &`, even with `< /dev/null`) keeps serving, but a plugin that
   spawns a child process to compile — vanilla-extract does, per CSS module, lazily on first
   request — fails with `spawn EBADF` once the parent's descriptors go away. The page then
   returns 200 with an empty body, so the run aborts on a missing selector and looks like a
   bad journey rather than a broken server. Use the harness's own detached-process mechanism,
   check the server log for `EBADF`, and confirm the route's key element renders first.

## Running it

```sh
node driver.mjs journeys/my-journey.json --out ./recording
```

Outputs `recording/<name>.mp4`, the frames and concat list, and `journey.json` with every
fact the run collected plus a list of held frames. A `verifyViewport` step also writes
`verify-viewport.jpg`. `--no-encode` skips ffmpeg. The `frames/` subdirectory of `--out` is
cleared on each run; nothing else in it is touched.

## Before/after comparisons

Recording the same journey against two builds is the common case, and the pair only reads as
evidence if the presentation is identical every time. Run the same journey file twice, into
separate `--out` directories, then compose:

```sh
scripts/side-by-side.sh <before.mp4> <after.mp4> <out-dir> <TICKET> [before-label] [after-label]
```

**The standard, so a comparison looks the same across tickets:**

- **Filename** `<TICKET>-before-after-side-by-side.mp4`, with the single-build clips as
  `<TICKET>-before.mp4` / `<TICKET>-after.mp4` and stills as `<TICKET>-still-<what>.png`.
  Recognisable from the filename alone, and successive tickets sort together.
- **Labels are floating badges in each pane's top-left corner**, over the video: pastel red
  `#F2A6A6` for before, pastel green `#A8DCB0` for after, so the colour says bad/good before
  a word is read. Ink is a deep tint of the same hue (`#5A1111`, `#14431F`), never white —
  white on either pastel measures under 2:1 and is unreadable, while these land at 7.1:1 and
  7.3:1. 50px tall, inset 17x20 in a 1280-wide pane. Not a header bar above the panes — a bar
  steals height from both and pushes the app's own top-of-screen UI (a search field, the
  caption) away from the frame edge it was designed against. The badge sits in a corner apps
  leave empty.
- **Geometry** two 1280x720 panes plus a 4px separator, so 2564x720; 30fps CFR, yuv420p.
- **A markdown summary next to the video**, `<TICKET>-before-after.md`: what was recorded in
  two lines, then a table of every fact field whose value differs between the runs. The
  script generates it from the two facts files, and omits rows that are identical — a table
  where most rows say "unchanged" buries the two or three that carry the result.
- **Keep implementation detail out of that table, and make every row that stays readable on
  its own.** A summary is read by people who were not in the investigation, and a number they
  cannot interpret is worse than no number: it invites a wrong conclusion. Declare the noisy
  fields in the journey as `summaryExclude` (leaf names, or `fact.field` for one specific
  row); the script drops them and footnotes how many it withheld, so nothing is hidden
  silently. Two kinds belong there:
  - **Technical** — internal geometry with no user-visible meaning (a virtualizer's row
    height in px, its loaded-row count, a JS heap figure that excludes the resource the fix
    is actually about).
  - **Misleading** — anything where a bigger number is not plainly better or worse. A raw
    count of "tiles in view" varies with row height, overscan and how far a list has
    paginated, so the same value can move in either direction for reasons unrelated to the
    change. Prefer a self-describing form: `"6 of 6 recording tiles"` says what a bare `6`
    cannot, and stays true whatever the window happens to contain.
- **Alignment** a journey with fixed holds runs to the same length twice, so any difference
  is start-up latency at the head. The script trims the head of the longer clip so the two
  align at the *tail*, where the summary panel is, and says so when it does. Drift then
  lands in the idle opening rather than across a caption, where one pane would appear a step
  ahead of the other.

The script needs ImageMagick: most ffmpeg builds ship without libfreetype, so `drawtext` is
unavailable and the badges have to be rendered as PNGs and overlaid.

**Both runs must see the same fixture data.** Two runs against drifting fixtures produce a
diff of the fixtures, not of the builds. Confirm the data is stable before the first run
rather than between them: a seeding job still landing rows during run one showed a third of
the continue-watching bars missing, which read exactly like the branch having dropped them.

**Keep the journey as short as the evidence allows.** Every extra step is a step that can
diverge between two runs, and a comparison is only as trustworthy as its shortest path to
the thing being shown.

- **Do not drive UI to reach a state the default view already shows.** A leg that switches a
  filter or opens a menu to surface some item type is wasted when the unfiltered view already
  contains it — and worse, a convergence target that is already satisfied lets the step skip
  itself while the caption still claims the switch happened.
- **Scroll two or three rows, not to the end of the list.** Enough to force the next page and
  show what stays mounted; more just adds runtime and lets the two runs drift apart. Reaching
  the end of a list also changes what the virtualizer keeps, which muddies exactly the
  measurement a scroll leg is there to take.

From LRNZ09/skills, MIT.

Signals

Stars
0
Forks
0
Open issues
0
Last commit (this folder)
Oct 13, 2026 (16 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from LRNZ09

Cite this page

record-user-journey skill. Agent Mart. https://agentmart.dev/skills/lrnz09-record-user-journey (last updated 2026-10-24)