blurt

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

blurt 🐔 — show it, say it, get structured work back

blurt 🐔 — 展示、说出来,得到结构化工作成果

People think best out loud with their eyes on the screen. They jump between topics, correct themselves, point at things. Your job: capture that with no friction, then do the tedious part (splitting, writing up, picking and marking screenshots, finding the code, filing) with care. Optimise for the user's flow: never interrupt a recording, ask few questions, make review fast.
Scripts live in
scripts/
next to this file; run them with
uv run <skill-dir>/scripts/<name>.py ...
(each declares its deps;
uv
installs them on first use). Every script has
--help
. Always reply in the user's language; write items in the language the user spoke.
人们盯着屏幕、边说边想时最容易理清思路。他们会跳到不同话题,纠正自己,指着屏幕上的内容。 你的任务是零摩擦地捕捉这些表达,再细致完成繁琐工作:拆分、撰写、挑选并标注截图、查找代码、归档。 优先适配用户的工作节奏:录制过程中绝不打断,尽量少提问,让审核快捷高效。
脚本位于本文件旁边的
scripts/
;使用
uv run <skill-dir>/scripts/<name>.py ...
运行(每个脚本都会声明自己的依赖;
uv
会在首次使用时自动安装)。每个脚本都支持
--help
。始终使用用户的语言回复;条目也应使用用户说话时的语言撰写。

0. Setup (first run, or when something fails)

0. 设置(首次运行或执行失败时)

  • doctor.py
    → OS, RAM/GPU, ffmpeg, configured ASR, recommendations,
    todo
    list.
  • Missing ffmpeg/uv: offer the install command; run it only after the user agrees.
  • ASR: if none configured, pick from
    asr_recommendations
    + the language the user speaks, tell the user in one line what and why (size, local vs cloud, cost), run its
    setup
    . Details:
    reference/asr.md
    . Cloud keys are set by the user in their env — never ask them to paste keys in chat.
  • record.py build
    — macOS: compiles the native recorder (Xcode Command Line Tools; else a Tk fallback) and installs the Blurt menu-bar app into ~/Applications. Windows: the Start-menu shortcut appears on first recording. Mention it in one line: "Blurt is also in your Applications — ⌥⇧R records from anywhere".
  • record.py test
    → look at the returned
    frame
    yourself. Wallpaper-only/black or
    ok: false
    ⇒ Screen Recording permission missing;
    mic_silent: true
    ⇒ Microphone permission / wrong mic. On macOS the permission belongs to the app hosting you (Terminal, iTerm, VS Code, Claude, Codex…) and that app must be restarted after granting. macOS 15+ may show an "allow … to bypass the window picker" prompt — the user clicks Allow themselves.
  • Optional project config
    .blurt/config.json
    : export target, owners/module map, column mapping, custom lenses in
    .blurt/lenses/
    . Suggest adding
    .blurt/sessions/
    to
    .gitignore
    .
  • doctor.py
    → 检查 OS、RAM/GPU、ffmpeg、已配置的 ASR,并给出建议和
    todo
    列表。
  • 缺少 ffmpeg/uv:提供安装命令;只有用户同意后才能运行。
  • ASR:如果尚未配置,根据
    asr_recommendations
    和用户使用的语言进行选择,用一行说明所选方案及原因(大小、本地或云端、成本),然后运行其
    setup
    。详情见
    reference/asr.md
    。Cloud keys 由用户在环境变量中设置——绝不能要求用户在聊天中粘贴 keys。
  • record.py build
    — macOS:编译原生录制器(需要 Xcode Command Line Tools;否则使用 Tk fallback),并将 Blurt 菜单栏 app 安装到
    ~/Applications
    。Windows:首次录制时会出现开始菜单快捷方式。用一行提醒用户:“Blurt 也位于你的‘应用程序’中——⌥⇧R 可从任意位置开始录制”。
  • record.py test
    → 自行查看返回的
    frame
    。如果画面只有壁纸或全黑,或显示
    ok: false
    ,说明缺少 Screen Recording 权限;如果显示
    mic_silent: true
    ,说明缺少 Microphone 权限或选错了麦克风。在 macOS 上,权限归属于承载你的 app(Terminal、iTerm、VS Code、Claude、Codex……),授权后必须重启该 app。macOS 15+ 可能显示“允许……绕过窗口选择器”的提示——需要用户自行点击“允许”。
  • 可选的项目配置
    .blurt/config.json
    :导出目标、owners/module 映射、列映射,以及
    .blurt/lenses/
    中的自定义 lenses。建议将
    .blurt/sessions/
    添加到
    .gitignore
    。

1. Record (or pick up a recording)

1. 录制(或获取已有录像)

From the chat: if the thing to look at is a local dev server/app in this repo, check it is running. Start
record.py start
in the background (
--last-region
to reuse the last area) and tell the user in a few lines what happens:
  • a dimmed overlay: drag to draw the area (or click a window, F = full screen) → 开始录制 / Enter. Only that area is recorded — tabs, bookmarks and other windows stay private;
  • 3-2-1 countdown (click to skip), then a small floating bar: timer · mic level · ⏸ pause · ↺ restart/discard · 完成. ⌥⇧P pause/resume, ⌥⇧S finish (Windows: Alt+Shift). The bar is never in the recording;
  • talk naturally, point with the mouse; hold ⌃ and drag to circle / underline what you mean (macOS; the ink fades after 3 s; ✎ on the bar or ⌥⇧D keeps the pen on, Esc / ⌥⇧D / ✎ turns it off); click 完成 — no need to send another chat message. The task ends with
    DONE video=…
    → continue with §2 right away (
    CANCELLED
    , exit 2 → acknowledge and stop). From the chat you can also
    record.py stop | pause | resume | restart
    .
Waiting on a background step (here and in §5): if your harness wakes you when a background task finishes (Claude Code), end your turn — you'll be notified. If it doesn't (Codex), a finished turn can't be resumed by the child process: keep the turn open and wait on that same tool session with long polls (no busy loop); don't send a final response while it runs.
Existing video (QuickTime, OBS, Loom, phone, a teammate's Blurt recording…): create
.blurt/sessions/<timestamp>/
, copy it in as
recording.<ext>
(with
events.jsonl
/
meta.json
if it came from Blurt), continue with §2.
Blurt app recordings: the menu-bar app records into the current workspace —
~/Blurt/recordings/<ts>/
by default, or
<project>/.blurt/sessions/<ts>/
when a project is bound.
record.py inbox
lists all of them with
processed
/
reviewed
flags. "Process my recordings" → do §2–§4 for each unprocessed one (fan out to subagents if available), then one review per session (or merge into one session dir if the user wants a single list).
meta.json
has
author
— keep it on items when several people's recordings are combined.
从聊天发起:如果待处理对象是本 repo 中的本地 dev server/app,先检查它是否正在运行。在后台启动
record.py start
(使用
--last-region
可复用上次区域),并用几行文字说明接下来会发生什么:
  • 出现变暗的 overlay:拖动绘制录制区域(或点击一个窗口,按 F 全屏)→ 开始录制 / Enter。只有该区域会被录制;标签页、书签和其他窗口均保持私密;
  • 3-2-1 倒计时(点击可跳过),随后出现小型悬浮栏:计时器 · 麦克风音量 · ⏸ 暂停 · ↺ 重录/丢弃 · 完成。⌥⇧P 暂停/继续,⌥⇧S 完成(Windows:Alt+Shift)。悬浮栏不会出现在录像中;
  • 自然地说话并用鼠标指向内容;按住 ⌃ 并拖动,即可圈出或下划出你所说的位置(macOS;笔迹会在 3 秒后淡出;点击悬浮栏上的 ✎ 或按 ⌥⇧D 可保持笔开启,Esc / ⌥⇧D / ✎ 可将其关闭);点击 完成——无需再发送聊天消息。 任务以
    DONE video=…
    结束 → 立即继续执行 §2(
    CANCELLED
    、退出码 2 → 确认后停止)。也可以在聊天中执行
    record.py stop | pause | resume | restart
    。
等待后台步骤时(此处及 §5):如果 harness 在后台任务完成时唤醒你(Claude Code),结束当前 turn——届时你会收到通知。如果不会(Codex),已结束的 turn 无法由子进程恢复:保持当前 turn 打开,在同一个 tool session 上使用长轮询(long polls)等待(不要 busy loop);任务运行期间不要发送最终回复。
已有视频(QuickTime、OBS、Loom、手机、队友的 Blurt recording……):创建
.blurt/sessions/<timestamp>/
,将视频复制为
recording.<ext>
(如果来自 Blurt,同时复制
events.jsonl
/
meta.json
),然后继续执行 §2。
**Blurt app 录像:**菜单栏 app 默认将录像录到当前 workspace 的
~/Blurt/recordings/<ts>/
;绑定项目后,则录到
<project>/.blurt/sessions/<ts>/
。
record.py inbox
会列出所有录像及其
processed
/
reviewed
标记。“处理我的录像” → 对每个未处理的录像执行 §2–§4(如果 harness 支持,可并行分派给 subagents),随后每个 session 审核一次;如果用户希望得到一份统一列表,也可以合并到一个 session dir。
meta.json
中包含
author
——合并多人录像时,应将 author 保留在对应 items 上。

2. Transcribe

2. 转录

transcribe.py run <session>/recording.mp4
→
transcript.json
+
transcript.txt
(
[mm:ss.s-mm:ss.s] text
). Recorded with system audio (
record.py start --system-audio
, or the app's menu toggle — calls, product demos), the other side's lines are marked
(system)
/
speaker: "system"
; unmarked lines are the user. Speaker bleed can repeat a system line on the mic. For Whisper/API backends pass
--prompt
with a short glossary (product, page/module names, people) from the repo. Also run
frames.py scan <video>
(visual-activity index for candidates/sheets) and
frames.py marks <video>
: what the user drew with the pen — when, where (box), what was being said — plus ⌥⇧M markers. A
warning
in the output, or a transcript that reads as nonsense (SenseVoice turns unsupported languages such as French into fake English), means the language needs another backend: set it up (
reference/asr.md
) and re-run.
transcribe.py run <session>/recording.mp4
→
transcript.json
+
transcript.txt
(格式为
[mm:ss.s-mm:ss.s] text
)。 使用系统音频录制时(
record.py start --system-audio
,或使用 app 菜单中的开关——适用于通话、产品演示),对话另一方的话语会标记为
(system)
/
speaker: "system"
;未标记的 lines 属于用户。串音可能导致系统端的话语在麦克风中被重复记录。 对于 Whisper/API 后端,请传入
--prompt
,并提供从 repo 中提取的简短术语表(产品、页面/模块名称、人员)。 还要运行
frames.py scan <video>
(生成用于筛选候选项/拼图的视觉活动索引)以及
frames.py marks <video>
:记录用户用笔标注了什么——何时标注、位置(方框)、当时说了什么——同时包含 ⌥⇧M markers。 如果输出中出现
warning
,或 transcript 读起来毫无意义(例如 SenseVoice 会把法语等不支持的语言硬转成类似英文的错误内容),说明需要更换语言后端:按照
reference/asr.md
进行设置,然后重新运行。

3. Understand → items

3. 理解 → 条目

Read the whole transcript first, glance at a few frames, then write
<session>/items.json
(schema:
reference/schema.md
). Decide per item what it is — the recording decides, not a mode switch:
kindwhenlens
issue
something in the product to fix or polish
reference/lenses/issue.md
idea
something to build / change / borrow ("这个网站的这里好")
reference/lenses/idea.md
note
an observation / finding / fact worth keeping
reference/lenses/note.md
task
an action item that isn't a product issue
reference/lenses/task.md
customa lens in
.blurt/lenses/
or
~/.blurt/lenses/
fits, or the user asked for it
that file
Principles — judgement, not rules:
  • A pen mark is the user saying "this, exactly": it anchors an item's time and subject. What they circled outranks your reading of a vague sentence — but a mark is not an item by itself, and items without marks are normal.
  • One item = one thing. People jump around, revisit, correct themselves ("不对,是…"), or say two things in one sentence: merge revisits, drop retracted remarks, split compounds. Pure narration is not an item.
  • Fix ASR errors from context (repo vocabulary, what's on screen). Keep
    quote
    close to what was said.
  • Don't invent. When unsure, write your best guess, set
    confidence: "low"
    , add a short
    questions
    entry.
  • Read URLs / product names off the frames into
    source
    .
  • code_refs
    (issues, inside a repo): grep the visible text / route / component; list the likely
    path:line
    s.
  • Give the session a
    title
    . For idea-heavy or exploratory recordings write a
    digest
    (markdown): themes, the strongest ideas, how they connect, suggested next step — it becomes the review page's Overview.
先完整通读 transcript,再浏览几帧,然后写入
<session>/items.json
(schema:
reference/schema.md
)。逐条判断它是什么——由 recording 决定,而不是切换模式:
kind何时使用lens
issue
产品中需要修复或打磨的某项内容
reference/lenses/issue.md
idea
需要构建、修改或借鉴的某项内容(“这个网站的这里好”)
reference/lenses/idea.md
note
值得保留的观察、发现或事实
reference/lenses/note.md
task
不属于产品 issue 的行动项
reference/lenses/task.md
custom
.blurt/lenses/
或
~/.blurt/lenses/
中的某个 lens 适用,或用户明确提出要求
该文件
原则——依靠判断,而不是机械规则:
  • 笔迹标记意味着用户在说“就是这个”:它会锚定条目的时间和主题。圈画内容优先于你对模糊语句的解读——但标记本身并不自动构成一个条目,没有标记的条目也很正常。
  • 一个 item 只对应一件事。人们会跳来跳去、反复讨论、纠正自己(“不对,是……”),或在一句话里说出两件事:合并回访内容,删除已撤回的表述,拆分复合内容。单纯叙述不是条目。
  • 根据上下文修正 ASR 错误(repo 词汇、屏幕上的内容)。让
    quote
    尽量贴近原话。
  • 不要臆造。不确定时,写下最佳推测,设置
    confidence: "low"
    ,并添加一条简短的
    questions
    。
  • 从 frames 中读取 URL / 产品名称并写入
    source
    。
  • code_refs
    (repo 内的 issues):grep 可见文本、route 或 component;列出可能的
    path:line
    。
  • 为 session 设置
    title
    。对于包含大量 ideas 或探索内容的录像,编写
    digest
    (markdown):包括主题、最有价值的 ideas、它们之间的联系以及建议的下一步——它将成为审核页的 Overview。

4. Evidence: frames & clips

4. 证据:frames 与 clips

Pick 1–3 frames per item that show the point (the bug itself, the part of the page that inspired the idea):
  • frames.py sheet <video> --from S --to E -o <session>/sheets/<id>.jpg
    → ~6 diverse settled candidates with timestamps in one image;
    --at t1 t2 …
    for specific moments ("这里 / this / look"). Speech often trails the action.
  • The user drew on it (
    marks
    )? Their ink is in the video:
    frames.py grab --at <frame_t>
    and the frame is already annotated — add no box.
    --crop stroke
    for a zoomed second frame;
    --box stroke
    on a frame where the ink is gone.
  • Otherwise, marking the spot — never estimate coordinates from a thumbnail or contact sheet:
    1. frames.py grid <video> --at T -o <session>/sheets/<id>-grid.jpg
      → labelled 0–1 grid plus the recorded cursor and nearby clicks (events.jsonl — exact). Read box edges off the grid (
      --crop
      zooms, labels stay full-frame).
    2. frames.py grab <video> --at T -o <session>/frames/<id>-1.jpg --box x,y,w,h
      ;
      --ring cursor|click
      when the user pointed at / clicked it. Tiny detail → second frame with
      --crop
      .
    3. Look at every annotated frame before using it. Box not on the point → fix and re-grab.
  • Animations / flows / timing:
    frames.py clip --from --to -o <session>/clips/<id>.mp4
    (< 20 MB).
  • Many items (> ~12)? Fan out frame work to subagents in batches if your harness has them.
每个条目挑选 1–3 个能够展示要点的 frames(bug 本身,或启发 idea 的页面部分):
  • frames.py sheet <video> --from S --to E -o <session>/sheets/<id>.jpg
    → 在一张图片中提供约 6 个内容多样且画面稳定的候选项,并附带时间戳;使用
    --at t1 t2 …
    可指定特定时刻(“这里 / this / look”)。语音往往滞后于操作。
  • 用户是否在画面上做了笔迹标注(
    marks
    )?笔迹已经录入视频:使用
    frames.py grab --at <frame_t>
    得到的 frame 已带标注——不要再添加方框。
    --crop stroke
    可生成第二张放大 frame;笔迹消失后的 frame 使用
    --box stroke
    。
  • 否则需要标注目标位置——绝不能根据缩略图或 contact sheet 估算坐标:
    1. frames.py grid <video> --at T -o <session>/sheets/<id>-grid.jpg
      → 生成带 0–1 网格坐标的标注图,同时显示录制时的光标及附近点击(events.jsonl——坐标精确)。根据 grid 读取方框边缘(
      --crop
      可放大,同时保留完整画面上的坐标标签)。
    2. frames.py grab <video> --at T -o <session>/frames/<id>-1.jpg --box x,y,w,h
      ;用户指向或点击的位置使用
      --ring cursor|click
      。如果目标很小,再使用
      --crop
      生成第二张 frame。
    3. **使用每一张标注 frame 前都要亲自查看。**如果方框没有对准要点 → 修正并重新抓取。
  • 涉及动画、流程或时序的问题:
    frames.py clip --from --to -o <session>/clips/<id>.mp4
    (小于 20 MB)。
  • 条目很多(> ~12)?如果 harness 支持 subagents,可按批次并行处理 frame 工作。

5. Review with the user

5. 与用户审核

Always open the review page — the frames are the point. Run
review.py <session>
in the background (opens the browser, exits when the user finishes). In the same message:
  • ≤ 5 items: the full numbered list (kind · title · owner/module, plus
    questions
    ); more: a short summary (counts by kind, the headline items, open questions);
  • two lines on the page: one item at a time — A keep · X drop · J/K next/prev · Z undo · ? keys; fields editable in place; G list view; V overview (when there's a digest); "完成审核" hands it back. The user may answer in chat or on the page. Wait as in §1 until the review summary prints, then reload
    items.json
    (dropped items have
    status: "deleted"
    , answers are in
    answer
    , merged items are gone on purpose and listed in the target's
    merged_from
    ) and continue with §6. If they reply in chat instead, apply it yourself and close the page (
    pkill -f "review.py <session>"
    ).
Unattended runs (started by the Blurt app via
claude -p
/
codex exec
— env
BLURT_APP=1
— or any other non-interactive mode): don't ask anything; do §2–§4 and write
items.json
, then finish with a 2–3 sentence summary. With
BLURT_APP=1
don't start the review page — the app opens it when you exit; otherwise start it detached (
nohup uv run …/review.py <session> >/dev/null 2>&1 &
). Never export to external systems unattended.
始终打开审核页——frames 才是关键。在后台运行
review.py <session>
(打开浏览器,并在用户完成审核后退出)。在同一条消息中:
  • 不超过 5 个条目:提供完整编号列表(kind · title · owner/module,以及
    questions
    );超过 5 个:提供简短摘要(按 kind 统计、重点条目、待解决的问题);
  • 用两行说明页面操作:每次显示一个条目——A 保留 · X 丢弃 · J/K 下一个/上一个 · Z 撤销 · ? 查看按键; 字段可就地编辑;G 切换列表视图;V 查看 Overview(存在 digest 时);“完成审核”后交回结果。 用户可以在聊天中或页面上回答。按照 §1 的方式等待,直到审核摘要输出,然后重新加载
    items.json
    (丢弃的条目会显示
    status: "deleted"
    ,回答保存在
    answer
    中,被合并的条目会按预期消失,并列在目标条目的
    merged_from
    中),然后继续执行 §6。如果用户改为在聊天中回复,则自行应用其修改并关闭页面(
    pkill -f "review.py <session>"
    )。
无人值守运行(由 Blurt app 通过
claude -p
/
codex exec
启动——环境变量
BLURT_APP=1
——或任何其他非交互模式):不要询问任何问题;执行 §2–§4 并写入
items.json
,然后用 2–3 句话总结结束。 当
BLURT_APP=1
时,不要启动审核页——你退出后 app 会自动打开;否则应以后台分离方式启动(
nohup uv run …/review.py <session> >/dev/null 2>&1 &
)。无人值守时绝不能向外部系统导出。

6. Export / act

6. 导出 / 执行

Ask once where things go (remember in
.blurt/config.json
→
export
). Typical: issues → the team's bug table; ideas → an ideas board / doc; notes → Markdown; tasks → the user's todo tool.
  • Feishu/Lark Bitable →
    feishu.py export <session> "<table url>" [--kind issue|idea|…]
    (lark-cli if installed, else app credentials; default columns per kind, creates missing ones, uploads frames + clips, resumable). No table yet →
    feishu.py create "<name>"
    . Other columns →
    feishu.py fields
    then
    --map
    . Details:
    reference/export-feishu.md
    .
  • Markdown + CSV →
    export_local.py <session>
    (all kinds; always a good local record).
  • GitHub Issues / Linear / Jira / Notion / Obsidian / anything else →
    reference/export-other.md
    ; use the CLI or MCP tool the user has; map fields by meaning.
  • A document rather than a list ("整理成需求文档和设计文档", a brief, a comparison — typically after walking through reference sites or a competitor, often across several recordings) →
    reference/docs.md
    . Confirm destination and count before creating anything remotely; report links afterwards. Then offer the natural next step — for issues "want me to start fixing these?" (you have
    code_refs
    ), for ideas "want a quick prototype / spec of the top one?".
只需询问一次内容要导出到哪里(记住
.blurt/config.json
→
export
中的设置)。典型映射:issues → 团队的 bug table;ideas → ideas board 或文档;notes → Markdown;tasks → 用户的 todo 工具。
  • Feishu/Lark Bitable →
    feishu.py export <session> "<table url>" [--kind issue|idea|…]
    (如果已安装 lark-cli,则使用 lark-cli,否则使用 app credentials;每种 kind 都有默认列,可创建缺失的列,并上传 frames 与 clips,支持断点续传)。 还没有 table →
    feishu.py create "<name>"
    。需要其他列 →
    feishu.py fields
    ,然后使用
    --map
    。 详情见
    reference/export-feishu.md
    。
  • Markdown + CSV →
    export_local.py <session>
    (支持所有 kinds;始终适合作为本地记录)。
  • GitHub Issues / Linear / Jira / Notion / Obsidian / 其他任何系统 →
    reference/export-other.md
    ;使用现有 CLI 或 MCP tool;按含义映射字段。
  • 如果用户需要的是文档而不是列表(“整理成需求文档和设计文档”、brief、comparison——通常发生在浏览 reference sites 或 competitor 之后,而且经常横跨多个 recordings)→
    reference/docs.md
    。 在远程创建任何内容前,确认目标位置和条目数量;完成后报告链接。随后提供自然的下一步——对于 issues,询问“需要我开始修复这些问题吗?”(你已有
    code_refs
    );对于 ideas,询问“需要为其中最好的一个快速制作 prototype / spec 吗?”。