Claude Code Signal Plugin - Marcel-Bich/marcel-bich-claude-marketplace GitHub Wiki
Desktop notifications showing what Claude Code is working on - stay informed even when the terminal is not in focus.
Use case: You're working in your IDE or browser while Claude Code runs in a terminal. With this plugin, you'll see desktop notifications about what Claude is doing - no need to constantly switch back to the terminal.
Works great with claude --dangerously-skip-permissions for autonomous workflows where you want to monitor progress without watching the terminal.
- Live Status - See what Claude is working on without switching to the terminal
- Desktop Notifications - Non-stacking notifications that replace each other
- Location Context - Every notification shows the cwd, the git repo the session works in, and the tmux session / kitty tab (see Notification Format)
- Sound Alerts - Configurable volume, separate for completion and attention sounds
- AI Summaries - Optional Haiku-powered summaries of completed work (disabled by default)
- Kitty Tab Indicator - Visual tab title prefix during active Claude sessions (kitty terminal only)
- Smart Filtering - No spam from subagents, debounced notifications, no "Tool waiting" hints in bypass permissions mode
- Cross-Platform - Works on Linux and WSL2 (Windows 10/11)
- Desktop notifications (GNOME, KDE, etc.)
-
jq- JSON processor (install:sudo apt install jq) -
gdbusornotify-send- For desktop notifications - Sound alerts (optional) - the plugin uses the first available player, in this order:
-
paplay+pactl(PulseAudio,pulseaudio-utils) - honours the configured volume -
pw-play(PipeWire,pipewire-binon Debian/Ubuntu) - honours the configured volume -
ffplay(ffmpeg) - last resort, plays at full volume
-
-
bc- For volume calculations (optional)
-
jq- JSON processor (install:sudo apt install jq) -
powershell.exe- For Windows toast notifications and sounds. It does not have to be onPATH(v1.5.4+): signal also finds it below the Windows drive mounts (see Delivery and Preflight) - Optional: BurntToast PowerShell module for better notifications
claude plugin marketplace add Marcel-Bich/marcel-bich-claude-marketplace
claude plugin install signal@marcel-bich-claude-marketplaceConfigure via environment variables in ~/.claude/settings.json:
{
"env": {
"CLAUDE_MB_NOTIFY_HAIKU": "false",
"CLAUDE_MB_NOTIFY_SOUND_COMPLETE": "0.4",
"CLAUDE_MB_NOTIFY_SOUND_ATTENTION": "0.25"
}
}| Variable | Default | Description |
|---|---|---|
CLAUDE_MB_NOTIFY_HAIKU |
false |
Enable AI summaries on task completion |
CLAUDE_MB_NOTIFY_SOUND_COMPLETE |
0.4 |
Completion sound volume (0-1, 0 = off) |
CLAUDE_MB_NOTIFY_SOUND_ATTENTION |
0.25 |
Attention sound volume (0-1, 0 = off) |
CLAUDE_MB_NOTIFY_SUBAGENT_TOOLS |
true |
"Tool waiting" hints for subagent tool calls (true/false, false silences them) |
CLAUDE_MB_NOTIFY_BYPASS_TOOLS |
false |
"Tool waiting" hints in bypass permissions mode (true/false, true shows them anyway) |
CLAUDE_MB_NOTIFY_TOAST |
true |
(v1.5.4+) Toasts and desktop notifications (true/false; off, no, 0, disabled also count as false, any case, surrounding spaces ignored). false skips every attempt and the preflight; sounds are unaffected |
CLAUDE_MB_SIGNAL_STATE_DIR |
${XDG_STATE_HOME:-$HOME/.local/state}/claude-mb-signal |
(v1.5.4+) State dir for the cached powershell.exe path, signal.log and the once-a-day markers (mode 0700, owner-checked; below $HOME every level must be a real directory owned by you and not world-writable (unless sticky) and group-writable only for one of your own groups (default umask 002), no symlink below the anchor; files in it are never written through a symlink) |
CLAUDE_MB_SIGNAL_PS_TIMEOUT |
20 |
(v1.5.4+) Seconds before a powershell.exe toast/sound run is killed |
CLAUDE_MB_KITTY_TAB |
true |
Kitty tab title indicator (true/false) |
Sound volume is relative to your system volume:
-
0.4= 40% of current system volume -
0.25= 25% of current system volume -
0= Sound disabled
Cost Warning: Enabling this feature will use your Anthropic API credits. Each notification triggers a Haiku API call which costs real money. You are responsible for monitoring your own API usage and costs.
When enabled (CLAUDE_MB_NOTIFY_HAIKU=true), the plugin uses Haiku to generate a brief summary of the work completed. This:
- Costs API credits (~0.001-0.01 USD per notification, depending on context size)
- Requires the
claudeCLI to be available and authenticated - Shows a one-sentence summary in the notification
- Triggered when a task completes
- Shows AI summary (if enabled) or generic message
- Plays
complete.ogasound
- Triggered when Bash commands need approval
- Shows the command being executed
- Plays
message.ogasound -
Skipped in bypass permissions mode (v1.3.0+):
PreToolUsefires before Claude Code decides whether to ask at all, so it is only a hint. Withpermission_modebypassPermissions(e.g.--dangerously-skip-permissions) no tool ever waits, so no "Tool waiting" notification is sent. Real permission prompts still arrive via the Notification hook (permission_prompt). (v1.5.1+) SetCLAUDE_MB_NOTIFY_BYPASS_TOOLS=trueto get the hints in bypass mode anyway. -
Subagent tool calls (v1.3.0+): notified by default (
CLAUDE_MB_NOTIFY_SUBAGENT_TOOLS=true); set it tofalseto silence "Tool waiting" hints for tool calls made by subagents
- Triggered for permission prompts, idle prompts, etc.
- Shows what type of input is needed
- Plays
message.ogasound
(v1.4.0+) Every notification (Stop, PreToolUse, Notification) shows where the session works:
alice-task | cwd: .../marcel/workstation
git: Marcel-Bich/marcel-bich-claude-marketplace
Bash: ls -la
tmux: workspace | kitty: workspace
<name> | cwd: .../<parent>/<dir> - the last two segments of the hook's cwd. Short paths with nothing to shorten are shown as is (/, /tmp, /home/marcel). What the toast is about (done, tool waiting, permission prompt) is in the body. The Done toast keeps its sparkle in front (<sparkle> <name> | cwd: ...) as the only event marker.
(v1.5.3+) <name> is the same for EVERY toast (Done, Tool waiting, permission prompt, waiting for input, questions). First hit wins:
- The session name set by the user: field
nameof the session file<config dir>/sessions/<pid>.json, only whennameSourceisuser. A name Claude Code derived on its own never counts. The session transcript (custom-title) is not used as a fallback - The kitty tab title (clean, same source as the last body line)
- The tmux session name of the session's pane
- The short session id: first character of each dash group joined by
-, plus the last character, e.g.a1b2c3d4-e5f6-7890-8bcd-0123456789d8becomesa-e-7-8-08 -
Claude Codewhen no session id is known
The session file is read safely (owned regular file, symlinks are not followed, first 256 KiB only, control characters removed). A file naming another session id, or none while the session id is known, is skipped. Every name (user name, kitty label, tmux label) has all control characters removed and is cut to 20 characters (no ...). Example: alice-task | cwd: .../marcel/workstation.
Older versions used a fixed Tool waiting / ✨ Done text, and (v1.5.0+) the session_name of the hook input, the /rename title, the Limit statusline caption, kitty and tmux for general notifications only. The session_name hook field and the Limit statusline caption are no longer used (the caption could be a name Claude Code derived on its own).
git: <parent>/<repo> - the last two path segments of the repo toplevel (same format as the git line of the Limit statusline, path only, no branch). The repo is resolved in this order, the first hit wins:
-
Work-repo state (limit plugin): the per-session file
/tmp/claude-mb-workrepo_<session_id>, i.e. the repo the main agent last worked in - follows the agent even from a non-git hub directory -
Git discovery from the cwd:
git rev-parse --show-toplevel -
Credo session pin (credo plugin):
credo-config.sh resolve-projectfor the session; accepted only if the pinned target is a git repo
Limit and credo are optional (soft dependencies). If no repo resolves, the line is omitted entirely.
tmux: <session> | kitty: <tab title>, set off by an empty line, containing only the parts that exist (tmux: workspace, kitty: workspace, or both). Outside tmux and kitty the line is omitted.
-
tmux: the session name of the pane Claude Code runs in (
tmux display-message -t "$TMUX_PANE"), not the most recently used client. (v1.5.3+) For sessions hosted by the Claude Code background daemon, or whenTMUX_PANEis missing in the hook environment, the pane is taken from the client terminal process (claude daemon runis found in the process ancestry; its parent, else the process named by its--spawned-bylink, must be a Claude client of the same user; onlyTMUXandTMUX_PANEare read from its environment and both are validated). A client that cannot be verified is ignored and the tmux part is omitted. The same pane is used for the title fallback -
kitty: the tab title without the indicator prefixes (
[ai...],[ask],[fin]). Source order:- The clean title saved by the Kitty Tab Indicator (only when the indicator is enabled)
- Fallback (indicator disabled or no saved title yet): the real title of the tab containing this window, read via
kitty @ ls(needs the kitty socket, see Requirements); indicator prefixes are stripped
Each lookup has a short timeout; any failure silently drops that part.
The Windows toast shows the body as a single wrapping text field, so on WSL2 the body lines are joined with | instead of line breaks (e.g. git: Marcel-Bich/repo | Bash: ls -la | tmux: workspace).
GNOME Shell (46 and older) replaces every \n in a notification body with a space, in the banner and in the expanded message list alike (gnome-shell#7705). Only \n is replaced, so signal sends the line breaks as carriage returns (\r) when the notification server reports itself as gnome-shell. Result: every line and every empty line is shown as intended, and the notification is shown fully without expanding. GNOME offers the expand arrow only when a line is too long and gets cut with .... Other servers (KDE, dunst, ...) keep \n and get the body unchanged.
Tested alternatives that do not work on GNOME 46: <br> / <br/> (only <b>, <i>, <u> markup is allowed, other tags are shown as text); Unicode U+2028 / U+2029 break lines but show a box glyph in the collapsed view.
Before this release signal called powershell.exe bare and swallowed every error, so on a WSL where powershell.exe is not on PATH the toasts silently never appeared.
-
powershell.exeonPATH - The path cached in the state dir (
powershell-path), used only while it is still an absolute, executable file namedpowershell.exe - A scan of
/proc/mountsfor Windows drive mounts (type9pordrvfswithpath=<Letter>:in the options or a<Letter>:device) andWindows/System32/WindowsPowerShell/v1.0/powershell.exebelow each of them. The WSLdriversmount has no drive letter and is skipped. No drive letter or mount point is hardcoded
When nothing is found, toasts and sounds are skipped and one warning per day goes to stderr and signal.log in the state dir.
-
powershell.exeruns happen in the background (detached, stdin/dev/null) and are killed afterCLAUDE_MB_SIGNAL_PS_TIMEOUTseconds (default 20); a non-zero exit code is logged and reported once a day by the next notification - The PowerShell script is passed with
-EncodedCommand(UTF-16LE base64), never as a multi-line argv string. The toast tag (session id) is restricted to[A-Za-z0-9-]before it reaches the script, and title and body are flattened to one line each - On Linux, a gdbus
Notifycall that returns exit code 0 counts as delivered even when the reply cannot be parsed (no duplicate vianotify-send) - On Linux the gdbus
Notifycall is checked, thennotify-sendis tried; when both are missing or fail, one warning per day is emitted - Hooks never wait for any of this and keep their timeouts
CLAUDE_MB_NOTIFY_TOAST=false turns off every toast and desktop notification attempt (also the toast-history cleanup at session start and the preflight). Sounds keep working.
At session start, at most once a day and only with the toast switch on, signal checks that a toast can show up at all:
-
WSL2: read-only registry reads through
powershell.exeunderHKCU:\Software\Microsoft\Windows\CurrentVersion:PushNotificationsToastEnabled,Notifications\SettingsNOC_GLOBAL_SETTING_TOASTS_ENABLEDand the per-app key of the toast sender (Notifications\Settings\{1AC14E77-...}\WindowsPowerShell\v1.0\powershell.exe, valueEnabled). A value of0means disabled, an absent value means enabled. Focus Assist is not checked. The script is passed topowershell.exewith-EncodedCommand(one single-line argument). A coldpowershell.exestart can take longer than the 5 second SessionStart timeout, so the read runs detached in the background (stdin/dev/null, killed afterCLAUDE_MB_SIGNAL_PREFLIGHT_TIMEOUTseconds, default 20) and writes its result to the state dir; the NEXT session start reports it. The daily stamp is only set once a usable result was reported. A failed read (no output, killed by the timeout) or apowershell.exethat cannot be found leaves a short-lived marker (the latter is logged and mentioned once a day), the next session retries but at most once per hour -
Native Linux: only whether
gdbusornotify-sendexists;powershell.exeis never used - If toasts look disabled,
powershell.execannot be found or no Linux tool exists, signal adds one short line to the session context. Claude then tells you once and asks whether it should openms-settings:notifications; it only runsopen-settingsafter you said yes, never on its own. Nothing is ever changed automatically. To enable toasts yourself: Settings > System > Notifications > "Get notifications from apps and other senders" = On (German: "Benachrichtigungen von Apps und anderen Absendern abrufen" = Ein) - No other fallback (such as a push service) is used
Commands (replace <plugin> with the plugin directory):
| Command | Effect |
|---|---|
bash <plugin>/scripts/toast-preflight.sh decline |
No further hints (marker preflight-declined in the state dir) |
bash <plugin>/scripts/toast-preflight.sh reset |
Removes the decline, the daily stamp, the probe state (result, failure and pending markers) and the warning markers, so hints and warnings come back |
bash <plugin>/scripts/toast-preflight.sh open-settings |
Opens the Windows notification settings (WSL2 only, changes nothing) |
When running Claude Code inside the kitty terminal, the plugin can mark the tab title with a prefix so you can see at a glance which tab has an active session -- even when you have many tabs open.
-
Session start: The tab title is prefixed with
[ai...](e.g.[ai...] my-project) -
Input required: The prefix changes to
[ask]when user input or permission is needed -
Session end: The prefix changes to
[fin](e.g.[fin] my-project) - Tab focused for 3 seconds: The original title is restored automatically
The clean kitty tab title (without prefix) is also shown in the last line of the notification body, so you can see which tab a notification belongs to (see Notification Format).
This makes it easy to spot which tab Claude is working in and whether the session is still running or finished.
The indicator is enabled by default when kitty is detected. To disable it:
{
"env": {
"CLAUDE_MB_KITTY_TAB": "false"
}
}Your kitty.conf must have remote control enabled:
allow_remote_control yes
listen_on unix:/tmp/mykitty
Without these settings, kitty does not expose the socket needed to read and set tab titles. The plugin will silently skip the indicator if the socket is not found.
The indicator also works inside tmux sessions running in kitty. The plugin detects the tmux client of the current pane (-t "$TMUX_PANE", so the right client is used even with many attached clients) and resolves the correct kitty window PID through the process tree. Kitty is recognized by its process name or by its executable, so kitty started via the x-terminal-emulator alternative (process name x-terminal-emul) is detected as well.
- Check if
notify-sendorgdbusis installed - Verify your desktop environment supports notifications
- Check if a supported player is installed:
paplay(PulseAudio),pw-play(PipeWire), orffplay(ffmpeg) - For PulseAudio, verify it is running:
pactl info - On PipeWire-only systems (e.g. Ubuntu 24.04 without
pulseaudio-utils), installpipewire-binforpw-play - Check sound volume isn't set to 0
- The plugin uses gdbus for notification replacement: one slot per session and hook type (
/tmp/claude-mb-notify-id-session-<session_id>-<hook>, falls back to the directory name without a session id). Tool waiting, general notifications and Done keep separate slots on purpose -
(v1.5.0+) The read-close-send-store sequence is serialized per slot with
flock. Before, hooks firing at the same moment (e.g. parallel tool calls) all read the same old ID and each left its own notification behind - If falling back to notify-send, stacking may occur
-
(v1.5.4+)
powershell.exedoes not need to be onPATH, signal finds it below the Windows drive mounts. Look atsignal.login the state dir (default~/.local/state/claude-mb-signal/) for "powershell.exe not found" or failed runs with their exit code - Check that
CLAUDE_MB_NOTIFY_TOASTis not set tofalse - If the session context mentions that toasts look disabled, switch them on in the Windows notification settings (see Preflight); to stop the hint run
toast-preflight.sh decline - Verify
powershell.exeis accessible from WSL:which powershell.exe(older versions needed it onPATH) - Install BurntToast for better notifications:
powershell.exe -c "Install-Module -Name BurntToast -Scope CurrentUser" - Check Windows notification settings (Settings > System > Notifications)
- Verify
allow_remote_control yesis set in yourkitty.conf - Verify
listen_on unix:/tmp/mykittyis set in yourkitty.conf - Check that the socket exists:
ls /tmp/mykitty* - Make sure
CLAUDE_MB_KITTY_TABis not set tofalse - Enable debug logging with
CLAUDE_MB_SIGNAL_DEBUG=truefor details
- Windows sounds are played via PowerShell's MediaPlayer API
- Check if Windows sounds are enabled in your system settings
- Volume is converted from Linux scale (0.4 Linux = 0.05 Windows)
- Run
/pluginin Claude Code - Go to Marketplaces tab and select "Update marketplace"
- Go to Installed tab and update the signal plugin
- Restart Claude Code
This software is provided "as is", without warranty of any kind. Use at your own risk.
- The author is not responsible for any costs, damages, or issues arising from use of this plugin
- You are solely responsible for any API costs incurred (especially when enabling Haiku summaries)
- You are solely responsible for ensuring this plugin is compatible with your system
- No support or maintenance is guaranteed
MIT - See LICENSE for full terms.
See also: Dogma | Limit | All Plugins
Keywords / Tags
Claude Code, Claude Code Plugin, Claude Code Extension, Claude Code Kitty, Claude Code Kitty Tab, Claude Code Tab Indicator, Kitty Terminal, Kitty Tab Title, Claude Code Notifications, Claude Code Desktop Notifications, Claude Code Terminal Notifications, Claude Code Alerts, Claude Code Sound, Claude Code Audio, Claude Code Toast, Claude Code Status, Claude Code Progress, Claude Code Monitoring, Claude Code Background, Claude Code Autonomous, Claude Code Dangerously Skip Permissions, Anthropic CLI, Anthropic Plugin, Anthropic Extension, Anthropic Claude, Anthropic AI, AI Agent Notifications, AI Agent Alerts, AI Agent Status, AI Agent Monitoring, AI Code Assistant, AI Coding, AI Programming, AI Development, Desktop Notifications, Terminal Notifications, System Notifications, Toast Notifications, Push Notifications, Sound Alerts, Audio Alerts, Notification Sound, Complete Sound, Attention Sound, WSL, WSL2, WSL Notifications, Windows Subsystem Linux, Windows 10, Windows 11, Windows Notifications, Linux Notifications, GNOME Notifications, KDE Notifications, Ubuntu Notifications, Debian Notifications, notify-send, gdbus, BurntToast, PowerShell Notifications, PulseAudio, paplay, pactl, Cross Platform, Background Tasks, Autonomous Coding, Haiku Summary, AI Summary, Task Completion, Tool Waiting, Permission Prompt, Input Required, Claude Code Hooks, Stop Hook, PreToolUse Hook, Notification Hook, Marcel Bich, marcel-bich-claude-marketplace, signal plugin, notification plugin