osascript-notify
Two notification systems + system event watching. All scripts are Python with JXA embedded.
Two Notification APIs
displayNotification (simple) |
AppleScript dialog (actionable) | |
|---|---|---|
| Buttons | No | Yes — custom labels |
| User response | No | Yes — returns choice |
| Persistent | No | Yes — blocks until dismissed |
| Setup | Zero | Zero |
Use scripts/notify.py for simple fire-and-forget alerts.
Use scripts/notify-actionable.py for "Proceed? Yes/No" style interactions.
Scripts
Send a simple macOS notification — title, subtitle, body:
uv run scripts/notify.py "Title" "Body text"
uv run scripts/notify.py "Build done" "Tests passed" --subtitle "CI"
Show an actionable dialog with custom buttons — blocks until user responds:
uv run scripts/notify-actionable.py "Deploy to production?"
uv run scripts/notify-actionable.py "Continue?" --buttons "Yes,No,Cancel"
Returns {"choice": "Yes", "cancelled": false} or {"choice": null, "cancelled": true} on Escape.
Watch for screen lock and unlock events (blocking — prints JSON on each state change):
uv run scripts/watch-screen-lock.py
uv run scripts/watch-screen-lock.py --count 3
Reference
- reference/11-notifications.md — Darwin notifications, NSDistributedNotificationCenter, common event names, notifyutil
- reference/19-usernotifications.md — Rich notifications with buttons, categories, scheduling (requires app bundle)
Key Darwin Notification Names
| Event | Notification name |
|---|---|
| Screen locked | com.apple.screenIsLocked |
| Screen unlocked | com.apple.screenIsUnlocked |
| Network change | com.apple.system.config.network_change |
Critical: Never pass null as notification name to NSDistributedNotificationCenter — causes NSNull length crash. Always pass a real string.