当 Claude Code 跑在远程服务器上时,notify-send 或 osascript hook 是在服务器上触发的,而服务器上没有桌面可以显示通知。可行的路子有两条。第一条是 terminal 转义序列:Claude Code 的内置通知,或者返回 terminalSequence 的 hook,会沿 SSH 连接传回来,由本地 terminal(Ghostty、Kitty 或 iTerm2)显示,但前提是你保持连接且 terminal 开着。第二条是通过网络从服务器 push 到手机,借助 ntfy、webhook 或 Claude Code Notifier,即使合上笔记本也照常工作。
01为什么本地通知命令在 SSH 下没反应
hook 是 Claude Code 在运行 Claude Code 的那台机器上执行的命令。如果是通过 SSH 连接的服务器,那就是在服务器上执行。在那里用 notify-send 需要桌面通知守护进程,而 Anthropic 的 hooks 指南中提到,headless 服务器和 SSH 会话都没有这个守护进程。至于 osascript 和 PowerShell toast 通知,在服务器上根本就不存在。
所以问题不在于“用哪个通知命令”,而在于“信号怎么从服务器传到我这里”。有三种方式:
02方案 1:通过 SSH terminal 接收通知
Claude Code 自带的通知其实是写到 terminal 的一段转义序列。Anthropic 的 terminal 指南提到它会经 SSH 传到本地机器,所以远程会话也能提醒你。Ghostty 和 Kitty 无需配置就会把它转给桌面通知中心。iTerm2 需要手动开启:Settings > Profiles > Terminal,勾选 Notification Center Alerts,然后在 Filter Alerts 下打开 Send escape sequence-generated alerts。
如果你的 terminal 不在上面之列,或者想自定义文字,可以让 hook 返回一段转义序列,交给 Claude Code 写出。hook 本身没有 terminal,所以要把序列放在 terminalSequence 字段里返回。在服务器上把下面内容保存为 ~/.claude/hooks/notify-ssh.sh:
#!/bin/bash
body=$(jq -r '.message // "Claude Code needs your attention"')
# OSC 9 for iTerm2, WezTerm and ConEmu; use '\033]777;notify;%s;%s\007' for Ghostty
seq=$(printf '\033]9;%s\007' "$body")
jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
然后把它加到服务器上的 ~/.claude/settings.json:
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "~/.claude/hooks/notify-ssh.sh" }
]
}
]
}
}
执行 chmod +x ~/.claude/hooks/notify-ssh.sh,并在服务器上安装 jq。Anthropic 的参考文档列出了支持的序列:OSC 9(iTerm2、ConEmu、Windows Terminal、WezTerm)、OSC 99(Kitty)、OSC 777(urxvt、Ghostty、Warp)以及单纯的响铃。Claude Code 只会在交互式会话中、且界面显示在屏幕上时写出该序列。
这种方式的局限是天生的:SSH 断开、笔记本休眠或关掉标签页,就什么都收不到。如果在 tmux 里运行 Claude Code,要在服务器的 ~/.tmux.conf 中加上 set -g allow-passthrough on;tmux 指南里讲了这一点以及 detached 会话的情况。
03方案 2:从服务器 push
push 不依赖 terminal,所以很适合长时间任务。hook 从服务器发出一个 HTTPS 请求,由某个服务投递到你的手机或聊天工具。ntfy 指南和 Telegram、Slack 和 Discord 指南里都有可直接用的 hook。它们只能告诉你发生了什么,没法批准命令或回答问题,所以 Claude 还是得等你重新连上。
04方案 3:在服务器上运行 Claude Code Notifier
Claude Code Notifier 是一个独立工具(由 TouchTap 开发,并非 Anthropic 出品)。它的免费命令行工具 ccn 支持 Mac、Windows 和 Linux,因此直接装在运行 Claude Code 的服务器上即可:
curl -fsSL https://claudecodenotifier.com/install.sh | sh
它会把自己的 hook 条目加到服务器的 ~/.claude/settings.json 中,保留其余配置并做好备份。ccn 的桌面通知显示在 ccn 所在的机器上,在无桌面服务器上等于没用。真正有用的是手机:手机通知经由 TouchTap 的加密中继服务器发送,不走 SSH 连接,所以只要能联网,ccn 跑在哪台机器上都能用。
通过 SSH 配对
配对不需要服务器上有浏览器。一种方式是在 SSH 会话中运行 ccn pair,它会在 terminal 里打印一个二维码供手机相机扫描,外加一个 24 小时内有效的链接。另一种是在手机上打开 app,进入 Computers > Add a computer,运行它显示的那行命令,安装和配对一步完成:
curl -fsSL https://claudecodenotifier.com/install.sh | sh -s 482913
(六位数验证码只是示例,请使用 app 中显示的那个。)一部手机可以绑定多台电脑,所以笔记本和服务器都能向它推送。详情见配对指南。
在手机上能做什么
配对完成后,Claude 完成任务、需要权限或提出问题时,你都会收到 push。你可以对权限请求选择允许一次、本次会话内允许或拒绝,可以为 Claude 的问题选一个答案,也可以在 Claude 完成后发送下一条指令。你不在电脑前时,terminal 会等待手机的回复,最长等待时间由你设定;一旦你在键盘上输入,就会立即停止等待。在服务器上运行 ccn doctor 可以检查 hook、凭据以及与中继服务器的连接。手机 App 的价格见定价;命令行工具免费。
05SSH 断开时让 Claude Code 继续运行
这三种方式都要求 Claude Code 本身保持运行。如果你直接在 SSH shell 里启动 claude,连接一断,会话也随之结束。把它放在 tmux 或 GNU screen 里运行,断线后它仍会继续,之后再重新 attach 即可。在 detached 会话中 hook 照常触发,这正是手机 push 派上用场的地方。tmux 指南和离开长时间运行的任务介绍了这套工作流。
06常见问题
为什么通过 SSH 使用 Claude Code 时 notify-send 没有反应?
hook 运行在服务器上,而服务器没有桌面通知守护进程。改用本地 terminal 能识别的转义序列,或者使用 push 服务。
Claude Code 内置的通知能通过 SSH 工作吗?
可以,前提是 terminal 支持。Anthropic 的文档说明,桌面通知可以通过 SSH 到达你的本地机器;Ghostty 和 Kitty 无需配置即可显示,iTerm2 需要先开启转义序列提醒。这要求连接保持打开。
ccn 要装在笔记本上还是服务器上?
装在服务器上,因为 Claude Code 和它的 hook 都在那里运行。如果你在笔记本上也用 Claude Code,那就两边都装;一部手机可以同时与两者配对。
SSH 会话断开后还能收到通知吗?
只能靠服务器发出的 push,而且前提是 Claude Code 仍在运行,比如在 tmux 里。转义序列在连接关闭的那一刻就失效了。
手机通知需要服务器开放端口吗?
ccn 不需要任何入站连接,只需要能出站访问互联网以连接中继服务器。