前言:你是不是也有这个烦恼?
话说,自从用上了 Claude Code,生产力是蹭蹭往上涨,但问题也来了——
你盯着终端等 AI 跑代码的样子,真的很像在发呆摸鱼啊!
老板路过:「小王,在干嘛呢?」 你:「呃...等 AI 跑完...」 老板:「......」(一脸黑人问号)
而且更尴尬的是,等着等着,你可能就切到浏览器刷个微博、看个 B 站,结果 AI 早就跑完了,你却浑然不知,继续在那傻乐...
有没有一种优雅的方式,让我们光明正大地去摸鱼,等 AI 跑完了自动通知我?
答案是:有!而且还能让御姐小姐姐叫你回来干活!
解决方案:Claude Code Hooks
Claude Code 提供了一个神器功能——Hooks(钩子)。
简单来说,就是在 Claude Code 运行到特定阶段时,自动执行你预先设置的脚本。比如:
- AI 回答完毕时 → 发送通知 ✅
- 开始新会话时 → 打个招呼 👋
- 执行命令时 → 记录日志 📝
我们今天要用的就是 Stop 这个钩子,它会在 AI 回答完毕时触发。
💡 注意:如果你手动中断(Ctrl+C)AI 的运行,
Stophook 不会触发哦!
配置步骤(超简单,3 分钟搞定)
第 1 步:创建配置文件
打开 Claude Code 的配置文件:
~/.claude/settings.json
添加以下配置:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/scripts/notify-with-summary.sh",
"timeout": 10000
}
]
}
]
}
}
这样就告诉 Claude Code:「嘿,每次你回答完,帮我跑一下这个脚本!」
第 2 步:创建通知脚本
在 ~/.claude/scripts/ 目录下创建 notify-with-summary.sh 脚本(完整代码见文末)。
脚本的核心功能:
- 提取项目名称 → 让你知道是哪个项目的 AI 跑完了
- 发送系统通知 → macOS 右上角弹窗
- 播放自定义音效 → 御姐小姐姐的声音!
第 3 步:准备御姐音效(重点!)
这才是整个方案的灵魂所在!
我用的是 MiniMax AI 语音生成,步骤如下:
-
访问 MiniMax 官网
-
选择音色:傲娇御姐(这个很重要!)
-
设置情绪:开心
-
输入文案:
「本小姐已经完成任务了,赶紧去看看吧!」
-
生成并下载 MP3 文件
-
保存到:
~/.claude/scripts/cc-complete-music.mp3
当然,你也可以选其他音色,比如:
- 元气少女:「主人~任务完成啦~」
- 低沉大叔:「干得漂亮,兄弟。」
- 霸道总裁:「给我盯紧点,项目跑完了。」
发挥你的想象力,让工作变得有趣起来!
进阶优化
✅ 通知持久化显示
默认情况下,macOS 的通知会自动消失。如果你想让它一直显示,需要手动点击关闭:
- 打开 系统设置 → 通知
- 找到 脚本编辑器(Script Editor)
- 💡 小技巧:如果找不到,先手动触发一次通知,它就会出现在列表中
- 将通知样式改为 「提醒」 或 「持续」
这样通知就会一直挂在屏幕上,直到你手动关闭。
✅ 跨平台工具推荐
如果你想要更强大的通知功能(比如自定义图标、按钮等),可以考虑使用开源工具:
| 系统 | 推荐工具 | 特点 |
|---|---|---|
| macOS | terminal-notifier | 支持自定义图标、按钮、声音,功能强大 |
| Windows | BurntToast | PowerShell 模块,支持图片、按钮、进度条 |
不过,我最终选择了 macOS 原生通知,因为:
- 简单,不依赖第三方工具
- 够用,能显示项目名称和消息
- 结合自定义音效,体验已经很棒了
效果展示
当 Claude Code 运行完毕后:
- 右上角弹出通知:
-
播放御姐语音:
「本小姐已经完成任务了,赶紧去看看吧!」
-
你的反应:
- 🤔 在刷微博 → 听到声音 → 秒切回终端
- 😎 在摸鱼 → 听到御姐 → 瞬间精神抖擞
- 🎉 工作变得有趣多了!
总结
通过 Claude Code Hooks + 系统通知 + 自定义音效,我们实现了:
✅ 不用盯着终端发呆 ✅ AI 跑完自动通知 ✅ 御姐小姐姐叫你回来干活 ✅ 工作变得有趣多了
摸鱼,也要摸得有技术含量!
附录:完整代码
1. Claude Code 配置文件
文件路径:~/.claude/settings.json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "~/.claude/scripts/notify-with-summary.sh",
"timeout": 10000
}
]
}
]
}
}
2. 通知脚本
文件路径:~/.claude/scripts/notify-with-summary.sh
#!/bin/bash
# 读取 Claude Code 传入的 JSON 数据
INPUT=$(cat)
# 调试:记录原始 JSON 输入
echo "[DEBUG $(date '+%Y-%m-%d %H:%M:%S')] Raw input: $INPUT" >> ~/.claude/notify-debug.log
# 提取会话信息
SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"')
TRANSCRIPT_PATH=$(echo "$INPUT" | jq -r '.transcript_path // ""')
WORKING_DIR=$(echo "$INPUT" | jq -r '.working_dir // ""')
CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
# 调试:记录提取的字段
echo "[DEBUG] SESSION_ID=$SESSION_ID" >> ~/.claude/notify-debug.log
echo "[DEBUG] TRANSCRIPT_PATH=$TRANSCRIPT_PATH" >> ~/.claude/notify-debug.log
echo "[DEBUG] WORKING_DIR=$WORKING_DIR" >> ~/.claude/notify-debug.log
echo "[DEBUG] CWD=$CWD" >> ~/.claude/notify-debug.log
# 获取项目文件夹名称(按优先级尝试多个来源)
PROJECT_NAME=""
# 优先级 1: 使用 CWD 字段(如果存在)
if [ -n "$CWD" ] && [ "$CWD" != "null" ]; then
PROJECT_NAME=$(basename "$CWD")
echo "[DEBUG] Using CWD: $PROJECT_NAME" >> ~/.claude/notify-debug.log
fi
# 优先级 2: 使用 WORKING_DIR 字段
if [ -z "$PROJECT_NAME" ] && [ -n "$WORKING_DIR" ] && [ "$WORKING_DIR" != "null" ]; then
PROJECT_NAME=$(basename "$WORKING_DIR")
echo "[DEBUG] Using WORKING_DIR: $PROJECT_NAME" >> ~/.claude/notify-debug.log
fi
# 优先级 3: 从 TRANSCRIPT_PATH 推断
if [ -z "$PROJECT_NAME" ] && [ -n "$TRANSCRIPT_PATH" ] && [ "$TRANSCRIPT_PATH" != "null" ]; then
# transcript 可能在项目目录或全局目录
CLAUDE_DIR=$(echo "$TRANSCRIPT_PATH" | grep -o '.*/.claude' | head -1)
if [ -n "$CLAUDE_DIR" ]; then
PROJECT_DIR=$(dirname "$CLAUDE_DIR")
PROJECT_NAME=$(basename "$PROJECT_DIR")
echo "[DEBUG] Using TRANSCRIPT_PATH: $PROJECT_NAME from $PROJECT_DIR" >> ~/.claude/notify-debug.log
fi
fi
# 优先级 4: 使用环境变量 PWD(最后的 fallback)
if [ -z "$PROJECT_NAME" ]; then
PROJECT_NAME=$(basename "$PWD")
echo "[DEBUG] Using PWD fallback: $PROJECT_NAME" >> ~/.claude/notify-debug.log
fi
# 构建标题(包含项目名称)
TITLE="🤖 AI - $PROJECT_NAME"
MESSAGE="任务已完成"
# 如果有 transcript 文件,尝试提取最后的操作
if [ -n "$TRANSCRIPT_PATH" ] && [ -f "$TRANSCRIPT_PATH" ]; then
# 获取最后一条用户消息(作为任务描述)
LAST_PROMPT=$(tail -100 "$TRANSCRIPT_PATH" | jq -r 'select(.role == "user") | .content[0].text // ""' | tail -1 | head -c 60)
# 如果有用户提示,用它作为消息内容
if [ -n "$LAST_PROMPT" ]; then
MESSAGE="${LAST_PROMPT}..."
fi
fi
# 自定义音效文件路径
CUSTOM_SOUND="/Users/yourusername/.claude/scripts/cc-complete-music.mp3"
# 发送通知(只包含标题和消息,不含副标题)
# macOS 通知不支持自定义音效,所以我们先发送静默通知,然后播放自定义音效
osascript -e "display notification \"$MESSAGE\" with title \"$TITLE\""
# 播放自定义音效(如果文件存在)
if [ -f "$CUSTOM_SOUND" ]; then
afplay "$CUSTOM_SOUND" &
echo "[DEBUG] Playing custom sound: $CUSTOM_SOUND" >> ~/.claude/notify-debug.log
else
# 如果自定义音效不存在,播放系统默认音效
afplay /System/Library/Sounds/Glass.aiff &
echo "[DEBUG] Custom sound not found, using system Glass sound" >> ~/.claude/notify-debug.log
fi
# 记录日志(包含项目名称)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$PROJECT_NAME] Session: $SESSION_ID | $MESSAGE" >> ~/.claude/completion.log
exit 0
3. 使用说明
赋予执行权限
chmod +x ~/.claude/scripts/notify-with-summary.sh
准备音效文件
将你生成的御姐音效 MP3 文件放到:
~/.claude/scripts/cc-complete-music.mp3
如果想使用其他音效,修改脚本中的 CUSTOM_SOUND 路径即可。
关注我,获取更多摸鱼技巧...啊不,生产力工具教程!