Blog · September 23, 2026 · 9 min read

Claude Code Notifications on WSL and Windows

If you run Claude Code inside WSL on Windows, you have probably noticed that every notification guide on the internet quietly assumes you are on a Mac. You set up the hook, Claude finishes a task, and — nothing. No sound, no toast, no taskbar flash. You go back to staring at the terminal, which is the exact thing you were trying to stop doing.

This is not you misconfiguring something. WSL is a genuinely awkward environment for notifications, for reasons worth understanding before you start pasting config. Here is what actually breaks, and the three approaches that work.

Why WSL notifications fail in the first place

There are three separate failure points, and most people hit at least two of them.

The terminal bell usually goes nowhere. The classic cross-platform trick is to echo the ASCII bell character — echo -e "\a" — and let the terminal turn it into a sound. In WSL this frequently produces silence. The bell has to survive the trip from the Linux process, through the terminal emulator, to a Windows sound device, and any link in that chain can swallow it.

Linux notification tools do not cross the boundary. The obvious Linux answer is notify-send. Under WSL2 it does not reach Windows: there is no desktop notification daemon on the Windows side listening for it. You can install it, run it, get exit code zero, and see nothing at all. This is the single most common dead end.

Windows Terminal has toasts, but Claude Code does not use them. Windows Terminal supports progress indicators and toast notifications natively. Claude Code running inside WSL does not emit the sequences that trigger them, so the capability sits there unused.

The consequence is that you cannot fix this from the Linux side alone. Something has to deliberately call out to Windows.

The mechanism: hooks plus Windows interop

Claude Code fires hooks on specific events, configured in ~/.claude/settings.json. The two that matter here are Stop, which fires when Claude finishes a response and is waiting for you, and Notification, which fires when Claude needs approval or input mid-task. Hooks receive JSON context on stdin, so a script can read what happened and react to it.

The WSL-specific part is that your hook command needs to invoke powershell.exe rather than a Linux notification tool. WSL interop lets a Linux process launch Windows executables directly, as long as powershell.exe is reachable on your PATH. That single detail is what makes the whole thing work, and checking it is the first thing to do when a setup silently fails:

which powershell.exe

No output means interop is off or PowerShell is not on your path, and nothing below will work until that is fixed. If you have never set up hooks before, our guide to Claude Code hooks covers the general structure first.

Option 1: a sound, in one line

If all you want is an audible ping, this is the lowest-effort thing that reliably works. It calls into Windows and plays a system sound, with no modules to install:

powershell.exe -c "[console]::beep(800,300)"

Wire that as the command for a Stop hook and you are done. It is crude, it carries no information about what happened, and it will not help if your headphones are off — but it takes two minutes and it removes the need to keep glancing at the terminal.

Option 2: real Windows toast notifications

A toast is better than a beep because it survives you looking away and tells you which project finished. The common route is the BurntToast PowerShell module. In a Windows PowerShell session, not inside WSL:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Install-Module BurntToast -Scope CurrentUser -Force

Then your hook command shells out through interop to raise a toast with a title and message. Because hooks receive JSON on stdin, you can parse out the session or project name first and put it in the toast body, which matters a lot once you are running more than one Claude Code session at a time and a bare "done" tells you nothing useful.

Two practical warnings. Windows Focus Assist will suppress toasts without telling you, so check it before concluding your script is broken. And quoting is genuinely painful here: you are nesting a PowerShell string inside a shell string inside JSON, and a single mis-escaped quote fails silently. Put the logic in a small .sh file and point the hook at the file rather than inlining it.

Option 3: skip the desktop entirely

Worth saying plainly, because the WSL toast rabbit hole can eat an afternoon: a desktop notification only helps if you are at the desktop. The whole reason people want Claude Code notifications is usually that they have gone to make coffee, moved to a meeting, or started doing something else while a long task runs.

If that is your situation, routing the notification off the machine is both more useful and considerably easier to configure — there is no interop layer, no execution policy, and no Focus Assist to fight. Phone notifications for Claude Code covers that path, and the same Stop and Notification hooks drive it.

The honest trade-off: a toast is instant and free, and it is the right answer if you mostly stay at your desk and just want to stop context-switching every ninety seconds. Push to a phone wins the moment you leave the room.

A debugging order that saves time

When nothing appears, work through these in order rather than changing several things at once.

  1. Run which powershell.exe. No path, no notifications.
  2. Run your notification command by hand in the WSL shell. If it does not fire when you run it directly, the problem is not Claude Code.
  3. Check Windows Focus Assist and the notification settings for the terminal app you are using.
  4. Confirm the hook is actually firing at all — have it write a line to a log file as well as raising the toast.
  5. Check whether you have settings in both the project .claude/settings.json and your home directory. Precedence surprises are a common cause, and our notifications-not-working guide covers the non-WSL versions of the same problem.

The short version

WSL notifications fail because the Linux side has no way to reach the Windows notification system on its own. The fix is always the same shape: a Claude Code hook that calls powershell.exe through WSL interop. A beep takes two minutes, a BurntToast toast takes about twenty, and if you are not at the desk anyway, sending it to your phone is less work than either.

Keep reading

Claude Code Tips and Tricks: 12 Ways to Use Claude Code Effectively

8 min read

Claude Code Multiple Sessions: How to Run Agents in Parallel Without Losing Track

6 min read

A Claude Code Workflow That Doesn't Involve Watching the Terminal

5 min read

Claude Code Hooks: A Practical Guide to Automating Your Agent Workflow

7 min read

Claude Code Auto Mode: Fewer Permission Prompts Without Living Dangerously

7 min read

Claude Code Subagents: How to Delegate Work to Specialized Agents

7 min read

Claude Code Context Management: Treat the Context Window Like a Budget

6 min read

Per-Subagent Model Selection: Route the Grunt Work Down, Keep the Judgment Up Top

7 min read

Skills and Plugins: How to Teach Claude Code Your Way of Working

7 min read

Claude Code Background Tasks: Run Long Commands Without Blocking Your Session

6 min read

Codex CLI Notifications: How to Get a Ding When Codex Is Done or Needs Input

7 min read

Cursor Notification When Done: Every Way to Get Notified When Cursor Finishes

6 min read

Claude Code Notifications: How to Get Notified When Claude Code Finishes or Needs Your Input

6 min read

Want to Be Notified When Claude Responds? How Claude Notifications Work on Web, Desktop, and Mobile

5 min read

Claude Code Notification Scripts: Copy-Paste Recipes for Every Platform

6 min read

Get a Ding the Moment Codex Needs Your Response

6 min read

Get Notified the Moment Claude Code Is Waiting for Your Input

6 min read

“Notifications Are Turned Off for Claude” — Here Is the Fix

6 min read

Codex Sound When Done: Make Codex CLI Play a Sound When It Finishes

6 min read

terminal-notifier + Claude Code: Native macOS Alerts When Your Agent Finishes

6 min read

Gemini CLI Notifications: How to Get a Sound or Alert When Gemini Finishes

6 min read

Get Claude Code Notifications on Your Phone

6 min read

Claude Code Remote Control, Explained

7 min read

preferredNotifChannel: Claude Code's Built-In Notification Setting

6 min read

Claude Code Notifications in tmux and Over SSH

7 min read

Claude Code Effort Levels: Why Your Setting Keeps Getting Ignored

8 min read

Codex vs Claude Code Notifications: How Each One Tells You It Is Done

8 min read

Claude Code Notifications Not Working: A Diagnostic Checklist

8 min read

Claude Code Notifications Inside Your Editor's Terminal

7 min read

CLAUDE_CODE_DISABLE_BACKGROUND_TASKS Explained

7 min read

CLAUDE_CODE_DISABLE_BG_SHELL_PRESSURE_REAP Explained

8 min read

Cursor Alerts Explained: Every Alert Cursor Raises, and How to Control Them

7 min read

Claude Code Environment Variables: The Groups That Actually Matter

10 min read