Skip to content

About

macOS menu bar app for intelligent memory monitoring with app-specific process grouping

Resources

Stars

4 stars

Watchers

0 watching

Forks

Repository files navigation

Total Recall icon

Total Recall

A macOS menu bar app that provides intelligent, grouped views of memory (RAM) usage. Unlike Activity Monitor, Total Recall groups processes by logical application using built-in knowledge of how apps like Chrome, VS Code, Docker, Claude Code, and system services manage their process hierarchies.

The one thing to know: blue is RAM, amber is not

The number Activity Monitor gives you is an app's footprint — what it is charged for, not what it occupies. macOS compresses pages it thinks you are done with and writes others out to swap, and on a loaded machine the gap between the two runs to gigabytes. Total Recall's whole reason to exist is showing you that gap, so it spends its entire palette on it — two colors, and no others:

Means Where it comes from
🟦 In RAM Pages really sitting in physical memory right now residentSize
🟧 Compressed / swapped Memory macOS has squeezed out of physical RAM — compressed in place or written to disk Each process's compressed pages from its VM regions, with shared ones split between the processes mapping them, kept current by the kernel's per-process count (task_vm_info.compressed); physFootprint - residentSize for other users' processes

Nothing else in the app is colored, so there is no palette to memorize. The Memory River names its two halves down the left gutter in those same two colors, and carries a written key beneath the bar whenever you are not hovering a segment; the detail panel repeats it against the actual numbers. A group with a deep amber stub is not costing you RAM right now — but going back to it means waiting on decompression or swap I/O, which is what "my machine has plenty of free memory and still feels slow" usually turns out to be.

Features

  • Smart process grouping: Chrome processes grouped by profile, Electron apps by bundle, Claude Code by workspace, Xcode Simulator devices with the apps running on them broken out, system daemons with human-readable explanations
  • Memory River: proportional stacked bar across all your RAM — apps on the left, then segments measured from the kernel's own page counts: "Other" (app memory in no group, such as processes Total Recall can't inspect), "Kernel" (wired memory, never compressed or swapped), "Compressor" (the RAM the compressor pool occupies; hover to see how much it holds uncompressed), and "Available" (free pages plus file cache macOS can drop on demand, the same figure Activity Monitor reports). Apps are sized by their proportional share of RAM: memory a process shares with others, like system libraries, is split between them instead of counted once per process, so the apps add up to real app memory. The bar splits at a midline: blue segment widths above it are that in-RAM memory, and below it each app hangs an amber stub for what has been compressed or swapped out. Because width is already in-RAM memory, stub depth makes each rectangle's area the memory it holds — a deep stub is an app much larger than it looks, and two stubs of equal area hold equal memory wherever they sit in the bar. Hovering an app gives its in-RAM, compressed, and shared figures; with the Compressor drawn as its own segment, hovering it gives how much it holds and how much of that has been written to swap (the summary bar always shows both). A toolbar toggle ("Compressor in apps", on by default) shares the Compressor out to the apps instead: each gets an estimated slice of the pool's RAM in proportion to its compressed memory, so the bar shows apps rather than one large pool — each stub then holds only the part estimated to be in swap, at its uncompressed size, labelled "Swapped (estimated)". The readout marks both estimates with "~", since how much of any one app's compressed memory is in RAM rather than swap isn't something macOS reports. Groups too small to draw to scale fold into one "small groups" segment with its own stub (they keep their own rows in the list, and hovering the segment highlights them). A left gutter names the two halves in their own colors; the line beneath the bar carries the key until you hover a segment, when it becomes that segment's readout
  • Swap activity: a group reading back from swap faster than 1 MB/s gets an amber "↓ 9 MB/s" badge on its row, in its river readout, and in the detail panel — the kernel's own per-process swap-in counter, so you see which app is waiting on disk right now
  • Memory composition bars: per-process breakdown of resident (in RAM) vs compressed/swapped, in the same two colors, with both figures in the tooltip
  • VM region breakdown: the Regions tab in the detail panel walks a single-process app's virtual address space and shows categories (__TEXT, Heap, Anonymous, Stack, File-backed) with virtual size and resident pages; system and other-user processes show a clear access-denied explanation
  • Per-group sparklines: each group row charts its memory footprint over the last ~2 minutes, so a leak's slow ramp, a GC sawtooth, or a one-off step-change is recognizable by shape at a glance
  • Menu bar presence: memory pressure indicator + used/total display, with compressed and swap totals in the dropdown
  • Trend indicators: see which apps are growing or shrinking over time
  • Sort by footprint or resident: understand total impact vs what's actually in RAM
  • Instance merging: toggle between merged view (all Chrome instances as one) and separate view
  • Safe kill actions: PID-verified termination with system process protection and audit logging
  • Working directory context: see which directory Claude Code sessions are running in
  • Process identification: resolves node, python3, volta shims to what they're actually running (TypeScript Server, Webpack, MCP Server, etc.)

Screenshot

Total Recall inspection window

Requirements

  • macOS 26 (Tahoe) or later
  • Xcode 17+ (for building from source)
  • Apple Silicon or Intel Mac

Installing

Download the latest TotalRecall-<version>-arm64.dmg from Releases, open it, and drag Total Recall to Applications.

Total Recall is ad-hoc signed but not notarized (I don't have a paid Apple Developer account). The first time you launch it, macOS will show:

"Apple could not verify 'Total Recall.app' is free of malware..."

To allow it:

  1. Double-click the app → click Done on the warning.
  2. Open System Settings → Privacy & Security.
  3. Scroll to the security section — you'll see "'Total Recall' was blocked..." with an Open Anyway button.
  4. Click Open Anyway and authenticate.
  5. Launch the app again — you'll get one more confirmation dialog; click Open Anyway.

You only need to do this once. Alternatively, from Terminal:

xattr -d com.apple.quarantine "/Applications/Total Recall.app"

Building

git clone https://github.com/alecf/totalrecall.git
cd totalrecall
swift build
swift run TotalRecall

Running the diagnostic CLI

The diagnostic tool outputs the full classified process tree to the terminal:

swift run TotalRecallDiag

Running tests

swift test

Architecture

ProcessMonitor (actor, background thread)
  → SystemProbe (libproc/sysctl/Mach API wrappers)
  → ClassifierRegistry → ChromeClassifier, ElectronClassifier,
                          ClaudeCodeClassifier, SimulatorClassifier,
                          SystemServicesClassifier, GenericClassifier
  → Returns [ProcessGroup] + SystemMemoryInfo

AppState (@MainActor, @Observable)
  → Receives classified groups, computes trends
  → Drives SwiftUI views

Views (SwiftUI)
  → MenuBarExtra(.menu) — compact menu bar dropdown
  → Window — Memory River, group list, detail panel

Tiered data collection

Tier API Cost (886 PIDs) Strategy
0 proc_listallpids 0.17ms Every cycle
1 proc_pid_rusage 2.6ms Every cycle
2 proc_pidinfo + proc_pidpath 2.8ms Cached per PID
3 KERN_PROCARGS2 9.2ms Cached per PID
4 task_name_for_pid + TASK_VM_INFO (compressed, swap-ins) ~12ms Every cycle, same-user processes
5 PROC_PIDREGIONINFO walk (proportional share) ~2s 100ms budget per refresh, cached per PID

Tiers 0–3 take ~15ms for 886 processes (0.3% of a 5-second interval). Tier 4 reads the kernel's per-process compressed count and lifetime swap-in counter; a task name port is enough, and macOS hands one out for any process owned by the same user without root or entitlements. Tier 5 walks each process's VM regions to split shared pages — resident and compressed — between the processes mapping them; it spends at most 100ms per refresh (2% of a core), stalest and never-measured processes first, with a larger budget until every process has been measured once, and skips processes younger than 15 seconds.

Memory model

  • Physical footprint (phys_footprint): the primary metric, same as Activity Monitor's "Memory" column
  • Resident: pages currently in physical RAM — drawn in blue everywhere, labelled "In RAM"
  • Non-resident: compressed in-place or swapped to disk — drawn in amber everywhere, labelled "Compressed". For same-user processes it is the process's compressed pages from the region walk, with each shared object's compressed pages split between the processes mapping it so every page counts once, moved between walks by the kernel's own compressed count (task_vm_info.compressed, the figure Activity Monitor's "Compressed Memory" column shows); other users' processes fall back to physFootprint - residentSize, which undercounts when resident size includes shared mappings. The count includes compressed pages macOS has written to swap: it swaps whole compressor segments mixing many processes' pages, so the in-RAM vs on-disk split exists only system-wide, not per process. A per-process figure can therefore only name one of them; it names the compressor because that is the half macOS reaches first, and because it is the word Activity Monitor uses for the same memory. The wording lives in Theme.residentLabel / Theme.nonResidentLabel so every view says it the same way
  • Swap activity: the kernel's lifetime swap-in counter (task_vm_info.ledger_swapins), differenced between refreshes, gives an exact per-process rate of reads back from swap
  • Shared memory: deduplicated via RSHRD heuristic for group totals
  • Proportional resident (PSS): private pages plus each shared object's resident pages split evenly across the processes mapping it — what sizes the Memory River's app segments, so they sum to real app memory instead of counting a shared library once per process

Project structure

TotalRecall/           — App source
  Models/              — ProcessSnapshot, ProcessGroup, SystemMemoryInfo
  DataLayer/           — SystemProbe, ProcessMonitor, RedactionFilter, ProcessActions
  Profiles/            — ProcessClassifier protocol + 6 classifiers
  Theme/               — Colors, typography, spacing
  Views/               — SwiftUI views
  Utilities/           — Formatting, diagnostics, river layout, swap activity
TotalRecallDiag/       — CLI diagnostic tool
TotalRecallTests/      — Tests with synthetic fixtures
tools/                 — Benchmark scripts
docs/                  — PRD, research, plans
site/                  — Marketing website (React + Vite) + Sparkle appcast

Auto-updates

Released builds use Sparkle to check for new versions daily and offer them via the menu bar. The appcast feed lives at https://alecf.github.io/totalrecall/appcast.xml; updates are verified with EdDSA before installation. See docs/sparkle-setup.md for the one-time key generation steps required before the first signed release.

Contributing

This project is in early development. Issues and PRs welcome.

License

MIT

About

macOS menu bar app for intelligent memory monitoring with app-specific process grouping

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages