Self-hosted service
mac-cleanup/mac-cleanup-py avatar
mac-cleanup/mac-cleanup-py

mac-cleanup-py: one force flag, 43 modules, and a dry run you should trust first

👨‍💻 Python cleanup script for macOS

2,379 stars99 forksPythonApache-2.0

At a glance

What is it?
A Python rewrite of an older macOS shell cleaner, packaged under three different names, shipping 43 cleanup modules that range from package manager caches to iOS device backups. The safety story is one flag wide, and the manifest has a few edges worth reading before you install it.
Who is it for?
Judgment: this is a defensible tool for a Mac you own and a home directory you have already backed up, and the first command anyone should run is the dry run, because the module list reaches well past caches into device backups and simulators. Three things to settle first.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 175 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 5, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Three names for one tool, and only one of them is the command

Installing means picking between two package managers that disagree on the name. The Homebrew formula is `mac-cleanup-py`, the pip distribution is `mac-cleanup`, and the command you end up typing is a third name again, `mac-cleanup`, because that is what the console script entry point declares. All four lines, install and uninstall for both managers, are one command each:

bash
brew install mac-cleanup-py
pip3 install mac-cleanup
brew uninstall mac-cleanup-py
pip3 uninstall mac-cleanup

The import name is a fourth variant. The package directory drops both hyphens and uses `mac_cleanup`, and the distribution metadata carries that same underscored form, so a Python side import matches neither of the hyphenated names you type in a shell. The project is described as a rewrite of an earlier shell script, mac-cleanup-sh, which is the fifth name in the family and the likeliest reason the pip distribution took a shorter form than the repository.

The help text offers -v and leaves it out of the usage line

The help output is the only place every flag is written down, and it disagrees with itself. The usage line advertises six optional switches: `-h`, `-n`, `-u`, `-c`, `-p` and `-f`. The options list underneath adds a seventh, `-v, --verbose`, described as printing the folders to be deleted.

code
$ mac-cleanup -h
usage: mac-cleanup [-h] [-n] [-u] [-c] [-p] [-f]

    Python cleanup script for macOS
    Version: 3.3.0
    https://github.com/mac-cleanup/mac-cleanup-py

options:
  -h, --help         show this help message and exit
  -n, --dry-run      Run without deleting stuff
  -u, --update       Update Homebrew on cleanup
  -c, --configure    Open module configuration screen
  -p, --custom-path  Specify path for custom modules
  -f, --force        Accept all warnings
  -v, --verbose      Print folders to be deleted

The descriptions are terse to the point of ambiguity. `-u, --update` reads as update Homebrew on cleanup, which tells you when the update happens and nothing about what it touches, so it is worth deciding for yourself whether a cleanup run should be the thing that refreshes your package manager. The version in that banner, 3.3.0, is the same number the manifest carries and the same tag the newest release uses, which is one consistency point in the project's favour.

Forty-three default modules, and four of them delete rather than clear a cache

Three headline actions are promised up front: empty the Trash, delete unnecessary logs and files, clear the cache. The detail sits in a collapsed section listing 43 default modules, and reading them changes how much the third promise covers. Most are caches named for the tool that made them: `brew`, `bun`, `npm`, `pnpm`, `yarn`, `poetry`, `gem`, `composer`, `conan`, `go`, `gradle`, `pod`, `pyenv` and `nuget`. Others are logs: `system_log`, `wget_logs`, `java_cache` for Java head dumps in the home directory, `cacher`, `kite`, and `jetbrains` for logs from editors such as PhpStorm and PyCharm.

Then there are the ones that do not merely clear a cache. `ios_backups` removes iOS device backups. `ios_apps` cleans up iOS applications. `xcode_simulators` resets the iOS simulators. `trash` empties the Trash on all mounted volumes and the main drive, not only your home directory. `gem` removes old versions of gems, and `docker` removes dangling images and stopped containers. Which of these run is a configuration choice, opened by `-c, --configure`, so the module list is a menu rather than a fixed behaviour.

-p, --custom-path plus a template file is how outside modules arrive

The extension mechanism is visible in three places that agree with each other. A file called `module_template.py` sits at the repository root and reads as the scaffold for writing a new module. `jinja2` appears among the development dependencies. And the CLI carries a switch for pointing at modules that are not built in: `-p, --custom-path Specify path for custom modules`.

Configuration itself is TOML, since `toml` is a runtime dependency, and `-c, --configure` opens a module configuration screen instead of asking you to edit a file by hand. That screen is also where a destructive module such as `ios_backups` gets switched on, so the decision about what to delete and the decision about how to extend the tool meet in the same place.

Version bumps have their own tooling. A `bumpVersion` file at the repository root carries no extension, and `commitizen` sits in the development dependencies next to `pre-commit`, while `tox.ini` and a `.pre-commit-config.yaml` cover the checks.

py.typed is excluded from the built artifact while pyright is a dependency

Two paths are stripped from what gets packaged. The manifest excludes `mac_cleanup/__main__.py` and `mac_cleanup/py.typed`, and includes `LICENSE`. The second exclusion deserves a pause: `py.typed` is the marker that tells a type checker a distribution ships inline annotations. A repository that carries one and then excludes it from the build declares itself typed during development and untyped once installed.

That gap is more noticeable here because type checking is wired in from both directions. `pyright` sits in the test dependency group, and `beartype` is a runtime dependency rather than a development one, which means types are checked statically during the test run and again at import time. `attrs` is present as well, so the module metadata has a class based library to lean on.

None of this stops the tool working. It does mean that a downstream project which wants annotations from `mac_cleanup` will not get them from the installed package.

The Python range reaches 3.14 while the classifiers stop at 3.13

The dependency range is `>=3.10,<3.15`, so a 3.14 interpreter satisfies it. The classifiers stop one version earlier, listing 3.10, 3.11, 3.12 and 3.13 alongside `Operating System :: MacOS` and `Environment :: Console`. The gap between the declared range and the declared classifiers means a 3.14 install resolves its dependencies while nothing describes that combination as supported.

The formatters disagree in the other direction. `black` targets `py313` and `isort` is pinned to `py_version=313`, while the project still claims to run on 3.10, so the tools that decide what the code looks like are configured for a language level above the oldest interpreter on the support list. Linting is split three ways instead of one: `ruff` sits in the test group, `black` and `isort` in the lint group, and `docformatter` joins them there for docstrings, with `pyright` covering types and `pytest` plus `pytest-cov` and `tox` covering the test run.

The documentation link in the manifest points at an anchor that does not exist

The project metadata declares a documentation URL with a fragment in it. The Documentation entry is the repository page with `#install-automatically` on the end. The README has no heading, link or anchor by that name. Its installation section is titled Installation and opens with two subsections, Using Homebrew and Using pip.

So the one link a package index would render as the documentation link lands on the top of a page rather than on the automatic install instructions it names. The rest of that table is sound: the issue tracker entry points at the issues path of the same repository, and both the homepage and repository fields name the repository itself. The readme field points at README.md, which makes it the only path in the manifest written with a file extension rather than as a URL.

The newest tag is from March 2025 and the branch moved in April 2026

Version numbers here move in steps and then stop. The tags run v3.1.2 on 13 October 2024, v3.2.0 on 1 March 2025, and v3.3.0 on 19 March 2025, each carrying nothing beyond the tag name as a release note. The manifest still declares 3.3.0, so nothing has been cut since March 2025, while the default branch was pushed on 14 April 2026. That leaves more than a year of commits past the newest published release, and a working tree that has moved beyond the only version anyone can install by tag.

The release step is a local script rather than a published action: a `bumpVersion` file with no extension at the root, `commitizen` in the development dependencies, and exactly one console script declared. Governance files are present and unremarkable, with `SECURITY.md`, `CODE_OF_CONDUCT.md` and `CONTRIBUTING.md` at the root and 21 open issues against 2377 stars, which is a low enough ratio to suggest the issue tracker is being worked rather than abandoned.

Editorial conclusion

Judgment: this is a defensible tool for a Mac you own and a home directory you have already backed up, and the first command anyone should run is the dry run, because the module list reaches well past caches into device backups and simulators. Three things to settle first. Know that `-f, --force` accepts all warnings in one step, which is the difference between a reviewable run and an unreviewable one. Know that `-p, --custom-path` lets modules from outside this repository run under your own command, so the trust boundary is wider than the version number suggests. And know that the newest published tag is v3.3.0 from March 2025 while the branch has moved on since, so install from the branch you intend rather than assuming the tag is current.

Frequently asked questions

Is mac-cleanup-py safe to run on my Mac?

It deletes, so start with `-n, --dry-run`, which runs without deleting anything, and read the list of folders with `-v, --verbose`. Note that `-f, --force` accepts all warnings in one step, and that the default module list includes `ios_backups` for iOS device backups, `xcode_simulators`, `ios_apps`, and `trash` which empties the Trash on all mounted volumes and the main drive.

How do I install mac-cleanup-py and what is the command called?

Two routes with two different names. `brew install mac-cleanup-py` installs the Homebrew formula, and `pip3 install mac-cleanup` installs the pip distribution. Either way the command you type is `mac-cleanup`, and uninstalling is `brew uninstall mac-cleanup-py` or `pip3 uninstall mac-cleanup`.

What does mac-cleanup-py delete beyond caches and logs?

The 43 default modules go past caches: `ios_backups` removes iOS device backups, `ios_apps` cleans up iOS applications, `xcode_simulators` resets the iOS simulators, `gem` removes old gem versions, `docker` removes dangling images and stopped containers, and `trash` empties the Trash on all mounted volumes and the main drive. Which modules run is chosen through `-c, --configure`.

Can I add my own module to mac-cleanup-py?

Yes, through `-p, --custom-path`, which specifies a path for custom modules. The repository root carries `module_template.py` as a scaffold and `jinja2` is a development dependency. Module settings are held in TOML, since `toml` is a runtime dependency, and `-c, --configure` opens the module configuration screen.

Which macOS and Python versions does mac-cleanup-py support?

The classifiers declare `Operating System :: MacOS` and Python 3.10, 3.11, 3.12 and 3.13, while the dependency range is `>=3.10,<3.15`. The newest release is v3.3.0, published on 19 March 2025, and the default branch was last pushed on 14 April 2026.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. mac-cleanup/mac-cleanup-py on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mac-cleanup-mac-cleanup-py.svg)](https://hysenlabs.com/projects/mac-cleanup-mac-cleanup-py)