A shared Windows 11 toast notifier with thin adapters for Codex CLI, Claude Code, and Pi.
- Codex CLI: the custom
Stophook is used only for completion notifications, with filtering for known background/synthetic events. Questions and approvals use Codex's native TUI notifications (async-questionandapproval-requested) delivered through Windows Terminal OSC9, so only prompts that actually reach the user produce attention notifications. - Claude Code:
Stopsends completion notifications,PreToolUse(AskUserQuestion)notifies for structured questions, and selectedNotificationevents (permission_prompt,elicitation_dialog,agent_needs_input) notify when user attention is required. On Windows the installer uses Claude Code exec-form hooks (powershell.exe+args) so stdin reaches the adapter without a nestedcmd.exeshell. - Pi: the extension records the last
turn_endassistant text and sends completion onagent_settled. When@juicesharp/rpiv-ask-user-questionis installed, it also listens to that plugin's stablerpiv:ask-user:promptevent and sends a question notification without modifying the plugin. - Shared layer: Windows PowerShell 5.1/WinRT
ToastNotificationManager. PowerShell 7 runs the installer, while the toast adapters use Windows PowerShell 5.1 because its .NET Framework host exposes the legacyContentType=WindowsRuntimeprojection directly. PowerShell 7 runs on modern .NET and needs additional Windows SDK .NET interop assemblies for the same projection; this project avoids that dependency.
The default AppUserModelID is Windows Terminal:
Microsoft.WindowsTerminal_8wekyb3d8bbwe!App
That keeps the notification routed through an installed Windows application identity instead of requiring a custom Start-menu shortcut registration.
From this directory in PowerShell 7 (required by the installer for ConvertFrom-Json -AsHashtable):
pwsh -NoProfile -File .\install.ps1The installer is additive and idempotent:
- copies the shared runtime to
~/.agent-hooks/windows-notify; - appends only the Codex
Stopcompletion hook, removes legacywindows-cli-notifyPreToolUse/PermissionRequestattention hooks, and configures native TUI notifications forapproval-requestedandasync-question; - appends or migrates Claude Code
Stop,PreToolUse(AskUserQuestion), and selectedNotificationgroups in~/.claude/settings.jsonwithout replacing unrelated hooks; Windows handlers use exec form rather thancmd.exe; - installs Pi from
git:https://github.com/nonlog/windows-cli-notify, sopi updatecan update the extension; an old local~/.pi/agent/extensions/windows-notify.tscopy is backed up and removed during migration; - creates timestamped backups before modifying an existing config file.
Codex only needs the windows-cli-notify Stop hook trusted. Questions and approvals use Codex's native TUI notification path and require no extra hook trust.
Current Codex has a Windows hook runner bug when commandWindows contains embedded quoted paths. The installer therefore uses a space-free install root and configures a quote-free command such as:
cmd.exe /d /c C:\Users\www\.agent-hooks\windows-notify\adapters\codex-stop.cmd
The batch wrapper may quote its own script paths safely after Codex has launched it.
Foreground suppression is disabled by default so every completion can toast, even while Windows Terminal is in the foreground. Set this to true only if you explicitly want to suppress those notifications:
{
"suppressWhenWindowsTerminalForeground": false
}The current implementation cannot reliably map a Windows Terminal HWND back to a specific WT_SESSION, so suppression is process-wide rather than tab-specific.
Set AI_CLI_NOTIFY_FORCE=1 to bypass foreground suppression for testing.
Edit the installed ~/.agent-hooks/windows-notify/notify-config.json or the repository copy before reinstalling:
{
"appId": "Microsoft.WindowsTerminal_8wekyb3d8bbwe!App",
"maxMessageChars": 420,
"maxCwdChars": 140,
"suppressWhenWindowsTerminalForeground": false,
"showWorkingDirectory": true,
"logFailures": true
}Failures are best-effort logged to %LOCALAPPDATA%\AgentHooks\windows-notify.log and never fail an agent turn.
Pi can also be installed independently with pi install git:https://github.com/nonlog/windows-cli-notify. When loaded as a Pi Git package, the extension uses the repository's bundled shared/notify.ps1; the ~/.agent-hooks/windows-notify fallback remains for local/manual installs.
Adapter parsing without a real toast:
pwsh -NoProfile -File .\tests\smoke.ps1Force one real toast:
pwsh -NoProfile -File .\test-notification.ps1| CLI | Event | Notification |
|---|---|---|
| Codex CLI | Stop |
Foreground/root task completion after background-event filtering |
| Codex CLI | native async-question |
A question actually reached the Codex TUI |
| Codex CLI | native approval-requested |
An approval actually reached the Codex TUI |
| Claude Code | Stop |
Main-agent completion |
| Claude Code | PreToolUse(AskUserQuestion) |
Claude asks a structured question |
| Claude Code | Notification (permission_prompt, elicitation_dialog, agent_needs_input) |
Claude requires user attention |
| Pi | agent_settled |
Completion after retry/compaction/queued continuation is finished |
| Pi | rpiv:ask-user:prompt |
Question emitted by @juicesharp/rpiv-ask-user-question |
Codex subagent/non-root transcript events are intentionally suppressed. Legacy hook-based Codex question/permission notifications are removed during install because PermissionRequest can fire before auto-review and create false alerts. Pi's question notification is optional and activates automatically when the ask-user-question plugin emits its public event.