DEV Community

Abbey 🌠
Abbey 🌠

Posted on

Sloth Tidy: A Local AI That Cleans Your Messy Folders While You Nap

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

Sloth Tidy is a command-line tool that cleans up a messy folder (think Downloads) using an open-weight model running on my own machine.

You point it at a folder. For each file it reads a short snippet, then proposes a category, a clean filename, and a destination: scan0012.pdf becomes Invoices/2026/2026-10-31_meralco-electricity-bill.pdf. Nothing moves until you review a dry-run plan and apply it, and every move can be undone with one command. There's also a watch mode that files new arrivals in the background.

It's for anyone who has a folder full of scan0012.pdf, Document (3).docx, and Screenshot 2026-10-03.png and keeps putting off the cleanup. The sloth move is to run it once and walk away.

Code

Sloth Tidy

Point it at a messy folder; a local open-weight model proposes where everything belongs.

Why local and open

Sloth Tidy sends readable file snippets to Ollama on your machine by default. After you pull a model, it can run without internet access, hosted model APIs, or API keys; file contents stay on your machine. Choose another Ollama model with SLOTH_MODEL, and steer its decisions with rules.yaml. A remote Ollama server is possible only when you explicitly pass --allow-remote.

Requirements and setup

  • Node.js 20 or newer
  • Ollama installed and running
  • A pulled model; the default is qwen2.5:7b
  • Model weights are not included and are subject to their own licenses.
ollama pull qwen2.5:7b
npm install
npm run build
npm test
Enter fullscreen mode Exit fullscreen mode

Quick start with the demo

Generate the 30-file demo, copy it, and plan against the copy. The plan is written beside the copy so it is not…

MIT licensed. TypeScript, Node 20+, and Ollama.

How I Built It

The open parts at runtime: Ollama serves qwen2.5:7b locally. The tool talks to it over plain HTTP on localhost, with no API keys and no hosted services. The model name is one environment variable, SLOTH_MODEL.

How I built the project: I wrote a SPEC.md and built it in seven milestones with OpenAI Codex, committing after each one. The runtime doesn't depend on Codex, only the building did. Dependencies are small: commander, zod, pdf-parse, mammoth, and vitest.

The main lesson is that a small local model needs a tight leash. My first version asked the model for a folder and a filename, and the results were bad:

  • Reasons came back in Chinese, because Qwen drifted languages.
  • Folder names were garbage, like Invoices/2026-10-20-09-02-34-Meralco_Electricity_Billpdfgz-invoices-2026-10-20.
  • Timestamps were invented.
  • Files kept their original names.

So I changed the design so the model decides as little as possible:

  1. The model picks a category from a fixed list (enforced with a JSON schema) and writes a 2 to 6 word description. It never writes a path.
  2. Code builds the folder and filename and keeps the original extension.
  3. Dates must be verified. A date the model returns has to actually appear in the file's text, and the checker understands things like "01–31 October 2026". Otherwise the file's modified date is used.
  4. Output is validated. Non-English text, invalid categories, and bad JSON are rejected and retried once, then the file is left in place.
  5. Files with no readable content (images, installers) never reach the model. They're filed by extension. On my demo folder that was 10 of 30 files, so they cost nothing.

Safety is designed in: dry-run by default, never overwrite or delete, destinations can't escape the root folder, files that changed since planning are skipped, and every batch goes in an undo log. Watch mode only moves files with an explicit --apply flag and only above a confidence threshold. Anything it isn't sure about waits in a pending plan.

A rules.yaml file steers it without touching code: allowed folders, files to never touch, and overrides like "worksheet*.docx always goes to School".

Why Does Open Innovation Matter?

A Downloads folder is some of the most personal data on a computer: invoices, school forms, lease summaries, job applications. Sending a stranger's server the first lines of every file to sort them is a hard sell. With a local open-weight model, the file contents never leave the machine, and it works offline once the model is pulled.

Three more things open made possible:

  • Cost. My plan run takes several minutes, which is fine when the model is free. With a metered API, "run it on every new file in the background" becomes a bill.
  • Swappability. One environment variable changes the model, and I could compare two models on the same folder with no new accounts.
  • Control. Because the model runs locally with schema-enforced output, I could build guardrails around it and test them with a mocked model, 71 tests in total.

To be fair to closed models: a larger hosted model would probably be more consistent on borderline files. In my runs, the lease summary landed in Personal once and in Work another time, even at temperature 0. That's why rules.yaml overrides exist. For this particular job, I'd take a slightly less consistent model that never sees my files.

Top comments (0)