Last active
July 11, 2026 17:46
-
-
Save Gravifer/cdcb36e2f0622ade9e5faf16e68fae93 to your computer and use it in GitHub Desktop.
Use Windows Powershell 5.1 + WinRT to let Claude Code CLI notify with toasts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| $AppId = 'ClaudeCode.Notify' | |
| $RegPath = "HKCU:\Software\Classes\AppUserModelId\$AppId" | |
| New-Item -Path $RegPath -Force | |
| New-ItemProperty -Path $RegPath -Name DisplayName -Value 'Claude Code' -PropertyType ExpandString -Force | |
| New-ItemProperty -Path $RegPath -Name IconUri -Value $pngPath -PropertyType ExpandString -Force |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Add-Type -AssemblyName System.Drawing | |
| $icon = [System.Drawing.Icon]::ExtractAssociatedIcon("~\.local\bin\claude.exe") | |
| $bmp = $icon.ToBitmap() | |
| $pngPath = "C:\path\you\choose\claude-icon.png" # will be 32x32; need to dig further to get larger ones | |
| $bmp.Save($pngPath, [System.Drawing.Imaging.ImageFormat]::Png) | |
| "$pngPath -> $($bmp.Width)x$($bmp.Height)" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { // ~/.claude/settings.json | |
| "hooks": { | |
| "Notification": [ | |
| { | |
| "matcher": "", // remember to customize | |
| "hooks": [ | |
| { | |
| "type": "command", // remember to customize the text | |
| "command": "powershell -nol -noni -nop -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > \\$null; \\$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); \\$x = [xml]\\$t.GetXml(); (\\$x.toast.visual.binding.text | Where-Object id -eq '1').AppendChild(\\$x.CreateTextNode('Claude Code')) > \\$null; (\\$x.toast.visual.binding.text | Where-Object id -eq '2').AppendChild(\\$x.CreateTextNode('powershell + WinRT')) > \\$null; \\$s = New-Object Windows.Data.Xml.Dom.XmlDocument; \\$s.LoadXml(\\$x.OuterXml); \\$n = [Windows.UI.Notifications.ToastNotification]::new(\\$s); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ClaudeCode.Notify').Show(\\$n)\"" | |
| } | |
| ] | |
| } | |
| ] | |
| } | |
| } |
Author
Author
Filled Example:
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "powershell -nol -noni -nop -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > \\$null; \\$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); \\$x = [xml]\\$t.GetXml(); (\\$x.toast.visual.binding.text | Where-Object id -eq '1').AppendChild(\\$x.CreateTextNode('Permission requested')) > \\$null; (\\$x.toast.visual.binding.text | Where-Object id -eq '2').AppendChild(\\$x.CreateTextNode('Do you want to proceed?')) > \\$null; \\$s = New-Object Windows.Data.Xml.Dom.XmlDocument; \\$s.LoadXml(\\$x.OuterXml); \\$n = [Windows.UI.Notifications.ToastNotification]::new(\\$s); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ClaudeCode.Notify').Show(\\$n)\""
}
]
},
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "powershell -nol -noni -nop -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > \\$null; \\$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); \\$x = [xml]\\$t.GetXml(); (\\$x.toast.visual.binding.text | Where-Object id -eq '1').AppendChild(\\$x.CreateTextNode('Claude Code CLI: idle')) > \\$null; (\\$x.toast.visual.binding.text | Where-Object id -eq '2').AppendChild(\\$x.CreateTextNode('Claude is done and waiting')) > \\$null; \\$s = New-Object Windows.Data.Xml.Dom.XmlDocument; \\$s.LoadXml(\\$x.OuterXml); \\$n = [Windows.UI.Notifications.ToastNotification]::new(\\$s); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ClaudeCode.Notify').Show(\\$n)\""
}
]
},
{
"matcher": "auth_success",
"hooks": [
{
"type": "command",
"command": "powershell -nol -noni -nop -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > \\$null; \\$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); \\$x = [xml]\\$t.GetXml(); (\\$x.toast.visual.binding.text | Where-Object id -eq '1').AppendChild(\\$x.CreateTextNode('Authentication succeeded')) > \\$null; (\\$x.toast.visual.binding.text | Where-Object id -eq '2').AppendChild(\\$x.CreateTextNode('Return to the CLI to proceed')) > \\$null; \\$s = New-Object Windows.Data.Xml.Dom.XmlDocument; \\$s.LoadXml(\\$x.OuterXml); \\$n = [Windows.UI.Notifications.ToastNotification]::new(\\$s); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ClaudeCode.Notify').Show(\\$n)\""
}
]
},
{
"matcher": "elicitation_dialog",
"hooks": [
{
"type": "command",
"command": "powershell -nol -noni -nop -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > \\$null; \\$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); \\$x = [xml]\\$t.GetXml(); (\\$x.toast.visual.binding.text | Where-Object id -eq '1').AppendChild(\\$x.CreateTextNode('MCP call requested')) > \\$null; (\\$x.toast.visual.binding.text | Where-Object id -eq '2').AppendChild(\\$x.CreateTextNode('Do you want to proceed?')) > \\$null; \\$s = New-Object Windows.Data.Xml.Dom.XmlDocument; \\$s.LoadXml(\\$x.OuterXml); \\$n = [Windows.UI.Notifications.ToastNotification]::new(\\$s); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ClaudeCode.Notify').Show(\\$n)\""
}
]
},
{
"matcher": "agent_needs_input",
"hooks": [
{
"type": "command",
"command": "powershell -nol -noni -nop -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > \\$null; \\$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); \\$x = [xml]\\$t.GetXml(); (\\$x.toast.visual.binding.text | Where-Object id -eq '1').AppendChild(\\$x.CreateTextNode('Input requested')) > \\$null; (\\$x.toast.visual.binding.text | Where-Object id -eq '2').AppendChild(\\$x.CreateTextNode('Agent is waiting for your input.')) > \\$null; \\$s = New-Object Windows.Data.Xml.Dom.XmlDocument; \\$s.LoadXml(\\$x.OuterXml); \\$n = [Windows.UI.Notifications.ToastNotification]::new(\\$s); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ClaudeCode.Notify').Show(\\$n)\""
}
]
},
{
"matcher": "agent_completed",
"hooks": [
{
"type": "command",
"command": "powershell -nol -noni -nop -Command \"[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType=WindowsRuntime] > \\$null; \\$t = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent([Windows.UI.Notifications.ToastTemplateType]::ToastText02); \\$x = [xml]\\$t.GetXml(); (\\$x.toast.visual.binding.text | Where-Object id -eq '1').AppendChild(\\$x.CreateTextNode('Claude Code CLI: done')) > \\$null; (\\$x.toast.visual.binding.text | Where-Object id -eq '2').AppendChild(\\$x.CreateTextNode('Agent is done working.')) > \\$null; \\$s = New-Object Windows.Data.Xml.Dom.XmlDocument; \\$s.LoadXml(\\$x.OuterXml); \\$n = [Windows.UI.Notifications.ToastNotification]::new(\\$s); [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('ClaudeCode.Notify').Show(\\$n)\""
}
]
}
]
}
}
Author
Per https://code.claude.com/docs/en/hooks#notification-input, you can even use a .ps1 script to parse the json and extract actual messages; I'm cutting corners here to avoid an external script dependence.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
See also: