Skip to content

Instantly share code, notes, and snippets.

@Gravifer
Last active July 11, 2026 17:46
Show Gist options
  • Select an option

  • Save Gravifer/cdcb36e2f0622ade9e5faf16e68fae93 to your computer and use it in GitHub Desktop.

Select an option

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
$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
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)"
{ // ~/.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)\""
}
]
}
]
}
}
@Gravifer

Copy link
Copy Markdown
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)\""
          }
        ]
      }
    ]
  }
}

@Gravifer

Copy link
Copy Markdown
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