Skip to content
| Marketplace
Sign in
Visual Studio Code>Other>Claude NotificationsNew to Visual Studio Code? Get it now.
Claude Notifications

Claude Notifications

dimokol

|
958 installs
| (1) | Free
All-in-one Claude Code notifications — sound alerts, OS notifications, and terminal focus. One-click setup, zero external dependencies.
Installation
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press enter.
Copied to clipboard
More Info

Claude Notifications

All-in-one Claude Code notification system: sound alerts, OS banners, and terminal focus. Zero-interaction setup, fully customizable.

OS notification → terminal focus

In-VS-Code toast → terminal focus

When running multiple Claude Code sessions across different VS Code windows and terminals:

  1. Hear a sound when Claude finishes a task or needs your input.
  2. See an OS banner showing which project needs attention, even when VS Code is not in focus.
  3. Click the banner to jump directly to the correct VS Code window and terminal tab.

Works on macOS, Windows, and Linux, across multiple VS Code windows and terminals simultaneously.

Quick Start

  1. Install from the VS Code Marketplace:

    • Extensions (Ctrl/Cmd+Shift+X) → search "Claude Notifications" → Install.
  2. That's it. Hooks are installed automatically on first activation, no prompts, no clicks. You'll see a confirmation toast and the status bar shows $(bell) Claude: Notify.

    If you ever need to re-run setup: Ctrl/Cmd+Shift+P → "Claude Notifications: Set Up Claude Code Hooks".

What's New in v3.5.5

A big maintenance release rolling up everything since the last Marketplace publish (v3.3.2).

Windows notifications work reliably end-to-end

  • OS toast fires every time, no missed banners. Earlier 3.5.x builds silently dropped the toast on real Claude Code sessions because the PowerShell child that registers the toast was getting killed inside Claude Code's hook job-object before reaching ToastNotificationManager.Show(). The toast spawn now uses a proven cmd /c start "" /B wscript.exe hide.vbs powershell.exe … chain. start /B escapes Claude's job so PowerShell survives, while wscript hide.vbs launches PowerShell at intWindowStyle=0 so no console window is ever allocated. No more "desktop refresh" / PS console flash before each notification, and no missed toasts.
  • Notification sound plays every time. Same root cause and same fix as the toast: the sound subprocess was being killed inside Claude's job. Wrapped in the same chain, sound now fires reliably with no flash.
  • Clicking the toast actually focuses the right terminal again. 3.4.0 had switched the toast launch URI to a custom claude-notif:// scheme to skirt VS Code's "external application wants to open" prompt, but Windows' toast click-activation pipeline silently dropped custom schemes for our AUMID. The toast now uses vscode://dimokol.claude-notifications/click?marker=..., which Windows routes through VS Code to our extension's registered UriHandler. The click event is processed in-process, no file mediation, no race. Multi-session-in-same-workspace disambiguation works via PID/AI-title tiers on the marker payload. (You'll see VS Code's "external application wants to open?" prompt on the first banner click after upgrade, click "Open" and tick "Do not ask me again for this extension" to make it permanently silent.)
  • No more duplicate hook entries on Windows. A path-quoting bug used to append a fresh hook entry to ~/.claude/settings.json on every VS Code restart (one tester reached 12 entries per event). Fixed in place, with auto-migration: install v3.5.5 over a buggy older install and the 12 duplicates collapse to 1 on first activation. Plus an idempotency regression test so it can't come back.
  • Banner click jumps to the correct terminal tab. Clicking a Windows toast routes through VS Code to the originating session and focuses the right terminal. Note: bringing the VS Code window to the foreground on click is a known Windows limitation (the OS shields the notification surface from background focus changes), so the taskbar flashes instead, and with several VS Code windows open that flash can land on the active window rather than the one that fired. See docs/windows-banner-focus-handoff.md for the full investigation.
  • Clicking a notification opens your actual VS Code build, including Insiders. Windows sends vscode:// links to whichever build owns the scheme (usually Stable), so Insiders users used to get a fresh Stable window instead of the Insiders window the notification came from. The toast now detects which build your Claude session is running in (Stable, Insiders, or forks like VSCodium, Cursor, Windsurf) and opens the matching scheme (vscode-insiders://, and so on), so the click lands in the right instance. Thanks @mlidbom for filing #4 with the suggestion.
  • No PowerShell console window flash. Several spawn paths used to allocate a brief console window before -WindowStyle Hidden took effect. Every PS spawn now either runs through wscript hide.vbs or uses windowsHide: true, so no flash on notification, sound, or click.

Reliability everywhere

  • No more MODULE_NOT_FOUND errors after the extension updates or uninstalls. Hooks now point at a stable wrapper under ~/.claude/claude-notifications/ instead of the versioned extension dir. When the extension is gone, the wrapper detects this on its next fire and self-cleans every Claude profile (default and .claude-* siblings), the Windows registry handler, the launcher dir, and the per-workspace state, no leftover trash. Thanks @iodar for filing #1 with a precise root-cause and the exact wrapper-script suggestion.
  • "Uninstall" cleans every Claude profile, not just the default. Multi-profile users (.claude-work, .claude-other, …) used to be left with dangling hook entries pointing at the deleted wrapper. Both the Uninstall command and "Remove Hooks" now iterate every discovered profile and clean them all.
  • No more Stop-hook hang on Windows. Sound playback used to keep Node's event loop alive on Windows for several seconds (sometimes minutes if a latent PowerShell NaturalDuration polling loop tripped). All three sound spawns are now detached + unref'd, with an explicit watchdog. Thanks @valdiks for filing #2 with the diagnosis and the exact fix.
  • Turns finish instantly: no more "running Stop hook" pause. On top of the detached-sound fix, hooks now install with async: true, so Claude fires them and continues immediately instead of waiting ~1.2s for the notification handshake to complete. The notification still fires (a beat after the turn completes); the wait is just gone. Older Claude Code builds that don't recognize the flag behave exactly as before.

Better terminal matching + notification dedup

  • Right terminal focused on Git Bash + Windows. Tiered terminal matching (PID → shell-integration cwd → Claude title markers → AI-generated session title → single non-default-shell-named) replaces the previous PID-only match that silently broke under MSYS2 / winpty / ConPTY indirection. Multi-session-in-one-workspace setups also disambiguate via the unique AI-generated task title each Claude session writes to its terminal.
  • Exactly one notification per attention point: no duplicates, no late repeats. You get a single alert each time Claude finishes, asks a question, or needs permission, and never miss one. Previously a completion could fire twice (a second alert seconds later) and sometimes a third a minute or two on, because Claude re-emits "still waiting" reminders for the same moment. The dedup now treats those reminders as what they are (trailers) and collapses them, while still firing once for every genuinely new event, including back-to-back multi-choice AskUserQuestions, which each fire their own request. Fast banner-clicks no longer double-sound either.
  • Session title in notifications. Banners and toasts include Claude Code's auto-generated session title: Task completed in: my-project — Refactor the auth middleware.

New

  • claudeNotifications.toastWhenFocused (default false). Opt-in visual toast when you're already on the Claude terminal, useful for multi-monitor or small-terminal-panel setups where the audio cue alone can be missed. The companion soundWhenFocused setting continues to control audio independently.

Massive thanks to @AdaWanheda for thorough Windows testing across PowerShell, Git Bash, and multi-monitor setups, and to the 2026-05-23 live-test session that surfaced the toast/sound/click regressions caught and fixed in 3.5.5.

See CHANGELOG.md for the full history.

How It Works

Claude fires hook (Stop / Notification / PermissionRequest / UserPromptSubmit)
       │
       ▼
hook.js consults stage-dedup state for this session
       │
       ├─ Re-fire of an already-notified, unresolved stage → exit silently
       │
       └─ Fresh stage (first event for the session, or previous stage acked):
             │
             ▼
       Write signal file → sleep 1.2 s → race the extension
             │
             ├── Extension wins the claim (VS Code is focused):
             │     ├─ Already on the correct terminal → sound only (and ack)
             │     └─ Different terminal / tab        → sound + in-window toast
             │
             └── Hook wins the claim (VS Code not focused / closed):
                   └─ OS banner + sound; clicking it focuses the terminal (and ack)

Key design. Exactly one notification path fires per stage: never zero, never two for the same stage. Both sides claim the same marker file atomically via O_EXCL, so the winner is unambiguous even under rapid concurrent events. A stage advances only when you've engaged (clicked, focused, responded) or Claude moves to a genuinely new state, so re-fires of the same event minutes later are silently dropped.

Focus Behavior

The extension never changes terminal focus without an explicit user action:

  • Clicking "Focus Terminal" on an in-window toast.
  • Clicking an OS banner (focuses VS Code and auto-focuses the matching terminal, no extra toast).

You will never lose your place in a terminal because of a notification.

Windows note: clicking the banner flashes the taskbar instead of raising the window. On Windows, clicking an OS banner reliably switches to the correct terminal in the correct window, but it currently can't pull the VS Code window itself to the front over another app. Windows flashes the taskbar button and you click it to come up (already on the right terminal). This is the same behavior as Slack/Discord/Teams toast clicks.

Help wanted: Windows banner-click window focus

I spent a long, instrumented session trying to make a Windows banner click bring the VS Code window to the foreground, and could not do it reliably. The blocker is ShellExperienceHost (the toast surface) owning the foreground at click time, which Windows shields. Every approach I tried (SetForegroundWindow, AttachThreadInput, SendInput/Alt-key, SwitchToThisWindow, a shell-launched handler with the activation grant, ForegroundLockTimeout=0, even VS Code's own vscode://file/ core activation) reduced to a taskbar flash on a real click. It matches a documented Microsoft limitation and open issues ([microsoft-ui-xaml #1939](https://github.com/microsoft/microsoft-ui-xaml/issues/1939), #5499); Electron/Chromium hit the same wall.

If you know how to make this work on a current Windows + VS Code (e.g. a working COM activator / INotificationActivationCallback approach for an unpackaged app, or anything that beats the ShellExperienceHost foreground guard), I'd love a PR or an issue. The full investigation (everything tried, why each failed, the proven facts, and how to approach the next attempt) is documented in docs/windows-banner-focus-handoff.md. The focus-raising code itself (lib/win-focus.js) is proven correct outside the toast-click path; the open problem is narrowly the banner-click activation context.

Status Bar

The extension adds a status bar item with three states:

  • $(gear) Claude: Set Up - hooks not installed (click to install).
  • $(bell) Claude: Notify - notifications active (click to mute).
  • $(bell-slash) Claude: Muted - notifications muted (click to unmute).

When muted, signal files are still written (so terminal focus still works if you click the banner) but no sound or notification is shown.

Settings

Settings are grouped per event so you can configure Waiting and Completed independently. All settings are prefixed with claudeNotifications., e.g. claudeNotifications.volume.

Top

Setting Default Description
autoSetupHooks true Install and upgrade Claude Code hooks automatically. Uncheck to be prompted before any change to ~/.claude/settings.json.
volume 50 0 = silent, 50 ≈ typical OS notification, 100 = the sound file's native level. OS master volume still applies.

Waiting

Fires when Claude is waiting for your response (Notification + PermissionRequest).

Setting Default Description
waiting.action Sound + Notification One of Sound + Notification · Sound only · Notification only · Nothing.
waiting.sound bundled:notification Dropdown of cross-platform values (none, two bundled chimes, custom). For every sound on your actual OS, use the Choose Sound… command.
waiting.customSoundPath (empty) Absolute path to a custom audio file. Used only when waiting.sound is custom.

Completed

Fires when Claude finishes a task (Stop).

Setting Default Description
completed.action Sound + Notification Same options as waiting.action.
completed.sound bundled:task-complete Same options as waiting.sound.
completed.customSoundPath (empty) Absolute path to a custom audio file. Used only when completed.sound is custom.

Bottom

Setting Default Description
soundWhenFocused sound What to do when you're already on the terminal Claude just wrote to: sound (play audio cue) or nothing (stay silent).
macOS.setup n/a macOS only. Link to the Configure command that detects whether terminal-notifier is installed and offers install / reinstall / test / open Notification Settings.

Picking a system sound

The Settings-UI dropdown only lists cross-platform values because VS Code settings schemas can't be populated at runtime. Every sound actually available on your OS (macOS /System/Library/Sounds, Windows C:\Windows\Media, Linux freedesktop theme) lives in the Choose Sound… command:

  1. From a Waiting Sound or Completed Sound row in Settings, click the Choose Sound… link. The picker opens pre-targeted at that event. From the command palette, invoke "Claude Notifications: Choose Sound" and pick the event first.
  2. Click the 🔊 speaker icon on any row to hear it at your configured volume. Playback is strictly opt-in: arrow-keying through the list doesn't play anything. The current selection is marked with a ✓.
  3. Highlight the one you want and press Enter to save, or Escape to cancel.

Picking a system sound writes system:<Name> to the setting. The Settings UI accepts the value and the extension resolves it at runtime.

Previewing your configured sounds

"Claude Notifications: Preview Sound" shows exactly two rows (Waiting and Completed), each with the current sound name and a speaker button. Click a speaker (or highlight + Enter) to hear that notification at your configured volume. Use this to check what your notifications will actually sound like.

Commands

Open the command palette (Ctrl/Cmd+Shift+P) and search for:

Command Description
Set Up Claude Code Hooks Install hooks in ~/.claude/settings.json.
Remove Claude Code Hooks Remove hooks (leaves any other settings untouched).
Test Notification Send a test notification to verify your setup end-to-end.
Toggle Mute Mute/unmute notifications (also available via the status bar).
Choose Sound Browse bundled, system, and custom sounds per event.
Preview Sound Listen to any available sound without changing settings.
Configure macOS terminal-notifier Install / reinstall / test / open macOS Notification Settings.

Monitored Events

The extension listens to three Claude Code hook events, grouped into two types:

Type Hook events Banner text Bundled sound
Waiting Notification, PermissionRequest "Waiting for your response in: {project}" notification.wav
Completed Stop "Task completed in: {project}" task-complete.wav
(stage advance) UserPromptSubmit none (bumps stageId so the next event re-notifies) n/a

macOS Setup

For the best click-to-open experience on macOS, install terminal-notifier. The extension prompts you on first activation only if it's missing, or you can run it anytime:

Ctrl/Cmd+Shift+P → "Claude Notifications: Configure macOS terminal-notifier"

The command detects whether terminal-notifier is already installed and offers the right action: install (via Homebrew), reinstall, send a test banner, or open System Settings → Notifications. The same entry is available under Settings → Claude Notifications → macOS: Setup.

After installing: System Settings → Notifications → terminal-notifier → set to Alerts (banners disappear after a few seconds; alerts stay until dismissed).

About duplicate terminal-notifier entries in System Settings. If you see two terminal-notifier rows, macOS is remembering registrations from past installs (e.g. an older brew version, or one bundled with node-notifier inside some node_modules). Keep the entry configured the way you want and leave the other off. This extension only talks to the terminal-notifier on your PATH. It never registers a second copy.

Without terminal-notifier, the extension falls back to osascript notifications (which work but don't support click-to-open).

Upgrading from v1.x

If you previously used the shell-script setup:

  1. The extension detects legacy hooks and offers to upgrade automatically.
  2. Choosing "Replace" removes the old shell hooks and installs the new Node.js hook.
  3. You can safely delete the old scripts (~/.claude/notify.sh, ~/.claude/task-complete.sh, etc.).

Troubleshooting

Problem Solution
No notifications at all Run "Test Notification" from the command palette. Check the status bar isn't showing Muted.
No sound Check that waiting.action / completed.action aren't set to Notification only or Nothing, and that volume is > 0.
Sound is too loud or too quiet Adjust volume. 50 matches typical OS-notification loudness; 100 plays the file at its native level. OS master volume still applies.
Notification doesn't open VS Code macOS: run "Configure macOS terminal-notifier". Windows: the extension auto-registers a claude-notif:// URI handler under HKCU\Software\Classes\ on activation, no setup needed. If clicks do nothing, check the "Claude Notifications" Output panel for Windows click-handler registered:.
Want to fully uninstall Just uninstall the extension from the VS Code Extensions view. The next Claude message after uninstall auto-cleans every artefact: hook entries from every Claude profile's settings.json, the per-workspace state in ~/.claude/focus-state/, the wrapper dir at ~/.claude/claude-notifications/, and (on Windows) the claude-notif:// registry key plus the launcher in %LOCALAPPDATA%\claude-notifications\. The "Claude Notifications: Uninstall" palette command does the same thing eagerly if you want everything gone immediately.
Duplicate notifications Update to v3.2+. The new stage-ID dedup suppresses re-fires of the same event until you acknowledge. See How It Works. If still duplicating, make sure the legacy dimokol.claude-terminal-focus extension is uninstalled.
Notifications stop firing Inspect ~/.claude/focus-state/<hash>/sessions (where <hash> is the 12-char hash for your workspace). If you see resolved:true stuck for the active session, that's the dedup remembering you acknowledged a stage. Delete the file to reset; the next event will create a fresh stage.
Two terminal-notifier entries in macOS Notifications macOS keeps notification settings per bundle, and a past install (e.g. bundled with node-notifier or an older brew version) can linger. Configure the entry you want and leave the other off. To fully reset: killall NotificationCenter then fire any notification once to re-register.
Wrong terminal focused Check the "Claude Notifications" Output panel for PID matching logs.
Hooks not firing Run "Set Up Claude Code Hooks" and restart any active Claude Code sessions so they re-read ~/.claude/settings.json.
Extension not activating Check the "Claude Notifications" channel in the Output panel.

How the Hook Works

The extension ships two bundled hooks that Claude Code invokes:

  • dist/hook.js: runs on Stop, Notification, and PermissionRequest. Decides whether to notify, writes the signal, and races the extension for the claim.
  • dist/hook-user-prompt.js: runs on UserPromptSubmit. Tiny: it just advances the session's stageId so the next Stop/Notification is treated as a fresh stage.

hook.js flow:

  1. Reads session_id, hook_event_name, and message from stdin (Claude's hook input).
  2. Reads the project directory from CLAUDE_PROJECT_DIR and walks up looking for a .vscode/ folder to identify the VS Code workspace root.
  3. Hashes that workspace root (sha1 → 12 hex chars) to derive ~/.claude/focus-state/<hash>/.
  4. Calls shouldNotify(workspaceRoot, sessionId, event); if the current stage was already notified for this event type and not yet acknowledged, exits immediately.
  5. Builds a PID ancestor chain so the extension can focus the exact terminal tab that spawned Claude.
  6. Writes a JSON signal file to ~/.claude/focus-state/<hash>/signal.
  7. Sleeps 1.2 seconds to give the extension time to claim if VS Code is focused.
  8. Atomically tries to claim the handled-marker (O_EXCL). If the extension or a sibling hook already claimed it, exits silently.
  9. Otherwise marks the signal fired, plays the configured sound, and shows an OS banner.

A stage is marked resolved when:

  • You click an OS banner (terminal-notifier -execute writes a clicked marker; the extension picks it up and marks resolved).
  • You click Focus Terminal on an in-window toast.
  • The notification fires while you're already focused on the matching terminal (sound-only path).

After markResolved, the next event of any type (even the same type) advances the stageId and notifies again.

hook.js, hook-user-prompt.js, and the extension are all bundled with esbuild, so the installed package has no runtime node_modules dependency, just self-contained JS files.

License

MIT

  • Contact us
  • Jobs
  • Privacy
  • Manage cookies
  • Terms of use
  • Trademarks
© 2026 Microsoft