DEV Community

Cover image for The laziest way to organize your files: a tiny local model and an undo button
Aditya Mote
Aditya Mote

Posted on

The laziest way to organize your files: a tiny local model and an undo button

Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady Submission 🦄

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

What I Built

Everyone has a folder they keep meaning to clean up. sloth-tidy is the lazy fix: a single Python file that sorts, renames and archives a messy folder using a tiny local model, gemma3:1b, through Ollama.

You point it at a folder and it prints a plan. Nothing moves until you add --apply, and every run can be undone.

  • Sorts files into Sorted/<Category>/ by type: Images, Documents, Installers, Archives, Code and so on.
  • Labels documents and .eml emails by reading a snippet locally: Invoices, Receipts, Certificates, Resumes, Study, Work, Legal, Finance, Travel, Personal, Newsletters.
  • Renames only junk names, like scan0001.pdf or Screenshot (12).png. Descriptive names are left alone.
  • Archives files that haven't been touched in a long time into Sorted/Archive/<year>/.

The people who get lazier are the ones whose files are too private for a cloud tool: invoices, certificates, personal email.

Demo

This is a real run on a scratch folder, using gemma3:1b on my own Windows machine:

PS> python tidy.py scratch --apply
[1/4] reading notes.txt
[2/4] reading scan0001.txt

notes.txt
    -> Sorted\Documents\Personal\notes.txt
scan0001.txt
    -> Sorted\Documents\Invoices\2026-10-21 Electricity bill October 2024.txt
Screenshot (12).png
    -> Sorted\Images\Screenshot 2026-10-21 1304.png
setup.exe
    -> Sorted\Installers\setup.exe

Moved 4 files.

PS> python tidy.py scratch --undo
Restored 4 files from the run at 2026-10-24T13:09:00.
Enter fullscreen mode Exit fullscreen mode

scan0001.txt contained only a line about an electricity bill. The model read it, picked a label and wrote a title, and the date prefix comes from the file's modified time. After the undo, all four files were back under their original names.

Code

GitHub logo Rx-Metallica / sloth-tidy

A lazy dev's file and inbox tidier. Sorts, renames and archives messy folders with a local gemma3:1b model via Ollama. No cloud, no API keys.

sloth-tidy

A lazy dev's file and inbox tidier. It sorts, renames and archives a messy folder using a local model (gemma3:1b through Ollama). Your files never leave your machine.

Single Python file, standard library only.

What it does

  • Sorts files into Sorted/<Category>/ by type: Images, Documents, Installers, Archives, Code, ...
  • Labels documents and .eml emails by reading a snippet locally: Invoices, Receipts, Certificates Resumes, Study, Work, Legal, Finance, Travel, Personal, Newsletters. A keyword fallback covers the cases where a 1B model answers "Misc".
  • Renames only messy names (scan0001.pdf, Screenshot (12).png), e.g. to 2026-10-21 Electricity bill October 2024.pdf. Descriptive names are left alone.
  • Archives files older than N days into Sorted/Archive/<year>/.
  • Stays safe: dry run by default, never deletes or overwrites, skips files modified in the last 10 minutes (likely still downloading), and every run can be undone.

Setup

ollama pull gemma3:1b
pip install
…

It's one file with no dependencies beyond the standard library. pypdf is optional, for reading PDFs.

How I Built It

Stack: Python standard library, Ollama's local HTTP API, gemma3:1b. There's no SDK and no API key. The script posts JSON to localhost:11434.

The pipeline: scan the top level of the folder, skip anything hidden, still downloading, or modified in the last 10 minutes, categorise by extension, pull a short text snippet from documents (.txt, .md, .docx via zipfile, .eml via email, PDFs via optional pypdf), ask the model for a label and a title, build a plan, print it, and only then move files and write an undo log.

A 1B model needs guardrails. Here is what I did about that:

  1. Constrain the output. Ollama's JSON mode, one few-shot example, a fixed list of allowed labels, temperature 0.1 and a snippet capped at about 1,200 characters.
  2. Never trust it. If the model returns a label outside the list, it's ignored. If it says "Misc", a small keyword fallback gets a second chance:
KEYWORDS = {
    "Invoices": ["invoice", "bill", "amount due", "total due"],
    "Certificates": ["certificate", "completion", "awarded"],
    "Newsletters": ["unsubscribe", "newsletter", "view in browser"],
    # ...
}
Enter fullscreen mode Exit fullscreen mode

In my first real run, the model left an obvious electricity bill unlabeled. With the fallback it landed in Invoices.

  1. Make mistakes cheap. Dry run by default, no overwriting or deleting, collision-safe names, Windows-safe filenames, and a JSON log that --undo replays in reverse.

A bug I found in my own tool: on a folder of certificate PDFs, pypdf wasn't installed, and the tool silently fell back to labeling PDFs by filename. The plan looked plausible, but the model had never read the files. The tool now prints a warning when PDFs can't be read.

Limitations:

  • Subfolders aren't scanned.
  • gemma3:1b is text-only, so images are sorted by type and never read.
  • Scanned PDFs with no text layer can't be labeled.
  • A 1B model will sometimes be wrong, which is why the dry run exists.

Why Does Open Innovation Matter?

Look at what this tool reads: invoices, certificates, emails. That's the last data I'd upload to a hosted API just to get a folder sorted.

An open-weight model changes the trade-off:

  • Privacy: file contents never leave the machine.
  • Cost and limits: it's free per file, with no rate limits, so it can scan thousands of files without a bill.
  • Offline: it works with no connection once the model is pulled.
  • Swappable: changing models is one environment variable (SLOTH_MODEL=gemma3:4b). I haven't benchmarked the larger model yet.

The honest trade-off is that a bigger closed model would probably label better. But for this job a small local model plus validation, a keyword fallback and an undo log is good enough, and it keeps my files on my own disk.

The Lazy Payoff

You set it up once, and you can then run it weekly with Windows Task Scheduler:

schtasks /Create /SC WEEKLY /D SUN /ST 20:00 /TN "SlothTidy" /TR "python C:\path\to\tidy.py C:\Users\you\Downloads --apply"
Enter fullscreen mode Exit fullscreen mode

Prize Categories

Best Use of Gemma: gemma3:1b runs locally through Ollama and does the labeling and titling for every document and email.

Top comments (1)

Collapse
 
ranjit_kmable_fadaf5f0731 profile image
Ranjit Kmable •

Brilliant work hope continue to progress šŸ˜Ž