惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recorded Future
Recorded Future
人人都是产品经理
人人都是产品经理
Google DeepMind News
Google DeepMind News
Google DeepMind News
Google DeepMind News
雷峰网
雷峰网
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
酷 壳 – CoolShell
酷 壳 – CoolShell
SecWiki News
SecWiki News
W
WeLiveSecurity
N
News | PayPal Newsroom
AI
AI
The Last Watchdog
The Last Watchdog
I
InfoQ
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
B
Blog RSS Feed
Hacker News: Ask HN
Hacker News: Ask HN
Hugging Face - Blog
Hugging Face - Blog
L
LINUX DO - 最新话题
Engineering at Meta
Engineering at Meta
Hacker News - Newest:
Hacker News - Newest: "LLM"
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
www.infosecurity-magazine.com
www.infosecurity-magazine.com
腾讯CDC
Attack and Defense Labs
Attack and Defense Labs
博客园 - Franky
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Apple Machine Learning Research
Apple Machine Learning Research
Stack Overflow Blog
Stack Overflow Blog
Forbes - Security
Forbes - Security
Martin Fowler
Martin Fowler
D
Docker
Last Week in AI
Last Week in AI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Privacy & Cybersecurity Law Blog
U
Unit 42
H
Help Net Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Schneier on Security
博客园 - 司徒正美
S
SegmentFault 最新的问题
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Schneier on Security
Schneier on Security
P
Palo Alto Networks Blog
Jina AI
Jina AI
V
Vulnerabilities – Threatpost
P
Proofpoint News Feed
大猫的无限游戏
大猫的无限游戏
WordPress大学
WordPress大学

人人都是产品经理

为什么你的产品找不到差异化?90%的失败都卡在第一步上(下) – 人人都是产品经理, 3年从30万到1300万用户、获2200万美元融资,这个AI教育产品用“抽卡”破解了获客难题 – 人人都是产品经理, 园区招商系统怎么做才能真正帮到去化?我加了这一个功能,推广链接转发400次阅读过万 – 人人都是产品经理, AI大事件:OpenAI发完网络安全模型又搞药物研发,小鹏汽车要抓”DeepSeek时刻” – 人人都是产品经理, 电商不是卖货,是一场更残酷的产品经理实战 – 人人都是产品经理, 没想到,活动营销又回来了! – 人人都是产品经理, 为何All-in海外KOC:一场关于AI时代窗口期的豪赌 – 人人都是产品经理, 重新理解企业的内部协作 – 人人都是产品经理, 苹果的 AI 战略到底是什么? – 人人都是产品经理, 医疗智能体·第2讲——合规护城河:等保、PIPL与HIPAA的架构实战 – 人人都是产品经理, 向量知识库五步法:从“答非所问”到“精准回复” – 人人都是产品经理, 鸿蒙PC三方库构建总指挥HPKBUILD(sha)库为例 – 人人都是产品经理, 何时该用LLM?AI产品经理的LLM设计指南 – 人人都是产品经理, 医疗信息领域的需求方、决策方、准入方以及关注点(二) – 人人都是产品经理, 即梦涨价:一场被误读的「傲慢」 – 人人都是产品经理, 面试AI PM必答题:Hermes和OpenClaw的区别,如何讲清楚业务价值 – 人人都是产品经理, AI的下一张船票:世界模型——AI产品经理必须理解的技术拐点 – 人人都是产品经理, 小红书做GEO,怎么让AI信你?记住这 3 个重要信息 – 人人都是产品经理, 5 家印度 AI 初创公司,看看印度 AI 再做什么 – 人人都是产品经理, AI项目跨团队协作:产品技术业务如何不打架 – 人人都是产品经理, Agentic Workflow(智能体工作流):让AI从”答案生成器”变成”数字员工” – 人人都是产品经理, lycium_plusplus 项目全景解读:OpenHarmony 三方库构建的“大管家” – 人人都是产品经理, 从爆单救火到前置履约:两套预采策略,把生鲜大促履约效率拉满 – 人人都是产品经理, 什么时候该补货?我用一轮数据做了一个决定 – 人人都是产品经理, 从“机械兜底”到“动态分流”:AI客服重复进线治理的4大底层逻辑 – 人人都是产品经理, 抖音拼效率,红书拼洞察 – 人人都是产品经理, 全民狂欢与退潮——为什么龙虾这波热潮冷却得如此之快? – 人人都是产品经理, Stripe押注!MPP重塑全球支付 – 人人都是产品经理, 小红书GEO:AI引用你的内容,不是因为你对,而是因为你看起来可信 – 人人都是产品经理, 前百度副总裁押注办公Agent,日韩付费爆发,Manus迎来强劲对手 – 人人都是产品经理, 企事业单位数字化的业务供需本质 – 人人都是产品经理, 医疗智能体·第1讲——医疗信息化重构:从“辅助软件”到“自主智能体”的范式转移 – 人人都是产品经理, 粉丝量就是空气!!! – 人人都是产品经理, 用户说“薯片碎了”,机器回“要买吗?”:意图识别的翻车与破局 – 人人都是产品经理, RAG召回准确率从75到90 我做对了这三件事 – 人人都是产品经理, AI大事件:Anthropic改收费、OpenAI发安全版、手术机器人纳入医保、阿里发布”秒悟” – 人人都是产品经理, Chrome 推出 Skills 新功能,Agent 重塑上网方式 – 人人都是产品经理, GitHub前创始人拿了a16z的1700万美元,做Agent时代的Git – 人人都是产品经理 拷贝或克隆其他 Flutter OH 项目到本地后无法运行 – 人人都是产品经理, 优惠券设计:优惠券创建 – 人人都是产品经理, 不用死磕文档!AI 助手 1 小时搞定飞书 CLI 安装 + 配置 + 知识库 – 人人都是产品经理, 用小龙虾做竞品分析报告:从2天到20分钟,我是怎么做到的 – 人人都是产品经理 用小龙虾做市场分析报告:搞懂这3个公式,市场规模不再靠猜 – 人人都是产品经理, 你早就在做 Harness 工程,只是不知道它叫这个名字 – 人人都是产品经理, Think Long就够?你可能想多了! – 人人都是产品经理, 货代SRM实战:供应商准入怎么做,才能让资源池不是通讯录而是可交付网络? – 人人都是产品经理, 如何做好用户调研?详解基本技巧 – 人人都是产品经理, 木鸟、途家、美团对打,平台春天行动开“卷” – 人人都是产品经理, 入职才发现公司不靠谱?小红书从业者求职避坑指南 – 人人都是产品经理, 美国 AI 三巨头联手封堵,中国 AI 突围之路在何方 – 人人都是产品经理, 小红书,放在需求对面的镜子 – 人人都是产品经理, AI 会带来大规模失业吗? – 人人都是产品经理, 从出单到补货前,我第一次犹豫:该不该放大? – 人人都是产品经理, Flutter 三方库鸿蒙化适配:5 种高效检查方式,快速判断是否需要适配 – 人人都是产品经理, 从做产品进阶拿结果:医美机构产品经理转岗科室运营经理 – 人人都是产品经理, 阿里HappyHorse,一场关于“Token经济”的阳谋 – 人人都是产品经理, To B AI:客户留存落地的观察与思考 – 人人都是产品经理, AI产品的“生命线”——数据采集、标注、清洗的产品化设计 – 人人都是产品经理, 谈谈AI Agent(二):当“孩子”能自己“体验世界”时,你该学什么? – 人人都是产品经理, UI/UX设计师的3层能力进阶,前两层让你活下来,第三层…才是真正的分水岭 – 人人都是产品经理, 2分钟 → 30秒,效率提升75%:B端产品经理如何用「规则枷锁」驯服AI幻觉? – 人人都是产品经理, 还没来得及学OpenClaw,来了个更猛的:Hermes Agent – 人人都是产品经理, AI日报:宇树机器人跑出10m/s刷新世界纪录 – 人人都是产品经理, 一文说透基金互金如何用情绪价值引导用户决策做转化 – 人人都是产品经理, 当浏览器开始替你”看”网页:AI 浏览器正在亲手拆掉它脚下的那张网 – 人人都是产品经理, 0代码,一天时间我Vibe Coding了个网站 – 人人都是产品经理, Hermes 和 OpenClaw 之争,Agent 的能力应该“装上去”还是“长出来”? – 人人都是产品经理 视频生成的“桌子”,字节Seedance 2掀完,阿里快乐马掀 – 人人都是产品经理, 从听不懂到完全信任:我的 Codex 深度产品体验 – 人人都是产品经理, 当虚拟偶像有了北京户口,与真人偶像还有什么区别? – 人人都是产品经理, 会说,远远比会做更重要 —— 对 SBTI 爆火现象的五层观察 – 人人都是产品经理, AI产品经理必看:当“搭环境”比“选模型”更重要,你的认知还在2024年吗? – 人人都是产品经理, 2026年AI产品商业化核心逻辑:从功能demo到规模化营收的3个必破卡点 – 人人都是产品经理, 京东围绕供应链,卷起裤腿下场的那些事儿 – 人人都是产品经理, SBTI一夜刷屏:它赢在了“太会说人话” – 人人都是产品经理, 折扣零售的真相:不是便宜,而是价值感! – 人人都是产品经理, 和甲方吵了一架,最后加钱做了——我学到的ToB产品经理生存法则 – 人人都是产品经理, 和几位小红书操盘手聊了8小时,干货全在这 – 人人都是产品经理, 智谱GLM-5.1登场,开源模型首超Opus4.6!!! – 人人都是产品经理 Anthropic收入凭什么反超OpenAI,终于有人把这事说清楚了 – 人人都是产品经理, 史上最有故事感的技术报告——Claude最强模型Mythos 7个极其精彩的细节 – 人人都是产品经理, 模型不是壁垒,Harness 也不是 – 人人都是产品经理, 抖音本地生活业务思考21 – 人人都是产品经理, Superpowers:145k Star的AI编码框架,到底是什么来头? Superpowers:145k Star的AI编码框架,到底是什么来头? – 人人都是产品经理, OpenAI 的路走错了,Anthropic Harness 解法启示:模型需要实践专科生 – 人人都是产品经理, 画原型图的前一步:设计站点地图 – 人人都是产品经理, 给 DeepSeek 的最后一封催更信 – 人人都是产品经理, 手把手教你用 Claude Code 搭建 AI 营销团队:5 个 Agent、12 项技能,独立完成研究、写作、设计全流程 – 人人都是产品经理, 你以为大模型在学语言?不,它在重新发明语言学 – 人人都是产品经理 所谓Skill,不过是AI时代的工业垃圾 – 人人都是产品经理, 聊一聊内容传播的几个方法 – 人人都是产品经理, 当平台开始吃掉生态:从 OpenClaw 被封杀,读懂 Anthropic 的这盘棋 – 人人都是产品经理, 你装了 10 个 AI 插件,Obsidian 还是一个文件夹 – 人人都是产品经理 关于AI智能体架构演进的系统性思考:从单体试水到多体协同的重构 – 人人都是产品经理, 当“人”变成Skill,我们又该何去何从? – 人人都是产品经理 Mythos 事件:前沿 AI 治理的意外实验 – 人人都是产品经理, 货代CRM:信用与风险管理怎么做,才能把坏账风险拦在放货之前? – 人人都是产品经理, 从HR收集自拍照到员工自助录入——我见证了园区人脸识别从”不可用”到”真好用”的全过程 – 人人都是产品经理 千问闯关AI混沌期:阿里画靶,吴嘉张弓,马云射箭? – 人人都是产品经理,
6个shell,我给 Claude Code 装上了“嘴” – 人人都是产品经理,
秋孝隱 · 2026-05-12 · via 人人都是产品经理

厌倦了盯着屏幕看AI输出代码而脖子酸痛?现在,Claude Code可以像电台主播一样为你朗读代码解析!本文手把手教你如何利用macOS的say命令和Shell脚本,将枯燥的代码输出变成语音播报,解放双眼的同时不遗漏任何关键信息。从安装准备到6个核心脚本的配置,零基础也能实现这一智能语音助手功能。

写代码的人多多少少都有过这种瞬间:

AI 在屏幕上哗啦啦输出一大段,你眼睛盯着光标跳,脖子越来越僵,三十分钟后回过神来——刚才到底在看什么?

那天我也是。窗外天黑了,屋里只剩屏幕的光,Claude Code 又在往外吐字。我突然冒出一个念头:

它要是能念给我听就好了

不用多花哨,就像有个人坐在旁边,一边敲代码一边把要紧的话讲出来。这样我可以靠在椅子上闭一会儿眼,可以去倒杯水,可以伸个懒腰——它该说的话我一句不落

我查了一圈,官方没这个功能。但 Claude Code 有个东西叫Hooks,是它在会话开始、结束、每次回答完之后会自动触发的”钩子”。理论上,我可以写几个脚本挂上去,让它每次回答完就调用 macOS 自带的say命令把内容念出来

折腾了一个周末,改了 6 个版本,写了 6 个 Shell 脚本,加起来四百多行。最后真做成了

现在我的 Claude Code 一边写代码一边说话,听上去像电台主播,别说,开始还有点不习惯

这篇文章就把整套配置完整写出来。不会写代码也没关系,我尽量把每一步都讲到能复制粘贴就跑通的程度

你需要先有什么

这套方案目前只在Mac 电脑上能用(Windows 和 Linux 需要改脚本,本文先不展开)

打开你的”启动台”,找到一个叫”终端”的应用——黑黑的,图标像个小窗口。这是后面所有操作要用的地方。不要怕,照着复制粘贴就行

接下来检查两样东西:

第一,你装了 Claude Code 吗?如果在终端里输入claude然后回车,看到提示就说明装了。没装的话先去 Claude 官网装一下,回头再继续

第二,你装了 jq 吗?jq 是个处理 JSON 数据的小工具。在终端里输入:

brewinstalljq

如果提示command not found: brew,说明你电脑上还没有 Homebrew(Mac 上最常用的软件管家),先去 brew.sh 网站照首页那一行命令装一下,再回来执行上面这句

装完之后,准备工作就完成了

第一步:建一个文件夹放脚本

打开终端,复制这一行进去,回车:

mkdir-p~/.claude/hooks

这句话的意思是:在你的用户目录下建一个.claude/hooks文件夹,专门放后面这些脚本

没有任何反应是正常的。终端的哲学就是”没消息就是好消息”,一旦报错它会很大声地告诉你

第二步:写 6 个脚本

下面 6 段命令,一段一段复制进终端,每段回车一次。每一段都是cat > 某个文件 << ‘EOF’开头、EOF结尾的格式——这是 Shell 的一种写法,意思是”把中间这一坨内容原封不动地写进这个文件里”

注意一定要连同最后那个EOF一起复制进去,不然终端会一直等你输完,光标卡在那儿不动

脚本 1:会话启动时叫醒”播音员”

cat > ~/.claude/hooks/tts-start.sh <<‘EOF’#!/bin/bashset-uMONITOR=”$HOME/.claude/hooks/tts-monitor.sh”DEBUG_LOG=”$HOME/.claude/hooks/tts-start-debug.log”log() {echo”$1″>>”$DEBUG_LOG”; }log”=== Starting TTS monitor at$(date)===”VOICE_ENABLED=$(jq -r’.voiceEnabled // false'”$HOME/.claude/settings.json”2>/dev/null ||echofalse)if[“$VOICE_ENABLED”!=”true”];then log”Voice disabled, not starting monitor” exit0fiINPUT=$(cat)TRANSCRIPT_PATH=$(echo”$INPUT”| jq -r’.transcript_path // empty’2>/dev/null)[“$TRANSCRIPT_PATH”=”null”] && TRANSCRIPT_PATH=SESSION_ID=$(echo”$INPUT”| jq -r’.session_id // .conversation_id // .sessionId // .conversationId // empty’2>/dev/null)[“$SESSION_ID”=”null”] && SESSION_ID=[ -z”$SESSION_ID”] && SESSION_ID=”session-$(date +%s)-$”if[ -z”$TRANSCRIPT_PATH”];then PROJECT_DIR=$(echo”$INPUT”| jq -r’.cwd // .workspace_roots[0] // empty’2>/dev/null) [“$PROJECT_DIR”=”null”] && PROJECT_DIR= if[ -n”$PROJECT_DIR”];then TRANSCRIPT_DIR=”$HOME/.claude/projects/$(echo “$PROJECT_DIR” | sed ‘s///-/g’)” SPECIFIC=”$TRANSCRIPT_DIR/$SESSION_ID.jsonl” [ -f”$SPECIFIC”] && TRANSCRIPT_PATH=”$SPECIFIC” fifiPID_SAFE=$(echo”$SESSION_ID”| tr -cd'[:alnum:]-_’| head -c 120)[ -n”$PID_SAFE”] || PID_SAFE=”unknown”PID_FILE=”$HOME/.claude/hooks/tts-monitor-$PID_SAFE.pid”if[ -f”$PID_FILE”];then OLD_PID=$(tr -d’ n'<“$PID_FILE”) if[ -n”$OLD_PID”] &&kill-0″$OLD_PID”2>/dev/null;then kill-TERM”$OLD_PID”2>/dev/null ||true sleep 0.15 kill-KILL”$OLD_PID”2>/dev/null ||true fi rm -f”$PID_FILE”fiSPAWN_LOG=”$HOME/.claude/hooks/tts-monitor-spawn.log”nohup”$MONITOR””$TRANSCRIPT_PATH””$SESSION_ID”>>”$SPAWN_LOG”2>&1 </dev/null &log”Started monitor PID $!”exit0EOF

这是会话开始时第一个被叫醒的脚本。它的工作是检查”语音开关”是不是打开的,然后在后台启动真正干活的”监控员”——也就是下面这一个

脚本 2:真正干活的”监控员”

这是最长的一个,也是最核心的。它负责盯着 Claude Code 的对话记录文件,一旦有新内容就读出来

cat > ~/.claude/hooks/tts-monitor.sh <<‘EOF’#!/bin/bashset-uif[“$#”-ge 2 ];then TRANSCRIPT_PATH=”$1″ [“$TRANSCRIPT_PATH”=”null”] && TRANSCRIPT_PATH= SESSION_ID=”$2″else TRANSCRIPT_PATH=”” SESSION_ID=”unknown”fiPID_SAFE=$(echo”$SESSION_ID”| tr -cd'[:alnum:]-_’| head -c 120)[ -n”$PID_SAFE”] || PID_SAFE=”unknown”PID_FILE=”$HOME/.claude/hooks/tts-monitor-$PID_SAFE.pid”DEBUG_LOG=”$HOME/.claude/hooks/tts-session-$PID_SAFE.log”log() {echo”$1″>>”$DEBUG_LOG”; }VOICE_ENABLED=$(jq -r’.voiceEnabled // false'”$HOME/.claude/settings.json”2>/dev/null ||echofalse)[“$VOICE_ENABLED”!=”true”] &&exit0resolve_by_session() { find”$HOME/.claude/projects”-maxdepth 15 -name”$1.jsonl”-typef 2>/dev/null | head -1}extract_speakable() { echo”$1″| jq -r’ (.message // {}) as $m | ($m.content | if type == “array” then . elif type == “string” then [{“type”:”text”,”text”: .}] else [] end) as $c | ([$c[]? | select(.type == “text”) | .text] | join(” “)) as $t | if ($t | length) > 0 then $t else ([$c[]? | select(.type == “thinking”) | .thinking] | join(” “)) end’2>/dev/null | head -c 500}log”=== Monitor PID $ at$(date)===”echo$ >”$PID_FILE”WAIT_COUNT=0while[“$WAIT_COUNT”-lt 180 ];do [ -n”$TRANSCRIPT_PATH”] && [ -f”$TRANSCRIPT_PATH”] &&break if[ -n”$SESSION_ID”] && [“$SESSION_ID”!=”unknown”];then if[“$((WAIT_COUNT % 3))”-eq 0 ];then RESOLVED=$(resolve_by_session”$SESSION_ID”) if[ -n”$RESOLVED”] && [ -f”$RESOLVED”];then TRANSCRIPT_PATH=”$RESOLVED” break fi fi fi sleep 1 WAIT_COUNT=$((WAIT_COUNT + 1))doneif[ ! -f”$TRANSCRIPT_PATH”];then rm -f”$PID_FILE” exit0filog”Tailing:$TRANSCRIPT_PATH”LAST_LINE=$(wc -l <“$TRANSCRIPT_PATH”| awk'{print $1+0}’)whiletrue;do sleep 0.4 [ ! -f”$TRANSCRIPT_PATH”] &&break CURRENT_LINES=$(wc -l <“$TRANSCRIPT_PATH”2>/dev/null | awk'{print $1+0}’) if[“$CURRENT_LINES”-gt”$LAST_LINE”];then tail -n +$((LAST_LINE + 1))”$TRANSCRIPT_PATH”|whileIFS=read-r line;do ROLE=$(echo”$line”| jq -r’.type // empty’2>/dev/null) if[“$ROLE”=”assistant”];then TEXT=$(extract_speakable”$line”) if[ -n”$TEXT”] && [“${#TEXT}”-le 2000 ];then if!printf’%s'”$TEXT”| grep -q’^“`’;then CLEAN=$(printf’%s'”$TEXT”| sed’s/“`[^`]*“`//g; s/**//g; s/*//g; s/`//g’| tr -d’n’| head -c 320) [ -z”$CLEAN”] && CLEAN=$(printf’%s'”$TEXT”| tr -d’n’| head -c 320) if[ -n”$CLEAN”];then (/usr/bin/say”$CLEAN”2>/dev/null) & fi fi fi fi done LAST_LINE=$CURRENT_LINES fidonerm -f”$PID_FILE”EOF

它会自动过滤掉代码块(不然念起代码来你会想砸电脑),只朗读 Claude “真正要说的”话

脚本 3:会话结束时让”播音员”下班

cat > ~/.claude/hooks/tts-stop.sh <<‘EOF’#!/bin/bashDEBUG_LOG=”$HOME/.claude/hooks/tts-stop-debug.log”echo”=== Stopping at$(date)===”>>”$DEBUG_LOG”INPUT=$(cat 2>/dev/null ||true)SESSION_ID=$(echo”$INPUT”| jq -r’.session_id // .conversation_id // .sessionId // .conversationId // empty’2>/dev/null)if[ -z”$SESSION_ID”] || [“$SESSION_ID”=”null”];then exit0fiPID_SAFE=$(echo”$SESSION_ID”| tr -cd'[:alnum:]-_’| head -c 120)[ -n”$PID_SAFE”] || PID_SAFE=”unknown”PID_FILE=”$HOME/.claude/hooks/tts-monitor-$PID_SAFE.pid”if[ -f”$PID_FILE”];then OLD_PID=$(tr -d’ n'<“$PID_FILE”) if[ -n”$OLD_PID”] &&kill-0″$OLD_PID”2>/dev/null;then kill-TERM”$OLD_PID”2>/dev/null ||true sleep 0.3 kill-KILL”$OLD_PID”2>/dev/null ||true fi rm -f”$PID_FILE”fiEOF

注意它只关掉当前这个窗口的监控,不影响你开着的其他 Claude 窗口。这是踩了好几个坑之后才改成这样的

脚本 4:一键开关语音

cat > ~/.claude/hooks/voice-toggle.sh <<‘EOF’#!/bin/bashSETTINGS_FILE=”$HOME/.claude/settings.json”CURRENT=$(jq -r’.voiceEnabled // false'”$SETTINGS_FILE”)if[“$CURRENT”=”true”];then jq’.voiceEnabled = false'”$SETTINGS_FILE”> /tmp/settings.json.tmp mv /tmp/settings.json.tmp”$SETTINGS_FILE” pkill -f”tts-monitor.sh”2>/dev/null ||true rm -f”$HOME/.claude/hooks/tts-monitor-“*.pid 2>/dev/null ||true killall say 2>/dev/null ||true echo”✓ 语音播报已关闭”else jq’.voiceEnabled = true'”$SETTINGS_FILE”> /tmp/settings.json.tmp mv /tmp/settings.json.tmp”$SETTINGS_FILE” echo”✓ 语音播报已开启”fiEOF

之后想开就开、想关就关,跑一次这个脚本即可

脚本 5:Stop 钩子的“占位脚本”

cat > ~/.claude/hooks/stop-speak.sh <<‘EOF’#!/bin/bashDEBUG_LOG=”$HOME/.claude/hooks/tts-debug.log”VOICE_ENABLED=$(jq -r’.voiceEnabled // false'”$HOME/.claude/settings.json”2>/dev/null ||echofalse)[“$VOICE_ENABLED”!=”true”] &&exit0KILL=$(jq -r’.env.TTS_KILL_ON_STOP // empty'”$HOME/.claude/settings.json”2>/dev/null)if[“$KILL”=”true”] &&command-v killall >/dev/null 2>&1;then killall say 2>/dev/null ||truefiEOF

这个脚本默认什么都不做。别小看它——之前的版本一旦 Claude 暂停就把朗读全部杀掉,结果话还没说完声音就断了,特别恼火。所以这个版本让它对 Stop 视而不见,朗读该念完就念完

脚本 6:自检小工具

cat > ~/.claude/hooks/tts-selftest.sh <<‘EOF’#!/bin/bashset-euo pipefailMON=”$HOME/.claude/hooks/tts-monitor.sh”UUID=”aaaaaaaa-bbbb-4ccc-dddd-eeeeeeeeeeee”TMP=$(mktemp /tmp/tts-selftest.XXXXXX)trap”rm -f$TMP$HOME/.claude/hooks/tts-monitor-$UUID.pid 2>/dev/null || true”EXITVOICE=$(jq -r’.voiceEnabled // false'”$HOME/.claude/settings.json”2>/dev/null ||echofalse)if[“$VOICE”!=”true”];then echo”请先开启语音再自检” exit0fiprintf’%sn”{“type”:”user”,”message”:{“role”:”user”,”content”:”ping”}}’>”$TMP””$MON””$TMP””$UUID”&MP=$!sleep 0.8printf’%sn”{“type”:”assistant”,”message”:{“role”:”assistant”,”content”:[{“type”:”text”,”text”:”自检通过”}]}}’>>”$TMP”sleep 2kill-TERM”$MP”2>/dev/null ||trueLOG=”$HOME/.claude/hooks/tts-session-$UUID.log”ifgrep -qE’Tailing|Speakable'”$LOG”2>/dev/null;then echo”OK: 监控正常”else echo”FAIL: 没有抓到内容” tail -20″$LOG”2>/dev/nullfiEOF

这个用来在不开 Claude 的情况下,单独验证脚本本身有没有问题

第三步:给脚本”通行证”

刚写完的脚本是一堆”无权限”的文件,得手动告诉系统这些是可以执行的程序。一行命令搞定:

chmod +x~/.claude/hooks/tts-*.sh~/.claude/hooks/voice-toggle.sh~/.claude/hooks/stop-speak.sh

第四步:让 Claude Code 知道这些脚本的存在

光写完脚本不够,还得告诉 Claude Code:”会话开始时调用这个、结束时调用那个”。这一步要修改它的配置文件

把下面整段复制进终端运行——它会自动帮你改好配置,不需要你手动写 JSON

cp~/.claude/settings.json ~/.claude/settings.json.backup2>/dev/nullpython3<<‘PYTHON_SCRIPT’import json, ossettings_path = os.path.expanduser(‘~/.claude/settings.json’)home = os.path.expanduser(‘~’)try: withopen(settings_path,’r’)asf: settings = json.load(f)except FileNotFoundError: settings = {}settings.setdefault(‘voiceEnabled’, False)settings.setdefault(‘hooks’, {})hooks_to_add = { ‘SessionStart’:f'{home}/.claude/hooks/tts-start.sh’, ‘SessionEnd’: f'{home}/.claude/hooks/tts-stop.sh’, ‘Stop’: f'{home}/.claude/hooks/stop-speak.sh’,}forevent, script in hooks_to_add.items(): settings[‘hooks’].setdefault(event, []) exists= any( h.get(‘hooks’, [{}])[0].get(‘command’,”).endswith(os.path.basename(script)) forh in settings[‘hooks’][event] ) ifnot exists: settings[‘hooks’][event].append({ ‘hooks’: [{‘type’:’command’,’command’: script}] })withopen(settings_path,’w’)asf: json.dump(settings,f,indent=2)print(“✓ 配置完成”)PYTHON_SCRIPT

看到 “✓ 配置完成” 就说明搞定了

第五步:开机仪式

现在所有零件都装好了,但语音开关还是关着的。打开它:

~/.claude/hooks/voice-toggle.sh

终端会回复你✓ 语音播报已开启

然后做一个最朴素的测试:

say”你好,我是 Claude,从今天开始我会念给你听”

如果你听到 Mac 用一种特别人工的腔调把这句话念了出来——恭喜,硬件层面没问题

接着关掉所有 Claude Code 窗口,重新打开一个。这一步很关键,因为 Hooks 配置只在新会话启动时生效

新开一个会话之后,随便问 Claude 一个问题,比如”你好”

如果一切顺利,你会听到它一边在屏幕上打字,一边把内容念了出来

用起来之后你可能想问的问题

怎么换个声音?

Mac 里其实藏着几十种语音。在终端里输入say -v “?”能看到全部清单,里面”Ting-Ting”是普通话女声,”Sin-Ji”是粤语女声,还有日语英语德语各种口音的

想换声音的话,打开~/.claude/hooks/tts-monitor.sh(用 VS Code 或者随便什么文本编辑器),找到/usr/bin/say “$CLEAN”这一行,改成/usr/bin/say -v “Ting-Ting” “$CLEAN”就行

它念得太快/太慢怎么办?

同一行里加个-r参数,后面跟一个数字:/usr/bin/say -r 200 “$CLEAN”。默认 175,越大越快,能调到 500,也能慢到 100

想暂时关掉怎么办?

~/.claude/hooks/voice-toggle.sh

这一句话是开关,再跑一次就重新打开

完全不想要了怎么删?

rm ~/.claude/hooks/tts-*.shrm ~/.claude/hooks/voice-toggle.shrm ~/.claude/hooks/stop-speak.shcp~/.claude/settings.json.backup ~/.claude/settings.json

干净利落

如果它没动静

第一招:看看开关

cat~/.claude/settings.json |grepvoiceEnabled

应该是true。如果是false,跑一次voice-toggle.sh

第二招:自检

~/.claude/hooks/tts-selftest.sh

看终端的输出。”OK”就说明脚本本身没问题,问题在 Claude Code 那一端,重启一下窗口大概率能好

第三招:看日志

ls-t ~/.claude/hooks/tts-session-*.log| head -1| xargs tail -50

这一句会把最新的会话日志最后 50 行打出来。里面如果出现Speakable len=字样,说明监控员抓到内容了,但可能say没跑起来——检查一下系统音量、输出设备是不是被切到了别的设备(比如蓝牙耳机断了之后没回到电脑)

第四招:核武器

pkill-f”tts-monitor.sh”rm -f ~/.claude/hooks/tts-monitor-*.pid

把所有残留进程清空,重新打开 Claude Code 窗口。99% 的疑难杂症这一招就能搞定

写在最后

配好这套东西后,写代码的感觉确实有点不一样

不知道是声音让它多了点什么。屏幕上的字我可以随时划走,但它念出来的时候,我会不自觉地听完。明明内容一样,感觉就是不一样

有时候它在念一段很长的解释,我靠在椅背上,没有去看屏幕,就这么听着。念完了,我才回过神来——哦,刚才在工作

当然,它不会变得更聪明,也不会变得更快。但总觉得屏幕和我之间的那道墙,消失了

总之,你也想体验一下,可以花10分钟给它配上“嘴”,相信我,你会爱上它的

配置文件清单

~/.claude/hooks/

├── tts-start.sh 会话开始时叫醒监控

├── tts-monitor.sh 真正干活的监控员

├── tts-stop.sh 会话结束时让监控下班

├── voice-toggle.sh 一键开关

├──stop-speak.sh Stop 钩子(默认装聋)

└── tts-selftest.sh 不开 Claude 也能自检

觉得有用的话,欢迎点赞转发收藏,遇到任何问题都可以留言或私信,就这样,下期见

本文由 @秋孝隱 原创发布于人人都是产品经理。未经作者许可,禁止转载

题图来自Unsplash,基于CC0协议