Your Downloads folder is a chaos zone.
Every file you've ever downloaded — installers, PDFs, photos, ZIP archives, videos — is dumped in one flat directory. Finding anything requires scrolling through hundreds of files.
SmartSort scans your Downloads folder and automatically moves every file into a named sub-folder based on its type. One command. No configuration needed.
Before After
────────────────────── ──────────────────────────────
Downloads/ Downloads/
photo.jpg Images/
assignment.pdf → photo.jpg
movie.mp4 PDF/
resume.docx assignment.pdf
song.mp3 Videos/
setup.exe movie.mp4
budget.xlsx Word/
resume.docx
Music/
song.mp3
Executables/
setup.exe
Spreadsheets/
budget.xlsx
| Feature | Status |
|---|---|
| ✅ Zero dependencies | Pure Python standard library |
| 🖥️ Cross-platform | Windows, macOS, Linux |
| 🗂️ 15+ categories | 96+ file extensions supported |
| 🔁 Duplicate-safe | Never overwrites an existing file |
| 📋 Full logging | Audit trail in logs/smartsort.log |
| 📊 Run summary | See exactly what moved and where |
| 🔍 Downloads detection | Automatic, with XDG fallback on Linux |
| 🧪 Tested | 60+ unit and integration tests |
SmartSort follows a clean, modular architecture designed to grow into future versions without rewrites.
src/smartsort/
├── config.py → Category enum + extension mappings (all constants)
├── detector.py → DownloadsDetector class (location only)
├── exceptions.py → Typed exception hierarchy
├── organizer.py → Organizer class (pipeline engine)
├── utils.py → Pure stateless helpers
└── logging_config.py → Logging setup and factory
Key design principles:
- Each module has exactly one responsibility
- All exceptions are typed and carry relevant
Pathattributes DownloadsDetectoraccepts an injectablehome_dirfor testabilityCategoryis aStrEnum— no magic strings anywhere in the codebase
SmartSort/
│
├── src/
│ └── smartsort/
│ ├── __init__.py Public API surface
│ ├── __main__.py python -m smartsort entry point
│ ├── config.py Category enum + constants
│ ├── detector.py Downloads folder detection
│ ├── exceptions.py Custom exception hierarchy
│ ├── organizer.py File organization engine
│ ├── utils.py Shared helpers
│ └── logging_config.py Logging configuration
│
├── tests/
│ ├── test_detector.py Detector + exception tests
│ ├── test_organizer.py Organizer integration tests
│ └── test_utils.py Utils unit tests
│
├── assets/
│ ├── logo.png
│ └── banner.png
│
├── logs/ Runtime logs (git-ignored)
├── screenshots/ UI screenshots
│
├── .github/
│ └── workflows/
│ └── ci.yml GitHub Actions (3 OS × 2 Python)
│
├── main.py CLI entry point
├── pyproject.toml Build config + tool settings
├── requirements.txt Dependency documentation
├── README.md
├── LICENSE
└── .gitignore
Requirements: Python 3.10 or higher
# Clone the repository
git clone https://github.com/your-username/SmartSort.git
cd SmartSort
# For development (installs pytest, ruff, pytest-cov)
pip install -e ".[dev]"
# No pip install needed for basic usage — zero runtime dependenciespython main.py──────────────────────────────────────────────────
SmartSort v0.1.0 — Downloads Organizer
──────────────────────────────────────────────────
✓ Downloads folder detected
/home/username/Downloads
──────────────────────────────────────────────────
SmartSort v0.1.0 — Downloads Organizer
──────────────────────────────────────────────────
✗ Unable to locate Downloads folder.
Reason:
No Downloads directory could be found.
Searched:
/home/username/Downloads
See logs/smartsort.log for details.
SmartSort automatically locates your Downloads folder using a two-step strategy:
| Step | Description |
|---|---|
| 1 | Check ~/Downloads — the standard location on Windows, macOS, and Linux |
| 2 | On Linux only: parse ~/.config/user-dirs.dirs for XDG_DOWNLOAD_DIR |
If neither path resolves to a valid directory, SmartSort raises a typed exception and exits with code 1.
| OS | Detection Method |
|---|---|
| Windows | %USERPROFILE%\Downloads |
| macOS | ~/Downloads |
| Linux | ~/Downloads + XDG fallback |
All errors produce a clean, human-readable message. Stack traces are never shown to the user — they go to the log file only.
| Situation | Exception | Exit Code |
|---|---|---|
| Downloads folder missing | DownloadsFolderNotFoundError |
1 |
| Path exists but is a file | DownloadsFolderNotDirectoryError |
1 |
| Permission denied | DownloadsFolderPermissionError |
1 |
| Home directory invalid | InvalidHomeDirectoryError |
1 |
| Category | Extensions |
|---|---|
| Images | jpg, jpeg, png, gif, bmp, svg, webp, ico, tiff, heic |
| Videos | mp4, mkv, avi, mov, wmv, flv, webm, 3gp |
| Music | mp3, wav, flac, aac, ogg, m4a, wma, opus |
| Word | doc, docx |
| Spreadsheets | xls, xlsx, csv |
| Presentations | ppt, pptx |
| Archives | zip, rar, 7z, tar, gz, bz2, xz, iso |
| Code | py, js, ts, html, css, json, yaml, sql, … |
| Executables | exe, msi, dmg, deb, rpm, sh, bat |
| Text | txt, md, rst, log |
| Fonts | ttf, otf, woff, woff2 |
| Ebooks | epub, mobi, azw3, djvu |
| Design | psd, ai, sketch, blend, stl |
| Other | (everything else) |
Every run appends to logs/smartsort.log:
[2026-07-18 09:30:00] [INFO ] SmartSort.main SmartSort v0.1.0 started.
[2026-07-18 09:30:00] [DEBUG ] SmartSort.detector Downloads detection started.
[2026-07-18 09:30:00] [INFO ] SmartSort.detector Downloads folder detected: /home/user/Downloads
[2026-07-18 09:30:00] [INFO ] SmartSort.main Detection successful: /home/user/Downloads
pytest tests/ -vpytest tests/ --cov=src/smartsort --cov-report=term-missingruff check src/ tests/ruff format src/ tests/| Version | Feature |
|---|---|
| v0.2 | Complete file organization pipeline |
| v0.3 | Detailed run summary |
| v1.0 | Stable public release |
| v2.0 | Keyword-based content classification |
| v3.0 | Real-time monitoring with watchdog |
| v4.0 | Desktop GUI with PySide6 |
| v5.0 | Undo functionality |
| v6.0 | Duplicate detection via SHA-256 |
| v7.0 | AI-powered file classification |
Contributions, issues, and feature requests are welcome!
- Fork the repository
- Create a feature branch (
git checkout -b feat/amazing-feature) - Commit your changes using Conventional Commits
- Push and open a Pull Request
(Screenshots will be added in a future milestone)
MIT License — free to use, modify, and distribute.
