# Verify

> Build, launch, and drive the mindwalk web UI end-to-end for verification.

- Skill: `cosmtrek/verify` (Agent Skill)
- Install (CLI): `npx skillmds@latest add cosmtrek/verify`
- Raw SKILL.md: https://api.skillmd.com/api/skills/cosmtrek/verify/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: cosmtrek (https://skillmd.com/u/cosmtrek)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/cosmtrek/verify

---


# Verifying mindwalk

## Build & launch

```sh
npm --prefix web run build                  # tsc -b && vite build → web/dist
go build -o bin/mindwalk ./cmd/mindwalk
bin/mindwalk serve --no-open --dev --port <PORT> # --dev serves web/dist from the working tree
```

Gotchas:

- Always pass `--no-open` during automated verification so repeated server
  starts do not create tabs or steal focus from the user's current work.
- Port 8765 is the vite-proxy convention and is often already taken by a dev
  server; pick another port and check the log for `bind: address already in use`.
- Sessions come from `~/.claude/projects`, `~/.codex/sessions`, and
  `~/.pi/agent/sessions` — this machine has real data, no fixtures needed.
  `testdata/claude-session.jsonl` works via `mindwalk open`.
- `bin/mindwalk map <repo>` (or the `/?map=1&repo=<path>` URL) serves the
  static citymap with no session.

## Drive (headless Chrome + CDP, no npm installs)

System Chrome + raw CDP over Node's built-in WebSocket works. WebGL renders
under plain `--headless=new` on the real GPU (Metal, ~120fps); add
`--use-angle=swiftshader --enable-unsafe-swiftshader` only if GPU init fails
(software rendering is ~3x slower):

```sh
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --headless=new --remote-debugging-port=9333 --user-data-dir=<tmp> \
  --window-size=1440,900 --no-first-run about:blank &
```

New-tab endpoint needs PUT: `fetch('http://127.0.0.1:9333/json/new?<url>', {method:'PUT'})`.

## Flows worth driving

- Load via `/?session=<key>` deep link (legacy bare session id resolves only if
  unique); assert `.session-row.active .session-title`.
- Readout `.deck-pos-count` shows `N / N` after load (playhead starts at end).
- `[aria-label="Restart playback"]` → `1 / N`; `[aria-label="Play playback"]`
  → ~3 ticks/second at 1× (the `.speed-btn` / `S` key cycles the multiplier);
  playback draws the ember trail + firefly.
- Scene view lives in the dock's scene section: the top strip icon (tree/
  mountain shape mirrors the current view) opens a compact pop with `Tree` /
  `Terrain` radio rows plus the encoding legend; pressing `V` cycles views
  directly. Switching rebuilds the scene — watch for `Runtime.exceptionThrown`.
  The pop coexists with an open sheet (report stays open while switching).
- `/?map=1&repo=<abs-path>` renders the citymap with no trace and no transport
  (map-only mode); the rail-head folder icon (`[aria-label="Open a repository
  map"]`) opens a popover — primary card for the active session's repo (name +
  path), then an "or open any repository" path input — and opens the map via
  `window.open`, so in headless drive the URL directly instead of clicking.
- The right-edge dock strip is a panel registry with two sections (scene /
  session, hairline divider): View (pop), `Crosshair` = Inspect (sheet; file
  details, teaching empty state when nothing is selected), `Sparkles` =
  Evaluate (sheet; judge report, status dot mirrors running/done/stale/failed).
  Clicking a report finding jumps the playhead to its evidence seq and selects
  the file; the rail rows mirror evaluation state with `.rail-eval` badges.
- `[aria-label="Export video"]` records playback client-side (MediaRecorder →
  webm download): the label flips to `Recording video`, the transport, rail,
  and view toggle lock while recording, and the playhead restores afterwards.
  Capture the download in CDP with `Browser.setDownloadBehavior`.
- Rapid session switch (click uncached row, 150ms later a cached row) must end
  showing the last-clicked session's data.
- Bogus `?session=` must fall back to the newest session with a console.warn.

