meeting-brief
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMeeting brief
会议简报
Two things that compose: turn recordings into an archived meeting report, and talk back to you in audio instead of text.
Either half works alone. on a folder of files does the first. "answer me in audio from now on" does the second.
/meeting-brief.m4a它由两部分组成:将录音转换为已归档的会议报告,以及用音频而非文本向您回复。
两部分均可单独使用。对某个 文件夹运行 可完成第一部分。“从现在起以音频回答我”则启用第二部分。
.m4a/meeting-briefHard rules
硬性规则
- Never upload the user's audio to a public host. Not tmpfiles, not 0x0.st, not transfer.sh, not a quick tunnel. These recordings can contain confidential information: salary negotiations, equity terms, revenue, customer names. The only sanctioned channel is a presigned S3 URL in a private bucket. This rule exists because it was broken once.
- Presigned only, private ACL. Never , never a bucket policy change, never a bucket whose name contains
--acl public-readorpublic.assets - Delete each clip once the user replies. Their next message is the signal they have listened. Run on the previous object before doing anything else in that turn.
unshare.sh - Never echo an API key or secret into the transcript. The scripts read them from the environment or a and never print them.
.env
- 绝不能将用户的音频上传到公共主机。 不得使用 tmpfiles、0x0.st、transfer.sh,也不得使用临时隧道。这些录音可能包含机密信息:薪资谈判、股权条款、营收和客户名称。唯一获准的渠道是私密存储桶中的预签名 S3 URL。之所以制定此规则,是因为该规则曾被违反过。
- 仅使用预签名链接,并设置 private ACL。 绝不能使用 ,绝不能修改存储桶策略,也绝不能使用名称中包含
--acl public-read或public的存储桶。assets - 用户回复后立即删除每个音频片段。 用户的下一条消息即表示其已经收听。在该轮执行任何其他操作之前,先对上一个对象运行 。
unshare.sh - 绝不要在转录文本中回显 API key 或 secret。 脚本从环境变量或 中读取这些信息,且绝不打印它们。
.env
AWS credentials come from the project, never from a global profile
AWS 凭据来自项目,绝不来自全局配置文件
A project can keep its own with its own AWS account, so credentials are resolved from the project rather than a global profile. walks up from the working directory to the first that yields usable credentials.
.envscripts/aws-env.sh.envVariable names are not always standardised. The resolver tries canonical / first, then the short forms / . Region falls back to , then gets corrected per bucket via .
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_ACCESS_KEYAWS_ACCESS_SECRETus-east-1get-bucket-locationSet to the private bucket the audio should go to. It must have public access blocked; this skill uploads with a private ACL and shares only via presigned URL, and never makes anything world-readable.
MEETING_BRIEF_BUCKET项目可以在自己的 中配置独立的 AWS 账户,因此凭据应从项目而非全局配置文件解析。 会从当前工作目录向上逐级查找,直到找到第一个可提供可用凭据的 。
.envscripts/aws-env.sh.env变量名称并不总是统一。解析器会先尝试标准名称 / ,然后尝试短格式 / 。区域最初回退为 ,随后根据存储桶通过 进行修正。
AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_ACCESS_KEYAWS_ACCESS_SECRETus-east-1get-bucket-location将 设置为存放音频的私密存储桶。该存储桶必须阻止公共访问;此 skill 使用 private ACL 上传,仅通过预签名 URL 分享,绝不会将任何内容设为全球可读。
MEETING_BRIEF_BUCKETFlow A: recordings to archived report
流程 A:从录音到已归档报告
bash
S=.claude/skills/meeting-brief/scripts
OUT=/tmp/claude/<project>/meeting-<date>
$S/transcribe.sh $OUT *.m4a # parallel, diarised, resumable
$S/format-transcript.mjs $OUT/raw-<x>.json \
--map speaker_0=Alice,speaker_1=Bob # speaker-grouped, timestampedThen read the transcripts, identify who is who from context, and write the report.
Always pass keyterms. ships with this skill and sends it automatically. Without it Scribe v2 mangles unusual product, company or tool names into similar-sounding common words, which then poisons every downstream summary. Add your project's nouns to that file as they come up.
keyterms.txttranscribe.shDiarisation gives , , not names. Work out the mapping from the content before writing anything, and say in the summary which label is whom. For load-bearing facts (who owns a follow-up, who is off tomorrow, personal context) confirm WHO with the user before saving if the mapping is at all ambiguous, and write the draft as "I put X on speaker A and Y on speaker B, flip if backwards" so they can correct fast.
speaker_0speaker_1bash
S=.claude/skills/meeting-brief/scripts
OUT=/tmp/claude/<project>/meeting-<date>
$S/transcribe.sh $OUT *.m4a # parallel, diarised, resumable
$S/format-transcript.mjs $OUT/raw-<x>.json \
--map speaker_0=Alice,speaker_1=Bob # speaker-grouped, timestamped然后读取转录文本,根据上下文确定每个说话人的身份,并撰写报告。
务必传入 keyterms。 随此 skill 一同提供, 会自动发送它。如果没有该文件,Scribe v2 会将不常见的产品、公司或工具名称误写成发音相近的常见词,进而污染所有下游摘要。出现项目专有名词时,应将其加入该文件。
keyterms.txttranscribe.sh说话人分离只会生成 、,而不是姓名。撰写任何内容前,应根据内容推断映射关系,并在摘要中说明哪个标签对应哪个人。对于关键事实(谁负责跟进、谁明天休假、个人背景等),如果映射有任何歧义,保存前应向用户确认具体是谁,并先写出这样的草稿:“我把 X 放在 speaker A,把 Y 放在 speaker B,如果对应反了请告诉我”,以便用户快速纠正。
speaker_0speaker_1Quota (quota_exceeded
)
quota_exceeded配额(quota_exceeded
)
quota_exceededScribe v2 charges about 1.1 credits per second of audio. On , do not give up: most long meetings have silent gaps (pre-start setup, dead air, long pauses). Use to strip silence and retry:
quota_exceededffmpegbash
ffmpeg -y -i input.m4a \
-af "silenceremove=stop_periods=-1:stop_duration=2:stop_threshold=-40dB" \
-c:a aac -b:a 64k trimmed.m4aThat removes 20-40% of duration with zero speech loss. Re-check duration () and recompute credits before resubmitting. Archive the ORIGINAL audio, never the trimmed copy: the trim is a transcription-time artifact, not the source of truth.
ffprobeScribe v2 的收费约为每秒音频 1.1 credits。遇到 时不要放弃:大多数长会议都存在静音间隙(会前准备、无人发言、长时间停顿)。使用 去除静音后重试:
quota_exceededffmpegbash
ffmpeg -y -i input.m4a \
-af "silenceremove=stop_periods=-1:stop_duration=2:stop_threshold=-40dB" \
-c:a aac -b:a 64k trimmed.m4a这样可以在不丢失任何语音内容的情况下将时长缩短 20% 至 40%。重新提交前,使用 重新检查时长并重新计算 credits。始终归档原始音频,绝不归档裁剪后的副本:裁剪仅是转录阶段的临时产物,不是事实来源。
ffprobeIngesting the recording (dating, sequencing, archive-first)
导入录音(确定日期、排序、先归档)
Recordings arrive however the project delivers them: a drop in the workspace root, an export in , a phone file, or an auto-upload to the S3 inbox. The name is usually generic (, , ) and carries no reliable date. Four rules hold regardless of source:
~/Downloadsmeet.m4arec.m4aaudio 3.m4a- Archive BEFORE summarising, always. The moment transcription succeeds, write the +
<audio>pair into.txtBEFORE the report, action items, or anything else, even if the user only asked "what did they decide". They should never have to ask for the archive. Verify it landed (checksum the copy against the source) rather than assuming.arch/transcripts/ - The date is the RECORDING date, never today and never the download date. A file's mtime is the copy/export time: for a fresh same-day drop that equals the meeting date, but an exported or re-shared file can be days off, and several files exported in one session share one mtime. Cross-check against the transcript (weekday mentions, "yesterday we shipped X", a recent-changes log) and the gap since the last file. Only ask the user when the evidence disagrees. If the source is an Apple Voice Memos original (
arch/transcripts/), that filename IS the start time: match the shared copy back to it by byte size then checksum, and a match is proof, so no need to ask.20260806 104557.m4a - Sequence number: take the highest existing in
rec-NNNand use the next integer; say so in chat so the user can correct a skipped one. If the export name already carries a number (arch/transcripts/->Mi grabación 202.m4a), keep it. Never leave a recording unarchived just because the number is uncertain.rec-202 - A drop box is not storage. When recordings land in a shared drop location (workspace root, a Downloads folder, an S3 inbox), MOVE the file into once the archived copy is checksum-verified, then delete the source so the next drop is unambiguous. Two or more audio files waiting at once means several meetings: process oldest first or ask which, never merge them.
arch/transcripts/
录音可能通过项目提供的任意方式到达:放入工作区根目录、导出到 、来自手机的文件,或自动上传到 S3 收件箱。文件名通常很通用(、、),不包含可靠日期。无论来源为何,都应遵循以下四条规则:
~/Downloadsmeet.m4arec.m4aaudio 3.m4a- 始终先归档,再进行摘要。 转录成功后,应立即将 +
<audio>文件对写入.txt,然后再处理报告、行动项或其他任何内容,即使用户只问了“我们决定了什么”。用户不应需要另行要求归档。应验证文件确实已落盘(将副本与源文件进行校验和比对),不能想当然地认为已成功。arch/transcripts/ - 日期是录音日期,既不是今天,也不是下载日期。 文件的 mtime 是复制或导出的时间:对于当天刚放入的录音,它可能等于会议日期;但导出或转发的文件可能相差数天,而且一次会话中导出的多个文件会共享同一个 mtime。应结合转录内容(星期几的表述、“昨天我们发布了 X”、近期变更日志)以及与 中上一个文件的时间间隔进行交叉验证。只有在证据相互矛盾时才询问用户。如果源文件是 Apple Voice Memos 原始文件(
arch/transcripts/),该文件名本身就是开始时间:先按文件大小将共享副本与其匹配,再通过校验和确认;匹配成功即可作为证据,因此无需询问。20260806 104557.m4a - 序列号: 找出 中现有的最大
arch/transcripts/,然后使用下一个整数;在聊天中告知用户,以便其纠正跳号。如果导出文件名已经带有编号(rec-NNN->Mi grabación 202.m4a),则保留该编号。绝不因为编号不确定而不归档录音。rec-202 - 投放箱不是存储位置。 当录音进入共享投放位置(工作区根目录、Downloads 文件夹或 S3 收件箱)时,在归档副本通过校验和验证后,将文件移动到 ,然后删除源文件,以免下一次投放产生歧义。如果同时有两个或更多音频文件等待处理,就表示存在多场会议:应先处理最早的录音或询问用户,绝不能将其合并。
arch/transcripts/
The archive convention
归档约定
Archiving is an optional convention. Keep an tree at the workspace root, spanning every repo in that workspace. If an already exists in the project, follow its layout; otherwise this is a sensible default:
arch/arch/README.mdarch/
README.md
meetings/ YYYY-MM-DD-<counterpart>-<topic>.md
transcripts/ YYYY-MM-DD-rec-<N>.txt + the original .m4a alongside
reports/ YYYY-MM-DD-<topic>.mdA typical report skeleton: TL;DR, Action items, Decisions, Things to remember, Open questions, What's done / in progress, Topics. Two conventions are worth keeping:
- No em dashes anywhere. Hyphens, colons, periods, parentheses.
- Every action item needs a named owner. "Someone should" is not an action item.
- Never paste a full transcript into the report. Link to the file under .
transcripts/
Get real durations with rather than estimating from file size:
ffprobebash
ffprobe -v error -show_entries format=duration -of csv=p=0 file.m4a归档是一种可选约定。在工作区根目录维护一个 目录树,涵盖该工作区中的每个仓库。如果项目中已经存在 ,应遵循其布局;否则可采用以下合理默认结构:
arch/arch/README.mdarch/
README.md
meetings/ YYYY-MM-DD-<counterpart>-<topic>.md
transcripts/ YYYY-MM-DD-rec-<N>.txt + the original .m4a alongside
reports/ YYYY-MM-DD-<topic>.md典型报告结构:TL;DR、行动项、决策、需记住的事项、待解决的问题、已完成或进行中、讨论主题。有两项约定值得保留:
- 任何位置都不得使用 em dash。 使用连字符、冒号、句号或圆括号。
- 每个行动项都必须有明确的负责人。 “有人应该……”不算行动项。
- 不要在报告中粘贴完整转录文本。应链接到 下的文件。
transcripts/
使用 获取真实时长,不要根据文件大小估算:
ffprobebash
ffprobe -v error -show_entries format=duration -of csv=p=0 file.m4aFlow C: ingest from the S3 inbox (browser extension)
流程 C:从 S3 收件箱导入(浏览器扩展)
The folder here is a browser extension that auto-records web meetings (Google
Meet, Zoom web, Teams web) and uploads them to a private S3 inbox, so you never have to
phone-record or hand over files. A recording lands as
plus a sidecar (platform, title, meeting url, participants, start/end, mic-captured
flag, contentType). See for the capture side and
for the endpoint.
extension/inbox/<workspace>/<ts>-<title>.webm.jsonextension/README.mdingest/presign-lambda/The inbox is the FIRST place to look whenever the user refers to a call, not only when
they say "check the inbox". "I just had a call", "what did we decide on the call",
"transcribe my last meeting", "process my meetings" all start here, before asking for a
file. Only if the inbox has nothing that fits do you fall back to the project's dropped-file
locations (Flow A) and then ask.
bash
I=.claude/skills/meeting-brief/ingest/ingest.sh # set MEETING_INBOX_BUCKET + AWS creds (env or AWS_PROFILE)
$I list # pending clips, newest first: title | start | participants
$I pull inbox/<ws>/<file>.webm /tmp/claude/<project>/meeting-inPick the clip by time first (a call "just had" ends within the last hour or two;
/ are in the sidecar), then by title/participants matching who was named.
If two or more clips fit, list them and ask which, do not guess.
startedAtendedAtAlways convert to first, then run the normal Flow A on the :
.m4a.m4abash
ffmpeg -v error -i clip.webm -vn -c:a aac -b:a 64k clip.m4a # then transcribe clip.m4aTwo reasons it is not optional. A call whose tab was closed mid-call (sidecar or ) arrives as a webm with no proper ending ("File ended prematurely"):
ffmpeg decodes it fine, Scribe may not. And a manual recording with video on is
; drops the video. Keep the original video only if the user wants to rewatch.
The sidecar's says how it was recorded: is automatic (call audio + the user's
mic taken inside the meeting page), is a manual popup recording.
reason: tab_closedstalledvideo/webm-vncapturepagetabRouting: the meeting's subject decides the archive, not the session you are in and not
the tag. The tag is just the default set on the browser that recorded it (one
browser can record calls for several projects), so a call can easily arrive tagged for the
wrong one. Decide from what the meeting is about: the people on it, the title, the topics in
the transcript. Say in chat which project you filed it under and why, then archive straight
into that project's .
workspacearch/If you cannot tell from the sidecar and do not want to spend credits transcribing it in the
wrong project, hand it over untouched: . Transcode to
with before archiving so the archive matches the usual convention. When the
pair is archived and checksum-verified:
$I retag <key> <workspace>.m4affmpeg.m4abash
$I done inbox/<ws>/<file>.webm # deletes the clip + sidecar from the inboxThe inbox is a drop box, not storage (same rule as any dropped recording in Flow A):
delete each clip only after its copy is verified.
arch/transcripts/此处的 文件夹是一个浏览器扩展,用于自动录制 web 会议(Google Meet、Zoom web、Teams web),并将其上传到私密 S3 收件箱,因此您无需使用手机录音或手动移交文件。录音会生成 以及一个 sidecar 文件(平台、标题、会议 URL、参与者、开始/结束时间、麦克风捕获标志、contentType)。捕获端详情参见 ,端点参见 。
extension/inbox/<workspace>/<ts>-<title>.webm.jsonextension/README.mdingest/presign-lambda/只要用户提到通话,收件箱就是第一检查位置,而不只是当用户明确说“查看收件箱”时。“我刚开完会”、“我们在通话中决定了什么”、“转录我最近的会议”、“处理我的会议”等请求都应先从这里开始,然后再向用户索要文件。只有当收件箱中没有匹配内容时,才回退到项目投放文件的位置(流程 A),随后再询问用户。
bash
I=.claude/skills/meeting-brief/ingest/ingest.sh # set MEETING_INBOX_BUCKET + AWS creds (env or AWS_PROFILE)
$I list # pending clips, newest first: title | start | participants
$I pull inbox/<ws>/<file>.webm /tmp/claude/<project>/meeting-in按时间优先选择片段(“刚结束”的通话通常在最近一两个小时以内;/ 位于 sidecar 中),然后根据用户点名的人物匹配标题或参与者。如果有两个或更多片段符合条件,应列出并询问用户,不要猜测。
startedAtendedAt始终先转换为 ,然后对 运行正常的流程 A:
.m4a.m4abash
ffmpeg -v error -i clip.webm -vn -c:a aac -b:a 64k clip.m4a # then transcribe clip.m4a这一点不可选,原因有二。如果通话过程中关闭了标签页(sidecar 中为 或 ),到达的 webm 文件没有正常结尾(“File ended prematurely”):ffmpeg 可以正常解码,但 Scribe 可能无法处理。而手动开启视频的录音是 ; 会丢弃视频。除非用户想回看,否则只保留原始视频。sidecar 的 字段说明录音方式: 表示自动录制(在会议页面内捕获通话音频和用户麦克风), 表示手动弹窗录制。
reason:\ntab_closedstalledvideo/webm-vncapturepagetab路由:由会议主题决定归档位置,而不是由当前会话或标签决定。 标签只是录制该通话的浏览器上的默认设置(同一个浏览器可以为多个项目录制通话),因此通话很容易被错误标记。应根据会议内容决定:参会人员、标题和转录文本中的主题。在聊天中说明将其归入哪个项目及原因,然后直接归档到该项目的 。
workspacearch/如果无法从 sidecar 判断,又不想浪费 credits 将其转录到错误的项目中,应原样移交:。归档前使用 将其转码为 ,使归档符合惯用的 约定。当文件对完成归档并通过校验和验证后:
$I retag <key> <workspace>ffmpeg.m4a.m4abash
$I done inbox/<ws>/<file>.webm # deletes the clip + sidecar from the inbox收件箱是投放箱,不是存储位置(与流程 A 中任何投放的录音遵循同一规则):只有在 中的副本验证通过后,才删除收件箱中的每个片段。
arch/transcripts/The capture side: install, ship a change, debug
捕获端:安装、发布变更、调试
-
How it records, and the one thing not to undo. Automatic recordings happen inside the meeting page (, a
extension/capture.main.jscontent script that wrapsworld: MAINandRTCPeerConnection). Never move auto-start back togetUserMedia: Chrome only allows tab capture after a click on the extension, so it cannot start on its own, and v0.1/v0.2 recorded nothing on the first real Meet call because of it. Tab capture is only the popup's manual Start, which is also the only way to get video. Full design inchrome.tabCapture.extension/README.md -
Install or update: run the install one-liner your deployment prints (), then
curl -fsSL <your-endpoint>/install | sh-> Load unpacked (first time;chrome://extensions, paste) or the reload arrow (update). Loaded unpacked from a stable folder, the extension keeps the same ID across updates, so the token in Options survives updates. Never load it from Downloads.Cmd+Shift+G -
Ship a change to the extension: edit, bump
extension/manifest.json, thenversion(with AWS creds for your account in the environment; the token is in the Lambda env, seecd ingest/presign-lambda && BUCKET=<your-inbox-bucket> TOKEN=<current> ./deploy.sh). That re-bundles the zip served atextension/README.md; re-run the install line and hit reload. Prove a recorder change on a real WebRTC call before calling it done (the README describes the Chromium harness)./extension -
"Did my call record?" and the inbox is empty: ask the endpoint, not the code.bash
aws cloudwatch get-metric-statistics --region us-east-1 --namespace AWS/ApiGateway \ --metric-name Count --dimensions Name=ApiId,Value=<your-api-id> --statistics Sum --period 300 \ --start-time $(date -u -d '-3 hours' +%FT%TZ) --end-time $(date -u +%FT%TZ)No requests during the call: the browser never tried (auto-record off, no token, an old build still on tab capture, or the page hook missed the call). 4xx: token or endpoint wrong. A presign with nothing in S3: the PUT failed. The popup's last-upload line is the browser's side of the same story. -
Status: confirmed on a real Google Meet call (2026-10-01, v0.3.0): started with no click (even alone in the call), mic captured, stopped on hang-up, uploaded, transcribed cleanly. Zoom web and Teams web use the same recorder but are not yet confirmed live. For acall the title is just the meeting code; a calendar meeting carries its name. Participant names are best-effort and often empty, so identify people from the transcript.
meet.new
-
录制方式,以及唯一不能撤销的改动。 自动录制发生在会议页面内部(,一个
extension/capture.main.jscontent script,会包装world: MAIN和RTCPeerConnection)。绝不能将自动启动改回getUserMedia:Chrome 仅允许在用户点击扩展后捕获标签页,因此无法自行启动;v0.1/v0.2 在第一次真实 Meet 通话中没有录到任何内容,正是因为这一点。标签页捕获仅用于弹窗中的手动 Start,也是录制视频的唯一方式。完整设计参见chrome.tabCapture。extension/README.md -
安装或更新: 运行部署输出的单行安装命令(),然后进入
curl -fsSL <your-endpoint>/install | sh-> Load unpacked(首次安装时;chrome://extensions,粘贴),或点击重新加载箭头(更新时)。从未稳定目录以 unpacked 方式加载后,扩展在更新前后会保持相同 ID,因此 Options 中的 token 在更新后仍然有效。绝不要从 Downloads 加载。Cmd+Shift+G -
发布扩展变更: 编辑,递增
extension/中的manifest.json,然后运行version(环境中需配置对应 AWS 账户的凭据;token 位于 Lambda 环境中,参见cd ingest/presign-lambda && BUCKET=<your-inbox-bucket> TOKEN=<current> ./deploy.sh)。这会重新打包由extension/README.md提供的 zip;重新运行安装命令并点击 reload。完成前,应在真实的 WebRTC 通话上验证录音器变更(README 中介绍了 Chromium harness)。/extension -
“我的通话录下来了吗?”以及收件箱为空: 应查询端点,而不是代码。bash
aws cloudwatch get-metric-statistics --region us-east-1 --namespace AWS/ApiGateway \ --metric-name Count --dimensions Name=ApiId,Value=<your-api-id> --statistics Sum --period 300 \ --start-time $(date -u -d '-3 hours' +%FT%TZ) --end-time $(date -u +%FT%TZ)通话期间没有请求:浏览器从未尝试过(自动录制关闭、没有 token、仍是基于标签页捕获的旧版本,或页面 hook 未捕获到通话)。4xx:token 或端点错误。预签名成功但 S3 中没有内容:PUT 失败。弹窗中的最后一行上传信息反映的是浏览器端的同一情况。 -
状态: 已在一次真实的 Google Meet 通话中确认(2026-10-01,v0.3.0):无需点击即可开始(即使通话中只有自己)、可捕获麦克风、挂断时停止、成功上传且转录清晰。Zoom web 和 Teams web 使用同一个录音器,但尚未进行真实验证。对于通话,标题只是会议代码;日历会议则带有名称。参与者姓名仅供参考,而且通常为空,因此应从转录文本中识别人。
meet.new
Flow B: audio-reply mode
流程 B:音频回复模式
The user reads on their phone and often cannot skim a long answer. In this mode every substantive reply is spoken.
bash
S=.claude/skills/meeting-brief/scripts用户经常在手机上阅读,可能无法快速浏览长回答。在此模式下,每个实质性回复都以语音形式交付。
bash
S=.claude/skills/meeting-brief/scripts1. delete the clip from the previous turn; they have replied so they have heard it
1. delete the clip from the previous turn; they have replied so they have heard it
$S/unshare.sh "s3://<bucket>/<previous-key>" <project-dir> <previous-local-file>
$S/unshare.sh "s3://<bucket>/<previous-key>" <project-dir> <previous-local-file>
2. write the reply as a SPOKEN script, then
2. write the reply as a SPOKEN script, then
$S/say.sh reply.txt /tmp/claude/<project>/reply-<n>.mp3 1.5
$S/say.sh reply.txt /tmp/claude/<project>/reply-<n>.mp3 1.5
3. private link
3. private link
$S/share.sh /tmp/claude/<project>/reply-<n>.mp3 <project-dir>
Then post the URL with **two or three lines of text at most**: what the clip covers and anything they must act on. Not a transcript of the audio. The point of the mode is that they do not have to read.
Keep a note of the returned `s3://` URI and the local path so the next turn can delete them.
**Default speed is 1.5.** ElevenLabs' own `speed` setting maxes out at 1.2, so `say.sh` renders at normal speed and applies the change with `ffmpeg atempo`, chaining filters for anything outside 0.5-2.0. Pitch is preserved.$S/share.sh /tmp/claude/<project>/reply-<n>.mp3 <project-dir>
然后发布 URL,并**最多附带两到三行文本**:说明音频涵盖的内容以及用户必须处理的事项。不要提供音频的文字稿。该模式的目的在于让用户无需阅读。
保留返回的 `s3://` URI 和本地路径,以便下一轮删除它们。
**默认速度为 1.5。** ElevenLabs 自身的 `speed` 设置最高只能到 1.2,因此 `say.sh` 会先以正常速度渲染,再使用 `ffmpeg atempo` 调整速度;对于 0.5-2.0 范围之外的速度,会串联滤镜。音高保持不变。Writing for the ear
为听觉而写
Reading markdown aloud is unlistenable. Convert before calling :
say.sh- Spell numbers out: "four hundred ninety-nine a month", not "$499/mo".
- No file paths, no URLs, no code identifiers. Those go in the text message beside the link.
- No bullet characters, no headers, no bold. Use "First", "Second", "The next thing" instead.
- Say acronyms as letters where that is how they are said: "M R R", "U X", "U I".
- Warn about known transcription mangling up front if the summary depends on it.
- Blank lines between paragraphs. chunks on those boundaries and stitches with
say.sh/previous_textso prosody carries across the joins.next_text
Default voice is a calm broadcast read (). Override with . Model defaults to via .
onwK4e9ZLuTAKqWW03F9MEETING_BRIEF_VOICEeleven_multilingual_v2MEETING_BRIEF_MODEL直接朗读 Markdown 难以收听。调用 前应进行转换:
say.sh- 将数字拼写出来:“每月四百九十九美元”,而不是“$499/mo”。
- 不要出现文件路径、URL 或代码标识符。这些内容应放在链接旁边的文字消息中。
- 不要使用项目符号字符、标题或粗体。改用“首先”、“其次”、“下一件事”等表达。
- 如果缩写的读法就是逐字母发音,则按字母朗读,例如“M R R”、“U X”、“U I”。
- 如果摘要依赖某个已知容易转写错误的术语,应在开头提醒。
- 段落之间保留空行。会根据空行对内容分块,并使用
say.sh/previous_text拼接,以保证连接处的韵律自然。next_text
默认声音是平稳的播音式朗读()。可通过 覆盖。模型默认通过 设置为 。
onwK4e9ZLuTAKqWW03F9MEETING_BRIEF_VOICEMEETING_BRIEF_MODELeleven_multilingual_v2Scripts
脚本
| Script | Does |
|---|---|
| Scribe v2, diarised, keyterms, parallel, skips existing output |
| Timestamped, speaker-grouped transcript |
| Chunked TTS, stitched, speed-adjusted |
| Private S3 upload, presigned URL (7 day max) |
| Deletes the object and optionally the local file |
| Per-project credential resolution, sourced by the above |
| ElevenLabs key loading |
| Regenerates the extension's toolbar icons (idle + recording) |
| The S3 meeting inbox (Flow C) |
| Redeploys the endpoint and re-bundles the extension zip served at |
ELEVENLABS_API_KEYELEVENLABS_ENV_FILE.env| 脚本 | 作用 |
|---|---|
| 使用 Scribe v2 进行说话人分离转录,支持 keyterms、并行处理,并跳过已有输出 |
| 生成带时间戳、按说话人分组的转录文本 |
| 分块 TTS、拼接并调整速度 |
| 上传至私密 S3,生成预签名 URL(最长 7 天) |
| 删除对象,并可选删除本地文件 |
| 按项目解析凭据,供上述脚本加载 |
| 加载 ElevenLabs key |
| 重新生成扩展工具栏图标(空闲与录制状态) |
| S3 会议收件箱(流程 C) |
| 重新部署端点,并重新打包由 |
ELEVENLABS_API_KEYELEVENLABS_ENV_FILE.envEnvironment notes
环境说明
- Backgrounding with or
&may not survive the tool call. Use the Bash tool'snohupinstead, which is the reliable way to hold a process.run_in_background - A presigned URL is signed per HTTP method. against a GET-signed URL returns 403 and that is correct, not a failure. Verify with a ranged GET:
curl -I.curl -r 0-2000 "$URL" - and
ffmpegare required (install them with your package manager).ffprobe - Keep scratch files out of the repo (e.g. under ).
/tmp/claude/<project>/
- 使用 或
&进行后台处理可能无法在工具调用结束后继续运行。应改用 Bash 工具的nohup,这是保持进程运行的可靠方式。run_in_background - 预签名 URL 按 HTTP 方法签名。对 GET 签名的 URL 执行 会返回 403,这是正确行为,并非失败。应使用分段 GET 验证:
curl -I。curl -r 0-2000 "$URL" - 需要安装 和
ffmpeg,可使用系统的包管理器进行安装。ffprobe - 临时文件应放在仓库之外,例如 。
/tmp/claude/<project>/
When not to use
不适用场景
- A short factual answer. Do not make the user play a clip to hear one sentence.
- Anything they need to copy and paste: paths, URLs, commands, IDs. Those must be text.
- Code review or diffs. Audio is useless for reading code.
- 简短的事实性回答。不要让用户为了听一句话而播放音频片段。
- 任何需要复制粘贴的内容:路径、URL、命令、ID。这些内容必须以文本形式提供。
- 代码审查或 diff。音频不适合用于阅读代码。