By default, Caelestia's Notifs.qml service handles incoming notifications using a NotificationServer. It holds a list of active alerts:
property list<NotifData> list: []
readonly property list<NotifData> notClosed: list.filter(n => !n.closed)
When a notification is dismissed (either by clicking the close button or clearing all), the NotifData object gets removed from the memory list, and the cache is updated. There is no historical log to review missed alerts.
To implement a notification history/log, I mirrored the design of the clipboard service by adding cache serialization and separate data models.
Extend the Notifs Service
In services/Notifs.qml, I add a separate cache file (~/.cache/caelestia/notif_history.json) to hold dismissed notifications and intercept the deletion event:
// Inside Notifs.qml
property list<var> historyList: []
function addToHistory(notif) {
let serialized = {
title: notif.summary,
body: notif.body,
appName: notif.appName,
time: new Date().toLocaleTimeString(),
icon: notif.appIcon
};
// Add to top and cap list at 50 items
historyList.unshift(serialized);
if (historyList.length > 50) historyList.pop();
// Persist to json cache
saveHistoryToFile();
}
Hook the Dismiss Event
In services/NotifData.qml, right before the notification is removed from the active lists, I invoke the new service function:
// Inside NotifData.qml (close/destruction logic)
onClosedChanged: {
if (closed) {
Notifs.addToHistory(this);
}
}
Create the History UI
I create a new NotifHistoryView.qml under modules/sidebar/. It uses a ListView displaying the Notifs.historyList array, allowing scrolling through past alerts, clearing individual items, or flushing the entire JSON log.
By separating active/floating notifications from historical serialized logs:
- The active notification UI stays extremely fast and responsive.
- Dismissed notifications don't waste system resources or memory inside in-flight QML objects.
- Data is written asynchronously to a local JSON cache, making it lightweight and persistent across reboots.