Open source · macOS · Rust + Tauri 2

See clearly. Tidy safely.

Tidy is Mole's open-source macOS desktop app. Cleaning, uninstalling, optimizing, and disk analysis all put the full candidate list in front of you first. Whatever you tick is exactly what gets removed — the architecture makes one extra file impossible.

macOS 11+Universal (Intel & Apple silicon)English / 中文Version 0.1.0 · 17 MB

0.1.0 is the first public release. The installer is signed with a Developer ID and notarized by Apple, so it opens without the "unidentified developer" warning. The app checks for its own updates and sends anonymous usage statistics — both can be turned off in Settings, and the privacy page lists every field collected. All releases

The Tidy Clean view before a scan, reading "Ready to scan reclaimable space" over the subtitle "Caches · logs · dev leftovers, fully previewable", with a Start Scan button below and the Clean, Apps, Optimize, Analyze, Status navigation above
Where Clean starts. The product states the promise itself: fully previewable. Captured from a 0.1.0 local build; no installer has been released.

One place in the whole workspace can delete

clippy.toml bans every std::fs::remove_* outside mole-core::sink through disallowed-methods. The workspace contains exactly one #[allow], inside the sink; new destructive behavior has to go through a DeletionPlan.

Source: desktop/clippy.toml, crates/mole-core/src/sink.rs

Preview and execution share one candidate set

plan_* commands scan and store the preview in a PlanStore; execute_plan accepts only (plan_id, your selected subset). Nothing is re-scanned after confirmation, so the UI cannot execute anything it never previewed.

Source: the two-phase IPC contract in src-tauri

Deletions route to Trash, history matches the CLI

Removals go through NSFileManager into the Trash. operations.log and deletions.log are byte-compatible with the Mole CLI and pinned by golden tests, so mo history reads both surfaces.

Source: crates/mole-macos, the mole-core log writers

The interface

The list comes before the deletion

The Uninstall view lists every app on the machine and what it occupies; expand any row to see everything that app left behind. Whatever you tick is the entire set that moves to the Trash — nothing is re-scanned after you confirm.

The Tidy Apps view listing 131 installed applications sorted by size — Xcode 4.25GB, IntelliJ IDEA 4.22GB, GoLand 3.61GB, MounRiver Studio 2 3.24GB, Android Studio 2.65GB and more — each row ending in an expand arrow and a checkbox
Uninstall: 131 installed apps sorted by size. The expand arrow on each row lists that app's App Support, caches, logs, preferences, and containers; the checkbox decides what actually runs. Captured from a 0.1.0 local build.

Workflows

Four jobs, each one able to stop at preview

Reclaim the space caches ate

Before: you know ~/Library/Caches is huge but will not delete it wholesale.

  1. YouPress Start Scan
  2. TidyLists every item and its size grouped by App caches, logs, developer tools, AI tools, browsers, design tools, messaging, and installers; running apps are called out with how much more closing them would free
  3. ResultSelected items move to Trash, the view reports what was freed, and the run is written to operations.log

Actually finish an uninstall

Before: drag to Trash, leave Application Support, containers, and LaunchAgents behind.

  1. YouSelect an app under Apps
  2. TidyLists each leftover by category — App, App Support, Cache, Logs, Preferences, Launch Agents, HTTP Storage, WebKit, Saved State, Containers. System components and apps that require their official uninstaller are blocked with the reason shown
  3. ResultReview item by item, then remove in one pass — still to Trash, still recoverable

See what actually needs updating

Before: open each app and click Check for Updates.

  1. YouOpen Apps → Updates
  2. TidyGroups by Homebrew / App Store / Sparkle / Electron / Website. Homebrew is read-only here and only produces an exact Terminal command; other sources open the app's own updater or the precise App Store product page
  3. ResultSources that failed to probe are listed under Source diagnostics — a failed probe is never reported as "all up to date"
The Tidy Updates view: a collapsible "Source diagnostics (9)" panel on top, then 28 apps updatable inside Tidy — Apifox (Electron), BetterDisplay (Sparkle), Bitwarden (App Store) and others — each row showing current version to new version with Ignore and Update actions
Updates: the source is labelled on every row, and sources that failed to probe are collected in the "Source diagnostics (9)" panel rather than counted as up to date. Captured from a 0.1.0 local build.

Run a bounded maintenance pass

Before: paste a command from the internet and hope you know what it changes.

  1. YouPress Optimize once
  2. TidyRuns four task areas: launch speed, system databases, network and search, system maintenance. It installs no packages, resets no privacy permissions, and deletes no personal documents
  3. ResultEach task reports done / skipped / failed, and a skip names its cause: unchanged, apps_running, probe_failed, requires_admin, skipped

Five modules

Five destinations, and they never move

Clean

Reclaimable space grouped by origin.

  • App caches, logs, developer tools
  • AI tools, browsers, design tools, messaging
  • Leftover dmg / pkg / xip installers
System caches and logs need the privileged helper and currently refuse with requires_admin

Apps

Uninstall, Updates, and Login Items.

  • Every leftover expanded by category
  • Updates grouped by source, with diagnostics
  • Login items and background services
Homebrew is read-only in the desktop app; system login items are display-only

Optimize

One bounded maintenance pass.

  • Launch speed: QuickLook, fonts, Launch Services
  • System databases: compaction, notification history
  • Network and search: DNS, route caches, Spotlight
Installs nothing, resets no privacy permissions, deletes no personal documents

Analyze

A treemap of the disk or the current folder.

  • Click a folder to drill down
  • Scans can be cancelled at any point
  • Move a selected directory straight to Trash
A cancelled scan is labelled "results incomplete" rather than presented as a conclusion

Status

What this Mac is busy with right now.

  • CPU, memory, disk, network, battery, GPU
  • Fan speeds (fanless models show passive cooling)
  • Process detail: threads, open files, disk I/O, listening ports
Processes listening on public interfaces are flagged explicitly

Settings

Language, whitelist, history.

  • English / 中文, following the system by default
  • Whitelist: paths never offered as candidates
  • Operation and deletion history
Shared state lives in ~/.config/mole, history in ~/Library/Logs/mole

Safety boundary

Every destructive action goes down one funnel

This is code structure, not a copywriting promise: each destructive feature builds a DeletionPlan and can only execute through the single sink. Whitelist checks, session markers, logging, and progress reporting therefore cannot diverge between features.

  • 1ScanEnumerate candidates without modifying anything
  • 2PreviewEvery path, category, and size, plus the reason anything is blocked
  • 3ConfirmCandidate count and byte total stay identical between preview and confirmation
  • 4ExecuteOnly your selected subset, with cooperative cancellation
  • 5ResultsCompleted, refused, and failed are separated; partial success is never rendered as total success

Data stays on the machine

Shared state lives in ~/.config/mole; operation and deletion history in ~/Library/Logs/mole. The repository contains no analytics, telemetry, or crash-reporting code, and the window CSP is default-src 'self'.

Network access only during update checks

An update scan reaches Apple's bundle-ID lookup, an app's own Sparkle feed, and the GitHub release API, and reads local Homebrew output. A scan expires after 15 minutes, and update buttons carry only opaque backend-issued IDs.

Protection lists are generated at compile time

build.rs parses app_protection_data.sh into Rust constants and fails the build on any unrecognized line. The list's DATA_SHA256 is surfaced in the About row so it can be checked.

When unsure, refuse

The helper's in-helper re-validation and mutable-ancestor refusal already ship in the repository, but the SMAppService/XPC transport does not. System-scope actions therefore refuse with requires_admin rather than falling back to a shell elevation prompt.

Getting it

Download it, or compile your own copy

For most people the DMG is all you need. If you would rather verify for yourself exactly what it deletes, the source lives in the desktop/ directory of github.com/rambocode/tidy; you need Rust stable and Node ≥ 20.

git clone https://github.com/rambocode/tidy.git
cd tidy/desktop

# backend checks
cargo test --workspace
cargo clippy --workspace -- -D warnings

# run the desktop app
cd ui && npm install && npx tauri dev

Known caveat: the mole-core test dangerous_paths_corpus_all_rejected reads an adversarial corpus from the parent repository. In a checkout containing only desktop/, that one test fails, and that is expected.

FAQ

What people ask before trying it

Can I download an installer today?

Yes. Download the 0.1.0 DMG (17 MB, Universal, runs on both Intel and Apple silicon, needs macOS 11 or later). It is signed with a Developer ID and notarized by Apple, so it opens without a Gatekeeper prompt. The app also checks for its own updates.

Can I get something back if I delete the wrong thing?

User-scope deletions all go to the Trash through NSFileManager and can be restored from there. System-scope actions are not executed at all right now — they refuse with requires_admin — so there is no path that quietly removes a system file. Every run is written to ~/Library/Logs/mole.

Does it upload my files or usage data?

The repository has no analytics, telemetry, or crash-reporting code, and the window CSP is limited to default-src 'self'. The only outbound requests happen when you deliberately check for software updates: Apple's bundle-ID lookup, an app's own Sparkle feed, and the GitHub release API.

How does this relate to the Mole CLI?

Tidy is Mole's desktop surface, and its safety layer is a Rust port of the CLI's. Public product copy uses Tidy; internal crate names, compatibility events, and shared logs keep the Mole name. operations.log and deletions.log stay byte-compatible, so mo history reads both.

Why are some rows not actionable?

The interface names the cause: unchanged (target missing or already healthy), apps_running (close the named app first), probe_failed (the step could not be proven safe), requires_admin (needs the unreleased privileged helper), skipped (whitelisted or blocked by another safety condition). Disabled controls keep their label and expose the reason instead of just dimming.

Is there a Windows or Linux build?

Not currently. The adapter layer is mole-macos and depends on NSFileManager Trash semantics and the macOS privileged-helper model; no other platform implementation exists yet.

Feedback

If a refusal reason does not make sense, open an issue

See it first, then decide what to remove

Source, safety boundary, and log formats are all public and checkable.