Skip to content

Repository files navigation

🔔 claude-notify

Know what Claude Code is doing — even when you're not at your desk.

Currently Windows-only (PowerShell + USB HID).

claude-notify demo

Four outputs, one hook, zero lag:

  • 🔔 Windows toast popup
  • 🖱️ Logitech G102 RGB color change
  • 🌐 Live dashboard with JCVD GIFs + usage stats
  • 📱 Push notification to your phone (→ smartwatch)

Uses ntfy.sh — open source, no account needed.


Quick start

git clone https://github.com/bojnesh/ClaudeNotify
cd ClaudeNotify
.\setup.ps1 -Channel "claude-yourname-xk7q2"

Restart Claude Code. Full setup walkthrough (phone app pairing, etc.) below.


What it looks like

State Windows toast Phone G102 Dashboard
🟡 Running Silent Silent Yellow JCVD doing the splits
🔴 Waiting for you Popup "Needs your confirmation" (urgent) Red JCVD staring impatiently
✅ Done Popup + usage stats "Task finished!" + usage stats Green JCVD thumbs up
🚀 Ready Silent Silent Blue Ready
👋 Session ended Silent Silent Off Session ended

Phone notifications only fire on Waiting for you and Done — free ntfy.sh has a daily message quota, and PreToolUse fires on every single tool call. G102 + dashboard still update on every event, including UserPromptSubmit (fires the instant you hit enter, turns Running yellow even for a turn that never calls a tool — otherwise the icon just sits on whatever color the previous turn ended on for the entire time Claude is "thinking").

Stop notification (phone + watch)

✅ Claude finished!
Task complete — ready for your next prompt.
Context: 34% used
5h limit: 12% · resets in 4h 22m
7d quota: 8% · resets in 6d 14m

See it in action

Live dashboard Real-time state, JCVD status indicator, and session usage — all local, no cloud.

Dashboard

Phone + watch Stacked ntfy notifications on lockscreen, mirrored to your smartwatch.

Phone notifications Watch notification

Settings Toggle each output independently, or drop in your own GIF per state.

Settings


Files

File Purpose
notify.py Hook entrypoint — fires all three outputs in parallel
rgb.py G102 RGB controller (via USB HID + pywinusb, no G HUB needed)
dashboard.py FastAPI + SSE dashboard server
statusline.ps1 Terminal status bar + writes usage cache for notify.py
settings.json Claude Code hooks + statusline config
setup.ps1 One-time install script
tray_app.py System tray icon — live state color, double-click opens dashboard, right-click menu (test notification, force color, settings incl. run-on-Windows-startup)
build.ps1 Builds tray_app.py into a standalone dist\claude-notify-tray.exe via PyInstaller

Full setup (10 minutes)

1. Install ntfy on your phone

2. Choose a unique channel name

claude-neba-xk7q2     ← good (hard to guess)
claude-code            ← too generic

3. Run setup (PowerShell, one time)

cd path\to\claude-notify
.\setup.ps1 -Channel "claude-neba-xk7q2"

This installs Python deps, copies scripts to %USERPROFILE%\.claude\, and merges settings.json.

4. Subscribe in ntfy app

Open ntfy → tap + → enter your channel name → Subscribe.

5. Start the dashboard (when you want it)

Either run the tray app (hosts the dashboard in-process, shows live state in a tray icon, double-click icon to open dashboard):

python tray_app.py
# or build once: .\build.ps1  →  dist\claude-notify-tray.exe

...or run the dashboard server alone:

python $env:USERPROFILE\.claude\dashboard.py

Open http://localhost:8765 in your browser.

6. Restart Claude Code

Hooks load on session start.


How it works

Claude Code lifecycle event
        │
        ▼
  hooks in settings.json
        │
        ▼
  notify.py <EventName>              ← reads hook JSON from stdin
        │
        ├── thread 1 → ntfy.sh → 📱 phone → ⌚ GT5 watch   (Stop / Notification only)
        ├── thread 2 → USB HID → 🖱️  G102 RGB color
        ├── thread 3 → localhost:8765/update → 🌐 dashboard SSE → browser
        └── thread 4 → Windows Notification → 🔔 toast popup   (Stop / Notification only)

All three fire in parallel threads — total latency = slowest one (~300ms). All hooks use "async": true — Claude Code never blocks waiting on them, they fire and forget. The hook script itself still costs real CPU/time to run; it just doesn't add latency to your session. Every output fails silently — a dead ntfy, disconnected mouse, or closed dashboard never blocks Claude.

Usage stats in Stop notifications

Claude Code does not expose token usage in hook stdin. The workaround: statusline.ps1 runs after every turn, receives usage data in its payload, and writes ~/.claude/session-usage.json. notify.py reads this file when the Stop hook fires and appends the stats to the notification.


Terminal status bar

statusline.ps1 renders a live bar at the bottom of Claude Code after every turn:

[claude-sonnet-4-6] ctx: 34% [██████░░░░░░░░░░░░░░]
5h: 12% (resets 4h 22m)  |  7d: 8% (resets 6d 14m)

Customization

Change notification text / priority

Edit notify.pyEVENTS dict.

ntfy priority levels: min, low, default, high, urgent ntfy emoji tags: docs.ntfy.sh/emojis

Change G102 colors

Edit rgb.pyCOLORS dict. Values are hex strings ("ff0000").

Dashboard settings page

Open ⚙ Settings from the dashboard header (or http://localhost:8765/settings) to:

  • Toggle Windows toast / phone (ntfy) / G102 RGB on or off
  • Paste your own GIF URL per state (waiting/running/done/idle/off) — blank reverts to the default JCVD gif

Saved to the same claude-notify-config.json used by notify.py and the tray app — takes effect on the next hook event, no restart needed.

Track multiple agents in the system tray

Running several Claude Code sessions at once? The tray icon normally shows only the single most attention-worthy state across all of them. Tick "track in tray" on any agent card in the dashboard to pin an extra tray icon just for that session — its own color, its own tooltip (project — state), right-click → Open Dashboard / Stop Tracking.

Requires tray_app.py (or the built exe) to be the process hosting the dashboard — it's the one with the tray event loop. Plain python dashboard.py has no tray to add icons to.

Disable individual outputs

Set environment variables — no need to touch hooks config:

$env:CLAUDE_NOTIFY_DASHBOARD = "0"   # stop dashboard updates
$env:CLAUDE_NOTIFY_RGB = "0"         # stop G102 color changes
$env:CLAUDE_NOTIFY_NTFY = "0"        # mute phone notifications
$env:CLAUDE_NOTIFY_TOAST = "0"       # mute Windows toast

Self-hosting ntfy (optional)

Free ntfy.sh has a daily message quota per IP — notify.py already limits phone pushes to Stop/Notification to stay well under it. If you still hit the quota (or want 100% privacy), run ntfy on your own server:

docker run -p 80:80 -v /var/cache/ntfy:/var/cache/ntfy binwiederhier/ntfy serve

Then change NTFY_BASE in notify.py to your server's IP or domain.


Roadmap

  • Phone notifications via ntfy.sh
  • Huawei GT5 via notification mirror
  • Usage stats (context %, 5h limit, 7d quota) on Stop
  • Terminal status bar
  • Logitech G102 RGB color change
  • Live dashboard with JCVD GIFs + SSE
  • Razer Chroma RGB support (same hooks, different controller)
  • Session duration on SessionEnd
  • ntfy topic per-project (CLAUDE_PROJECT_DIR)
  • pip install claude-notify one-command setup

License

MIT — free to use, modify, sell, or package as a product.

About

RGB mouse, phone push, and live dashboard alerts for Claude Code — know when Claude needs you without watching the terminal.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages