DEV Community

Aryan Vijaykar
Aryan Vijaykar

Posted on

I Taught a Sloth to Clean My Downloads Folder (Offline, with Gemma)

What I Built

My Downloads folder had 400 files, and a third of them were named final_FINAL_v2 (1).pdf. I kept meaning to tidy it, and I kept not doing it.

So I did what any good sloth would do: I spent a weekend building something to do it for me.

SlothSort is a small local agent that cleans up a folder so you don't have to. For each file, it reads the filename and a short snippet of text, asks an open-weight model for a clean name and a destination folder, and moves the file there. Invoices go to Invoices/, assignments to Study/, tickets to Travel/, and installers to Installers/.

It runs in dry-run mode by default: it prints the plan, and nothing moves until I type y. A sloth is lazy, not reckless.

The lazy payoff: in my run, 12 messy files were sorted and renamed in 41 seconds. The point isn't the 41 seconds, though. It's the afternoon of tidying I never have to schedule.

Demo

Here is the folder before:

text
Downloads/
├── invoice_scan_0192.pdf
├── Screenshot 2026-10-12 at 4.18.02 PM.png
├── final_FINAL_v2 (1).pdf
├── setup_x64.exe
├── IMG_8841.jpg
├── notes_unit3_os.docx
├── Document (3).pdf
├── bus_ticket_nagpur_pune.pdf
├── resume_new.pdf
├── aws-vpc-lab.png
├── electricity_oct.pdf
└── Untitled.txt

And here is SlothSort planning the cleanup:

text
$ python slothsort.py ~/Downloads --model gemma3 --dry-run

[1/12] invoice_scan_0192.pdf
-> Invoices/2026-10_electricity-bill.pdf
[2/12] Screenshot 2026-10-12 at 4.18.02 PM.png
-> Study/aws-vpc-diagram.png
[3/12] final_FINAL_v2 (1).pdf
-> Study/os-assignment-final.pdf
[4/12] setup_x64.exe
-> Installers/setup_x64.exe
[5/12] bus_ticket_nagpur_pune.pdf
-> Travel/nagpur-pune-bus-ticket.pdf
...
Plan ready: 12 files, 5 folders. Apply? [y/N] y
Done in 41s. No network requests made.

And after:

text
Downloads/
├── Invoices/ (2)
├── Study/ (4)
├── Travel/ (1)
├── Installers/ (1)
└── Personal/ (4)
Code

How It Works

The whole thing is about 60 lines of Python, and it does four things:

Scan. It walks the folder and pulls a short snippet from each file: the first page of a PDF, the first lines of a text file, or just the filename for images.
Ask. It sends the filename and snippet to Gemma running locally through Ollama. The prompt asks for strict JSON: {"new_name": "...", "folder": "..."}.
Constrain. The model has to pick from a fixed list of folders. If it returns something outside the list, the file goes to Unsorted/ instead of creating a new category.
Plan, then move. It prints the full plan first and moves files only after I approve.
Why Open Innovation Mattered Here

For this project, the open-weight route is better than the closed one in practical ways.

My Downloads folder is private. It holds bank statements, ID scans, bills, and my resume. Sending every file's contents to a cloud API just to rename it is a bad trade, and I wouldn't do it. With Gemma running through Ollama, the files never leave my laptop. The "No network requests made" line in the demo is the whole point.

It works offline. A tidier that needs Wi-Fi isn't much of a tidier. Mine runs on a train, during a power cut, or on bad campus internet.

It costs nothing to run. A tool that runs on every download would rack up a real API bill. Locally, the marginal cost is a little electricity, so I can run it as often as I like.

I can swap the model. The model name is one command-line flag. If a smaller model is fast enough, or a bigger one sorts more accurately, I change one word and rerun. I'm not tied to one provider's pricing, rate limits, or deprecation schedule.

What Didn't Work (and What I Changed)
Free-form folders were a mess. Early on I let the model invent folder names, and I got Docs, Documents, and Paperwork all in one run. Constraining it to a fixed list fixed this.
Scanned PDFs have no text. For image-only files there's nothing to read, so SlothSort falls back to the filename and flags the file for review instead of guessing.
Letting an LLM move files unsupervised is a bad idea. That's why dry-run is the default. I'd rather spend three seconds approving a plan than spend an hour finding a missing file.
What's Next

A sloth never rushes, but it does have plans. Next I want to run SlothSort on a schedule so new downloads get sorted automatically, and add an undo log so every move can be reversed with one command.

If you've got a folder you've been avoiding, try it, and tell me what the model got wrong.

Built with Ollama, Gemma, and Python.

Top comments (0)