Features and enhancements to consider for future development.
Ability to define rules based on the sending application:
[[rules]]
match = { app_name = "discord" }
action = { suppress = true } # Hide Discord notifications entirely
[[rules]]
match = { app_name = "slack" }
action = { urgency = "low", timeout = 3000 } # Reduce urgency, short timeout
[[rules]]
match = { app_name = "signal" }
action = { persist = true, urgency = "critical" } # Always require manual dismissalMatch notification content (summary, body) with regex or substring:
[[rules]]
match = { body_contains = "claire" }
action = { urgency = "critical", persist = true, bypass_dnd = true }
[[rules]]
match = { summary_regex = "(?i)error|failed|critical" }
action = { urgency = "critical" }
[[rules]]
match = { body_regex = "meeting (started|in 5)" }
action = { sound = "~/sounds/meeting.wav" }suppress: Don't show popup at all (still logged to history)hide: Don't show popup or log to historypersist: Require manual dismissal (never timeout)urgency: Override urgency level (low/normal/critical)timeout: Override timeout in millisecondssound: Override notification soundbypass_dnd: Show even when DnD is enabledmute_sound: Suppress sound for this notification
app_name: Exact match or regex on application nameapp_name_contains: Substring match on app namesummary: Exact match or regex on summarysummary_contains: Substring match on summarybody: Exact match or regex on bodybody_contains: Substring match on bodycategory: D-Bus notification categoryurgency: Match specific urgency leveldesktop_entry: Match desktop entry hint
Schedule DnD automatically:
[dnd.schedule]
enabled = true
start = "22:00" # 10 PM
end = "08:00" # 8 AM
days = ["mon", "tue", "wed", "thu", "fri"] # Weekdays onlyAuto-enable DnD based on focused window or running applications:
[[dnd.rules]]
name = "fullscreen"
trigger = "fullscreen_app" # Any fullscreen application
action = { enable_dnd = true, reason = "fullscreen application detected" }
[[dnd.rules]]
name = "zoom-meeting"
trigger = { app_running = "zoom" }
action = { enable_dnd = true, reason = "Zoom meeting in progress" }
[[dnd.rules]]
name = "gaming"
trigger = { window_class_regex = "steam_app_.*" }
action = { enable_dnd = true, reason = "gaming session" }
[[dnd.rules]]
name = "screenshare"
trigger = "screenshare_active" # Requires integration with Wayland compositor
action = { enable_dnd = true, reason = "screen sharing" }user- Manual toggle via CLI, TUI, or GUIrule- Triggered by a DnD rule (with rule name)schedule- Time-based schedulesystem- System event (fullscreen, screenshare, etc.)
Notifications with persist = true or the D-Bus "resident" hint:
- Never auto-timeout (ExpireTimeout = 0)
- Require explicit user dismissal
- Show a visual indicator (e.g., pin icon)
- Always shown even when DnD is active (if
bypass_dnd = true)
stack_duplicates: Combine identical notifications with count badgegroup_by_app: Group notifications from same appmax_visible_per_app: Limit popups per application
- Multi-monitor support with per-monitor positioning
- Follow focused window/mouse
- Avoid fullscreen windows
Override notification sounds based on rules:
[[rules]]
match = { app_name = "calendar" }
action = { sound = "~/sounds/calendar-reminder.wav" }Support XDG sound themes and freedesktop.org sound naming:
[audio]
theme = "freedesktop" # Use system sound theme
fallback = "~/sounds/default.wav"- Inline actions: Execute notification actions from TUI
- Bulk operations: Select multiple notifications for dismiss/delete
- Search/filter by app, content, date range
- Notification preview with full body text
- Rule editor: Create/edit notification rules from TUI
- Show notification preview on hover
- Right-click context menu
- Scroll to cycle through notifications
- HTTP/REST API for external control
- D-Bus interface for scripting
- Integration with Sway/Hyprland IPC for window/workspace events
Currently, the mapping between D-Bus notification IDs and GTK popup windows is managed by:
DisplayStateManager: Maps D-Bus ID <-> histui ULIDManager.popups: Maps D-Bus ID ->PopupState(containsPopupGTK window)
Consider adding:
- Direct ID storage on the
Popupstruct for debugging - Window naming with notification ID for compositor rules
- Layer-shell namespace per notification for window manager integration
- Lazy loading of notification icons
- Virtual scrolling in TUI for large history
- Indexed search on history store
- D-Bus integration tests with mock bus
- GTK widget tests
- Theme/CSS validation tests
Extract relative time formatting to shared library:
RelativeTime(t time.Time) string- "5 minutes ago"RelativeTimeShort(t time.Time) string- "5m ago"FormatDuration(d time.Duration) string- "2h 15m"
Already implemented in tvarr's pkg/format/format.go - candidate for extraction.