Know what Claude Code is doing — even when you're not at your desk.
Currently Windows-only (PowerShell + USB HID).
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.
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.
| 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").
✅ 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
|
Live dashboard Real-time state, JCVD status indicator, and session usage — all local, no cloud. |
Phone + watch Stacked ntfy notifications on lockscreen, mirrored to your smartwatch. |
Settings Toggle each output independently, or drop in your own GIF per state. |
| 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 |
- Android: Play Store
- iOS: App Store
claude-neba-xk7q2 ← good (hard to guess)
claude-code ← too generic
cd path\to\claude-notify
.\setup.ps1 -Channel "claude-neba-xk7q2"This installs Python deps, copies scripts to %USERPROFILE%\.claude\, and merges settings.json.
Open ntfy → tap + → enter your channel name → Subscribe.
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.pyOpen http://localhost:8765 in your browser.
Hooks load on session start.
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.
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.
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)
Edit notify.py → EVENTS dict.
ntfy priority levels: min, low, default, high, urgent
ntfy emoji tags: docs.ntfy.sh/emojis
Edit rgb.py → COLORS dict. Values are hex strings ("ff0000").
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.
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.
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 toastFree 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 serveThen change NTFY_BASE in notify.py to your server's IP or domain.
- 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-notifyone-command setup
MIT — free to use, modify, sell, or package as a product.




