This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
If you work in design, your Downloads folder probably looks like this: Screen Shot 2026-10-14 at 9.41.02 PM.png, Untitled-1.png, document(3).pdf, logo_FINAL_final_v3 (1).png. Every one of those files meant something the day it landed. A month later, finding the right one means opening them one by one.
Tidying it is the job everyone means to do on Friday and nobody does. So in the spirit of International Sloth Day, I built something that does it for you.
Slothsort reads every loose file in a folder, gives each one a name you'd actually search for, and files it into a sensible folder:
-
Screen Shot 2026-10-14 at 9.41.02 PM.png→Screenshots/2026-10-06_lakeside-cafe-online-order-checkout-failure.png -
document(3).pdf→Invoices & Receipts/2026-10-11_invoice-88231-for-500-a2-posters.pdf -
IMG_4471.png→Illustrations/2026-10-04_farmers-market-schedule.png -
logo_FINAL_final_v3 (1).png→Duplicates/(byte-identical to the original, which stays put)
It runs entirely on your own machine with Gemma 3 and Tesseract. Set it up once as a nightly job and you never think about the folder again. That's the whole pitch: the laziest possible way to have an organised drive.
Demo
Before: thirteen files, the usual mix of screenshots, exports, a duplicated logo, an invoice, a brief, a font and source files.
The plan: python3 -m slothsort plan ~/Downloads looks at everything and moves nothing. It writes a single HTML page with a thumbnail, the old name, the new home and who decided: the file extension, a duplicate check, or the model. You approve with apply.
After: one run, 38 seconds on an otherwise idle 8-core CPU with no GPU (slower when the machine is busy).
And if you don't like it, python3 -m slothsort undo ~/Downloads puts every file back exactly where it was.
The demo folder is generated by a script in the repo with made-up brands, so you can reproduce this run yourself. No real client files were used.
Code
ctopp11
/
slothsort
Tidies your Downloads folder overnight with local Gemma + OCR, then finds any file in milliseconds. Private, offline, one-command undo.
Slothsort 🦥
Do nothing. Find everything.
Slothsort tidies your Downloads folder overnight with a local open model, then finds any file in milliseconds. Your files never leave your machine.
- 🌙 Wake up tidy. Every loose file gets a dated, searchable name and a proper folder: Screenshots, Invoices & Receipts, Logos & Brand, Source Files and more. Duplicates are set aside.
- ⚡ Find anything fast.
slothsort find "northgate invoice"answers from a private index, including text read inside screenshots and PDFs. Median 20 ms on a 100,000-file synthetic benchmark (numbers). - 🔒 Private and 100% local. Gemma 3 through Ollama, plus Tesseract OCR. No account, no API key, no per-file cost. Works offline.
- ↩️ One-command undo. Nothing moves until you've seen the plan, and
slothsort undoputs every file back.
ollama pull gemma3:4b
python3 -m slothsort run ~/Downloads # plan, tidy and index in one go
python3 -m slothsort…ollama pull gemma3:4b
python3 -m slothsort plan ~/Downloads
python3 -m slothsort apply ~/Downloads
The truly lazy version is one cron line:
0 2 * * * cd ~/slothsort && python3 -m slothsort run ~/Downloads --overnight
How I Built It
Open pieces: Gemma 3 4B running locally through Ollama, Tesseract for OCR, and Pillow for image measurements. The rest is standard-library Python. It's MIT licensed with 30 unit tests.
The design principle I care most about: the model describes, the code decides. I'm comfortable letting a language model tell me that a PDF is an invoice from a print shop. I'm not comfortable letting it rename files on my disk. So Gemma's only job is to return two fields through Ollama's structured outputs: a kind from a fixed list and a 3–6 word subject. Everything that touches the file system is plain, testable code:
- dated, slugified names (
2026-10-11_invoice-88231-for-500-a2-posters.pdf), - collision-safe suffixes, so nothing is ever overwritten,
- SHA-256 duplicate detection, which keeps the original and moves the
(1)copy, - a check that skips any file edited between planning and applying,
- and a journal written as it goes, which is what makes
undotrustworthy.
Being honest about what the model can see. The Gemma build on my machine is text-only. Rather than pretend otherwise, Slothsort checks the model's capabilities through Ollama's API. If vision is available, Gemma sees a 768px thumbnail. If it isn't, Gemma gets the text Tesseract reads out of the image plus facts measured with Pillow: pixel size, whether it matches a common screen resolution, colour count and dominant colours. That turned out to be enough to tell a checkout-error screenshot from a market poster from a logo.
Then I hit a lesson. For an image with no text, the model had nothing to go on, and it started borrowing the example phrase from my prompt as the "subject". So images without readable text skip the model entirely and get named from measured colours and shape (navy-purple-wide-artwork). It's less poetic, but it's never wrong about what it saw.
It isn't perfect. In the demo it filed a phone mockup under Logos & Brand, because without vision all it had to work with was the brand name on the screen. That's why there's a plan page and an undo button.
Slow and steady, literally. --overnight lowers the process priority and rests between files. Every result is cached by file hash the moment it's computed, so if the laptop sleeps halfway through a 2,000-file folder, the next night picks up where it left off, and files it has already seen cost nothing.
Then the lazy question after tidying: "where did I put that invoice?" Opening folders is still work, so Slothsort keeps a running index: one SQLite file next to your files. slothsort find "northgate invoice" answers from the index alone and never rescans the disk.
In plain terms it has three layers, loosely modelled on the way people describe memory. It's an analogy for organising data, not a brain:
-
Recall by words. SQLite FTS5 covers file names, Gemma's description and whatever text Tesseract read inside the file. That's why
find "card declined"turns up a screenshot whose name never mentioned a card. -
Recall by similarity. One vector per file, searched with a single matrix multiply and blended with the word results. I wanted the
nomic-embed-textmodel for this, but my machine's network blocked the download. So Slothsort falls back to built-in vectors made from words and word fragments. That fallback is fuzzy matching (it forgives "pine peek"), not true understanding, and it switches to the real embedding model automatically once that's installed. -
Episodes and topics. Every index, apply and undo is logged as a run, and
slothsort topicsgroups related files under labels like "pine / peak / outfitters".
The index updates incrementally. A file with the same path, size and modified time isn't even re-hashed. Moved or renamed files are matched by their hash, so they keep their description and never go back to the model.
I benchmarked it on 100,000 synthetic entries (generated metadata, no model calls) on the same 8-core CPU. With the index loaded, median search times were 11.7 ms for words, 4.2 ms for similarity and 20.1 ms for both combined. A cold open takes about 155 ms. Re-indexing 100,000 real, unchanged files took 0.8 seconds. The full method is in the repo's docs/BENCHMARKS.md.
Why Does Open Innovation Matter?
Because of what's in a Downloads folder. A designer's Downloads folder holds client invoices, unreleased brand work under NDA, contracts, and screenshots of banking and admin dashboards. I would never upload that folder to a cloud API just to get tidier file names, and no client would thank me if I did.
With open weights running locally:
- Nothing leaves the machine. The model, the OCR and the files are all on the same laptop. It works on a plane.
- It costs nothing to run nightly. A cloud API charges per call. Slothsort's marginal cost per file is zero, which is the only way an "every night, forever" automation makes sense.
-
I can swap the model.
SLOTHSORT_MODEL=gemma3:1bfor an older laptop, or a vision-capable Gemma build to read images directly. No vendor gets a vote. - Search stays private too. The index of everything Gemma and Tesseract read from your files sits in one SQLite file on your disk. A cloud search service would need a copy of all of it.
- I can inspect every decision. The plan page shows which files were decided by the model and which by deterministic rules. That transparency is what lets you trust an agent with your file system.
The Lazy Payoff
On the demo folder, Slothsort planned and filed 13 files in 38 seconds, with 8 of them read by the model. Doing the same by hand means opening each file, deciding what it is, typing a name and dragging it somewhere: easily 20–30 seconds a file, before you even get to spotting the duplicate. For a folder that collects a few hundred files a month, the nightly job turns a dreaded afternoon into zero minutes, and finding something later is one command that answers in milliseconds. The sloth would approve.
Prize Categories
- Best Use of Gemma: Gemma 3 4B, running locally through Ollama, classifies and describes every file (structured outputs, capability detection), and its descriptions feed the search index.
Transparency note: an AI coding agent wrote most of the code and drafted this post under my direction. I chose the problem, set the design rules (the model describes, the code decides; always plan before moving; always undoable) and reviewed the results.



















