Skip to main content
Glama
Wadehl
by Wadehl

Drive a browser once (by an agent, a script, or by hand). Every action is captured to a Trace (JSONL). Transpile that Trace into a declarative Replay Spec (YAML), then replay it deterministically forever — for regression checks, smoke tests, or reproducing a bug.

  • Record — every command (navigate / click / fill / …) auto-writes one Trace line with a full locator descriptor (all candidate selectors + role/text + rect) and the network requests it produced.

  • Transpile — mechanical Trace → Replay Spec. Drops failed attempts, carries the locator fallback chain, turns wait_for_request steps into assertions. Marks anything a human/LLM should review with _review.

  • Replay — reads the spec, locates each target by the fallback chain (selector → role+text → rect), and verifies assertions against the request store. Deterministic and cheap.

Ships three ways to use it: a CLI, an MCP server (for agents), and a Skill.

Requirements

  • Bun — build tool + dev runtime (runs the TypeScript directly).

  • Node ≥ 18 — runtime for the shipped dist/*.mjs artifacts.

  • Chrome / Chromium — the CLI launches and owns a managed instance.

Related MCP server: OLTestStack

Install

As a Claude Code plugin

The plugin bundles an MCP server whose tools an agent calls to drive + record.

git clone <this-repo> browser-trace
cd browser-trace
bun install
bun run build        # produces dist/cli.mjs + dist/mcp.mjs

.claude-plugin/plugin.json registers the MCP server as node ${CLAUDE_PLUGIN_ROOT}/dist/mcp.mjs. Install the plugin via your marketplace/local plugin path, or register the server directly:

claude mcp add browser-trace --scope local -- node /abs/path/to/browser-trace/dist/mcp.mjs

As a standalone CLI

bun run build
node dist/cli.mjs help

Quickstart (CLI)

# 1. launch a managed browser (headful; add --headless for CI)
node dist/cli.mjs launch --session demo

# 2. drive it — each action records one Trace line
node dist/cli.mjs navigate "https://example.com" --intent "open page"
node dist/cli.mjs snapshot                       # read-only: see clickable elements
node dist/cli.mjs click --role link --text "Learn more" --intent "open docs"
node dist/cli.mjs wait --url-pattern "*/api/track*" --intent "verify beacon"

# 3. stop (kills the browser)
node dist/cli.mjs stop

# 4. mechanical Trace → Replay Spec
node dist/cli.mjs transpile output/demo.trace.jsonl

# 5. deterministic replay (launches its own browser, checks assertions)
node dist/cli.mjs replay output/demo.replay.yaml

Replay writes a <spec>.compare.json with recorded_ms vs replay_ms (record-time command execution excludes agent think time, so a real agent recording is far slower than replay).

Commands

Command

Records?

Purpose

launch / stop / status

own the browser lifecycle (random port, temp profile)

snapshot / screenshot

no (read-only)

perceive the page to pick a locator

navigate <url>

yes

go to a URL

click / fill

yes

act via --selector or --role+--text (never coordinates)

clear-cookies --patterns "reA,reB"

yes

delete cookies by name regex (e.g. force a deduped beacon to re-fire)

evaluate <js>

yes

escape hatch

wait --url-pattern P

yes

sync point / assertion — did a matching request fire this session

transpile <trace.jsonl>

Trace → Replay Spec (YAML)

replay <spec.yaml>

deterministic replay + assertions + timing

MCP tools

Same surface as the CLI, prefixed mcp__browser-trace__: trace_start / trace_stop / snapshot / screenshot / navigate / click / fill / clear_cookies / evaluate / wait_for_request. The MCP server is a thin forwarder — every tool shells out to the CLI, so MCP-driven and CLI-driven recording share one code path.

How it works

record (any driver, all via one entry)
  → Trace (JSONL, one line per command)
  → transpile (mechanical; _review flags for LLM/human)
  → Replay Spec (YAML)
  → replay (locator fallback chain + assertions) → pass/fail + timing

Trust boundary. The CLI is the sole entry that launches and owns the browser (random debugging port, private profile). Whatever drives it — agent, script, human — can only act through these commands, so the Trace is complete by construction. Don't run another browser-driving tool in the same session, or you get holes in the Trace.

Local development

bun install
bun run typecheck              # tsc --noEmit
bun run cli help               # run the CLI from TypeScript (no build)
bun run mcp                    # run the MCP server from TypeScript (stdio)
bun run build                  # bundle to dist/*.mjs for shipping

Dev runs the TypeScript directly with bun; the MCP server auto-detects .ts (dev, spawns bun) vs bundled .mjs (prod, spawns node). Runtime output (traces, request stores, session state) lands under output/ (gitignored).

Related MCP Connectors

Related MCP Servers