What actually cuts a coding agent's token use: 19 measured studies
We measured what lowers Codex token usage over whole tasks. Prompts and retrieval barely helped; a structured workflow cut 87.56% on suitable migrations.
Read the articleIn Windows Terminal, Claude Code does not notify you by default. You find out it was waiting for permission ten minutes after it started waiting. Here are two fixes, one of them a tested PowerShell script.
powershell.exe, not PowerShell 7. The newer one cannot load the Windows notification classes.You give Claude Code a task, switch to your browser, and come back fifteen minutes later to find it stopped after thirty seconds to ask whether it may run npm install. On a Mac in iTerm2 you would have had a notification. On Windows you got nothing.
Here is why, and two ways to fix it. Everything is based on Anthropic's settings and hooks documentation and Microsoft's Windows Terminal docs as of 4 October 2026.
We ran into this problem while building AigoPilot, a Claude Code GUI for Windows that sends these notifications for every Claude Code and Codex session. You do not need it to fix the problem: both fixes below work on their own.
Claude Code has a setting called preferredNotifChannel, shown as "Local notifications" in /config. Its default is auto. In iTerm2, Ghostty and Kitty, auto sends a desktop notification. In Apple's Terminal it rings the bell in some cases. In every other terminal, Anthropic's docs say, it does nothing. Windows Terminal is one of those others.
So there are two ways out: ask Claude Code to ring the terminal bell and let Windows Terminal turn that into something visible, or attach your own notification with a hook.
This takes a minute and needs no scripts. In Claude Code, run /config and set Local notifications to terminal_bell, or put this in %USERPROFILE%\.claude\settings.json:
{
"preferredNotifChannel": "terminal_bell"
}Then tell Windows Terminal what to do with a bell. Open its settings (Ctrl + ,), choose "Open JSON file" at the bottom left, and add bellStyle to the profile defaults:
"profiles": {
"defaults": {
"bellStyle": "all"
}
}With all, a bell plays a sound and flashes the Windows Terminal button on the taskbar; when the window is in the background, only the taskbar flashes. The other values are audible (the default), window, taskbar and none.
The limit of this fix: a flashing taskbar button tells you something happened, not what, and not in which of your four terminal tabs.
Hooks are commands Claude Code runs when something happens. Two events matter here:
Notification fires when Claude Code wants your attention. Its permission_prompt type fires once a permission prompt has waited about six seconds, and idle_prompt fires about sixty seconds after Claude finished, if you have not typed since. In a terminal, both fire only when you seem to be away.Stop fires every time Claude finishes a reply.Hooks run alongside the built-in setting, so you can keep Fix 1 as well.
Save this as notify.ps1 in your %USERPROFILE%\.claude folder. It reads what Claude Code sends the hook, builds a two-line notification and shows it through Windows' own notification system. No module to install.
# notify.ps1: shows a Windows notification for Claude Code.
# Run it with Windows PowerShell (powershell.exe), not PowerShell 7.
[Console]::InputEncoding = [Text.Encoding]::UTF8
$data = [Console]::In.ReadToEnd() | ConvertFrom-Json
$project = Split-Path $data.cwd -Leaf
if ($data.hook_event_name -eq 'Stop') {
$title = "Claude Code finished"
$text = "The session in $project is waiting for your next prompt."
} else {
$title = "Claude Code needs you"
$text = "$($data.message) ($project)"
}
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
$xml.LoadXml(@"
<toast><visual><binding template="ToastGeneric">
<text>$([Security.SecurityElement]::Escape($title))</text>
<text>$([Security.SecurityElement]::Escape($text))</text>
</binding></visual></toast>
"@)
# Windows PowerShell's own app id, so the notification has a sender Windows already knows.
$appId = '{1AC14E77-02E7-4E5D-B744-2EB1AE5198B7}\WindowsPowerShell\v1.0\powershell.exe'
$toast = [Windows.UI.Notifications.ToastNotification]::new($xml)
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier($appId).Show($toast)The notification appears under the name "Windows PowerShell". That is the sender the script borrows, because Windows only shows notifications from programs it knows.
Before wiring it to Claude Code, check that Windows shows it. In PowerShell:
'{"hook_event_name":"Notification","message":"Test from PowerShell","cwd":"C:\\demo"}' | powershell.exe -NoProfile -ExecutionPolicy Bypass -File "$env:USERPROFILE\.claude\notify.ps1"A notification titled "Claude Code needs you" should slide in at the bottom right. If nothing appears, check that notifications and Do not disturb are set the way you expect in Windows Settings, under System, Notifications.
Open %USERPROFILE%\.claude\settings.json and add a hooks section. Replace YOUR-NAME with your Windows user folder name. The path uses forward slashes on purpose: they work whether Claude Code runs the hook through Git Bash or through PowerShell.
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [{ "type": "command", "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:/Users/YOUR-NAME/.claude/notify.ps1" }]
},
{
"matcher": "idle_prompt",
"hooks": [{ "type": "command", "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:/Users/YOUR-NAME/.claude/notify.ps1" }]
}
],
"Stop": [
{
"hooks": [{ "type": "command", "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:/Users/YOUR-NAME/.claude/notify.ps1" }]
}
]
}
}If your settings.json already has content, merge the hooks key into it rather than pasting a second set of braces. Restart Claude Code, or open /hooks to check that it sees them.
Stop fires after every reply, including the ones you were watching. If that gets noisy, delete the Stop block and keep idle_prompt, which only fires when a finished session has sat untouched for about a minute. If six seconds is too long to wait for permission prompts, the PermissionRequest event fires the moment a tool call needs your decision.
claude --debug; the log in %USERPROFILE%\.claude\debug\ shows each hook that ran and what it printed.Windows.UI.Notifications. The script probably ran in PowerShell 7 (pwsh). .NET 5 and later removed built-in support for these Windows classes. Call powershell.exe, as in the settings above.powershell.exe can be found from Linux. Point -File at the Windows path of the script.Most older guides use the BurntToast PowerShell module: Install-Module -Name BurntToast, then New-BurntToastNotification -Text 'Claude Code', 'Needs you'. It still installs and works. But its repository was archived and the README says it is no longer maintained, which is why the script above does the same job without it.
Its default notification setting, auto, sends desktop notifications only in iTerm2, Ghostty and Kitty and rings the bell in some cases in Terminal.app. In other terminals, including Windows Terminal, it does nothing.
Use Notification with the permission_prompt and idle_prompt matchers for 'needs you' alerts, and Stop if you also want an alert every time Claude finishes a reply. PermissionRequest fires at once if you want no delay at all.
The script uses Windows Runtime types, and .NET 5 and later dropped built-in support for them. Run it with powershell.exe, which is Windows PowerShell 5.1, not pwsh.exe.
It still installs and works, but its repository was archived and it is no longer maintained. The script in this article needs no module at all.
We measured what lowers Codex token usage over whole tasks. Prompts and retrieval barely helped; a structured workflow cut 87.56% on suitable migrations.
Read the articleOpenAI Codex and Anthropic's Claude Code compared on Windows support, sandboxing, models, plans, limits and daily use. And why many people end up running both.
Read the articleHow to install Claude Code on Windows 10 and 11 with PowerShell, CMD, WinGet, npm or WSL, check that it works, and fix the errors people hit most.
Read the article