Skip to content

Proposal: add a confidence-based App Uninstaller plugin with reviewed associated-file removal #350

Description

@xcv58

Summary

Add a standalone App Uninstaller plugin that removes a selected application and helps the user review files associated with it.

The defining product principle is evidence and confidence, not aggressive deletion.

Every associated item should explain:

  • What it is
  • Why MacTools believes it belongs to the selected application
  • Whether it may be shared with another application
  • Whether it contains user-created data
  • Whether it is selected by default
  • Whether it can be safely moved to Trash
  • Whether a vendor-provided uninstaller or package manager should be used instead

Illustrative confidence groups:

Verified application bundle
Verified application container
Verified application cache
Verified preference
Verified helper or launch item
Shared vendor data
Possible associated data
Ambiguous user-created data
Protected

The user must review the exact application and associated files before removal.

This plugin should be built after the Storage Explorer scanner and shared file-safety primitives are sufficiently proven, but the product boundary can be agreed in advance.


Motivation

Dragging an application to Trash often leaves behind:

  • Caches
  • Preferences
  • Saved application state
  • Application Support data
  • Containers
  • Login items
  • Launch agents
  • Helper tools
  • Logs
  • Web data
  • Extensions
  • Vendor-specific support directories

However, filename similarity alone is not enough to prove ownership.

Aggressive uninstaller tools risk removing:

  • Data shared by several applications from the same vendor
  • Group containers
  • Plug-ins used by another application
  • User documents
  • Presets
  • Templates
  • Downloaded models
  • Licensed content
  • Browser profiles
  • Project files
  • Shared helpers

MacTools should provide a conservative uninstall workflow that makes association evidence visible and keeps the user in control.


Product boundary

App Uninstaller owns:

  • Selecting or dropping an application
  • Application identity
  • Associated-file discovery
  • Association evidence
  • Confidence classification
  • Application-specific review
  • Quit and removal planning
  • Trash-first execution
  • Uninstall history

It does not own:

  • Generic cleanup of leftovers from unknown applications
  • Whole-volume analysis
  • Duplicate detection
  • Application updates
  • Malware removal
  • Package management
  • Enterprise device management
  • Automatic bulk uninstall
  • Removal of system applications
  • Generic cache cleanup unrelated to the selected application

Relationship to other plugins:

Plugin Responsibility
Disk Cleanup Known cleanup rules independent of an uninstall operation
Storage Explorer Neutral disk-usage analysis
App Uninstaller Evidence that files belong to one selected application
Homebrew Formula and cask management
Launch Items General launch-agent browsing and control
Empty Trash Explicit permanent Trash emptying

Goals

  • Let users select or drag an application into a dedicated workspace.
  • Identify the app’s bundle ID, team/vendor identity, version, path, and installation source.
  • Discover associated files from fixed, reviewed locations.
  • Attach structured evidence to every associated file.
  • Classify confidence and data sensitivity.
  • Select only high-confidence disposable or application-owned data by default.
  • Keep shared, ambiguous, and user-created data unselected.
  • Protect system applications and critical roots.
  • Detect running processes and offer a safe quit flow.
  • Detect package-manager or vendor-uninstaller cases.
  • Build an immutable removal plan.
  • Revalidate identity and ownership before execution.
  • Move the app and selected files to Trash by default.
  • Record structured results and history.
  • Expose only safe foreground actions through Command Palette and other action surfaces.
  • Keep all analysis local.
  • Use an independent implementation.

Non-goals

  • One-click aggressive removal without review
  • Automatic leftover cleanup for every missing bundle ID
  • Bulk unattended uninstall
  • Removing system applications
  • Removing macOS components
  • Removing applications managed by an organization
  • Removing kernel extensions, system extensions, privileged helpers, or drivers without a dedicated supported flow
  • Silently running vendor uninstall scripts
  • Deleting user documents
  • Deleting shared vendor data by default
  • Deleting group containers by default
  • Guessing ownership from a broad vendor folder alone
  • Emptying Trash
  • Malware scanning
  • License deactivation
  • Subscription cancellation
  • App update management
  • Replacing Homebrew cask uninstall
  • Copying third-party uninstaller code, path lists, or heuristics
  • Requiring a new host-wide operational window

Dependency and sequencing

This proposal should be tracked separately but implemented after:

  1. Storage Explorer or equivalent file-tree scanning primitives have proven file identity, path safety, bounded traversal, and Trash execution.
  2. Disk Cleanup’s explainability and provenance work has established a consistent evidence vocabulary.
  3. The project has a clear approach to shared narrow storage primitives.

App Uninstaller must not be implemented merely by copying a list of common ~/Library folders and matching names.


Primary user flow

Open App Uninstaller
→ Drop or choose an application
→ Identify app and installation source
→ Scan reviewed association roots
→ Group results by confidence and type
→ Explain every association
→ User selects or deselects individual items
→ Review exact removal plan
→ Quit application if needed
→ Move app and selected files to Trash
→ Show structured result and history

Application selection

Support:

  • Drag an .app bundle into the workspace
  • Choose Application…
  • Select from an installed-application browser
  • Open App Uninstaller from Command Palette
  • A future Finder integration or live Command Palette result

Validate:

  • The path is an application bundle.
  • The bundle has a readable identity.
  • The application is not a protected system app.
  • The application is not MacTools itself.
  • The application is not inside a read-only or system-managed location.
  • The application has not changed since it was selected.

Show:

  • Icon
  • Name
  • Bundle identifier
  • Version and build
  • Developer/team identifier where available
  • Installation path
  • Installation source
  • Running state
  • Estimated bundle size
  • Code-signing status where useful

Do not require code-signing identity for every app, but use it as evidence where available.


Installation-source detection

Potential sources:

Mac App Store
Homebrew cask
Standalone application
Vendor suite
Managed application
System application
Unknown

Homebrew

If the selected app is managed by a Homebrew cask:

  • Explain that Homebrew is the authoritative manager.
  • Offer to open the Homebrew plugin or execute an eligible confirmed cask-uninstall action.
  • Do not independently remove files that Homebrew tracks unless the user explicitly chooses a follow-up associated-data review.
  • Keep package-manager execution and associated-data cleanup as separate steps.

Vendor uninstaller

If an application contains or installs a known vendor uninstaller:

  • Show it prominently.
  • Explain why vendor removal may be required for privileged helpers, drivers, extensions, or licensing components.
  • Do not execute it silently.
  • Allow the user to launch it.
  • Optionally offer associated-file review after it completes.

Managed or system application

  • Block removal.
  • Explain the reason.
  • Do not provide an override.

Association evidence

Define structured evidence rather than a Boolean “belongs to app.”

Illustrative model:

enum AppAssociationEvidence: Hashable, Sendable {
    case exactBundleIdentifier
    case containerMetadata(bundleIdentifier: String)
    case savedApplicationState(bundleIdentifier: String)
    case preferenceDomain(bundleIdentifier: String)
    case executableInsideApplicationBundle
    case helperDesignatedRequirement
    case launchItemExecutablePath
    case loginItemEmbeddedInApplication
    case applicationGroupIdentifier(String)
    case teamIdentifier(String)
    case packageReceipt(String)
    case exactKnownVendorMetadata
    case vendorNamespace(String)
    case filenameSimilarity
    case userSelected
}

Each candidate may carry several pieces of evidence.

Evidence strength must be explicit and testable.


Confidence model

Illustrative classification:

enum AppAssociationConfidence: Comparable, Sendable {
    case verified
    case strong
    case shared
    case possible
    case ambiguous
    case protected
}

Verified

Examples:

  • The application bundle selected by the user
  • Container metadata names the exact bundle ID
  • Saved Application State uses the exact bundle ID
  • Preference domain exactly matches the bundle ID
  • Embedded login item or helper resides inside the app bundle
  • Launch item executable path resolves inside the app bundle

Default:

  • App bundle selected
  • Verified disposable associated data may be selected
  • User-created data still requires separate classification

Strong

Examples:

  • Exact bundle ID in a reviewed standard support root
  • Helper code signature or designated requirement maps to the app’s team and identifier
  • Package receipt directly identifies the selected app

Default:

  • Disposable caches/logs may be selected
  • Application Support remains dependent on data sensitivity

Shared

Examples:

  • App Group or Group Container
  • Vendor suite support data
  • Shared helper used by another installed app
  • Team-identifier directory

Default:

  • Unselected
  • Explain which other installed applications may use it

Possible

Examples:

  • Vendor namespace match
  • Exact product-name folder without stronger metadata
  • Helper label resembles the bundle ID

Default:

  • Unselected

Ambiguous

Examples:

  • Generic folder name
  • Filename similarity only
  • User Documents
  • Project or media content

Default:

  • Unselected
  • Strong warning
  • Never categorized as disposable automatically

Protected

Examples:

  • System root
  • Shared system component
  • Another installed app’s data
  • MacTools data
  • Read-only system app
  • Uncertain privileged component

Default:

  • Cannot be selected

Data sensitivity

Confidence that a file belongs to an app is separate from whether it is safe to remove.

Illustrative model:

enum AppAssociatedDataClass: Sendable {
    case applicationBundle
    case cache
    case log
    case preference
    case savedState
    case container
    case applicationSupport
    case loginItem
    case launchAgent
    case helper
    case extensionComponent
    case userDocument
    case presetOrTemplate
    case downloadedContent
    case sharedVendorData
    case unknown
}

Suggested default-selection policy:

Data class Verified/strong Shared/possible Ambiguous
Application bundle Selected N/A N/A
Cache Selected Unselected Unselected
Log Selected Unselected Unselected
Preference Selected Unselected Unselected
Saved state Selected Unselected Unselected
Container Review policy Unselected Unselected
Application Support Unselected unless known disposable Unselected Unselected
Login item Selected only with exact executable evidence Unselected Unselected
Helper Review Unselected Unselected
Extension component Manual/vendor flow Unselected Unselected
User document Unselected Unselected Unselected
Preset/template Unselected Unselected Unselected
Downloaded content Unselected Unselected Unselected
Shared vendor data Unselected Unselected Unselected

The exact matrix should be finalized after research and tests.


Reviewed association roots

Scan only fixed, reviewed roots.

Potential user-domain roots to research:

~/Library/Application Support
~/Library/Caches
~/Library/Preferences
~/Library/Preferences/ByHost
~/Library/Saved Application State
~/Library/HTTPStorages
~/Library/WebKit
~/Library/Logs
~/Library/Containers
~/Library/Cookies
~/Library/LaunchAgents
~/Library/Application Scripts

Potential local-domain roots:

/Library/Application Support
/Library/Caches
/Library/Preferences
/Library/LaunchAgents
/Library/LaunchDaemons
/Library/PrivilegedHelperTools

Inclusion here is not approval to delete all matches.

For every root, the implementation must define:

  • Discovery evidence
  • Confidence ceiling
  • Data sensitivity
  • Permission behavior
  • Whether the root is user-domain or shared
  • Whether another installed app can own the same item
  • Whether Trash is supported
  • Whether administrator approval is required

Do not recursively scan arbitrary filesystem roots.


Other installed applications as an ownership oracle

Before presenting an associated item:

  • Inventory installed applications from reviewed application roots.
  • Include running applications.
  • Include embedded login items and helpers where discoverable.
  • Use bundle IDs, team IDs, app groups, package receipts, and executable paths.
  • Reject or downgrade candidates claimed by another installed application.
  • Treat shared vendor namespaces conservatively.
  • Do not assume an unregistered app is uninstalled merely because LaunchServices lookup fails.

The oracle must be testable with fixtures.


Running application behavior

If the selected application is running:

  • Show the running state.
  • Disable final removal until it quits.
  • Offer Quit Application.
  • Wait for termination with a bounded timeout.
  • If ordinary quit fails, offer Force Quit only as a separate explicit action.
  • Re-run association checks that depend on process state.
  • Do not terminate unrelated helpers automatically.

If a related helper remains running:

  • Explain which component is active.
  • Skip it or require the vendor flow.
  • Do not silently kill system or privileged processes.

Privileged helpers and system extensions

The MVP should be conservative.

Detect and display:

  • Privileged helper tools
  • Launch daemons
  • System extensions
  • Driver extensions
  • Network extensions
  • Audio components
  • Finder extensions
  • Browser extensions

Possible outcomes:

Can move to Trash after administrator approval
Vendor uninstaller recommended
Manual removal required
Protected and unsupported

Do not claim successful uninstall while active privileged components remain.

A full supported-removal flow for system extensions or drivers requires separate research and may remain out of scope.


Workspace UX

Suggested sections:

Application
Verified Data
Shared or Possible Data
User-Created or Ambiguous Data
Protected or Manual Components
Removal Plan
History

Candidate row

Show:

  • Selection
  • Name
  • Full path
  • Size
  • Data class
  • Confidence
  • Evidence summary
  • Other applications that may share it
  • Safety status

Expanded details:

  • Every evidence item
  • Bundle/team/app-group identity
  • Why selected or unselected
  • What may be lost
  • Last modified
  • Reveal in Finder
  • Quick Look where safe
  • Copy path

Language

Prefer:

Verified cache
Exact preference domain
Shared vendor data
Possible associated folder
Contains user-created content
Vendor removal required

Avoid:

Junk
Safe leftover
Useless file
Guaranteed removable

unless the evidence supports the exact statement.


Removal plan

Build an immutable plan from:

  • Selected application identity
  • Scan artifact
  • User-selected candidate IDs
  • Current installed-app oracle
  • Current process state

The plan should:

  • Remove parent/child duplicates.
  • Refuse paths outside reviewed roots.
  • Refuse protected roots.
  • Refuse candidates whose identity changed.
  • Re-evaluate claims by other installed apps.
  • Re-evaluate shared app groups.
  • Separate package-manager and vendor steps.
  • Record expected administrator requirements.
  • Show exact item count and estimated size.

The UI must present the plan before execution.


Trash-first execution

Default behavior:

  • Move the application bundle to Trash.
  • Move selected eligible associated files to Trash.
  • Do not empty Trash.
  • Do not fall back silently to permanent deletion.
  • Record each result.
  • Support cancellation between items.
  • Preserve original path and resulting Trash/staged name where available.

Administrator-required items:

  • Use a standard, explicit macOS authorization path.
  • Batch requests where safe.
  • Never accept arbitrary privileged shell input from a profile or deep link.
  • Fail closed when authorization is denied.

If a selected item cannot be moved safely:

  • Skip it.
  • Explain why.
  • Do not report the uninstall as complete without qualification.

Structured result

Show:

Application moved to Trash
12 associated items moved
3 shared items left in place
1 helper requires vendor removal
2 items changed since review
0 permanent deletions

Outcome categories:

  • Trashed
  • Skipped by user
  • Shared and retained
  • Protected
  • Changed since scan
  • Still in use
  • Authorization denied
  • Vendor action required
  • Failed
  • Already absent

Do not collapse partial success into a generic success state.


History

Keep a bounded, local uninstall history.

Record:

  • Application name and bundle ID
  • Version
  • Timestamp
  • Installation source
  • Selected item count
  • Estimated and actual result size where available
  • Per-item outcome
  • Original path
  • Trash/staged name
  • Manual steps remaining

Do not store file contents, license data, or unrelated directory listings.

History should support:

  • Expand details
  • Reveal retained item
  • Copy redacted diagnostics
  • Clear history
  • Highlight incomplete uninstalls

Canonical actions and Command Palette

Potential actions:

  • Open App Uninstaller
  • Choose Application to Review
  • Review Installed Application…
  • Open Latest Uninstall Review
  • Cancel Active Association Scan

Possible future live Command Palette behavior:

Select an application result
→ Command-K actions
→ Review in App Uninstaller

Requirements:

  • Review actions are foreground-interactive.
  • No canonical action directly uninstalls without review.
  • No uninstall action is eligible for automatic workflows.
  • No uninstall action is exposed through Run Links.
  • Command Palette is the primary global launcher.
  • The same scanner and plan are used regardless of entry point.

Relationship to Storage Explorer

Storage Explorer may provide reusable primitives:

File identity
Physical path resolution
Bounded directory traversal
Allocated-size calculation
Mount-boundary detection
Trash plan execution
Progress
History envelope

App Uninstaller owns:

Application identity
Installed-app oracle
Association evidence
Confidence
Data sensitivity
Default selection
Vendor/package-manager routing
Uninstall UX

Do not make Storage Explorer classify application ownership.


Relationship to Disk Cleanup

Disk Cleanup may identify generic known caches and leftovers through its own rules.

App Uninstaller should not blindly import those results.

A future integration may show:

Also covered by Disk Cleanup rule: Chrome cache

only when:

  • The exact physical path matches.
  • The Disk Cleanup rule is installed and available.
  • The association does not broaden App Uninstaller authority.
  • The user still reviews the item.

Independent implementation and provenance

  • Implement all association logic from first principles.
  • Use bundle metadata, container metadata, code signatures, package receipts, launchd configuration, and reproducible tests.
  • Do not copy third-party source.
  • Do not copy curated association path lists or distinctive heuristics without a compatible dependency and license review.
  • Record external research that materially informs a rule.
  • Treat every new association source as safety-sensitive.
  • Keep third-party notices complete.

Proposed implementation phases

Phase 0 — Association research

  • Define reviewed roots.
  • Define evidence types.
  • Define confidence and data-sensitivity models.
  • Research bundle, container, app-group, team, helper, and receipt metadata.
  • Research Homebrew cask detection.
  • Research App Store and managed-app detection.
  • Research vendor uninstaller discovery.
  • Research privileged helpers and extensions.
  • Build representative fixtures.
  • Define protected applications and roots.

Phase 1 — Read-only review MVP

  • Add the plugin package.
  • Add application selection and identity.
  • Add installed-app oracle.
  • Scan user-domain reviewed roots.
  • Add evidence and confidence.
  • Add grouped review UI.
  • Add Reveal and Quick Look.
  • Add Command Palette navigation.
  • Do not execute removal yet.

Phase 2 — Removal plan and user-domain Trash

  • Add immutable removal plans.
  • Add parent/child conflict resolution.
  • Add running-app quit flow.
  • Add path and identity revalidation.
  • Add Trash-first application removal.
  • Add eligible user-domain associated-file removal.
  • Add structured results.
  • Add history.

Phase 3 — Package managers and privileged components

  • Add Homebrew handoff.
  • Add vendor-uninstaller guidance.
  • Add administrator-required file handling.
  • Add launch-agent and helper review.
  • Add incomplete-uninstall reporting.
  • Keep unsupported system-extension cases explicit.

Phase 4 — Advanced integrations

  • Add Finder or Command Palette live-app integration.
  • Add shared component detection improvements.
  • Add post-vendor-uninstall associated-data review.
  • Add optional orphaned-item follow-up only through a separate reviewed flow.
  • Evaluate organization-signed removal policies separately.

Testing

Application identity

  • Standard app
  • App Store app
  • Homebrew cask app
  • Unsigned app
  • Nested app
  • Running app
  • System app
  • Managed app
  • MacTools itself
  • App replaced after selection

Evidence

  • Exact bundle ID
  • Container metadata
  • Preference domain
  • Saved state
  • Embedded login item
  • Launch item executable
  • Team ID
  • App group
  • Shared vendor directory
  • Filename similarity
  • Multiple evidence sources
  • Conflicting evidence
  • Another installed app claims the item

Selection policy

  • Verified cache selected
  • Verified preference selected
  • Shared data unselected
  • Application Support conservative
  • User documents unselected
  • App Group unselected
  • Protected item cannot be selected
  • Unknown metadata never upgrades confidence

Execution

  • Ordinary quit
  • Quit timeout
  • Force Quit separate confirmation
  • Trash app
  • Trash associated file
  • Authorization denied
  • Candidate changed
  • Candidate missing
  • Symlink escape
  • Mount boundary
  • Shared ownership appears after scan
  • Partial failure
  • Cancellation
  • Vendor flow required
  • Homebrew handoff

History and privacy

  • Run summary
  • Incomplete uninstall attention
  • Path redaction
  • Bounded retention
  • Clear history
  • No file content
  • No license data
  • No network activity

UX and accessibility

  • Drag and drop
  • Choose Application
  • Installed app browser
  • Confidence grouping
  • Expand evidence
  • Keyboard selection
  • VoiceOver
  • Long localization
  • Light and Dark appearance
  • Narrow workspace

Acceptance criteria

  • App Uninstaller is a standalone plugin.
  • The plugin opens from Command Palette.
  • Users can choose or drop an application.
  • The app’s identity and installation source are shown.
  • Associated files carry structured evidence.
  • Confidence and data sensitivity are separate.
  • Shared and ambiguous data are unselected by default.
  • User documents are never selected from name similarity alone.
  • Protected system applications cannot be removed.
  • Other installed applications prevent or downgrade shared candidates.
  • Running applications must quit before removal.
  • Homebrew and vendor-uninstaller cases are routed appropriately.
  • An immutable reviewed plan is shown before execution.
  • The app and eligible associated files move to Trash.
  • Permanent deletion is not a silent fallback.
  • Results distinguish complete and partial removal.
  • History highlights remaining manual steps.
  • No uninstall action is eligible for unattended automation or Run Links.
  • All implementation is independently authored and license-compliant.

Open questions

  1. Which confidence levels and names are clearest to nontechnical users?
  2. Which verified associated-data classes should start selected?
  3. Should exact Application Support matches remain unselected by default?
  4. How should App Groups and Group Containers be explained?
  5. Which installed-app roots should the ownership oracle scan?
  6. How reliable is team-identifier evidence across vendor suites?
  7. Should Homebrew removal be executed from this plugin or handed to the Homebrew plugin?
  8. How should App Store receipt evidence affect removal?
  9. Which privileged-helper cases can MacTools safely support?
  10. Should the MVP be read-only before adding Trash execution?
  11. Which narrow storage primitives should be shared with Storage Explorer?
  12. Should post-uninstall orphan review be part of this plugin or remain a separate future flow?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions