This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
My Desktop has 269 folders. I'm clearly willing to file things. I'm just not willing to do it today, so my Downloads folder fills up with IMG_4821.HEIC, document (3).pdf and four ebooks I swear I'll read.
Every file tidier I know of wants rules first: "PDFs go here, screenshots go there". Writing rules is the chore I was avoiding in the first place. So I built the laziest version I could think of.
Tidy Sloth looks at the files I've already filed, works out my system from them, and proposes a tidy for Downloads and Desktop. I get one screen, one sentence and one button. Then I get to watch a sloth do the work: it fetches each file, reads it, gives it a real name, and drops it in the right basket.
- It moves a file only when it's confident. Files it isn't sure about stay where they are.
- It renames only junk names (
IMG_β¦,Screenshot β¦,Untitled, UUIDs). Gemma 4 reads the picture or the first page and suggests a real name. - If several files of one kind have nowhere to go, like four ebooks, it suggests a new folder for them.
- It never deletes, never touches anything that looks like a key or a password, and Undo puts everything back.
Installing it is one line in Terminal. After that it's an app in your Applications folder: open it and press Approve. And because sloths don't hurry, the installer offers to build a fresh plan every night at 3 am, so in the morning it's already waiting for your one click.
Demo
Try it in the browser. The demo uses a made-up Downloads folder, so nothing real moves. The sloth starts working on its own; press Approve all to have it finish the rest at once, or "Let me check first" to see the whole plan.
The real version runs on your Mac (Apple silicon, macOS 14+). Paste this into Terminal once:
curl -fsSL https://mohamedaminehamdi.github.io/tidy-sloth/install.sh | sh
It installs everything into your home folder, with no admin password: Tidy Sloth, Ollama with Gemma 4, the TabPFN weights, and a Tidy Sloth app. Why a Terminal line and not a .dmg? macOS blocks downloaded apps unless they're notarized, which needs a paid Apple developer account. An app built on your own Mac by the installer has nothing for Gatekeeper to block.
Code
mohamedaminehamdi
/
tidy-sloth
Tidies your Downloads and Desktop by learning how you already file things. TabPFN + local Gemma 4, fully offline, never deletes.
Tidy Sloth π¦₯
Puts your Downloads and Desktop away by learning how you already file things. One click to approve, one click to undo. Runs on your Mac, never deletes anything.
Try the demo (made-up files, nothing real moves)
Install
Paste this into Terminal once (Apple silicon, macOS 14+, no admin password):
curl -fsSL https://mohamedaminehamdi.github.io/tidy-sloth/install.sh | sh
It installs uv, Tidy Sloth, Ollama with Gemma 4 (about 6.6 GB, the bulk of the download), and the open TabPFN weights. Then it makes a Tidy Sloth app in your Applications folder. From then on it's one click: open the app, and the sloth looks through your Downloads and Desktop while you watch.
The installer also asks whether to build a plan every night at 3 am. It's off unless you say yes. A Mac that's asleep at 3 am builds the plan when it next wakes. The nightly run neverβ¦
How I Built It
1. Your folders are the training data
Every file sitting in one of my folders is a labelled example: this file belongs in that folder. So Tidy Sloth turns each file into one row of a table:
| extension | family | size | created | lat | lon | downloaded from | filename (8 numbers) | folder |
|---|---|---|---|---|---|---|---|---|
| .heic | image | 2.1 MB | 2026-06-14 | 38.71 | -9.14 | β¦ | Lisbon 2026 | |
| 88 KB | 2026-02-03 | irs.gov | β¦ | Taxes 2026 |
Nearly all of these columns were already on the disk. macOS Spotlight keeps a file's capture date, photo GPS and the website it was downloaded from. Tidy Sloth reads them with mdls, so no extra dependency is needed. For the filename, character n-grams are squashed into 8 numbers with TF-IDF and SVD.
Then TabPFN reads the table. TabPFN is a tabular foundation model: you hand it the labelled rows and it predicts new ones in a single forward pass. There's no training run, no hyperparameters and no GPU needed. For a lazy person, that's exactly right.
clf = TabPFNClassifier.create_default_for_version(ModelVersion.V2, categorical_features_indices=CATEGORICAL)
clf.fit(featurizer.transform(filed_paths, meta), folder_labels) # files I already filed -> their folder
proba = clf.predict_proba(featurizer.transform(loose_paths, meta)) # loose files -> where they probably go
TabPFN handles up to 10 classes, so it learns from my 10 biggest filing folders, with up to 100 files from each. That stays well under its comfortable table size and keeps one huge photo folder from drowning out the rest.
2. Does it actually learn? A held-out test on my real Desktop
Before letting anything move my files, I wanted proof. I took the files I'd already filed, hid 30% of them, fitted on the other 70%, and asked TabPFN to put the hidden ones back:
| put back correctly | |
|---|---|
| A rule based on the file extension | 28.9% |
| TabPFN | 98.6% |
| TabPFN, only when it's β₯ 90% sure (that's 93.8% of files) | 100% |
| TabPFN, only when it's β₯ 70% sure (97.2% of files) | 99.5% |
That's 547 training files, 211 test files and 10 folders. The confidence is what makes this safe to automate: above 90% it didn't make a single mistake. So Tidy Sloth only moves a file at 70% or more, and leaves everything else alone.
Then I removed the date and GPS columns, and accuracy fell to 45%. Most of my folders are trips, and a trip folder is defined by when and where, not by what the photos are called. The model worked that out without being told. A rules-based tidier would never have guessed "look at the GPS".
The honest weak spot is documents. My folders hold few PDFs, and TabPFN's accuracy on them was lower: 80%, on only 5 test files. That's where the second model comes in.
3. Gemma 4 reads what TabPFN can't
Gemma 4 (gemma4:e4b) runs locally through Ollama and has two small jobs:
-
Naming junk. If a filename is one nobody really chose (
IMG_4821,Screenshot 2026-10-19 at 09.12.44,document (3)), Gemma looks at a small preview made with macOSsips, or at the first page of a PDF read withpypdf. It suggests a 3β8 word name such as "landlord reply about heating". The prompt tells it never to put account or ID numbers in a name. - A second opinion on documents. When TabPFN isn't sure about a PDF, Gemma reads it and picks one of my folders, or "none".
Both calls use Ollama's structured output, so the answer is always valid JSON. For routing, Gemma's choice is an enum of my real folder names, so it can't make up a folder. Only a high-confidence answer counts. Anything less and the file stays where it is:
schema = {"type": "object", "properties": {
"folder": {"type": "string", "enum": [*folder_names, "none"]},
"confidence": {"type": "string", "enum": ["high", "medium", "low"]}},
"required": ["folder", "confidence"]}
4. Plan, one click, undo
Nothing moves while the plan is being built. The review screen is a small page served on 127.0.0.1. You can untick any file and edit any new name. Approve all then runs the plan:
- Every move is written to a journal in
~/.tidy-sloth/before it happens, so even a crash halfway through can be undone. - A name clash becomes
name (2).pdf. Nothing is ever overwritten. - There is no delete anywhere in the code.
- Undo everything replays the journal backwards.
- Secrets are never planned:
.pem,.key,id_rsa,.env, wallets, and anything named like a password or recovery code. - Also never touched: code projects (anything with
.git,package.json,pyproject.tomlβ¦), app bundles, hidden files, and files changed in the last 10 minutes.
Two more safety details:
- A double-click on Approve, or a browser tab left open from an older plan, is refused instead of acted on. Each plan has a token, and only one change runs at a time.
- If macOS says no when Tidy Sloth asks to look in Desktop or Downloads, the page says how to allow it, instead of quietly planning nothing.
The important parts have tests: secrets and code projects never end up in a plan, an apply/undo roundtrip with a name clash restores every file, and a typed name like ../../etc/passwd is cleaned before it can go anywhere. The server refuses requests from other hosts, which blocks a malicious web page from reading your file list through DNS rebinding. The tests run in GitHub Actions on every push.
5. A sloth you can watch
A tidy you can't see is a tidy you don't trust. So the review screen is a little forest: a branch, a pile of file cards, and one basket per destination folder. The sloth slides along the branch, lowers itself on a vine, and does each file in four steps:
- Reads it. A scan line runs over the card and a bubble says what it's looking at ("HEIC photo Β· 2.1 MB").
- Names it. Gemma's new name types itself onto the card.
- Decides. The bubble shows the real reason from the plan: "TabPFN: 99% sure β Lisbon 2026", "Gemma 4 read it β Taxes 2026", or "None of your folders fit β a new Books folder".
- Puts it away. The card drops into its basket and stays there, and the basket's count ticks up.
It's plain SVG and the Web Animations API, with no libraries and no CDN, so it also works offline. The animation is decoration only. The page never waits for it to finish, and if you click the forest it skips to the real end state. On your own Mac nothing goes in a basket until you press Approve. Before that, the sloth just ambles along the branch and peers at the pile.
6. One line to install, then it's an app
install.sh is a short POSIX script you can read before running it:
- It installs uv, then installs Tidy Sloth from a wheel that GitHub Pages serves next to the demo. That avoids
git, which on a fresh Mac pops up the developer-tools installer. - It downloads Ollama if you don't have it.
- It runs
tidy-sloth --setup, which pulls Gemma 4 through Ollama's API, warms the TabPFN weights on a dummy table, and buildsTidy Sloth.appwithosacompile.
The app gets the sloth icon and its own bundle id. It's re-signed after the icon is added, because macOS ties folder permissions to a valid signature. It also explains itself in the permission prompt: "Tidy Sloth looks at your files to suggest where they belong. Nothing moves until you approve."
The optional 3 am run is a LaunchAgent that opens the app in overnight mode rather than running Python directly. That way it uses the permissions you already gave Tidy Sloth.
The bug that took the longest
The first run said none of my downloads had a source website, which was obviously wrong. It turns out mdls -raw prints attributes in alphabetical order, not in the order you ask for them. Zipping my list against its output put the creation date in the "downloaded from" column. Sorting the attribute list first fixed it. If you ever script Spotlight, save yourself the hour.
The lazy payoff
On my own Mac, opening the app found 21 loose files in Downloads and Desktop. Tidy Sloth planned:
-
20 moves:
- 14 by TabPFN, one of them also renamed;
- 2 more after Gemma read the PDFs;
- 4 ebooks into a new Books folder.
- 1 file left alone, because it wasn't sure.
- 2 files flagged and never touched, one of them a private key sitting on my Desktop.
That's about 7 minutes of my time back, if you accept my guess that a person spends ~20 seconds finding a home for one file. The plan took under two minutes to build.
Seven minutes isn't much. The real saving is that I'll never have to sit down and do it at all.
Why Does Open Innovation Matter?
Look at a Downloads folder: tax forms, a lease, bank statements, photos with GPS in them. A filename list is personal data, and file contents even more so. A closed API would mean sending my files to someone else's server just to tidy them. With open models, nothing leaves the laptop:
- TabPFN's v2 weights are open and run on a laptop with no account or login. It learns my filing system in context, on my machine, every time it runs. A closed classifier couldn't learn my folders without me uploading them.
- Gemma 4 runs locally in Ollama, so the photos and PDF pages it reads stay on the Mac. Once the weights are downloaded, it all works offline, on a plane, with Wi-Fi off.
- It costs $0 and needs no API key. A tidy tool that charges per file would be a strange thing to run every night.
-
It's swappable.
SLOTH_MODEL=...points it at any other vision model in Ollama. Because the code is open, you can read for yourself that it never deletes, and trust it with your Desktop because of that.
Prize Categories
- Best Use of TabPFN: TabPFN is the tidier. It learns your filing system from the files you already filed, in one forward pass, and only acts on its own confidence. Held-out on my real Desktop: 98.6% vs 28.9% for an extension rule, and 100% when it's β₯ 90% sure.
- Best Use of Gemma: Gemma 4 runs locally to name junk files from a picture or the first page, and to route documents TabPFN isn't sure about. It uses schema-constrained JSON and can only pick folders that already exist.
-
Best Use of GitHub Copilot: the project is automated with GitHub Actions.
- On every push, CI runs the safety tests on macOS: secrets skipped, path tricks cleaned, the apply/undo roundtrip, a double Approve refused, and the review server refusing other hosts.
- It shellchecks the installer, then runs it on a clean macOS runner to prove the app gets built, signed and uninstalled.
- A second workflow builds the wheel and publishes the demo, the installer and the wheel to GitHub Pages.




Top comments (0)