Skip to content

feat: configurable memory threshold alerts via macOS notifications #32

Description

@alecf

Problem

Total Recall is purely reactive — you have to open the window and look. There's no way to be notified when a specific app balloons or when system pressure escalates, so memory problems often go unnoticed until the machine becomes sluggish.

Proposed Solution

Let users define alert rules that fire macOS notifications via UNUserNotificationCenter. Alerts are created contextually by right-clicking any group row in the main list — no separate settings screen needed to get started.

Context Menu UX

Right-clicking a group row opens the existing context menu, extended with an Alerts submenu. The submenu is context-aware: it shows the group's current memory, pre-computed suggestions, and any already-active alerts for that group.

Example — right-clicking Google Chrome at 1.2 GB:

Google Chrome
──────────────────────────────
  Copy PID
  Quit
  Force Quit
──────────────────────────────
  Alerts
  ├─ Alert if Chrome exceeds 1.3 GB  (+10% — add)  ← suggested
  ├─ Alert if Chrome exceeds 1.5 GB  (+25% — add)  ← suggested
  ├─ Alert if Chrome exceeds 2.0 GB  (add)          ← suggested round number
  └─ Alert if pressure goes Warning  (add)          ← system-level suggestion

If alerts already exist for the group, they appear at the top of the submenu with a checkmark and a "Remove" action:

  Alerts
  ├─ ✓ Chrome > 1.3 GB  [Remove]
  ├─ Add: Chrome > 1.5 GB
  └─ Add: Chrome > 2.0 GB

Suggested Thresholds (auto-computed from current footprint)

Suggestion Threshold
"+10%" currentFootprint × 1.10, rounded to nearest 100 MB
"+25%" currentFootprint × 1.25, rounded
"Round number" Next round GB boundary above current (e.g. current=1.2 GB → suggest 2 GB)
"Pressure Warning" System-level, always shown regardless of which group is right-clicked
"Pressure Critical" System-level, always shown

Alert Rule Model

struct AlertRule: Codable, Identifiable {
    let id: UUID
    var groupIdentifier: String?   // nil = any group / system-level
    var groupDisplayName: String   // for display in notifications
    var metric: AlertMetric        // .footprint, .resident, .pressureLevel
    var threshold: UInt64          // bytes, or pressure level raw value
    var cooldownMinutes: Int       // default 5
    var createdAt: Date
}

enum AlertMetric: String, Codable {
    case footprint, resident, pressureLevel
}

Rules are stored in UserDefaults (small, no file I/O needed). Evaluated inside the existing AppState refresh loop on every full poll tick.

Notification Behavior

  • Use UNUserNotificationCenter; request authorization on first rule creation
  • Notification title: "Total Recall: \(groupName)", body: "Memory footprint reached \(formatted threshold)"
  • Per-rule cooldown (default 5 min) prevents spam — store lastFiredAt alongside the rule
  • Tapping the notification brings the Total Recall window to front with that group selected

Implementation Notes

  • Add AlertRule and AlertStore to TotalRecallCore/DataLayer/
  • Extend the context menu in GroupRowView / ProcessRowView with the Alerts submenu
  • Threshold suggestions computed at menu-build time from the group's current physFootprint
  • AlertStore exposes rules(for groupIdentifier:) so the submenu can show existing alerts inline
  • A full Alerts management UI (list/edit/delete all rules) can be a follow-up; the context menu covers the primary add flow

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions