Recording session time-profile — v2 onboarding demo (2026-07-03)
TL;DR: Of a 77-minute session (06:57:55–08:14:56, snapshot — agent was still mid-compositing at cut-off), only ~11 min (15%) was actual recording. ~28 min (36%) went to interactive rehearsal (blind-click → screenshot → look → correct), ~15 min to state resets between rehearsal and takes, ~9 min to codebase archaeology (dev sign-in code, DevMode, plugin internals). One retake (seg3a, Obsidian list-autocomplete ate the typed content). The pipeline's cost center is not ffmpeg or ElevenLabs — it's unscripted UI state discovery and manual state reset.
Transcript analyzed: /home/alexes/.claude/projects/-home-alexes-projects2-trip2g/2f470def-1431-4ce5-a854-c2c9978e405d/subagents/agent-aec19c560d05f652e.jsonl (735 events, 251 tool calls). The session is a snapshot: it ends at Write post.py — compositing, encode, and GIF had not run yet, so their cost is not in this profile.
1. Time profile
| Phase | Window | Wall clock | % | What happened |
|---|---|---|---|---|
| Dress rehearsal round 2 (full S1→live-flip proof) | 07:28–07:40 | 12.6 min | 16% | Restricted-Mode trust miss, "files deleted on server" dialog, live-flip finally proven |
| Between-segment vault prep (prep1–prep10) | 07:48–07:57 | 9.6 min | 12% | Rebuild vault from on-camera zip, plugin re-setup, click-by-click with screenshot checks |
| Rehearsal round 1 (Obsidian launch, login, coords) | 07:07–07:15 | 8.3 min | 11% | shot1–shot17; mis-clicks (search icon vs sign-in), pre-filled field, stray Firefox |
| Sync-on-save debugging | 07:15–07:22 | 7.1 min | 9% | BRAT installed plugin 0.5.0 without autoSyncOnSave; local 0.6.1 installed + Obsidian restart |
| seg3a bug-fix + retake prep | 08:00–08:06 | 6.3 min | 8% | Obsidian auto-list + wikilink popup ate Returns → vault3 content garbage; cleanup + record.mjs edits |
| Zero-state reset + docker DEV flap | 07:22–07:28 | 5.3 min | 7% | root-owned sqlite (rm: Permission denied), container Exited (137) after DEV=true recreation |
| Takes seg3a(retake)+seg3a2+seg3b + verify | 08:06–08:11 | 5.1 min | 7% | frame-extraction verify after each |
| Recon: spec + optB reuse + codebase research | 06:58–07:02 | 4.2 min | 5% | Found dev code is 111111 not 000000; DevMode config hunt across ~15 greps |
| Endcard + record.mjs authoring | 07:40–07:44 | 3.9 min | 5% | 104s single Write of record.mjs |
| Takes seg1a + seg1b + verify | 07:44–07:47 | 3.5 min | 5% | Clean first takes |
| post.py compositing script write (cut-off) | 08:11–08:14 | 3.4 min | 4% | 205s single Write; session snapshot ends here |
| seg2 take + frame checks | 07:57–08:00 | 2.7 min | 4% | Clean take; 8 frame extracts to verify |
| memcli + trip2g boot, sign-in probing | 07:02–07:04 | 2.4 min | 3% | Boot fine; sign-in code hunted in prior-session tool-result files |
| Vault/Obsidian config prep | 07:05–07:07 | 1.4 min | 2% | |
| VO generation (ElevenLabs) + whisper check | 07:04–07:05 | 1.2 min | 2% | 2 API iterations, v3 accepted; not a time sink |
| Total | 77 min | 100% |
Grouped: rehearsal/verification 28 min (36%) · state reset/re-prep 15 min (19%) · recording+verify 11.3 min (15%) · script authoring 7.3 min (9%) · recon/boot/VO 9.2 min (12%) · bug-fix/retake 6.3 min (8%).
Longest single operations (gap to next tool call): 215s stall after a prep click (model latency digesting a screenshot), 205s Write post.py, 104s Write record.mjs, 103s docker DEV-wrapper flap (Exited (137)), 76s seg2 record+frame-extract, 67s Obsidian/Chromium teardown, 66s vault3 content restore.
The see-click loop itself is the diffuse killer: 66 screenshot Reads and 62 xdotool commands; gaps preceding screenshot Reads alone sum to ~16.5 min, and each cycle (click → import → Read PNG → think) runs 10–25s.
2. Retakes / retries / loops
- 1 true retake: seg3a — Obsidian's list auto-continuation + wikilink autocomplete popup swallowed Return keys, corrupting typed note content; content cleaned, record.mjs patched, re-rolled (~6 min lost). seg3a2 was a planned extra segment, not a retake.
- 4 Obsidian restarts: initial launch, plugin 0.5.0→0.6.1 upgrade, zero-state reset, mid-rehearsal pkill for vault2.
- 3 docker container cycles: initial boot, DEV=true recreation, recovery from
Exited (137). - 2 stray-window hunts: unexpected Chromium window (07:12) and a Firefox spawned by an off-script
xdg-open(07:13) — PID forensics + targeted kill, ~2.5 min. - ~6 coordinate mis-clicks corrected via screenshot loop (search toggle instead of sign-in icon, Restricted Mode instead of "Trust author", pre-filled email field needing ctrl+a, etc.).
- 2 full environment resets (rehearsal → zero state → dress rehearsal → zero state → takes). Each reset is click-by-click, ~5–10 min.
Total loop/rework loss: ~15–18 min (~20% of session).
3. Top difficulties (ranked by time cost)
- Unscripted UI state discovery (~28 min). Every button was found by blind-click +
import -window root+ Read PNG. Representative:07:08:40 "I hit the search toggle instead. The sign-in icon is the leftmost one."Coordinates from the v1 run were not reusable/recorded, so both rehearsal rounds re-derived them. - Environment state not resettable by script (~15 min). Zero-state restore fought root-owned docker volumes (
rm: cannot remove '.../local.sqlite3': Permission denied→ alpine-container rm workaround), a DEV=true container recreation that OOM/exited(137), and manual vault re-download/re-setup between segments. - Plugin/app behavior surprises (~13 min). (a) BRAT delivered plugin 0.5.0 without
autoSyncOnSave— the demo's core feature — vs local build 0.6.1; (b) "Trust author" click actually landed on Restricted Mode, silently disabling the plugin ("No push attempt at all — plugin may not have loaded"); (c) first sync of a downloaded vault raises a "Files deleted on server → Keep locally" dialog nobody planned for. - Obsidian typing semantics (~6 min + the only retake). Auto-continued lists and the
[[autocomplete popup eat Return keystrokes typed via xdotool. - Codebase archaeology mid-recording (~5 min). Dev sign-in code (
111111vs assumed000000), DevMode env plumbing, title-extraction rules — all hunted with grep during the session instead of being in the scenario/harness docs.
4. Speed-up levers
- Persist a coordinate/state map per stage layout. Both rehearsal rounds (20+ min) rediscovered the same buttons at 2560×1440. Save a
coords.json(sign-in icon, trust button, community-plugins toggle, ribbon sync, hamburger→live-reload, download button) next to record.mjs and validate it with one screenshot diff at boot instead of 66 look-loops. This attacks the single biggest cost. - Script the reset, not just the take. Make
reset-stage.shdo the full zero-state:docker run alpine rmfor root-owned data (already proven in-session), container recreate with DEV=true baked into the memcli wrapper from the start, vault wipe/restore, Obsidian relaunch with pre-trusted vault + pre-enabled plugin (community-plugins.json+data.jsonwritten before launch — skips the Trust/Restricted-Mode dialog class entirely, which cost ~5 min and one silent failure). - Pre-bake the plugin and dialogs. Install the local 0.6.1 build into the vault template (never BRAT), and pre-answer the first-sync "files deleted on server" dialog off-camera in the harness (the session did this manually at 07:36 — encode it).
- Kill the typing-retake class: paste note content via
xdotool key ctrl+vfrom clipboard (or write the .md file on disk and let Obsidian pick it up, which the session already used at 07:40 for_index.md) instead oftype-ing markdown that triggers list-continuation/wikilink popups. This removes the only retake. - Split content from capture. The 205s
post.pyand 104srecord.mjsWrites plus VO are text-only artifacts — keep them as committed, parameterized scripts inscripts/hero/v2/so a VO/endcard/timing tweak never re-triggers rehearsal or takes. VO is already cheap (~1 min) and cached per-beat; keep per-beat mp3s so one line change re-renders one beat. - Guard against off-script windows: the stray Firefox came from an
xdg-openon :98. SetBROWSER=/bin/true/neutralize xdg-open in the stage env, and have record.mjs assert the exact window list before rolling — a black-frame/extra-window check is cheaper than PID forensics mid-session.
Caveat: compositing/encode/GIF cost is unknown — the snapshot ends before they ran. Profile that tail in the next session before optimizing it.