Windows Toast Notifications - WSL Installation Guide with Claude Code integration
This guide covers installing toast notifications for WSL (Windows Subsystem for Linux) and MSYS2/Git Bash environments that integrate with Windows notifications.
- ✅ Automatic Backup: Your existing
.claude/settings.jsonis backed up with a timestamp - ✅ Non-Hook Settings Preserved: Model preferences, API keys, etc. are kept
⚠️ Hooks Are Replaced: Any existing Claude Code hooks will be replaced with toast notification hooks- 📍 Backup Location:
~/.claude/settings.json.backup_YYYYMMDD_HHMMSS
- Predictable behavior - You know exactly what hooks are active
- No conflicts - Prevents duplicate or conflicting hook configurations
- Clean installation - Ensures toast notifications work optimally
- Easy troubleshooting - Clear hook configuration for debugging
- Your hooks will be backed up automatically before installation
- Toast notification hooks will replace them for optimal functionality
- To restore your old hooks: Copy from the backup file after installation
- To merge hooks manually: Edit the settings.json file after installation
The WSL installer automatically handles Windows dependencies using a system-wide installation approach - just run the WSL script and it will set up everything needed!
-
For MSYS2/Git Bash users, export PowerShell to PATH first:
# Required for MSYS2/Git Bash environments export PATH="/c/Windows/System32/WindowsPowerShell/v1.0:$PATH" echo 'export PATH="/c/Windows/System32/WindowsPowerShell/v1.0:$PATH"' >> ~/.bashrc source ~/.bashrc # Verify PowerShell is accessible powershell.exe -Command "Get-Host | Select-Object Version"
Note: Skip this step if you're in true WSL - only needed for MSYS2/Git Bash.
-
Download and run the installer:
curl -fsSL 'https://gist.githubusercontent.com/ChrisColeTech/010a3a1f313fa39a10566a328c32424b/raw/wsl_toast_install.sh' -o install_toast_wsl.sh && bash install_toast_wsl.sh
The installer will:
- Check for existing global Windows toast installation
- Install Windows toast to system-wide location if needed
- Set up WSL integration using global paths
- Configure shell functions automatically
-
Reload your shell configuration (IMPORTANT - Shell Specific):
For Bash users:
source ~/.bashrc
For Zsh users:
source ~/.zshrc
For Fish users:
source ~/.config/fish/config.fish
Important Notes:
- The installer creates functions in BOTH
.bashrcand.zshrcfor compatibility - You MUST source the config file for your current shell
- If unsure which shell you're using, run:
echo $SHELL - For a completely fresh start: close and reopen your terminal
- The installer creates functions in BOTH
toast "Test" "Hello from WSL"Expected Result: You should see a Windows toast notification appear in the bottom-right corner of your screen.
Run these commands to verify everything is working correctly:
# Check that toast function is available
type toast
# Verify the system-wide Windows installation exists
ls /mnt/c/ProgramData/Toast/toast.ps1
# Test both function and binary methods work
toast "Function Test" "Testing shell function"
~/bin/toast "Binary Test" "Testing direct binary"
# Check your shell configuration was updated
grep -A 5 "wsl toast helper" ~/.bashrc ~/.zshrcIf any of these fail, see the Comprehensive Troubleshooting section below.
The WSL toast function:
- Calls the Windows PowerShell script via interop
- Uses the global system path
/mnt/c/ProgramData/Toast/toast.ps1 - Passes arguments through to Windows notification system
- Displays native Windows toast notifications
toast "Build Complete"
toast "Error" "Something went wrong"
toast "Long Running Task" "Your process has finished successfully"#!/bin/bash
# Build script example
npm run build
if [ $? -eq 0 ]; then
toast "Build Success" "Project built successfully"
else
toast "Build Failed" "Check the logs for errors"
fiIMPORTANT: Create the hooks configuration file in your HOME directory:
~/.claude/settings.json (typically /home/[username]/.claude/settings.json)
DO NOT create it in the project directory .claude/settings.json
{
"model": "sonnet",
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"New session started - Ready to help!\""
}
]
},
{
"matcher": "resume",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Session resumed - Continuing where we left off\""
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Processing your request...\""
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Executing bash command\""
}
]
},
{
"matcher": "Task",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Starting specialized task agent\""
}
]
}
],
"PostToolUse": [
{
"matcher": "Write",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"File created successfully\""
}
]
},
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"File edited successfully\""
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"⚠️ User input needed to continue\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"✅ Task completed successfully\""
}
]
}
],
"SubagentStop": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"🤖 Subagent task finished\""
}
]
}
]
}
}| Hook Type | When It Triggers | Purpose |
|---|---|---|
SessionStart |
New session or resume | Welcome notifications |
UserPromptSubmit |
When you send a message | Confirms input received |
PreToolUse |
Before tool execution | Shows what's about to happen |
PostToolUse |
After successful tool use | Confirms completion |
Notification |
Claude needs permission or idle timeout | Attention alerts |
Stop |
Main agent finishes responding | Task completion |
SubagentStop |
Specialized agent finishes | Subtask completion |
For production use, these essential hooks provide the most valuable notifications without overwhelming you:
{
"model": "sonnet",
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"New session started - Ready to help!\""
}
]
},
{
"matcher": "resume",
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Session resumed - Continuing where we left off\""
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"⚠️ User input needed to continue\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"✅ Task completed successfully\""
}
]
}
],
"SubagentStop": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"🤖 Subagent task finished\""
}
]
}
],
"PreCompact": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"📝 Compacting context to continue\""
}
]
}
]
}
}For a simpler setup, use just the essential hooks:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Task complete\""
}
]
}
],
"Notification": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Input needed\""
}
]
}
]
}
}Available Hook Events:
PreToolUse- Before tool executionPostToolUse- After tool executionNotification- For notificationsUserPromptSubmit- When user submits promptsStop- When sessions stopSubagentStop- When subagents stopPreCompact- Before context compactionSessionStart- When sessions begin
Configuration Parameters:
type: "command" (only supported type)command: Command to execute (bash compatible in WSL)timeout: Optional timeout in secondsmatcher: Tool name pattern (exact, regex, or*wildcard)
Configuration Files (in order of precedence):
.claude/settings.local.json(local project settings).claude/settings.json(project-wide settings)~/.claude/settings.json(user-wide settings)
Temporarily Muting Hooks: To temporarily disable specific hooks:
- Comment out: Add
//before the hook entry in JSON - Rename event: Change
"PreToolUse"to"_PreToolUse" - Remove temporarily: Delete the hook entry
Example of commenting out a hook:
{
"hooks": {
// "PreToolUse": [
// {
// "matcher": "Bash",
// "hooks": [
// {
// "type": "command",
// "command": "toast \"Claude Code\" \"Executing bash command\""
// }
// ]
// }
// ],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "toast \"Claude Code\" \"Task complete\""
}
]
}
]
}
}Important: Hooks are captured at startup, so restart Claude Code after making changes.
curl -fsSL 'https://gist.githubusercontent.com/ChrisColeTech/42d5862c4817c269ef6aa42f7ff490ce/raw/wsl_toast_uninstall.sh' -o uninstall_toast_wsl.sh
bash uninstall_toast_wsl.sh- Edit
~/.bashrcand~/.zshrc - Remove the toast function block between
# -- wsl toast helper start --and# -- wsl toast helper end -- - Reload your shell:
source ~/.bashrcorsource ~/.zshrc
Note: This only removes WSL integration. To remove Windows toast support, follow the uninstall instructions in README-Windows.md.
Cause: Shell config not loaded or wrong shell being used
Solutions (try in order):
-
Check your current shell:
echo $SHELL
-
Source the correct config file:
# If you're using bash: source ~/.bashrc # If you're using zsh: source ~/.zshrc # If you're using fish: source ~/.config/fish/config.fish
-
Verify function was installed:
# For bash/zsh: grep -A 5 "wsl toast helper" ~/.bashrc ~/.zshrc # Check if executable exists: ls -la ~/bin/toast
-
Fresh terminal:
- Close and reopen your terminal completely
- Or run:
exec $SHELL -lto restart shell
Symptoms: Error like C:\Users\username\bin\toast.ps1 not found
Cause: Old function definitions cached in current session or shell snapshots
Solutions:
-
Clear function and restart:
unset -f toast unalias toast 2>/dev/null source ~/.bashrc # or ~/.zshrc
-
For Claude Code users - shell snapshot conflict:
# Force fresh shell without snapshots exec bash -l # or exec zsh -l
-
Test with binary directly:
~/bin/toast "Test" "Direct binary test"
Solutions:
-
For MSYS2/Git Bash - ensure PowerShell in PATH:
export PATH="/c/Windows/System32/WindowsPowerShell/v1.0:$PATH"
-
Test PowerShell access:
powershell.exe -Command "Get-Host" -
Re-run installer to fix Windows components:
curl -fsSL 'https://gist.githubusercontent.com/ChrisColeTech/010a3a1f313fa39a10566a328c32424b/raw/wsl_toast_install.sh' -o install_toast_wsl.sh && bash install_toast_wsl.sh
Symptoms: C:\ProgramData\Toast\toast.ps1 not found
Solutions:
-
Check if system-wide installation exists:
ls /mnt/c/ProgramData/Toast/toast.ps1
-
Re-run installer to install Windows components:
# The installer automatically installs Windows components if missing bash install_toast_wsl.sh -
Manual Windows installation (if automatic fails):
# Run in Windows PowerShell as Administrator curl.exe -fsSL 'https://gist.githubusercontent.com/ChrisColeTech/1f79919c60bf210982a04bc607a1a1d7/raw/windows_toast_install.ps1' -o install_toast.ps1 powershell -ExecutionPolicy Bypass -File install_toast.ps1
Check your environment:
# WSL will show /mnt/c
ls /mnt/c 2>/dev/null && echo "WSL environment" || echo "MSYS2/Git Bash environment"
# Check mount points
mount | grep -E "/mnt/c|/c"Determine your shell environment:
# Current shell
echo "Current shell: $SHELL"
echo "Shell type: $0"
# Check which config files exist
ls -la ~/.bashrc ~/.zshrc ~/.config/fish/config.fish 2>/dev/null
# See which shell configs have toast function
grep -l "toast helper" ~/.bashrc ~/.zshrc 2>/dev/nullIf the automatic cleanup fails, manually remove all toast installations:
# Remove all toast scripts
rm -f ~/bin/toast ~/.local/bin/toast /usr/local/bin/toast /tmp/toast /var/tmp/toast
# Remove empty directories
rmdir ~/bin ~/.local/bin 2>/dev/null || true
# Clean shell configs
for rc in ~/.bashrc ~/.zshrc ~/.profile ~/.bash_profile; do
if [[ -f "$rc" ]]; then
echo "Cleaning $rc..."
# Remove toast helper blocks
sed -i '/# -- .*[Tt]oast.*helper start --/,/# -- .*[Tt]oast.*helper end --/d' "$rc"
# Remove standalone functions
sed -i '/^[[:space:]]*toast()[[:space:]]*{/,/^}/d' "$rc"
# Remove PowerShell PATH exports
sed -i '/export PATH.*WindowsPowerShell.*PATH/d' "$rc"
sed -i '/export PATH.*powershell.*PATH/d' "$rc"
fi
done
# Restart shell
exec $SHELL -l# Verify no toast functions remain
type toast 2>&1 | grep -q "not found" && echo "✓ Clean" || echo "⚠ Still found"
# Check for remaining files
ls ~/bin/toast ~/.local/bin/toast 2>/dev/null || echo "✓ No old scripts"
# Check shell configs
grep -r "toast" ~/.bashrc ~/.zshrc ~/.profile 2>/dev/null || echo "✓ Clean configs"# Run installer with debug output
bash -x install_toast_wsl.sh
# Test function with debug
set -x
toast "Debug Test" "Checking execution path"
set +x# Direct PowerShell test
"/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe" -ExecutionPolicy Bypass -Command "& 'C:\ProgramData\Toast\toast.ps1' 'Direct Test' 'Bypassing WSL function'"
# Check file permissions
ls -la "/mnt/c/ProgramData/Toast/toast.ps1"
# Test Windows notification system
powershell.exe -Command "[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null"If you're still having issues after trying these solutions:
-
Check your environment details:
echo "OS: $(uname -a)" echo "Shell: $SHELL" echo "PATH: $PATH" echo "Home: $HOME" ls -la ~/.bashrc ~/.zshrc 2>/dev/null
-
Create a minimal test case:
# Test basic PowerShell access powershell.exe -Command "Write-Host 'PowerShell works'" # Test Windows file access ls /mnt/c/ProgramData/ 2>/dev/null || ls /c/ProgramData/ 2>/dev/null
-
Report the issue with:
- Your environment details (above output)
- Complete error messages
- Which solutions you tried
- Whether you're using WSL vs MSYS2/Git Bash
After installation, verify everything is working correctly:
type toastExpected output should show:
toast is a function
toast ()
{
local title="${1:-Notification}";
shift;
local body="${*:-}";
"/c/Program Files/PowerShell/7/pwsh.exe" -ExecutionPolicy Bypass -Command "& 'C:\ProgramData\Toast\toast.ps1' '$title' '$body'"
}C:\Users\BvSsh_VirtualUsers\bin\toast.ps1C:\Users\[Username]\bin\toast.ps1
Then cached functions are still active - see troubleshooting below.
toast "Test" "Installation verification"Problem: Claude Code caches shell functions in ~/.claude/shell-snapshots/ which can persist old toast function definitions even after the installer cleans up your profile files.
Symptoms:
toastcommand gives errors about missing files in old pathstype toastshows old function definitions- Notifications don't work despite successful installation
Solutions (in order of preference):
- Close and reopen Claude Code completely
- This clears all cached shell snapshots
- Most reliable solution
unset -f toast && source ~/.bashrcOr for zsh users:
unset -f toast && source ~/.zshrcrm -f ~/.claude/shell-snapshots/*.sh- Open a completely new terminal window
- New terminals load clean function definitions
For MSYS2/Git Bash users:
export PATH="/c/Windows/System32/WindowsPowerShell/v1.0:$PATH"
# Or add to your ~/.bashrc- The installer should handle this automatically
- If issues persist, run in Windows PowerShell:
Install-Module -Name BurntToast -Scope CurrentUser -Force- Check if
~/bin/toastexists and is executable:
ls -la ~/bin/toast- Ensure
~/binis in your PATH:
echo $PATH | grep "$HOME/bin"- If missing, add to your shell profile:
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc- Test basic toast functionality first:
toast "Test" "Basic functionality"- Check Claude Code settings file exists:
ls -la ~/.claude/settings.json- Restart Claude Code after installation to apply hook changes
- Windows 10/11 with WSL installed OR MSYS2/Git Bash
- Bash or Zsh shell
- Access to Windows file system (
/mnt/c/for WSL,/c/for MSYS2) - PowerShell in PATH (automatic in WSL, requires export in MSYS2)
- Internet connection (for downloading and installing components)
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ WSL Terminal │───▶│ Windows Interop │───▶│ Windows Desktop │
│ │ │ │ │ │
│ toast "Hello" │ │ PowerShell.exe │ │ 🔔 Notification │
│ │ │ toast.ps1 │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
- For Windows Setup: See README-Windows.md
- For Development: Check out the local scripts in this directory
- Integration Ideas: Use in CI/CD, build scripts, long-running processes