neon-phal-plugin-notifications
Notification Manager for Neon/OVOS, packaged as a PHAL plugin. It is the single
chokepoint for ovos.notification.api.* traffic on the hub messagebus: it
validates producer requests, owns notification state (active / snoozed /
dismissed / expired), persists that state across restarts, enforces emission
and dismissal policy, and emits notify / dismiss / snoozed events for
consumers (the Node app today, other plugins later).
The plugin never renders anything and never talks to MQ. Bus in, bus out.
Transport lives in neon-messagebus-mq-connector and neon-hana; rendering
lives in consumers.
Requirements
Notification data models come from neon-data-models. Until the next release
they live on the FEAT_Notifications branch; install that branch first:
pip install git+https://github.com/NeonGeckoCom/neon-data-models@FEAT_Notifications
pip install neon-phal-plugin-notifications
Configuration
All keys live under the plugin's PHAL section. Every key is optional.
PHAL:
neon-phal-plugin-notifications:
store: json # persistence adapter; only "json" ships
store_path: null # override the JSON file path (default:
# $XDG_DATA_HOME/neon/neon-phal-plugin-notifications/notifications.json)
allow_global: # skill_ids permitted to use scope=GLOBAL
- skill-alerts.neongeckocom
allow_non_removable: # skill_ids permitted to set removable_by_user=false
- skill-alerts.neongeckocom
rate_limit: 30 # accepted `set` requests per producer per window
rate_window_seconds: 3600
consumers_allowed_to_dismiss: [] # empty/absent = every consumer may dismiss
consumers_blocked_from_dismiss: []
retention_max_age_days: 7 # tombstone window for dismissed/expired entries
tick_seconds: 60 # expiry + retention sweep interval
Policy defaults are asymmetric on purpose: dismissal is open, high-impact
emission (GLOBAL scope, non-removable) is closed except for seeded first-party
producers. An unlisted producer that requests either is refused with a reason
in .set.response; nothing is silently downgraded.
Message API
Every request gets a .response reply on the request's own context, so MQ
routing survives the round trip.
| Consumed | Reply |
|---|---|
ovos.notification.api.set {notification} |
.set.response {notification_id, status, reason?} |
ovos.notification.api.remove {notification_id?, skill_id?, dismissed_by?} |
.remove.response {notification_ids, status, reason?} |
ovos.notification.api.get {notification_id} |
.get.response {notification} |
ovos.notification.api.list {skill_id?, state?, since?, node_id?, user_id?} |
.list.response {notifications, states} |
ovos.notification.api.snooze {notification_id, duration} |
.snooze.response {notification_id, status, renotify_at?, reason?} |
ovos.notification.api.interaction {notification_id, action_id, callback_data?} |
none; re-emitted for the producer, then dismissed if the action's dismiss_on_activate is true |
ovos.notification.api.sync.request {since?} |
.sync.request.response {notifications, states, server_time} plus one notify per entry |
ovos.notification.api.set.controlled / .remove.controlled |
deprecated wrappers; reply as .set.response / .remove.response |
| Emitted | When |
|---|---|
ovos.notification.api.notify {notification} |
a set is accepted, a snooze elapses, mycroft.ready, sync.request |
ovos.notification.api.dismiss {notification_id, skill_id, scope, target, dismissed_by} |
a notification is removed, dismissed, or expires (dismissed_by: "expired") |
ovos.notification.api.snoozed {notification_id, renotify_at, scope, target} |
a snooze is granted |
Behavior notes:
setis an upsert. The sameskill_idre-sending an existingnotification_idreplaces it in place, resets it to ACTIVE, and re-emitsnotify. Anotification_idowned by a differentskill_idis refused.created_atis stamped by the manager on first accept and preserved on updates;updated_atis bumped on every change (upsert, snooze, re-notify, dismissal, expiry, per-client dismissal) and rides on the wireNotification. Everysincefilter (list,sync.request, and so the HANA REST catch-up) compares againstupdated_at.- Retention is a tombstone window, not history: DISMISSED and EXPIRED entries
stay for
retention_max_age_daysso a node that was offline learns on catch-up that a notification was dismissed elsewhere, then they are pruned. ACTIVE and SNOOZED entries are never pruned. - A missing
sessionis filled fromMessage.context.session. A CLIENT-scoped notification with notargettakes the requester's node identity from the context (context.node.node_id, thencontext.client_id, then a non-localsession.session_id). removeneedsnotification_id(the producer is resolved from the stored record; askill_idthat disagrees with it is refused) orskill_idalone (remove everything that producer owns). Neither is refused. The requester isdismissed_by, elseskill_id, else the context's node/session identity. A requester equal to the producer bypassesremovable_by_user; anyone else is a consumer subject toremovable_by_userand the consumer dismiss lists.dismiss_policy=PER_CLIENT: a consumer dismissal records that client and leaves the shared state ACTIVE;listwithnode_idreports DISMISSED for that client only.SHAREDdismissals set DISMISSED for everyone.- Legacy flat GUI-API payloads (
sender,text,action,type,style) are up-converted with a deprecation log.
Testing
pip install -e .[test]
pytest tests/
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file neon_phal_plugin_notifications-0.1.0.tar.gz.
File metadata
- Download URL: neon_phal_plugin_notifications-0.1.0.tar.gz
- Upload date:
- Size: 27.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dbe761b596b251c0b3b15f115ce9ee70f7f27ff6ae42d16199f20d5f9c4bdecf
|
|
| MD5 |
902f9119a3163b926d3a37f9b6a636fd
|
|
| BLAKE2b-256 |
69cc303360e0cd1c9e0242304b9fb9452a1f3268ecc1d13ac9fbade82a113d18
|
File details
Details for the file neon_phal_plugin_notifications-0.1.0-py3-none-any.whl.
File metadata
- Download URL: neon_phal_plugin_notifications-0.1.0-py3-none-any.whl
- Upload date:
- Size: 27.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4b598b700743b8b8e81e552c5c0706c4a80c1424aa8b1de17c3e9f0c1680918e
|
|
| MD5 |
795150f5f73f7ded235489f340cd4d36
|
|
| BLAKE2b-256 |
06da49b88e6b9b7b711ea4eaee9a6c14a76962b4a8bee302c13c51ae93a08463
|