1. WSL 里跑 Claude Code任务跑完了我却不知道如果你和我一样主力开发环境是 WSL2 Windows TerminalClaude Code 装在 Ubuntu 侧那你大概率遇到过这个场景让 Claude Code 跑一个稍大的重构任务切到浏览器查资料回来一看终端早就跑完了可能已经过去十几分钟。macOS 用户有osascript原生通知Linux 桌面有notify-send但 WSL 夹在中间——它既没有真正的 Linux 桌面总线又和 Windows 的通知中心不互通notify-send在 WSL 里要么报错要么静默失败。这个问题的本质是WSL 是一个没有桌面会话的 Linux 环境它无法直接调用 Windows 的 Toast 通知 API。但 WSL 有一个被很多人忽略的能力——互操作interop它可以直接执行 Windows 侧的.exe程序。所以思路就清晰了在 WSL 里检测到 Claude Code 任务结束时调用 Windows 的powershell.exe再由 PowerShell 的 BurntToast 模块弹出原生 Windows 通知。这篇文章解决的就是这件事让 WSL 里的 Claude Code 每次任务收尾时Windows 右下角弹出通知。适合所有在 WSL 下用 Claude Code 做长任务的开发者尤其是经常挂着任务去干别的事、回来发现早就跑完的人。下面我会给出完整的 PowerShell 通知脚本、WSL 侧调用配置、settings.json骨架以及一次真实的触发验证过程。2. 前置准备TaoToken 接入与 BurntToast 安装在动手改通知之前得先确保 Claude Code 本身能正常跑起来。Claude Code 需要一个可用的模型接入端点我用的是 TaoToken 的 API 服务它兼容 Anthropic 的接口格式配置起来比较直接。TaoToken 的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 端点是 https://taotoken.net/api 。你需要在控制台创建一个 API Key然后把它写进 Claude Code 的环境变量或配置文件里。Claude Code 读取配置的方式是环境变量ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY。在 WSL 的~/.bashrc或~/.zshrc里加上export ANTHROPIC_BASE_URLhttps://taotoken.net/api export ANTHROPIC_API_KEYsk-你的key改完执行source ~/.bashrc让它生效。这一步是后面所有通知逻辑的前提——如果 Claude Code 本身跑不起来通知也就无从谈起。接下来是 Windows 侧的 BurntToast 模块。BurntToast 是一个 PowerShell 模块专门用来发送 Windows Toast 通知比直接调 WinRT API 简单得多。在Windows PowerShell不是 WSL 里的中以管理员身份运行Install-Module -Name BurntToast -Scope CurrentUser -Force装完后验证一下Import-Module BurntToast New-BurntToastNotification -Text 测试标题, 测试内容如果右下角弹出了通知说明 Windows 侧准备好了。这一步很关键因为后面 WSL 调用的就是这个模块。如果这里不弹先排查 PowerShell 执行策略Set-ExecutionPolicy RemoteSigned -Scope CurrentUser和模块是否装到了当前用户目录。3. 可复制配置PowerShell 通知脚本 WSL 调用3.1 编写 PowerShell 通知脚本在 Windows 侧建一个脚本文件比如C:\Users\你的用户名\notify.ps1内容如下param( [string]$Title Claude Code, [string]$Body 任务已完成 ) try { Import-Module BurntToast -ErrorAction Stop New-BurntToastNotification -Text $Title, $Body exit 0 } catch { Write-Error BurntToast 发送失败: $_ exit 1 }这个脚本接收两个参数标题和正文。核心就一行New-BurntToastNotification外面包了 try/catch 方便排查。注意-ErrorAction Stop是必须的否则模块导入失败时不会抛异常脚本会静默返回 0你就不知道通知到底发出去没有。3.2 WSL 侧调用封装在 WSL 里建一个 shell 脚本~/.claude/notify.sh#!/bin/bash TITLE${1:-Claude Code} BODY${2:-任务已完成} # 优先用 pwsh.exe回退到 powershell.exe if command -v pwsh.exe /dev/null; then PSpwsh.exe elif command -v powershell.exe /dev/null; then PSpowershell.exe else echo 未找到 PowerShell跳过通知 2 exit 1 fi # 转义单引号防止注入 SAFE_TITLE$(printf %s $TITLE | sed s///g) SAFE_BODY$(printf %s $BODY | sed s///g) $PS -NoProfile -Command Import-Module BurntToast; New-BurntToastNotification -Text $SAFE_TITLE, $SAFE_BODY 2/dev/null给它执行权限chmod x ~/.claude/notify.sh。这里有几个设计点值得说明。第一pwsh.exe和powershell.exe的查找顺序——PowerShell 7pwsh性能更好但很多机器只装了 Windows PowerShell 5.1所以做了回退。第二单引号转义是必须的因为通知内容里如果出现单引号会破坏 PowerShell 命令的字符串边界轻则报错重则执行意外命令。第三-NoProfile能加快启动速度避免加载用户的 PowerShell 配置文件拖慢通知。3.3 settings.json 骨架Claude Code 支持通过 hooks 在特定事件触发时执行命令。在~/.claude/settings.json里配置 Stop hook让每轮对话结束时调用通知脚本{ hooks: { Stop: [ { matcher: , hooks: [ { type: command, command: bash ~/.claude/notify.sh Claude Code 任务已完成请查看终端 } ] } ] } }Stop事件在 Claude Code 完成一轮响应后触发正好对应任务收尾这个时机。matcher留空表示匹配所有情况。如果你只想在特定项目里启用可以把这段配置放到项目根目录的.claude/settings.json里。4. 验证请求跑一次任务看通知是否弹出配置写完了得实际验证。最直接的方式是手动调用脚本bash ~/.claude/notify.sh 测试通知 这是一条来自 WSL 的消息如果 Windows 右下角弹出通知说明 PowerShell 链路通了。如果没弹先看命令有没有报错再检查 BurntToast 是否装好。手动验证通过后跑一次真实的 Claude Code 任务。随便给个需要几秒的指令比如让它读一个文件并总结claude -p 读取 ~/.bashrc 并总结里面配置了哪些环境变量任务结束后Stop hook 会触发通知脚本。你应该能看到 Windows 通知中心出现Claude Code - 任务已完成请查看终端。我实测下来从 Claude Code 结束到通知弹出大约有 1 到 2 秒延迟主要花在 PowerShell 进程启动上。这个延迟完全可以接受毕竟通知的意义是提醒你回来看不是毫秒级同步。如果你想验证通知内容是否动态可以改一下脚本把任务摘要传进去。比如在 hook 命令里用$CLAUDE_LAST_MESSAGE之类的变量具体变量名看 Claude Code 版本把最后一条消息的前 100 字符作为通知正文。这样通知就不只是任务完成而是能直接看到结果概要。5. 本篇常见错排查5.1 通知完全不弹脚本也没报错最常见的原因是 PowerShell 执行策略限制。在 Windows PowerShell 里运行Get-ExecutionPolicy如果是Restricted改成RemoteSignedSet-ExecutionPolicy RemoteSigned -Scope CurrentUser另一个可能是 BurntToast 装到了系统级但当前用户加载不到。用Get-Module -ListAvailable BurntToast确认模块路径如果不在用户目录重装时加-Scope CurrentUser。5.2 报错 New-BurntToastNotification 不是可识别的命令这说明 BurntToast 模块没导入成功。可能是模块没装也可能是 PowerShell 版本太老。BurntToast 要求 PowerShell 5.1 以上Windows 10 自带的版本一般够用。如果用的是 PowerShell 7需要单独装模块Install-Module -Name BurntToast -Scope CurrentUser -Force注意 PowerShell 5.1 和 7 的模块目录是分开的在 5.1 里装的模块 7 里不一定能用反之亦然。建议两个都装一遍或者统一用pwsh.exe。5.3 通知弹出了但内容是乱码这是编码问题。WSL 默认 UTF-8Windows PowerShell 5.1 默认可能是 GBK。解决办法是在脚本里显式指定编码或者改用 PowerShell 7默认 UTF-8。如果必须用 5.1可以在调用时加-Encoding UTF8或者在 PowerShell 脚本开头加[Console]::OutputEncoding [System.Text.Encoding]::UTF85.4 hook 不触发先确认settings.json的路径对不对。Claude Code 读的是~/.claude/settings.json用户级或项目根目录的.claude/settings.json项目级。改完配置需要重启 Claude Code 会话才生效。另外检查 JSON 格式多一个逗号少一个括号都会导致整个配置被忽略。可以用python -m json.tool ~/.claude/settings.json验证格式。5.5 通知延迟特别大如果每次通知要等五六秒多半是 PowerShell 启动时加载了用户配置文件。确认调用时带了-NoProfile。另外如果 WSL 的/mnt/c挂载性能差比如跨文件系统访问慢也会拖慢.exe调用。这种情况可以把脚本放到 Windows 侧WSL 只负责传参。6. 把通知链路固化下来整套方案跑通后建议把notify.sh和settings.json纳入你的 dotfiles 管理换机器时直接同步。如果你用的是 TaoToken 的 Coding Plan 做长期编码任务配合这个通知机制体验会好很多——长任务跑着你可以放心去开会或查文档任务一结束 Windows 就提醒你。需要提醒的是通知脚本里的 API Key 不要硬编码在脚本里用环境变量引用。TaoToken 的 API Key 在控制台的 API Keys 页面管理定期轮换是个好习惯。接入文档在 https://taotoken.net/api 可以查到具体的接口格式和参数说明。最后说个实际踩过的坑BurntToast 的通知在 Windows 专注助手Focus Assist开启时会被静默拦截通知中心里能看到但不会弹横幅。如果你发现通知发了但没弹先检查专注助手是不是开着。这个不是脚本的问题是 Windows 的通知策略在设置里把专注助手关掉或者把 PowerShell 加入优先列表就行。