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.com for 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 --version returns a version string that matches what you installed in Step 1, 2, or 3.
  • A --dry-run pass 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 history shows an entry for every cleanup action taken, timestamped. To disable this logging for a specific reason, set MO_NO_OPLOG=1 before 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

  • If you've spent any time configuring user authentication on... Full Story

  • 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