Skip to main content
Glama

Voice-anchored causal evidence recorder for AI coding agents.

You experience the product and talk — “this button does nothing.” Witness welds every word to the causal evidence of that exact second: clicks, requests, console errors, DOM mutations, screenshots, full rrweb replay — then hands a structured evidence package to your AI coding agent.

Why

AI agents can't see what you see. Describing a visual bug costs ten minutes of screenshots and prompt crafting — and still loses the why. Voice is the cheapest annotation channel there is; it just never had a recorder.

Three streams run in parallel the moment wit start opens a managed browser:

  1. Your voice — continuous audio + live transcription. One take, many issues.

  2. Operations + causal bursts — every click captures its ~1.8s aftermath (requests, responses, console errors, DOM changes). A click with no aftermath is itself recorded as evidence.

  3. Page evolution — rrweb full-DOM replay + event-driven screenshots + periodic DOM snapshots.

Related MCP server: Krometrail

Install

npm i -g witness-recorder        # needs Node 18+ and system Edge/Chrome
wit start http://localhost:5173       # managed browser opens — talk & click

rec is an alias for wit — same binary, shorter to type.

No downloads, no API keys. System Edge/Chrome is preferred; bundled Chromium is the fallback.

During recording

Gesture

Effect

Browse + talk

Full audio; clicks/scrolls/inputs/navigation auto-logged; live transcript preview under the toolbar

Ctrl+click

Mark an element — selector, outerHTML, component chain, red-frame screenshot

M

Inspect mode: hover-highlight, click to mark; drag to crop a region

N

Explicit boundary marker — ⏺ ISSUE #n divider; a strong grouping hint for the agent

P

Pause/resume — all events and audio freeze (privacy)

Esc

Exit inspect mode

■ / Alt+Shift+R

Stop and finalize the evidence package

events.jsonl streams to disk as you go — kill the process and you lose only the last few hundred milliseconds. wit recover rebuilds everything.

What the agent reads

Each spoken fragment lands on a timeline as a SAY block carrying the causal burst of that moment — dead clicks, mutations, errors — with linked shots and DOM snapshots.

CLI

wit start <url> [--lang en-US] [--duration 60] [--no-rr] [--associate]
                [--shot-format jpeg|webp] [--dsf 1|2] [--keyframes]
wit list                          # sessions with url/duration/say count
wit open latest                   # open review.html
wit transcribe <dir>              # re-run cloud ASR
wit correct <dir>                 # re-run LLM text polish
wit associate <dir>               # LLM picks relevant evidence per SAY (ZHIPU_API_KEY)
wit recover <dir>                 # rebuild artifacts after a crash
wit segments <dir>                # regenerate speech-anchor index + bundles
wit keyframes <dir>               # render rrweb → per-segment keyframe jpgs
wit mcp [dir]                     # stdio MCP server over the evidence
wit config asr <engine>           # live ASR: auto|doubao-web|doubao-ime|sr|off

The evidence package — .witness/sessions/<ts>_<host>/

Agent-facing artifacts (PROMPT.md / SEGMENTS.md / session.md) are always generated in English — the most reliable corpus for LLMs; your words stay verbatim, never translated.

SEGMENTS.md       # speech anchors: verbatim + suspects + shot/dom refs (agents read first)
segments/*.md   # per-segment bundle: verbatim frags, dead clicks, errors, linked shots
keyframes/*.jpg  # rrweb-rendered replay frames per segment (wit keyframes)
KEYFRAMES.md     # keyframe index
segments.json    # machine-readable segment index (what MCP serves)
session.md      # timeline archive: each SAY block carries its causal burst
PROMPT.md       # paste-ready handoff instructions + page vocabulary
review.html     # human view: speech cards + audio seek + filmstrip + embedded rrweb replay
events.jsonl    # complete raw stream, crash-safe
rrweb.jsonl     # full DOM event stream (--no-rr to disable)
dom/*.html      # DOM snapshots on nav/mark/30s
assoc.json      # optional LLM evidence-association suggestions
shots/*.jpg     # click/mark crops + periodic + spoken-segment frames (--shot-format webp for ~35% smaller)
bodies/*        # response bodies ≤64KB (.json for JSON, .txt otherwise)
session.json    # meta: url, duration, asr engine, counts
audio.webm / transcript.json

MCP — evidence as an API

wit mcp serves the session over stdio. Point any MCP-capable agent (Claude Code, Cursor, Devin) at it and it pulls exactly what it needs:

list_segments · segment_detail(n) · session_overview · list_says · session_md · events_around(t_ms, radius, kinds) · get_errors · get_shot · get_body · get_dom_state(t) · get_asr · set_asr

Principles

  • Evidence is never rewritten — speech lands verbatim; merging/correction/association are display-layer suggestions.

  • Evidence ≠ intent — behavior without a spoken anchor is never presented as a bug.

  • Local-first — deterministic recording; live SAY subtitles stream through free cloud ASR (auto = doubao-web → doubao-ime → browser SR fallback — pick via wit config asr, --asr, WIT_ASR, or the get_asr/set_asr MCP tools); final transcript falls back to bcut (bilibili editor ASR, no key needed) when no OPENAI key is set. LLM layers are optional.

  • Privacy engineered in — password fields masked across four channels, credential fields redacted in POST bodies, WIT_NO_BODIES=1 disables body capture, P freezes everything, .witness/ is auto-gitignored.

Development

npm install && npm run build && npm link
npm test        # build + node:test suite (align / speech-run / bursts / prompts / review html)

Available Tools

12 tools
events_aroundB

Raw events within a time window. t_ms = timeline ms, radius_ms default 3000, kinds = comma list (click,req,res,console,error,mut,mark,nav,say,scroll,shot)

Inputs: t_ms (required), kinds, radius_ms.

get_asrB

Current live speech-recognition engine for future recordings (auto|doubao-web|doubao-ime|sr|off)

Inputs: no named parameters.

get_bodyC

Captured HTTP response body. path relative to session dir, e.g. bodies/r3.json

Inputs: path (required).

get_dom_stateA

DOM snapshot HTML nearest to a timeline ms (snapshots at nav/mark/every 30s). Returns path + html

Inputs: t_ms (required).

get_errorsB

All console errors, page errors and HTTP responses >= 400

Inputs: no named parameters.

get_shotC

A screenshot image. path is relative to the session dir, e.g. shots/011-mark.jpg

Inputs: path (required).

list_saysC

All spoken feedback fragments with timestamps — the issue anchors

Inputs: no named parameters.

list_segmentsA

Speech anchor index — every spoken segment with suspects, dead clicks and shot/dom refs. Segments are mechanically cut, NOT confirmed issues: merge adjacent ones or split as the semantics require. READ THIS FIRST.

Inputs: no named parameters.

segment_detailA

One speech segment's evidence bundle: verbatim speech, suspect elements, dead clicks, errors, and the exact shots/dom snapshots to inspect. n = segment number (1-based)

Inputs: n (required).

session_mdC

The rendered evidence timeline (SAY blocks + attached events)

Inputs: no named parameters.

session_overviewB

Session metadata: app URL, duration, counts of says/marks/errors/requests, file list

Inputs: no named parameters.

set_asrA

Switch the live ASR engine for FUTURE recordings (persists to .witness/config.json). doubao-web = best quality streaming; doubao-ime = sentence timestamps; sr = browser builtin; off = none.

Inputs: engine (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 12 tools

    Disambiguation4/5

    Each tool maps to a distinct evidence artifact (segments, says, errors, shots, DOM, bodies, raw events), and descriptions explicitly route the agent ("READ THIS FIRST" on list_segments, cross-references between list_says and segment_detail). Minor overlap exists between get_errors and events_around(kinds=error), and between session_overview and session_md, but the boundaries are stated clearly enough to avoid misselection.

    Naming Consistency4/5

    A readable pattern holds: get_* for fetching artifacts (get_shot, get_dom_state, get_body, get_errors), list_* for indexes, session_* for global metadata. Deviations exist (segment_detail, events_around, session_md) which break the verb_noun convention, but the set is still predictable.

    Tool Count5/5

    12 tools is squarely in the well-scoped range, with each tool covering a distinct layer of the evidence pipeline (overview, segmentation, raw events, artifacts, config). Nothing feels redundant or padded.

    Completeness4/5

    The surface covers the full investigation lifecycle: session metadata, speech anchors, per-segment evidence bundles, timeline rendering, raw events, errors, and artifact retrieval plus ASR get/set. Minor gaps remain—no session-wide search or filtering across all suspects/dead clicks, and no direct listing of available shots/bodies beyond the file list in session_overview.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers