Automatically organize your macOS Downloads folder in real-time.
Built with Swift 6, powered by SwiftTUI and LaunchAgent.
Download Organizer is a native macOS tool that keeps your Downloads folder clean and organized. It features a Terminal User Interface (TUI) for interactive management alongside a background service.
Instead of manually sorting files, it watches your ~/Downloads directory in real-time and automatically moves completed downloads into categorized folders.
- ⚡ Real-time monitoring using FSEvents
- 📂 Automatically categorizes downloaded files into 15+ categories
- ⏳ Waits until downloads are fully completed before moving
- 🔄 Handles filename collisions with configurable strategy (rename/overwrite/skip)
- 🗄 Stores complete move history in SQLite
- 📝 Detailed file logging
- 🖥️ Interactive dashboard with real-time status
- 📊 History viewer with filter (All/Moved/Restored/Failed) and sort (Date/Name/Size)
- 📈 Statistics page with per-category breakdown
- ⚙ Configuration editor with inline editing and duplicate strategy selector
- 📋 Rules manager with add/remove/reset and confirmation dialogs
- 🔮 Rule simulator - test any filename against current rules
- 📜 Log viewer
- 🩺 Doctor page for system diagnostics
- ♻ Undo last move or bulk undo multiple moves at once
- 🏃 Organize Now - immediately scan and organize
- 🔄 Auto-refresh toggle
- 🎨 5 built-in themes (dark, light, nord, gruvbox, dracula)
- ❓ Help overlay with keyboard shortcuts on every page
- 💾 Export/import configuration
- 📦 Backup/restore all data (config + rules)
- 🚀 Lightweight background LaunchAgent
- 🔥 Hot-reloads custom rules without restarting
- 🍺 Easy installation via Homebrew
- 🔒 No internet connection required
- ❤️ Built with native Swift
| Requirement | Version |
|---|---|
| macOS | 14 Sonoma or newer |
| Swift | 6.0+ |
| Xcode Command Line Tools | Latest |
| Swift Package Manager | Included |
brew tap fajaradisetyawan/tap
brew trust fajaradisetyawan/tap
brew install download-organizerDownload Organizer includes a full interactive Terminal User Interface built with SwiftTUI.
download-organizer dashboardOr using the flag form:
download-organizer --dashboardThe main menu lists all available pages. Use arrow keys to navigate and Enter to select.
Pages:
| Menu | Description |
|---|---|
| Dashboard | Real-time status, recent activity, quick actions |
| History | Browse all moves, filter & sort, undo |
| Statistics | Per-category file counts and breakdown |
| Configuration | Edit settings inline (watch folder, delay, etc.) |
| Rules | View/add/edit/remove categorization rules |
| Simulator | Test any filename against current rules |
| Logs | View application logs |
| Doctor | Run system diagnostics checks |
| About | Version info and credits |
| Key | Action |
|---|---|
↑ ↓ |
Move selection |
Enter |
Select / confirm |
Esc |
Cancel / go back |
R |
Refresh current page |
? |
Show help overlay |
T (or theme btn) |
Cycle theme |
Q |
Quit |
- Status: service running/stopped, watch folder, queue count
- Recent Activity: last 10 moved files
- Quick Actions: Undo last move, Organize Now, toggle auto-refresh
- Bottom bar: theme button, help, home
- Filter: All / Moved / Restored / Failed
- Sort: Date / Name / Size
- Search: type
/to search filename, category, or extension - Undo: single undo, or use
-/+to set bulk count thenUndo N
- Inline editing: click any row to edit
- Watch Folder: browse filesystem with FolderBrowserView
- Duplicate Strategy: dropdown with rename / overwrite / skip
- Export / Import: save config to Desktop, or restore from file
- Backup / Restore: backup both config.json + rules.json to timestamped folder
- Add rule: fill category name + extensions
- Edit: click any category to modify extensions inline
- Remove: confirm dialog before deleting
- Reset to defaults: confirm dialog before clearing all custom rules
Type a filename (e.g. photo.jpg or archive.zip) and press Enter to see which category it would be classified under. Maintains a history of the last 20 tests.
download-organizerdownload-organizer-installdownload-organizer-restartdownload-organizer-uninstalldownload-organizer --statsdownload-organizer --undo-lastdownload-organizer doctor
download-organizer --doctordownload-organizer history --limit 20
download-organizer history --today
download-organizer history --category PDF
download-organizer history --extension pdftail -f ~/.download-organizer/logs/download-organizer.loglaunchctl print gui/$(id -u)/com.downloadorganizer.agentClone the repository:
git clone https://github.com/FajarAdiSetyawan/macOS-Download-Organizer.git
cd macOS-Download-OrganizerRun the installer:
chmod +x install.sh
./install.sh| Category | Extensions (selected) |
|---|---|
| 📷 Images | jpg, jpeg, png, gif, webp, svg, heic, bmp, tif, raw, jxl, xcf |
| 🎥 Videos | mp4, mov, mkv, avi, webm, m4v, mpg, mpeg, 3gp, ogv, vob, ts |
| 🎵 Audio | mp3, wav, m4a, aac, flac, ogg, wma, opus, alac, aiff, mid |
| 📄 Documents | doc, docx, xls, xlsx, ppt, pptx, txt, csv, rtf, odt, md, log, msg, eml |
| 📦 Archives | zip, rar, 7z, tar, gz, xz, bz2, dmg, iso, jar, war, zst, lz4 |
| 💻 Code | swift, dart, js, ts, py, java, kt, go, rs, c, cpp, h, zig, hs, ex, lua, sh, rb |
| 🎨 Design | fig, xd, psd, ai, sketch, eps, ps, storyboard, xib, blend, c4d, max |
| 📱 Apps | app, pkg, exe, msi, apk, ipa, deb, rpm, appimage |
| 📚 eBooks | epub, mobi, azw, azw3, fb2, lit, lrf, cbr, cbz |
| 🔤 Fonts | ttf, otf, woff, woff2, eot, dfont, fon, ttc |
| 🗄 Database | sqlite, sqlite3, db, db3, sql, frm, myd, myi |
| ⚙ Config | plist, strings, xcconfig, entitlements, mobileprovision, pbxproj |
| 🔐 Certificates | cer, crt, pem, key, p12, pfx, der, csr |
| ❓ Others | Any unsupported extension |
macOS-Download-Organizer
├── Sources/
│ ├── App/ # Entry point
│ ├── TUI/ # Terminal UI (SwiftTUI)
│ │ ├── Core/ # Navigation, store, themes
│ │ ├── Pages/ # All page views
│ │ └── Views/ # Reusable components
│ ├── Services/ # Business logic
│ │ ├── RuleEngine/ # File categorization
│ │ ├── FileMover/ # File operations
│ │ ├── FileWatcher/ # FSEvents monitoring
│ │ └── HistoryService/ # SQLite history
│ ├── Database/ # SQLite layer
│ ├── Models/ # Data models
│ └── Core/ # Configuration, logging, paths
├── Formula/ # Homebrew formula
├── install.sh
├── uninstall.sh
├── restart.sh
├── Package.swift
└── README.md
Downloads Folder
│
▼
FSEvents detects changes
│
▼
Wait until file is stable
│
▼
Detect file extension
│
▼
Load custom rules (rules.json)
│
▼
Determine destination folder
│
▼
Handle duplicates (rename/overwrite/skip)
│
▼
Move file
│
▼
Save history to SQLite
│
▼
Write logs
Some browsers write files in multiple stages. The organizer waits until the file size no longer changes before moving it. If necessary, increase delay in config.json.
Grant Full Disk Access to the terminal:
System Settings → Privacy & Security → Full Disk Access
Then restart:
download-organizer-restartCheck LaunchAgent:
launchctl print gui/$(id -u)/com.downloadorganizer.agentReinstall if needed:
download-organizer-installMove history is stored locally in SQLite at ~/.download-organizer/history.db.
Each move records:
- Filename
- Source path → Destination path
- Category and file extension
- File size
- Timestamp
- Status (moved / restored / failed)
Contributions are welcome!
- Fork the repository.
- Create a feature branch.
- Commit your changes.
- Open a Pull Request.
This project is licensed under the MIT License.
Built with ❤️ in Swift
⭐ If this project helps you, consider giving it a star on GitHub!