Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

README.md

desktop-notification

A Claude Code plugin that alerts you the moment Claude needs your input. On a permission_prompt or idle_prompt notification it emits up to three additive, independently-toggleable channels: an audible terminal bell, an OSC 9 terminal notification, and, on macOS and Linux, an OS-native desktop toast.

Behavior

  • Fires on attention prompts. Only the permission_prompt and idle_prompt notification types trigger it; every other notification is a silent no-op.
  • Advisory, never blocking. The hook always exits 0 (Notification hooks cannot block).
  • Three additive channels, each default on and independently mutable:
Channel Option What it does
bell desktop_notification_bell_enabled Audible terminal bell (bare BEL).
terminal_notify desktop_notification_terminal_notify_enabled OSC 9 desktop notification, emitted via the hook's terminalSequence output (Claude Code v2.1.141+ writes it through its own terminal path).
os_toast desktop_notification_os_toast_enabled OS-native toast (see per-OS table).

Platform facts verified 2026-07-18: hook terminalSequence output landed in Claude Code v2.1.141 per the Claude Code changelog; channel semantics per the hooks reference.

Per-OS os_toast behavior

OS Tool Requirement
macOS osascript … display notification Built-in. No dependency. First run prompts to allow notifications for the terminal app.
Linux notify-send (libnotify) Install libnotify-bin (Debian/Ubuntu) or libnotify (Fedora). Absent → the os_toast channel is a silent no-op.
Windows / other none No OS-toast branch: a fire-and-forget hook process leaves no live activator host for a WinRT toast to render into, so it would never reliably surface. The terminal_notify channel (OSC 9) carries Windows attention. Windows Terminal handles OSC 9.

The OS toast body includes the current git branch when the project is a git repository (e.g. Waiting for your input — feat/my-branch); outside a repo it is just the message.

Requirements

The hook runs on Bash 3.2+. On native Windows, install Git for Windows so Git Bash is available. It needs Node.js on PATH: the hook launches through node hooks/exec-bash.mjs, and Claude Code's native binary neither ships nor uses Node, so without it the hook does not launch and notifications do not fire (install Node.js). It also needs jq on PATH; without jq, notifications are disabled with a visible notice, once per session and agent, renewed every eighth skip. macOS needs nothing further; Linux needs libnotify only for the os_toast channel; Windows needs nothing (terminal channels only). Telemetry timing uses EPOCHREALTIME (Bash 5.0+); on older bash the telemetry envelope is skipped while notifications still fire.

Node.js claim verified 2026-09-29 per the Claude Code setup page ("The installed claude binary does not itself invoke Node") and the hooks reference ("Exec form and shell form"). Recheck when either page changes those statements.

Install

/plugin marketplace add melodic-software/claude-code-plugins
/plugin install desktop-notification@<marketplace>

Then verify prerequisites with /desktop-notification:setup check.

Configuration

Every channel is toggled by its own userConfig boolean (default on; set to false to mute that channel). Mute the OS toast and keep the rest:

Option What it controls
desktop_notification_enabled Master toggle for the whole hook.
desktop_notification_bell_enabled The bell channel.
desktop_notification_terminal_notify_enabled The terminal_notify (OSC 9) channel.
desktop_notification_os_toast_enabled The os_toast channel.

Set them interactively with /plugin configure desktop-notification@<marketplace>, or headless on the install command:

claude plugin install desktop-notification@<marketplace> --config desktop_notification_os_toast_enabled=false

Option scoping (user vs project settings, and the per-repository escape hatch) per "How to set these" below.

Disable without uninstalling

Set desktop_notification_enabled to false (via /plugin configure desktop-notification@<marketplace> or --config desktop_notification_enabled=false).

Options reference

Generated from this plugin's .claude-plugin/plugin.json. Every option Claude Code will prompt for when the plugin is enabled, with the environment variable each hook reads it from.

Option Type Default Environment variable Description
desktop_notification_enabled boolean true CLAUDE_PLUGIN_OPTION_DESKTOP_NOTIFICATION_ENABLED Master switch for the whole notification hook
desktop_notification_bell_enabled boolean true CLAUDE_PLUGIN_OPTION_DESKTOP_NOTIFICATION_BELL_ENABLED Audible terminal bell (bare BEL)
desktop_notification_terminal_notify_enabled boolean true CLAUDE_PLUGIN_OPTION_DESKTOP_NOTIFICATION_TERMINAL_NOTIFY_ENABLED OSC 9 terminal notification emitted via the hook's terminalSequence output
desktop_notification_os_toast_enabled boolean true CLAUDE_PLUGIN_OPTION_DESKTOP_NOTIFICATION_OS_TOAST_ENABLED OS-native desktop toast: macOS (osascript) or Linux (requires notify-send). No effect on Windows, where the terminal channels carry the alert.

How to set these

Three supported routes, in the order most people want them:

  1. Interactively. Claude Code prompts for declared options when you enable the plugin. To change them later: /plugin configure desktop-notification@<marketplace>.

  2. Headless. Repeat --config for each option. Replace <marketplace> with the marketplace you installed this plugin from:

    claude plugin install desktop-notification@<marketplace> -s <scope> --config desktop_notification_enabled=<value>

    The same command reconfigures a plugin that is already installed: it prints already installed and still writes the value. The short-circuit message is about the install, not the config write. Do not claude plugin uninstall to reconfigure: uninstalling drops this plugin's whole stored pluginConfigs entry, resetting every option in the table above to its default. -s defaults to user, so pass the scope claude plugin list reports for this plugin. The verified-version record lives in the plugin-reconfiguration convention.

    The value is stored immediately; the session you are in does not change. Hooks are handed their CLAUDE_PLUGIN_OPTION_* when the session starts, so start a fresh Claude Code session before expecting new behavior. A check run in the old session still reports the old value, and that is not a failed write.

  3. By hand, in settings. Add the value under pluginConfigs in your user settings (~/.claude/settings.json):

    {
      "pluginConfigs": {
        "desktop-notification@<marketplace>": {
          "options": {
            "desktop_notification_enabled": <value>
          }
        }
      }
    }

    Plugin option values are read from user, --settings, and managed settings only, not from a project's .claude/settings.json. To vary behavior per repository, enable or disable the plugin in that project's enabledPlugins instead of setting an option there.

Do not set the CLAUDE_PLUGIN_OPTION_* variables yourself. They are how Claude Code hands a configured value to a hook process; the value comes from the routes above.

Upstream documentation

Telemetry (opt-in)

When the consumer sets HOOK_TELEMETRY_SINK to an executable, the hook emits one telemetry envelope per run. hook: "desktop-notification", hook_event: "Notification", and a data payload of notification_type plus the channels that fired. Unset → exact no-op.

License

MIT (SPDX-License-Identifier: MIT).