
面向 AI 编码代理的、以语音为锚的因果证据记录器。
你体验产品并开口说话——“这个按钮什么都不做。”Witness 会把每一个词与那一秒的因果证据焊接在一起:点击、请求、控制台错误、DOM 变更、截图、完整的 rrweb 回放——然后把结构化的证据包交给你的 AI 编码代理。

为什么
AI 代理看不到你所看到的东西。描述一个视觉 bug 要花十分钟截图和打磨提示词——而且仍然会丢掉“为什么”。语音是成本最低的标注通道;它只是从来没有人给它配一个记录器。
wit start 打开托管浏览器的那一刻,三条流并行运行:
- 你的语音——连续音频 + 实时转写。一次录制,多个问题。
- 操作 + 因果爆发——每次点击都会捕获其约 1.8 秒的后续影响(请求、响应、控制台错误、DOM 变化)。没有后续影响的点击本身也会作为证据被记录下来。
- 页面演化——rrweb 全 DOM 回放 + 事件驱动截图 + 周期性 DOM 快照。
安装
npm i -g witness-recorder # needs Node 18+ and system Edge/Chrome
wit start http://localhost:5173 # managed browser opens — talk & click
rec 是 wit 的别名——同一个二进制文件,输入更短。
无需下载,无需 API key。优先使用系统 Edge/Chrome;内置 Chromium 作为回退。
录制过程中
| 手势 | 效果 |
|---|---|
| 浏览 + 说话 | 完整音频;点击/滚动/输入/导航自动记录;工具栏下方实时转写预览 |
| Ctrl+点击 | 标记元素——选择器、outerHTML、组件链、红框截图 |
| M | 检查模式:悬停高亮,点击标记;拖拽裁剪区域 |
| N | 显式边界标记——⏺ ISSUE #n 分隔线;给 agent 的强分组提示 |
| P | 暂停/继续——所有事件和音频冻结(隐私) |
| Esc | 退出检查模式 |
| ■ / Alt+Shift+R | 停止并最终生成证据包 |
events.jsonl 会随录制实时写入磁盘——终止进程只会丢失最后几百毫秒。wit recover 可重建全部内容。
agent 读到什么
每段口述片段都会作为 SAY 块落到时间线上,携带该时刻的因果爆发——死点击、变更、错误——并附有关联截图和 DOM 快照。

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
证据包——.witness/sessions/<ts>_<host>/
面向 agent 的产物(PROMPT.md / SEGMENTS.md / session.md)始终以英文生成——这是对 LLM 最可靠的语料;你的原话保持逐字不变,绝不翻译。
SEGMENTS.md # 语音锚点:逐字稿 + 疑点 + shot/dom 引用(agent 优先读取)
segments/*.md # 逐段打包:逐字片段、无效点击、错误、关联镜头
keyframes/*.jpg # 每段由 rrweb 渲染的回放帧(wit keyframes)
KEYFRAMES.md # 关键帧索引
segments.json # 机器可读的段落索引(MCP 提供的内容)
session.md # 时间线归档:每个 SAY 块都带有其因果突发
PROMPT.md # 可直接粘贴的交接说明 + 页面词汇表
review.html # 人类视图:语音卡片 + 音频定位 + 胶片条 + 内嵌 rrweb 回放
events.jsonl # 完整原始事件流,崩溃安全
rrweb.jsonl # 完整 DOM 事件流(--no-rr 可禁用)
dom/*.html # 在导航/标记/30s 时的 DOM 快照
assoc.json # 可选的 LLM 证据关联建议
shots/*.jpg # 点击/标记裁剪图 + 周期性 + 语音段帧(--shot-format webp 可缩小约 35%)
bodies/* # 响应体 ≤64KB(JSON 存为 .json,其余为 .txt)
session.json # 元信息:url、时长、asr 引擎、计数
audio.webm / transcript.json
MCP — 把证据当作 API
wit mcp 通过 stdio 提供会话服务。把任何支持 MCP 的 agent(Claude Code、Cursor、Devin)指向它,它就能按需拉取所需内容:
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
原则
- 证据从不被改写 — 语音按原话落地;合并/纠正/关联都属于展示层的建议。
- 证据 ≠ 意图 — 没有语音锚点的行为永远不会被呈现为 bug。
- 本地优先 — 确定性录制;实时 SAY 字幕通过免费云端 ASR 流式输出(auto = doubao-web → doubao-ime → 浏览器 SR 兜底 — 可通过 wit config asr、--asr、WIT_ASR 或 get_asr/set_asr MCP 工具选择);未设置 OPENAI key 时,最终逐字稿回退到 bcut(bilibili 编辑器 ASR,无需 key)。LLM 层是可选的。
- 隐私内建 — 密码字段在四个通道上均被遮蔽,凭证字段在 POST body 中被打码,WIT_NO_BODIES=1 可禁用 body 捕获,P 键冻结一切,.witness/ 自动加入 gitignore。
- 匿名使用统计 — CLI 每条命令发送一次 ping(命令名、版本、OS/arch、Node 主版本;绝不包含 URL、路径或会话数据)到我们自己的 Cloudflare Worker — 无第三方分析、无 cookie。可用 WIT_TELEMETRY=0 禁用。
开发
npm install && npm run build && npm link
npm test # build + node:test suite (align / speech-run / bursts / prompts / review html)