witness
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:
Your voice — continuous audio + live transcription. One take, many issues.
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.
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 & clickrec 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 |
| Mark an element — selector, outerHTML, component chain, red-frame screenshot |
| Inspect mode: hover-highlight, click to mark; drag to crop a region |
| Explicit boundary marker — |
| Pause/resume — all events and audio freeze (privacy) |
| Exit inspect mode |
| 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|offThe 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.jsonMCP — 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 viawit config asr,--asr,WIT_ASR, or theget_asr/set_asrMCP 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=1disables body capture,Pfreezes 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 toolsevents_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
Scored across 12 tools
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.
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.
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.
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
Related MCP Connectors
Jam recordings (video, console, network) as context and proof of work for your coding agent.
Captured web interfaces, screenshots, flows and structured evidence for AI coding agents.
Bug tracking for AI agents: session replay, console/network logs, repro packs, test plans, evidence.
Evidence-backed project memory and checkpoints for AI coding agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI coding agents to capture screen and voice recordings, extract timestamped frames, and receive structured Markdown reports with context for bug fixing and UI feedback.9 npm19MIT
- AlicenseNot gradedqualityBmaintenanceGives AI coding agents eyes into running applications by recording browser activity and providing session investigation tools for debugging.82 npm3MIT
- AlicenseAqualityBmaintenanceVoice-powered bug reporting MCP server with 13 tools. Captures console logs, network errors, DOM traces, and developer voice descriptions. AI reads structured reports to find and fix bugs automatically. Chrome Extension + Python CLI.8MIT
- AlicenseNot gradedqualityBmaintenanceRecords browser sessions and provides structured context (clicks, console, network, screenshots) for AI coding agents to understand and act upon.2MIT