My Downloads folder had 1,187 files in it as of Sunday night. I know the exact number because I ran ls | wc -l specifically so I could be embarrassed by it in this post. Invoices, screenshots named "Screenshot 2026-04-11 at 3.42.17 PM.png," three separate PDFs all called "resume_final.pdf" that are absolutely not all the same resume, a folder of camera raws I forgot I imported. Its been like this since roughly 2019 and every "cleanup weekend" I've attempted has died within forty minutes.
This week I actually fixed it, and the fix was dumber than I expected, which is usually the sign a fix is going to stick.
What didn't work first
I tried Hazel a few years back and it was fine but rule-based sorting falls apart the second a file doesn't match your rules exactly, and mine never do. Then I tried one of those AI file-organizer apps that wants a subscription and cloud access to every document on your machine, which, no. Absolutely not. I am not shipping my tax PDFs to somebody's inference cluster so an app can rename them "Financial_Document_2026.pdf." That's the whole problem with a lot of these tools right now, they assume everyone's fine with the round trip to a server, and I'm just not, especially for stuff sitting in Downloads which is basically a junk drawer of personally identifying information.
What did work
I already had Ollama running for unrelated reasons (mostly asking a model to explain regex to me, which never stops being funny to need help with after fifteen years of writing code). So I pointed a small local model at the problem instead.
The setup is genuinely five pieces:
- A shell script that walks
~/Downloads, skips anything modified in the last 24 hours (so it's not yanking a file out from under me mid-download or mid-edit), and for each remaining file pulls the filename plus, if it's a text-based file, the first couple hundred words. - That gets piped to a local model — I'm using a small Qwen-family model, nothing fancy, it doesn't need to be smart, it needs to be fast and free — with a short prompt asking for one of about eight category folders: Receipts, Screenshots, Contracts, Photos, Installers, Reading, Work, Misc.
- The script moves the file into
~/Sorted/<category>/<year-month>/. - Anything the model isn't confident about gets left alone rather than guessed at. I'd rather have 40 stray files than one important PDF filed somewhere I'll never think to look.
- A cron entry runs the whole thing at 6:15 AM, before I'm awake enough to be annoyed by it doing something weird.
Here's the actual cron line, for anyone who wants to steal it:
15 6 * * * /Users/me/scripts/sort-downloads.sh >> /Users/me/scripts/sort.log 2>&1
The first run took about eleven minutes and moved 640 files. It got maybe 90% of them right on the first pass. The screenshots category was flawless, obviously, since filenames do all the work there. The stuff it got wrong was mostly ambiguous forwarded-email PDFs, which honestly I'd have filed wrong too.
The part I didn't expect
The genuinely useful bit wasn't the sorting, it was that writing the "first 200 words" extraction step made me actually look at what's been piling up. Turns out I had four different insurance documents from three different years, and finding that out via an automated script felt a lot less bad than finding it out by manually digging through a folder while procrastinating on something else. There's something to be said for outsourcing the boring reading part specifically so the noticing part still happens to you.
I'm not going to pretend this is a groundbreaking use of local models, running small inference on your own machine to sort files is about as unglamorous as it gets. But it's the first organization system in seven years that survived past week two, mostly because it asks nothing of me. No app to open, no rules to maintain, no dashboard to check. It just runs before I wake up and by the time I'm making coffee my Downloads folder has gone back to being mostly empty, the way God intended a Downloads folder to be, which is to say: a place things pass through, not a place things live.
If your Downloads folder is also a crime scene, the whole script is maybe 60 lines of bash plus a curl call to a local Ollama endpoint. Happy to paste it if anyone wants it, just say so in the comments.