A terminal-native macOS system monitor, cleaner and optimizer — a free, private, open-source CCleaner alternative built for developers. 100% local, zero telemetry.
Install • Quick Start • Screenshots • Sentinel • Features • Commands • SoClose
macmon is a free, open-source Mac system monitor and cleaner that runs entirely in your terminal. Think CCleaner Pro + Activity Monitor + Security Scanner + Docker Manager, reimagined as one fast CLI with a live TUI dashboard — purpose-built for developers who live in the shell.
If you have ever searched for "how to clean my Mac", "free CCleaner alternative for macOS", "free up disk space on Mac", "why is my Mac slow", or "macOS system monitor CLI" — this is the tool, and it never phones home.
30 commands · 21 modules · Live dashboard · MACMON-SENTINEL always-on watchdog · Keyboard shortcuts that execute real actions · Autopilot daemon · Thermal management · Security & malware scanner · Docker manager · 100% local, zero telemetry
- Free & open source (MIT) — no license, no account, no upsell, no cloud.
- Private by design — everything runs locally; nothing is uploaded, ever.
- Developer-first cleanup — reclaims
node_modules, stale venvs, Docker cache, Xcode/DerivedData, npm/pip/brew caches with safety guards. - Safe deletes — moves to Trash by default and never silently escalates to permanent deletion.
- One binary of a habit — monitor, clean, secure and keep your Mac fast from a single CLI.
macmon is macOS-first (that is where every feature works), with a cross-platform core so the portable tools also run on Windows and Linux. On other platforms, macOS-only commands degrade gracefully with a clear "requires macOS" message instead of crashing.
This is not a claim -- it is enforced. CI runs on macOS, Ubuntu and Windows (Python 3.11 and 3.13) on every push: it imports all 21 modules, smoke-tests the portable commands, and asserts that every macOS-only command exits cleanly with a "requires macOS" notice off-mac.
| Feature | macOS | Windows | Linux |
|---|---|---|---|
ps / kill / suspend / nice (processes) |
✅ | ✅ | ✅ |
disk / bigfiles / dupes |
✅ | ✅ | ✅ |
clean (temp / cache / logs / dev caches) 1 |
✅ | ✅ | ✅ |
gc (node_modules, venvs, docker, caches) 2 |
✅ | ✅ | ✅ |
network / flush-dns |
✅ | ✅ | ✅ |
docker management |
✅ | ✅ | ✅ |
health score |
✅ | ✅ (core checks) | ✅ (core checks) |
sentinel monitor + auto-remediation |
✅ | ✅ (schtasks) | ✅ (cron) |
Live dashboard (TUI) |
✅ | ✅ | ✅ |
security (pf, SIP, FileVault, Gatekeeper) |
✅ | -- | -- |
privacy / startup / uninstall / auto / focus |
✅ | -- | -- |
1 Core paths only (temp, caches, logs, dev caches) route through the
cross-platform layer. clean --browsers still uses macOS browser-profile paths
(~/Library/...), so it finds nothing on Windows/Linux today.
2 Core scanning (node_modules, venvs, __pycache__, Docker, npm /
pnpm / yarn / bun) is cross-platform, and the pip cache is resolved per OS
(~/Library/Caches/pip, %LOCALAPPDATA%\pip\Cache, $XDG_CACHE_HOME/pip).
On Windows/Linux install by cloning + pip install -r requirements.txt, then
python macmon.py. The macOS install.sh sets up the macmon shortcut on
macOS/Linux.
|
System health, scored /100 |
One-pass junk & cache cleaner |
|
Security & malware audit |
Categorized process monitor |
Above: the MACMON-SENTINEL tactical console (top of page). All output is real, rendered live — no mockups.
|
Full-screen TUI with real-time monitoring:
|
Execute real actions directly from the dashboard:
|
|
|
|
|
|
Background rules engine:
|
|
|
|
git clone https://github.com/SoCloseSociety/macmon.git
cd macmon
bash install.shThis will:
- Check Python 3.11+
- Create a venv at
~/.macmon/venv - Install dependencies (
rich,psutil,typer,send2trash,xxhash) - Create
/usr/local/bin/macmonwrapper - Initialize config at
~/.macmon/config.toml
macmon is a standard Python package (pyproject.toml), so it installs with pip
into any Python 3.11+ environment and puts the macmon command on your PATH:
git clone https://github.com/SoCloseSociety/macmon.git
cd macmon
pip install .Prefer an isolated install? pipx works out of the box:
pipx install .For development, use an editable install: pip install -e .
PyPI release planned under the brand name (the macmon name on PyPI belongs to
an unrelated project): pip install aegisforge will install the same macmon
command once published.
bash build_dmg.sh
open dist/macmon.dmg# Launch the live dashboard
macmon
# Full system clean
macmon clean --all -y
# Dev garbage collector
macmon gc --all -y
# Security audit
macmon security
# Health check + auto-fix
macmon health --fix
# Kill zombies & orphans
macmon sweep -y
# Purge RAM
macmon purge
# Start autopilot daemon
macmon auto --start
# Focus mode
macmon focus
# All commands
macmon --help| Command | Description |
|---|---|
macmon |
Live dashboard |
macmon ps |
Process list with categories |
macmon kill <target> |
Kill process |
macmon suspend / resume <target> |
Suspend / resume process |
macmon nice <target> <val> |
Renice process |
macmon quit / restart <app> |
Graceful quit / restart app |
macmon sweep |
Kill zombies, orphans, stale locks |
macmon ports |
Port manager |
macmon clean --scan |
Preview cleanable junk |
macmon clean --all -y |
Full system clean |
macmon clean --browsers |
Browser cleaner |
macmon gc --scan |
Preview dev garbage |
macmon gc --all -y |
Full dev GC |
macmon privacy --scan |
Preview privacy traces |
macmon privacy --full -y |
Wipe all traces |
macmon health |
Health check /100 |
macmon health --fix |
Auto-fix safe issues |
macmon startup --list |
List startup items |
macmon startup --audit |
Audit suspicious items |
macmon uninstall <app> |
Uninstall + leftover cleanup |
macmon dupes <path> |
Find duplicate files |
macmon bigfiles |
Find large files |
macmon disk |
Disk usage analyzer |
macmon network |
Network connections |
macmon flush-dns |
Flush DNS cache |
macmon security |
Security audit /100 |
macmon security --block-ip <ip> |
Block IP via pf firewall |
macmon security --quarantine <proc> |
Kill + block process |
macmon docker |
Docker overview |
macmon docker --prune -y |
Docker full cleanup |
macmon docker --scan |
Docker security audit |
macmon auto --start / --stop |
Start / stop autopilot daemon |
macmon focus / restore |
Focus mode on / off |
macmon purge |
Purge inactive RAM |
macmon report |
Session report |
macmon config --show / --edit |
View / edit config |
macmon sentinel --install |
Arm the always-on light monitor |
macmon sentinel |
Tactical console snapshot |
macmon sentinel --watch |
Live tactical console |
macmon sentinel --force-clean |
Manual override: scan then clean |
macmon sentinel --test-notify |
Test notification (shows the AegisForge icon) |
macmon sentinel --enable-auto |
Enable safe auto-remediation (unload idle ollama models + RAM purge) |
macmon sentinel --enable-auto --aggressive |
Also auto-close idle AI sessions |
macmon sentinel --enable-auto --reap |
Also auto-reap PROVEN leaked orphans (PID 1 + parent watched dying) |
macmon sentinel --disable-auto |
Disable all auto-remediation (back to notify-only) |
macmon sentinel --trim |
Close idle AI sessions now |
macmon sentinel --reap-orphans |
List proven leaked orphans and reap them now (asks first) |
macmon sentinel --unload-ollama |
Unload idle ollama models now (they reload on demand) |
macmon sentinel --setup-purge |
Grant passwordless purge via sudoers so auto-purge runs unattended |
An ultra-light watchdog that keeps the Mac operational without you watching it.
- Near-zero cost: a single-shot sampler fires every 60s via a LaunchAgent, measures in ~0.5s, appends one compact JSON line, then exits. No resident process between samples (~0.1% average CPU, ~20 MB peak per sample).
- Precise: tracks CPU, RAM, swap, load, disk, network RTT, the top CPU process, and the AI-agent fleet (Claude Code / codex / MCP counts + RSS) so forgotten sessions are surfaced, not rediscovered in a crisis.
- Hidden RAM hogs, surfaced: it also tracks the two big ones nothing else
shows you -- loaded ollama models (
ollama ps, multi-GB and easy to forget) and the Docker/Colima VM footprint. The VM is notify-only: the Sentinel warns abovevm_gband never stops it on its own. - Auto-interaction: threshold alerts fire native macOS notifications (swap high, memory pressure, runaway process, network saturated, low disk, AI fleet too large), each with a cooldown.
- Auto-remediation (safe escalation): nothing is automatic until you opt in.
Remediation only fires when memory pressure is genuinely critical (RAM above
ram_criticaland swap aboveswap_critical_gb), and the Sentinel always notifies what it did:- Level 1a --
auto_unload_ollama(non-destructive): unloads idle ollama models when RAM is critical and they hold at leastollama_gb. Never touches a model mid-inference (a busy runner is detected and skipped), and models reload automatically on the next request. Turned ON by--enable-auto. - Level 1b --
auto_purge(non-destructive, macOS only): frees inactive RAM viapurge. Turned ON by--enable-auto. - Level 2 --
auto_trim_fleet(opt-in): closes idle AI coding sessions (Claude Code) beyond a configurable minimum (fleet_keep), protecting the most recently active ones so the session you are using is never touched. A session must be idle foridle_samplessamples (~10 min) first, and sessions are resumable (--resume). Requiresmacmon sentinel --enable-auto --aggressive. - Turn everything back off with
macmon sentinel --disable-auto(notify-only). - Manual levers any time:
macmon sentinel --trimcloses idle sessions now,macmon sentinel --unload-ollamaunloads idle ollama models now.
- Level 1a --
Heads-up:
--enable-autoenables levels 1a and 1b. That means once RAM is critical, macmon may unload your loaded ollama models without asking. It is non-destructive (they reload on demand, and never mid-inference), but if you want notifications only, do not run--enable-auto.
purge requires root, so unattended auto_purge needs sudo without a password
prompt. macmon sentinel --setup-purge sets that up explicitly, and only that:
- It writes
/etc/sudoers.d/macmon-purgecontaining exactly one line:<your-user> ALL=(root) NOPASSWD: /usr/sbin/purge - The snippet is validated with
visudo -cbefore being installed (a malformed sudoers file would breaksudosystem-wide), then installed0440. - The grant is scoped to that single binary --
/usr/sbin/purgeand nothing else. It is not blanket passwordless sudo. - Without it,
auto_purgeis simply skipped and notifications still fire. It is optional. - Revoke at any time:
sudo rm /etc/sudoers.d/macmon-purge - Manual override: force levers when you must push the system --
--force-purge,--force-clean,--force-focus,--pause/--resume. - Branded notifications: alerts pop up as AegisForge carrying its icon
(not the generic Script Editor icon) via a tiny bundled notifier app. Try it
with
macmon sentinel --test-notify.
macmon sentinel --install # arm it (LaunchAgent, 60s sampler)
macmon sentinel # tactical snapshot with gauges + sparklines + FORGE panel
macmon sentinel --watch # live console
macmon sentinel --status # agent + config status
macmon sentinel --log # recent alertsmacmon is the engine; AegisForge ("fleet health, forged") is what you see:
the console theme and banner, the notification identity, and a set of
anticipatory detectors (macmon_core/aegis.py) that read the metrics
history so the sentinel alerts on trajectory, not just on the current
value. Nothing here is a rename: the CLI, the package, the console script and
the LaunchAgent labels are unchanged.
All detectors are on by default and notify-only:
| Detector | Fires when | Example notification |
|---|---|---|
| Swap climbing | swap >= swap_trend_min_gb, rising >= swap_slope_gb_min GB/min, and due to cross swap_critical_gb within swap_eta_min (before the line -- past it, the absolute alert owns it) |
Swap 5.7 GB, climbing +0.30 GB/min -- reaches the 8 GB critical line in ~8 min at this rate. Biggest RSS: ... |
| Memory pressure climbing | same contract on RAM% (ram_trend_min, ram_slope_pct_min, ram_eta_min -> ram_critical) |
RAM 84%, climbing +1.5%/min -- hits the 90% critical line in ~4 min |
| Load catastrophe | load1 > load_factor x logical cores for load_sustain consecutive samples |
Load 32.0 on 12 cores (2.7x) for 3 samples -- top CPU: node 41%, ... (CPU% is a share of the whole machine: per-process % divided by logical cores, so 100 = every core busy) |
| Process swarm | headless browsers (puppeteer / playwright / Chrome for Testing / any browser binary run --headless) grow by swarm_headless_growth within swarm_window samples or exceed swarm_headless_max; any other executable grows by swarm_growth while >= swarm_min |
59 headless browser processes (+35 in 5 min), spawned by node shoot.mjs (pid 4242). Not auto-killed (live workload) |
| Leaked orphans | >= orphan_alert_min dev processes (headless browsers, node incl. next-server, python) sit under PID 1 and their parent is proven dead |
3 leaked dev processes (parent exited, reparented to PID 1, +3 over the window): Google Chrome for Testing x3 |
The console's FORGE panel shows the same figures live (slope, ETA, sustained load, swarm growth and its spawner, proven vs. unproven orphans).
What "proven dead" means -- and the safety line. The only auto-action
AegisForge can take is reaping leaked orphans, and it is opt-in
(auto_reap_orphans, off by default; --enable-auto --reap, or on demand with
--reap-orphans). A process qualifies only if all of these hold:
- it is reparented to PID 1 and an earlier sample saw it under a live parent that a later sample saw exit (or turn zombie, or have its PID reused). A dead process-group leader is deliberately not accepted as proof: on macOS every launchd/brew-services job and the Android emulator look like that;
- it is in a dev family (headless browser, node, python) and outside the
never-touch set -- IDEs and their helpers, Claude/codex/MCP sessions and native
hosts,
~/.claude~/.codex~/.cursor~/.vscodeinfrastructure, ollama and local LLM runtimes, Sentinel/NeoBot/fleet processes (WireGuard, sshd), VMs and containers, terminals and shells, other users, anything under/System,/usr/libexec,/usr/sbin, and your apps under/Applications(except a browser binary running--headless, which is an automation instance); - it has been idle (< 1% CPU, itself and its descendants) for
reap_idle_samplessamples, holds no live socket -- no ESTABLISHED connection, and for node/python no LISTEN or bound unix socket either, since an idle backgrounded dev server is still in service (unknown => skip) -- and is still under PID 1 at signal time.
Then, and only then, it gets SIGTERM (never SIGKILL). A process with a live parent is never signalled, whatever the swarm looks like: the swarm detector names the spawner and leaves stopping it to you.
Prefer a real app window to the terminal? AegisForge.app is a TRUE native
desktop app -- PySide6 / Qt native widgets, not a webview (Dock icon, the
fleet's Sentinel model) -- wrapping the same engine, cross-platform, with a
sidebar of seven sections and a top bar of live vitals plus a global
worst-severity indicator:
| Section | What it shows | What it can do (each a confirmed funnel) |
|---|---|---|
| Overview | CPU / RAM / swap / load / disk bars + sparklines, FORGE anticipation lines, health score, recent alerts | -- |
| Processes | top processes, search + sort, PROTECTED rows |
Kill (SIGTERM) / Suspend / Resume per row, Purge RAM |
| Clean | Scan -> itemized Review (checkboxes, sizes) -> Confirm -> Done "freed X" | Trash-first clean of the ticked categories only |
| Security | scored scan, pass / warn / fail findings + fix hints | quarantine a process |
| Docker | overview stats, containers / images / volumes / disk usage | prune dangling images (never -a, never volumes) |
| Disk | top-level usage bars, big files | Reveal in Finder |
| Sentinel | sampler state, FORGE trends, the detectors, thresholds | Pause / Resume, the four opt-in auto-remediation switches (default OFF) |
The UI thread never calls the engine: every read and every action runs on a Qt
thread pool and returns on the UI thread through a queued signal, so a disk walk
or a security scan never freezes the window. Actions go through app_api.Api
in-process -- the one guarded entry point -- and only from a funnel's confirm
step; reads are the same pure dict builders the CLI shares. Every guardrail
holds: protected processes are refused, a guarded one (IDE, agent, LLM,
container, the fleet, the app's own render process ...) needs an explicit
acknowledgement, cleaning is preview-first and Trash-first, the docker prune is
dangling-only, only the four opt-in keys flip, nothing auto-runs on construction
or a timer. It does not sample on its own -- it reads what the 60s LaunchAgent
sampler wrote. If PySide6 is absent the entry point falls back to the pywebview
window, then the menu-bar agent, so nothing regresses. Full Disk Access is
still needed to analyze/clean macOS-protected folders (as for any Mac disk tool).
The page is built on one design system (assets/webui/app.css): the AegisForge
brand tokens (ground / mint / ember, the same C[] palette the Rich console
uses) behind a semantic layer, dark by default with a coherent light ramp
(follows the system, or Auto / Dark / Light from the sidebar), skeleton / empty
/ error / stale states, keyboard navigation (1-7 jump to a section), a
phone-width layout with a bottom tab bar, and no font, image or script from the
network. Build it (only needed for the app; the CLI never depends on it):
pip install -e ".[app]" # pywebview + rumps + pyobjc, app-only
./build_aegisforge.sh # -> dist/AegisForge.app (add --dmg for a disk image)
open dist/AegisForge.appIt builds like the fleet's Sentinel.app: PyInstaller --windowed, the
ember-shield icon, ad-hoc codesigned, a real windowed app (Dock icon); the page
lives in assets/webui/ (bundled). If pywebview is absent it degrades to a
menu-bar agent that opens the dashboard in the browser. It is a convenience
shell -- every safety guarantee above still comes from the one engine.
Full Disk Access. Like every macOS disk tool, the app needs Full Disk Access
to analyze or clean folders macOS protects (Documents, Desktop, Downloads, and
~/Library corners): grant it under System Settings > Privacy & Security > Full
Disk Access. Without it, a Disk analysis of a protected folder blocks on the
macOS TCC gate (the CLI, run from a terminal that already has access, is
unaffected); accessible paths like /usr/local or /Applications work either way.
Config lives in ~/.macmon/sentinel.conf (JSON). Any key you omit falls back to
the default below.
| Key | Default | Meaning |
|---|---|---|
swap_used_gb |
6.0 |
Alert when swap usage exceeds this many GB |
ram_pct |
92.0 |
Alert when RAM usage exceeds this percentage |
proc_cpu |
95.0 |
Alert when a single process exceeds this share of the whole machine's CPU (per-process % divided by logical cores: 100 = every core busy), i.e. a runaway |
rtt_ms |
400.0 |
Alert when network round-trip time exceeds this |
disk_free_gb |
15.0 |
Alert when free disk space drops below this |
ai_fleet |
12 |
Alert when the AI-agent fleet exceeds this many processes |
ping_every |
5 |
Ping only every Nth sample (spares a metered link) |
ollama_gb |
2.0 |
Warn when idle ollama models hold more than this |
vm_gb |
4.0 |
Warn when a Docker/Colima VM holds more than this (notify-only) |
auto_purge |
false |
Level 1b: purge inactive RAM when critical (macOS only) |
auto_unload_ollama |
false |
Level 1a: unload idle ollama models when critical |
auto_trim_fleet |
false |
Level 2: close idle AI sessions when critical |
fleet_keep |
4 |
Always keep at least this many AI sessions alive |
ram_critical |
90.0 |
Remediation triggers above this RAM% ... |
swap_critical_gb |
8.0 |
... and above this swap usage, never on one alone |
idle_samples |
10 |
A session must be idle this many samples (~10 min) before trimming |
trend_window |
10 |
Samples used for slope / ETA (~10 min) |
swap_trend_min_gb / swap_slope_gb_min / swap_eta_min |
3.0 / 0.1 / 20 |
Swap-climbing alert: floor (GB), slope (GB/min), ETA to swap_critical_gb (min) |
ram_trend_min / ram_slope_pct_min / ram_eta_min |
75 / 1.0 / 15 |
Memory-climbing alert: floor (%), slope (%/min), ETA to ram_critical (min) |
load_factor / load_sustain |
2.0 / 3 |
Load catastrophe: load1 > factor x cores, for this many consecutive samples |
swarm_window |
5 |
Growth is measured against the sample this many samples back |
swarm_headless_min / swarm_headless_growth / swarm_headless_max |
8 / 8 / 40 |
Headless-browser swarm: floor, growth in the window, absolute cap |
swarm_floor / swarm_min / swarm_growth |
8 / 24 / 12 |
Any executable: tracked from swarm_floor instances; alert at >= swarm_min with >= swarm_growth growth |
orphan_alert_min |
3 |
Alert when this many PROVEN leaked orphans are present |
auto_reap_orphans |
false |
Opt-in: SIGTERM proven leaked orphans (see the safety line above) |
reap_idle_samples |
5 |
A leak must be idle this many samples (~5 min) before reaping |
reap_families |
["headless","node","python"] |
Which leak families may be reaped |
reap_max |
40 |
At most this many reaps per cycle |
macmon.py CLI router (typer, 30 commands)
macmon_core/
dashboard.py Live TUI (rich) — 12 panels, keyboard shortcuts
sentinel.py MACMON-SENTINEL: 60s sampler, alerts, auto-remediation
aegis.py AegisForge layer: theme/brand, trend detectors, lineage-proven leak reaper
app_menubar.py AegisForge.app menu-bar face (rumps, optional): reads the sampler's rows, explicit actions only
app_webui.py AegisForge.app reads: loopback server (127.0.0.1, GET only) + the native window
app_api.py AegisForge.app actions: the pywebview js_api bridge (every guardrail enforced here)
assets/webui/ the app page (index.html, app.css = the design system, app.js, mark.svg) -- offline, no HTML-string sink
processes.py Process manager, sweep, ports
cleaner.py System cleaner (junk, browsers, apps)
gc.py Dev garbage collector
security.py Security scanner & IP blocking
docker_mgr.py Docker container/image/volume management
autopilot.py Daemon, thermal rules, security rules, focus mode
health.py Health check /100 & reports
privacy.py Privacy traces wiper
startup.py Startup/login items manager
uninstaller.py App uninstaller with leftover detection
duplicates.py Duplicate file finder (xxhash + SHA-256)
disk.py Disk analyzer & big file finder
network.py Network monitor
config.py TOML config manager
platform_compat.py Cross-platform layer (macOS / Windows / Linux paths, require_os)
utils.py Shared utilities, SQLite DB, logging
Config lives at ~/.macmon/config.toml:
macmon config --editKey sections: dashboard, thresholds, cleaner, privacy, gc, focus_mode, notifications, autopilot.
git clone https://github.com/SoCloseSociety/macmon
cd macmon
pip install -e ".[test]" # runtime deps + pytest
pytest -q # 519 hermetic tests: no network, no live subprocessThe suite is hermetic (tmp_path + monkeypatch only), so it runs anywhere. CI
(.github/workflows/ci.yml) runs it plus smoke
tests on macOS, Ubuntu and Windows (Python 3.11 and 3.13) on every push --
that matrix is what enforces the cross-platform behavior. Version history is in
CHANGELOG.md.
MIT -- see LICENSE. Free forever, for any use.
Is macmon really free? Yes — MIT licensed, no account, no telemetry, no paid tier.
Does it send my data anywhere? No. Everything runs locally on your Mac. There is zero network telemetry.
Is it a CCleaner alternative for Mac? Yes — it covers the same ground (caches, logs, temp, browser data, privacy traces) plus developer-specific cleanup (node_modules, venvs, Docker, Xcode) and safe Trash-first deletes.
Will it delete something important? Deletes move to the Trash by default and never silently escalate to permanent removal. Destructive categories are opt-in.
Which macOS versions? macOS 12 (Monterey) and newer, on Apple Silicon and Intel. Python 3.11+.
Keywords: mac cleaner · macOS system monitor · clean my Mac · free CCleaner alternative macOS · free up disk space Mac · why is my Mac slow · macOS terminal system cleaner · developer Mac tools · node_modules cleaner · Docker disk cleanup Mac · macOS privacy cleaner · macOS malware scanner CLI · Activity Monitor alternative · Mac optimizer open source · Python Typer Rich TUI · zero telemetry mac utility
Built with purpose by SoClose — Digital Innovation Through Automation & AI