Files
dots/common/.config/claude/hooks/notify.py
T
2026-09-17 20:58:21 +02:00

52 lines
1.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Notification hook: a desktop notification when Claude is waiting on you.
settings.json wires it to `idle_prompt|permission_prompt` (the Notification matcher is the
`notification_type`). Push notifications are off in this setup, so this is the local
counterpart of pi's notify.ts. Uses notify-send where present (the Wayland/GUI hosts) and
silently no-ops on a headless box or without a session bus. Payload fields are read
defensively -- the docs do not pin the Notification input schema: `message`, `title`,
`notification_type`, `cwd`.
"""
import json
import os
import shutil
import subprocess
import sys
TITLES = {
"idle_prompt": "Claude Code is waiting for you",
"permission_prompt": "Claude Code needs a permission",
}
def main():
try:
data = json.load(sys.stdin)
except Exception:
return
exe = shutil.which("notify-send")
if not exe:
return
kind = data.get("notification_type") or "notification"
title = data.get("title") or TITLES.get(kind, "Claude Code")
body = (data.get("message") or "").strip() or kind
cwd = data.get("cwd") or ""
if cwd:
home = os.path.expanduser("~")
body += "\n" + (("~" + cwd[len(home):]) if cwd.startswith(home) else cwd)
try:
subprocess.run(
[exe, "--app-name=Claude Code", "--urgency=normal", "--expire-time=8000",
# same tag -> a newer notification replaces the previous one instead of stacking
f"--hint=string:x-canonical-private-synchronous:claude-code-{kind}",
title, body],
timeout=5, capture_output=True,
)
except Exception:
pass
if __name__ == "__main__":
main()