Djaunt / MemGuard / macOS
Know before your Mac runs out of memory.
MemGuard watches the signals that actually move before macOS shows "your system has run out of application memory." It warns early, shows what is reclaimable, and never kills anything on its own.
Why the usual numbers lie
Two alarming numbers that mean nothing.
Activity Monitor and the out-of-memory dialog show figures that look like the problem and aren't. MemGuard ignores them and watches what actually moves first.
One VS Code extension host, measured. The huge figure is address space that V8 reserves for its pointer-compression cage. It is a promise to the allocator, not memory, and it cannot fill up.
Chrome reserves 89 TB of virtual space on the same machine and nobody blames it.
macOS keeps the swap file near capacity and grows it on demand. Free swap sits near zero on a healthy Mac. Measured: 0.7 GB free while total swap grew from 27 to 28 GB.
Across 41 recorded incidents the kernel's free-memory level read 33–62%, including three minutes before an out-of-memory dialog. It counts compressible pages as free.
Memory load (swap used plus compressor, as a share of RAM) climbed for 30 minutes before the same dialog. After recovery it read about 104%. This is the number MemGuard warns on.
What it watches
Signals that move ahead of the dialog.
Sampled every 10 seconds by a launch agent. Apps are ranked by physical footprint, the number Activity Monitor's Memory column and the out-of-memory dialog both use.
| Signal | Source |
|---|---|
| Memory load | vm.swapusage, vm_stat, hw.memsize |
| Swap growth | vm.swapusage over ~60s |
| Compressor size | vm_stat |
| Kernel pressure | kern.memorystatus_vm_pressure_level |
| Free % (backstop) | kern.memorystatus_level |
| Boot disk headroom | swap cannot grow past it |
| One extension host | Reading |
|---|---|
footprint -p | 785 MB |
top -stats mem | 785 MB |
ps rss | 485 MB, 38% low |
Tiers
Shape and color, so it reads either way.
The menu bar item labels itself with memory load, so you can read it without clicking.
Below every threshold.
Load ≥ 120%, free ≤ 10%, or swap growing ≥ 1.5 GB/min. Posts a banner.
Load ≥ 130%, free ≤ 5%, kernel pressure critical, or boot disk ≤ 15 GB. Banner plus a dialog that stays until dismissed.
Relief and alerts silenced for a set time.
Escalates after 2 samples (~20s). De-escalates after 30 (~5 min). A late warning is useless, and an early all-clear is misleading. Alerts repeat every 10 minutes while a tier holds.
Safety
Your agents and builds are never touched.
Every agent, dev server, build, and SSH session runs inside a shell. MemGuard protects every shell subtree, so it excludes them by structure, not by a name list that goes stale.
- Automatic relief never terminates anything. Every kill is one explicit click.
- Re-checked at click time. The target is validated against the protection rules again at the moment of the kill.
- Only idle GUI renderers are candidates. Browser and Electron renderer helpers, which reload when the window is next focused. Editor extension hosts are excluded because they hold state.
- Hard exclusions. Busy processes, root-owned processes, and PIDs below 500 are never candidates. Editor renderers are flagged risky and sorted last.
Relief ladder
What it can do about it.
The ladder ships conservative. Only the last rung frees real app memory, and it needs your click.
Purge off by default
Drops the file cache only. Pressure is usually anonymous app memory, which purge cannot free, and the cache refills in minutes. Kept as a manual menu item.
Pressure pulse opt-in
Signals critical pressure for ~3s so apps release internal caches, then resets. It writes a kernel sysctl, so it ships disabled.
Reclaim idle tabs manual
The action that frees memory. One click reclaims idle renderers, or pick one from a ranked list with app and megabytes for each.
Black box recorder
Evidence instead of a guess.
The out-of-memory dialog names a culprit, but nothing is measuring when it appears, so the claim can never be checked. On every escalation MemGuard writes a timestamped snapshot to ~/.djaunt/memguard/incidents/: per-app totals by physical footprint, the 25 largest processes with their protected or candidate status, and how much was reclaimable at that moment.
Install
No Homebrew. No dependencies.
Bash, launchd, and the system swiftc for the menu bar app. Everything lives in ~/.djaunt/memguard/.
Clone
git clone https://github.com/tory37/djaunt-memguard.git cd djaunt-memguard/mac
Install the launch agents and menu bar app
./bin/djt-memguard install
Optional: passwordless purge
Grants exactly two commands, nothing else.
./bin/djt-memguard install-sudoers
CLI
Everything the menu does, in a shell.
$ djt-memguard status # current tier and all metrics $ djt-memguard top # what is reclaimable, what is protected $ djt-memguard reclaim <pid> # terminate one idle renderer, re-checked first $ djt-memguard reclaim --safe # reclaim safe candidates up to a target $ djt-memguard relief # drop the file cache $ djt-memguard pause 60 # silence relief and alerts $ djt-memguard log # recent activity $ djt-memguard uninstall # unload and remove the launch agents
Platforms
macOS today. Laid out for more.
Each platform lives in its own top-level folder with its own probe, tiers, and UI. The ideas carry over. The signals do not.
macOS
supportedIn mac/. Launch agent, CLI, and native menu bar app. Tested on Apple silicon.
Linux
not startedWould watch PSI (/proc/pressure/memory) and the OOM killer.
Windows
not startedWould watch commit charge against the commit limit.