If you've spent any time configuring user authentication on... Full Story
By Manny Fernandez
September 22, 2026
Deploying and Running Mole on macOS: A Practitioner’s Guide
A practitioner’s guide to installing and running the open source mo command-line cleanup and monitoring tool.
Objective: Walk through a safe, repeatable deployment of Mole on macOS, covering both install paths, every core subcommand, and the safety controls that keep it from becoming a liability on a machine you care about.
Target audience: macOS power users, IT and security practitioners standardizing Mac hygiene across a fleet, and engineers who want one auditable tool instead of stacking several paid cleanup utilities.
Mole bills itself as a single binary covering the ground normally split across CleanMyMac, AppCleaner, DaisyDisk, and iStat Menus. It is free, open source under GPL-3.0, and runs entirely from the terminal. A separate paid native app, Mole for Mac, exists for people who want a GUI, but this guide stays scoped to the CLI.
Prerequisites & Architecture
Assumed knowledge: comfortable working in Terminal, understands what a sudo prompt is asking for, and has installed something through Homebrew before.
Environment and lab requirements:
- macOS 14 (Sonoma) or later for the Homebrew install path. Homebrew tracks Apple’s currently supported OS versions, so an older Mac needs the script installer instead.
- Apple Silicon or Intel, both supported.
- Administrator rights are needed for a handful of system-level maintenance tasks inside
mo optimize, not for the basic cleanup flow. - Internet access to Homebrew’s servers or to
raw.githubusercontent.comfor the script installer.
| Component | Purpose |
|---|---|
| mole / mo binary | The CLI itself; mo is the short alias used day to day |
| ~/.config/mole/whitelist | Caches and optimization rules explicitly protected from cleanup |
| ~/.config/mole/purge_paths | Custom project directories for mo purge to scan |
| ~/Library/Logs/mole/operations.log | Audit trail of every cleanup action Mole has taken |
| Mole for Mac | Separate, paid, closed-source SwiftUI app; not covered here |
Step-by-Step Implementation Workflow
Step 1: Install via Homebrew (preferred path)
Goal: Get the mo binary onto a supported macOS release with a single command.
Action:
brew install mole
Verification: brew list mole shows the formula, and a new shell has mo on PATH.
If Homebrew reports that it no longer supports the macOS version you’re running, skip straight to Step 2.
Step 2: Install via script (fallback, or unsupported macOS versions)
Goal: Install Mole on a Mac where Homebrew’s supported-OS tier has already moved past your release, or where you’d rather not add Homebrew at all.
Action:
curl -fsSL https://raw.githubusercontent.com/tw93/mole/main/install.sh | bash
This installs into /usr/local/bin by default, which is system-owned, so the script may ask for an administrator password.
Step 2b: Install to a user-owned directory
Goal: Keep future mo update runs from asking for a password every time.
Action:
mkdir -p "$HOME/.local/bin" curl -fsSL https://raw.githubusercontent.com/tw93/mole/main/install.sh | bash -s -- --prefix "$HOME/.local/bin" export PATH="$HOME/.local/bin:$PATH"
Add the export line to ~/.zshrc (or your shell’s profile) so new terminal sessions pick it up automatically. Commands that touch system-owned files can still prompt for elevation even with this install path; it is only routine updates that stop asking.
Step 3: Pin a specific release, or track development
Goal: Control exactly which build lands on the machine, useful when standardizing a fleet.
Action:
# A specific tagged release, with or without the leading V curl -fsSL https://raw.githubusercontent.com/tw93/mole/main/install.sh | bash -s -- 1.51.0 # The unreleased development branch curl -fsSL https://raw.githubusercontent.com/tw93/mole/main/install.sh | bash -s -- main
main pulls unreleased code, so expect rough edges on a production Mac. Note that latest is a legacy alias that also points at main, not the newest stable tag, so pin an explicit version number if you want reproducibility.
Step 4: Verify the installation
Goal: Confirm the binary is in place and functioning before touching any files.
Action:
mo --version mo --help
CLI Verification: mo --version prints an installed build string, and mo --help lists the clean, uninstall, optimize, analyze, status, purge, and installer subcommands along with touchid, completion, update, and remove.
Step 5: Preview everything with dry runs first
Goal: See exactly what each destructive subcommand would do without changing anything, especially important on a machine you did not set up yourself.
Action:
mo clean --dry-run mo uninstall --dry-run mo optimize --dry-run mo purge --dry-run mo installer --dry-run
Add --debug to any dry run for more detailed logging, for example mo clean --dry-run --debug.
Step 6: Run a deep cleanup pass
Goal: Reclaim disk space from caches, logs, temp files, developer artifacts, and leftovers from apps that are no longer installed.
Action:
mo clean
Mole walks the categories it considers known-safe (user app caches and logs, Trash, App Store cache, browser caches, developer tool caches such as npm and pnpm, unused Xcode simulator runtimes) and prints a per-category count of items and bytes freed, followed by a running total. Anything it cannot confirm is safe gets skipped with a stated reason rather than silently removed.
Step 7: Protect specific caches from cleanup
Goal: Keep Mole from touching a cache you rely on, for example a large local package-manager cache you don’t want rebuilt every week.
Action:
mo clean --whitelist
Selections persist in ~/.config/mole/whitelist and apply to every future mo clean run.
Step 8: Remove an installed application and its leftovers
Goal: Uninstall an app the way a dedicated uninstaller would, catching Application Support data, preference files, launch agents, and logs that dragging an app to the Trash leaves behind.
Action:
mo uninstall
This opens an interactive picker of installed apps. After you select one or more, Mole lists every file it plans to remove before touching anything, and it keeps shared data in place if another installed copy of the same app still depends on it. If an app has already been removed manually, its orphaned leftovers show up under mo clean instead.
Step 9: Run bounded system maintenance
Goal: Refresh caches and services that tend to accumulate cruft over weeks of uptime, without guessing at what “optimization” should mean.
Action:
mo optimize
This covers a DNS and Spotlight check, a Finder cache and icon-services refresh, database optimization for supported apps (skipped automatically if the app is currently open), and an optional disk health check. Every task reports back as applied, unnecessary, skipped, or unavailable, with a reason attached, rather than a task silently doing nothing.
Protect specific tasks or paths:
mo optimize --whitelist
This is also where you exclude a long-lived mounted disk image, for example a path like /Volumes/mail, from being flagged as a stale mount worth detaching.
Step 10: Explore disk usage interactively
Goal: Find what is actually consuming space, browsable rather than guessed at.
Action:
mo analyze mo analyze /Volumes # include external drives, skipped from the default overview mo analyze /private/tmp # review user-owned temp files without auto-flagging them for cleanup
Navigate with arrow keys or Vim-style bindings, filter and multi-select, preview in Finder, and send confirmed selections to Trash. Nothing is deleted outright from this view; everything routes through Trash first.
Step 11: Check live system health
Goal: Get a single dashboard for CPU, memory, disk, network, and power instead of switching between Activity Monitor panes.
Action:
mo status
This is read-only. It shows per-core CPU load, memory pressure, disk read/write throughput, network up/down, battery health and cycle count, and a combined 0-100 health score, plus read-only detection of zombie processes (it reports them, it does not kill them). Press k to toggle the mascot animation, c to cycle how many CPU cores are shown, and q to quit.
Machine-readable output:
mo status --json mo status --watch --interval 2s # streaming newline-delimited JSON
Step 12: Reclaim space from development projects
Goal: Delete rebuildable build artifacts (node_modules, target, .build, dist, and similar) without touching anything you’re actively working on.
Action:
mo purge
Mole groups artifacts by project and only pre-selects the ones with no file activity in the last 7 days by default, so an active build directory won’t get swept up by accident. It uses fd when available and falls back to find.
Custom scan directories:
mo purge --paths
Or edit ~/.config/mole/purge_paths directly, one directory per line. Once custom paths are configured, Mole scans only those; otherwise it defaults to locations like ~/Projects, ~/GitHub, and ~/dev.
Step 13: Clear out old installer files
Goal: Find and remove the DMG, PKG, MPKG, ISO, XIP, and installer ZIP files that pile up in Downloads after every app install or update.
Action:
mo installer
Mole checks Downloads, Desktop, Homebrew’s cache, and a few other common drop locations, and shows each candidate’s size and source before you confirm removal.
Step 14: Quality-of-life setup
Goal: Reduce friction for the commands you’ll run most.
Action:
mo touchid # enable Touch ID for sudo prompts mo completion # set up shell tab completion
Step 15: Keep Mole current, or remove it entirely
Action:
mo update # update to the latest release mo update --nightly # latest unreleased main build; script installs only mo remove # remove Mole from the system
Verification & Validation
Use these checks after any deployment, and again periodically if you’re standardizing Mole across more than one Mac:
# Confirm the installed build mo --version # Review what Mole has actually done, human-readable and machine-readable mo history mo history --json # One-time structured snapshots, useful for scripting or a fleet dashboard mo status --json mo analyze --json ~/Documents
Expected “success” signals:
mo --versionreturns a version string that matches what you installed in Step 1, 2, or 3.- A
--dry-runpass and the live run immediately after it report roughly the same categories and byte counts. If a dry run reports zero everywhere on a Mac that clearly has cache buildup, that points to a permissions problem, not an unusually clean machine. mo historyshows an entry for every cleanup action taken, timestamped. To disable this logging for a specific reason, setMO_NO_OPLOG=1before running a command.
Troubleshooting & Gotchas
1. Homebrew refuses to install the formula, or brew install mole fails outright.
Homebrew only supports Apple’s currently maintained macOS releases. If the Mac is running an older version that Homebrew has dropped, the fix is not to fight Homebrew: use the script installer from Step 2 instead, which works on a best-effort basis across older releases.
2. mo update asks for an administrator password every single time.
This means Mole is installed in a system-owned location, typically the default /usr/local/bin from the plain script install. Reinstall using the --prefix flag from Step 2b to point at a directory your user account owns, for example $HOME/.local/bin. Routine updates stop prompting; tasks that touch system-owned files during mo optimize can still ask for elevation, which is expected.
3. An install or update refuses to run and only reports a vague “busy” or lock error.
Recent releases (1.49.1 and later) replaced the generic lock message with a specific one that names the actual cause, whether that’s an untrusted parent directory, a lock path that got replaced by a symlink, or a missing admin session, and prints the exact command to fix it. If you’re on an older build and hit this, the safest path is to reinstall fresh with the curl script from Step 2. If mo update specifically needs admin rights, run it in a real terminal window (not embedded in another tool) and run sudo -v && mo update so the admin session is already primed before Mole asks for it.
This guide covers the free, open source mo CLI. Command behavior, flags, and output format can change between releases; check mo --help and the project’s release notes if something in this guide doesn’t match what you see on screen.
Recent posts
-
-
DNS is one of those technologies that quietly underpins... Full Story
-
BGP issues on FortiGate firewalls usually trace back to... Full Story
-
Every time your laptop talks to your router, a... Full Story
-
If you've spent any time configuring NAT on a... Full Story
-
If you have spent any time configuring firewall policies... Full Story
-
High availability on FortiGate is one of those features... Full Story
-
If you've configured SD-WAN on a FortiGate, you've almost... Full Story
-
FortiLink is the management protocol that turns a FortiSwitch... Full Story
-
FortiSwitches are pretty rock solid from Mean Time Between... Full Story
-
This is a quicky tip. Have you ever gone... Full Story
-
DNS is one of those quiet pieces of internet... Full Story
-
This article is an updated version of the previous... Full Story
-
You will add ns2 as a secondary (slave) BIND9... Full Story
-
In the process of deploying my lab, I needed... Full Story
-
RFC 8805, used to be known as Self-Correcting IP... Full Story
-
Years back, I wrote an article about certificate pinning. ... Full Story
-
FortiGates have the ability to send alerts to Microsoft... Full Story
-
In this post, I am going to walk through... Full Story
-
Troubleshooting VoIP on a FortiGate can feel like trying... Full Story
-
Prior to FortiOS 7.0, there were three commands to... Full Story
-
In this post, I am going to go over... Full Story
-
What we are going to do: We are going... Full Story
-
Choosing between FGCP (FortiGate Clustering Protocol) and FGSP (FortiGate... Full Story
-
Creating a VLAN on macOS (The "Pro" Move) A... Full Story
-
This blog post explores the logic behind how macOS... Full Story
-
Pretty Fly for a Wi-Fi Tell My Wi-Fi Love... Full Story
-
Part of my daily gig is creating BoMs (Bill-of-Materials)... Full Story
-
ICMP introduces several security risks, but careful filtering, rate... Full Story
-
The command diag debug application dhcps -1 enables full... Full Story
-
In the world of FortiOS, execute tac report is... Full Story
-
LLDP; What is it The Link Layer Discovery Protocol... Full Story
-
What it actually does When you run diagnose fdsm... Full Story
-
Monkey Bites are bite-sized, high-impact security insights designed for... Full Story
-
I have run macOS in macOS with Parallels but... Full Story
-
Don't be confused with my other FortiNAC posts where... Full Story
-
This is the third session in a multi-part article... Full Story
-
Today I was configuring key-based authentication on a FortiGate... Full Story
-
Netcat, often called the "Swiss Army knife" of networking,... Full Story
-
At its core, IEEE 802.1X is a network layer... Full Story
-
In case you did not see the previous FortiNAC... Full Story
-
This is our 5th session where we are going... Full Story
-
Now that we have Wireshark installed and somewhat configured,... Full Story
-
The Philosophy of Packet Analysis Troubleshooting isn't about looking... Full Story
-
Speed Up the Dock via TerminalOpen the Terminal app... Full Story
-
Executive Summary Argus (jasonxtn/Argus) is a Python based, all... Full Story
-
Windows 11 has well over a hundred keyboard shortcuts,... Full Story