The table
| CoreTend | CleanMyMac | Pearcleaner | PureMac | OnyX | |
|---|---|---|---|---|---|
| Licence | Apache-2.0 | proprietary | Apache-2.0 + Commons Clause¹ | MIT | proprietary |
| Source published | yes | no | yes | yes | no |
| Price | free | paid | free | free | free |
| Removal | Trash only, always | — | — | Trash in some paths, permanent in others² | — |
| Unattended deletion | never offered | — | — | scheduled auto-clean² | — |
| Runtime dependencies | zero³ | — | — | — | — |
| Network calls | one, user-initiated⁴ | — | — | — | — |
¹ Source-available, not OSI-approved — its own README calls it “fair-code”.
² PureMac’s README states this itself, which is more than most of this category does.
³ Package.resolved holds swift-testing and swift-syntax, both test-only.
⁴ grep -rn URLSession Sources/ returns exactly one file: the update check.
The row that matters
The fourth one. CoreTend has no code path that deletes — not for caches, not for duplicates, not under an administrator prompt, not from a schedule, not from a CLI. Everything eligible goes to the macOS Trash and stays recoverable there.
It is also why the app never reports a “freed” total: it is never told when the Trash is emptied, so it cannot honestly claim the space came back.
Gates, not adjectives
These are not promises in a README. Each one fails the build when it stops being true:
- Everything is recoverable —
Reversible means the Trash can give it back - No invented quantities —
Copy does not claim what the app cannot know - Every destructive path is validated —
PathValidator,SafetyCenter - A refusal is recorded as a refusal —
Refusals and failures stay distinct - The record cannot go silently short —
Audit log durability
Run them with bash Scripts/test.sh, from the public repository.
Method
Licences come from the GitHub API or the vendor's own site. PureMac's removal behaviour comes from its own README. The empty cells are the ones we did not verify: a visible gap beats a guess about somebody else's software.
Corrections are welcome — the table lives in the public repository, and a pull request is the shortest way to fix it.