#!/usr/bin/env python3 """ Pushover notification script for Daedalus. Sends push notifications when Claude needs human input, resolves questions, or reports session status. Environment variables required: PUSHOVER_USER_KEY — Your Pushover user key PUSHOVER_APP_TOKEN — Your Pushover application token Usage: notify.py blocking "Title" "Message body" # High priority, red alert notify.py question "Title" "Message body" # Normal priority, question notify.py resolved "Title" "Message body" # Low priority, question resolved notify.py info "Title" "Message body" # Lowest priority, FYI only notify.py error "Title" "Message body" # High priority, session error """ import sys import os import urllib.request import urllib.parse import json from datetime import datetime PUSHOVER_API_URL = "https://api.pushover.net/1/messages.json" # Priority levels map to Pushover priority values: # -2 = lowest, -1 = low, 0 = normal, 1 = high, 2 = emergency (requires ack) NOTIFICATION_TYPES = { "blocking": { "priority": 1, "sound": "persistent", "prefix": "šŸ›‘ BLOCKING", "description": "Work is stopped — response needed", }, "question": { "priority": 0, "sound": "pushover", "prefix": "šŸ’¬ QUESTION", "description": "Claude has a non-blocking question", }, "resolved": { "priority": -1, "sound": "none", "prefix": "āœ… RESOLVED", "description": "A previous question is no longer needed", }, "info": { "priority": -2, "sound": "none", "prefix": "ā„¹ļø INFO", "description": "Status update, no action needed", }, "error": { "priority": 1, "sound": "siren", "prefix": "āŒ ERROR", "description": "Session error or unexpected failure", }, } def send_notification(notif_type: str, title: str, message: str) -> bool: """Send a Pushover notification. Returns True on success, False on failure (prints error to stderr). """ user_key = os.environ.get("PUSHOVER_USER_KEY") app_token = os.environ.get("PUSHOVER_APP_TOKEN") if not user_key or not app_token: print( "ERROR: PUSHOVER_USER_KEY and PUSHOVER_APP_TOKEN must be set.", file=sys.stderr, ) return False if notif_type not in NOTIFICATION_TYPES: print( f"ERROR: Unknown notification type '{notif_type}'. " f"Valid types: {', '.join(NOTIFICATION_TYPES.keys())}", file=sys.stderr, ) return False config = NOTIFICATION_TYPES[notif_type] timestamp = datetime.now().strftime("%Y-%m-%d %H:%M") full_title = f"{config['prefix']}: {title}" full_message = f"{message}\n\nšŸ• {timestamp}" data = urllib.parse.urlencode({ "token": app_token, "user": user_key, "title": full_title, "message": full_message, "priority": config["priority"], "sound": config["sound"], }).encode("utf-8") try: req = urllib.request.Request(PUSHOVER_API_URL, data=data) with urllib.request.urlopen(req, timeout=10) as response: result = json.loads(response.read().decode("utf-8")) if result.get("status") == 1: print(f"Notification sent: {full_title}") return True else: print( f"ERROR: Pushover API error: {result}", file=sys.stderr, ) return False except Exception as e: print(f"ERROR: Failed to send notification: {e}", file=sys.stderr) return False def main(): if len(sys.argv) < 4: print("Usage: notify.py \"Title\" \"Message\"") print(f"Types: {', '.join(NOTIFICATION_TYPES.keys())}") print("\nDescriptions:") for name, config in NOTIFICATION_TYPES.items(): print(f" {name:10s} — {config['description']}") sys.exit(1) notif_type = sys.argv[1] title = sys.argv[2] message = sys.argv[3] success = send_notification(notif_type, title, message) sys.exit(0 if success else 1) if __name__ == "__main__": main()