diskforge 0.8.2

Intelligent disk cleanup CLI for developers — scan, find, deduplicate, and clean
# DiskForge

Intelligent disk cleanup CLI for developers. Scans your system for build caches, package manager artifacts, Docker leftovers, iOS simulators, Android SDK components — and now also uninstalls apps cleanly, finds forgotten large files, and detects duplicates.

**macOS-first. Written in Rust. Single binary.**

[![CI](https://github.com/joicodev/diskforge/actions/workflows/ci.yml/badge.svg)](https://github.com/joicodev/diskforge/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

## Install

### Homebrew (macOS)

```bash
brew tap joicodev/tap
brew install diskforge
```

### Cargo

```bash
cargo install diskforge
```

### From Source

```bash
git clone https://github.com/joicodev/diskforge.git
cd diskforge
cargo install --path crates/diskforge-cli
```

## Quick Start

Just run `diskforge` with no arguments for the unified smart scan dashboard:

```bash
diskforge                # Full smart scan: artifacts + large files + duplicates
diskforge --no-dupes     # Skip duplicate detection (faster)
diskforge dashboard      # Explicit alias for the same
```

The dashboard combines all scan types into a single view showing "You can free X.XX GB" with a category breakdown, disk usage bar, and one-click cleanup.

## Commands

### `scan` — Scan & show cleanable items

```bash
diskforge scan ~                       # Everything cleanable
diskforge scan ~ --min-size 100MB      # Only items > 100 MB
diskforge scan ~ --older 30d           # Untouched for 30+ days
```

### `clean` — Interactive TUI cleanup

```bash
diskforge clean                        # TUI, nothing pre-selected
diskforge clean --dry-run              # Preview mode (no deletion)
diskforge clean --risk low             # Pre-select None + Low risk items
diskforge clean --budget 20            # Auto-select safest items until 20% disk is free
```

### `uninstall` — Remove an app + all its traces

When you drag an app to Trash, it leaves behind caches, preferences, containers, launch agents, cookies, and more scattered across ~/Library. `uninstall` finds all of them.

```bash
diskforge uninstall --list             # Show all installed apps
diskforge uninstall slack              # Find & remove all Slack traces
diskforge uninstall docker --dry-run   # Preview what would be removed
```

**How it works:**
1. Parses `Info.plist` to extract the bundle ID (e.g., `com.tinyspeck.slackmacgap`)
2. Searches **14 ~/Library subdirectories** for matches (Application Support, Caches, Preferences, Containers, Group Containers, LaunchAgents, Saved Application State, HTTPStorages, WebKit, Logs, Cookies, Application Scripts, SyncedPreferences, Preferences/ByHost)
3. Shows all traces in the interactive TUI for selective deletion
4. Cross-references other installed apps to avoid deleting shared directories

### `find` — Find large & old forgotten files

Surfaces DMGs, ISOs, videos, archives, and other large files you forgot about.

```bash
diskforge find                                    # Default: ~/Downloads + ~/Desktop, > 50MB
diskforge find ~ --min-size 500MB --older 90d     # Big old files anywhere
diskforge find ~/Downloads --type disk-image      # Only DMGs/ISOs
diskforge find ~ --type video --min-size 1GB      # Forgotten large videos
diskforge find ~/Downloads ~/Desktop --top 20     # Top 20 largest files
```

**File types detected:** disk images (.dmg, .iso), archives (.zip, .tar, .7z, .rar), videos (.mp4, .mov, .mkv), installers (.pkg), VM images (.vmdk, .vdi), documents (.pdf, .psd).

**Smart detection:**
- Two-tier type detection: extension + magic bytes validation (via `infer` crate)
- Download detection via `com.apple.quarantine` xattr — knows if a file was downloaded from the internet
- Uses `mtime` for staleness (APFS disables `atime` by default)

### `dupes` — Find & remove duplicate files

Finds duplicate files using a high-performance 4-stage pipeline.

```bash
diskforge dupes ~/Documents              # Interactive TUI to select duplicates
diskforge dupes ~/Downloads --min-size 5MB
diskforge dupes ~/Pictures --no-tui      # Table output only
diskforge dupes ~ --dry-run              # Preview without deleting
```

**How the pipeline works:**
1. **Size grouping** — files with unique sizes can't be duplicates (eliminates ~95%)
2. **Inode dedup** — filters hard links (same file, different paths)
3. **Partial hash** — blake3 hash of first 4KB (eliminates ~90% of remaining)
4. **Full hash** — complete blake3 hash confirms true duplicates

**Safety:**
- Grouped TUI enforces **"keep at least 1"** — you can never delete all copies
- Detects APFS clones (shared blocks, deleting one frees zero space)
- Filters empty files (all identical, zero space savings)
- Hard links detected and excluded

## TUI Keybindings

### Clean / Uninstall TUI

| Key | Action |
|-----|--------|
| `j` / `k` | Navigate up/down |
| `Space` | Toggle item |
| `a` | Select/deselect all |
| `n` | Select all Risk None items |
| `l` | Select all Risk Low items |
| `Enter` | Confirm selection |
| `y` / `n` | Confirm/cancel deletion |
| `q` / `Esc` | Quit |

### Dupes TUI

| Key | Action |
|-----|--------|
| `j` / `k` | Navigate within group |
| `Tab` | Next group |
| `Shift+Tab` | Previous group |
| `Space` | Toggle file for deletion |
| `Enter` | Confirm selection |
| `q` / `Esc` | Quit |

## What It Detects (scan/clean)

| Category | Examples |
|----------|---------|
| **Dev Artifacts** | `node_modules`, `target/`, `build/`, `.next/`, `Pods/`, `__pycache__/` |
| **Package Managers** | npm, cargo, pub, gradle, bun, cocoapods, yarn, homebrew |
| **IDE Caches** | Xcode DerivedData, VS Code, Cursor |
| **Browser Caches** | Chrome, Edge, Brave |
| **App Caches** | Figma, Slack |
| **Docker** | Images, containers, volumes, build cache (via `docker system df`) |
| **iOS Simulator** | Individual devices + runtime downloads |
| **Android** | NDK versions, platforms, build-tools, system images, AVDs |
| **System** | Logs, Trash |
| **User Rules** | Custom paths via `~/.config/diskforge/rules.toml` |

15 project types detected: Node, Rust, Flutter, Gradle, Maven, Swift, CMake, .NET, Python, Go, Zig, Turborepo, Next.js, CocoaPods, React Native.

## Risk Levels

| Risk | Meaning | Auto-selected by budget? |
|------|---------|--------------------------|
| **None** | Safe to delete anytime. Regenerates automatically. | Yes |
| **Low** | Regenerates with a rebuild command (`npm install`, `cargo build`, etc.) | Yes |
| **Medium** | May require manual reinstall (simulators, SDK components). | No |
| **High** | User data (Downloads, Movies). Never auto-selected. | No |

## Custom Rules

Create `~/.config/diskforge/rules.toml` to add your own paths:

```toml
[[rules]]
name = "Windsurf Cache"
path = "~/Library/Application Support/Windsurf/CachedData"
category = "ide"
risk = "none"
regenerates = true

[[rules]]
name = "pnpm Store"
path = "~/Library/pnpm/store"
category = "pkg"
risk = "none"
regenerates = true
hint = "pnpm install"
```

See `rules.example.toml` for more examples.

### Auto-generate with AI

Instead of writing rules by hand, paste this prompt into Claude Code, ChatGPT, or any AI coding agent to generate a personalized `rules.toml` based on what's actually on your machine:

<details>
<summary>Click to copy the AI prompt</summary>

```
Scan my machine and generate a ~/.config/diskforge/rules.toml file with custom cleanup rules.

Instructions:
1. List large directories (>100MB) in these paths:
   - ~/Library/Application Support/
   - ~/Library/Caches/
   - ~/Library/Developer/
   - ~/Library/Containers/
   - ~/.local/
   - Any other common cache/data paths you find

2. Exclude paths already built into diskforge:
   - npm, cargo, pub, gradle, bun, cocoapods, yarn, homebrew (package managers)
   - Xcode DerivedData, VS Code, Cursor (IDE caches)
   - Chrome, Edge, Brave (browser caches)
   - Figma, Slack (app caches)
   - Docker, iOS Simulator, Android SDK
   - Trash, Downloads, Movies, Logs

3. For each remaining large directory, create a [[rules]] entry with:
   - name: human-readable name (e.g., "Discord Cache")
   - path: using ~ for home (e.g., "~/Library/Caches/com.discord")
   - category: one of ide, browser, pkg, system, or the app name
   - risk: "none" if it's clearly a cache, "low" if regenerable, "medium" if unsure
   - regenerates: true if the app will recreate it automatically
   - hint: (optional) how to regenerate if known

4. Create the config directory if needed: mkdir -p ~/.config/diskforge
5. Write the file to ~/.config/diskforge/rules.toml

Focus on apps I actually have installed. Don't add rules for apps that aren't on my machine.
```

</details>

## Architecture

```
crates/
  diskforge-core/   # Library: scanning, detection, rules, cleaner, file finder, duplicate engine
  diskforge-cli/    # Binary: clap CLI + ratatui TUI
```

- **Parallel scanning** via `rayon` (known paths) and `ignore::WalkParallel` (dev artifacts, file finder)
- **Marker-file detection** for 15 project types (inspired by kondo)
- **Budget mode** selects safest + largest items first to reach target free space
- **Plist parsing** via `plist` crate for app uninstaller (binary + XML transparent)
- **File type detection** two-tier: extension + magic bytes via `infer` crate
- **Download detection** via `com.apple.quarantine` xattr
- **Duplicate detection** 4-stage pipeline: size group -> inode dedup -> partial hash (4KB) -> full hash (blake3)
- **87 tests** across unit and integration suites

## License

MIT