This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
What I Built
snapfile points a local vision model at the folder of screenshots you've
been avoiding for two years and files every one of them while you make coffee.
You know the folder. 400 images called Screenshot 2026-10-24 at 11.42.07.png.
You keep taking screenshots because filing them is a chore, and you never find
them again because the filenames are timestamps. snapfile breaks that loop:
$ snapfile web ./examples/graveyard # http://127.0.0.1:8787
Gemma 3 looks at each image and answers three questions: what is this (kind),
what should it be called (a title a human recognises six months later), and
is it worth keeping at all. Kept shots get moved to sorted/<kind>/<slug>.png.
Junk is reported and never deleted — you get the del command and the
decision stays yours.
Who gets to be lazier: anyone with a screenshot graveyard, a camera roll full
of whiteboards, or a downloads folder full of receipts. Also anyone who has ever
opened a file named IMG_20261021_180329.jpg and closed it again.
Demo
Run it yourself — the repo ships a five-screenshot graveyard:
git clone https://github.com/itzneel05/snapfile && cd snapfile
pip install -e .
snapfile ./examples/graveyard # dry run — nothing moves
snapfile ./examples/graveyard --apply # files the keeps
snapfile web ./examples/graveyard # local UI at http://127.0.0.1:8787
Real terminal output from --apply:
snapfile :: 5 screenshots :: model gemma3:4b
[keep] Screenshot 2026-10-19 at 14.55.02.png
Pricing Plans - Free and Pro Tiers -> sorted\ui\pricing-plans-free-and-pro-tiers.png
[junk] Screenshot 2026-10-20 at 03.07.11.png
Solid black screen with no visible content (likely accidental capture)
[keep] Screenshot 2026-10-21 at 18.03.29.png
Cloud Storage Invoice - 2026-10-42 -> sorted\receipt\cloud-storage-invoice-2026-10-42.png
[keep] Screenshot 2026-10-23 at 09.15.44.png
Incident room Slack conversation - runner issue -> sorted\chat\incident-room-slack-conversation-runner-issue.png
[junk] Screenshot 2026-10-24 at 11.42.07.png
NGINX 404 Not Found Error Page (standard 404, not a useful state)
3 kept (moved), 2 junk, 0 failed
junk was left untouched; delete it yourself when you're sure:
del "examples\graveyard\Screenshot 2026-10-20 at 03.07.11.png"
The web UI shows the same verdicts streaming in card by card while the model
works, behind a confirm dialog — dry run by default, APPLIED only after you
click through.
Code
https://github.com/itzneel05/snapfile
-
snapfile/client.py— stdlib Ollama client:urllib+ base64 images, no third-party HTTP, no API key, no code path to any external host. -
snapfile/filer.py— the load-bearing part: scan → vision call → verdict → destination plan. Deliberately no heuristic fallback. -
snapfile/web.py—http.serveron127.0.0.1(refuses a non-loopback bind), verdicts stream as they land, idempotent confirm-gated apply. -
snapfile/web_page.py— one embedded HTML page, zero external requests, model output rendered viatextContentonly. -
tests/— 15 tests, none of which need a model: JSON repair, slug and destination math, a deadlock regression, and path-traversal rejection.
Zero runtime dependencies. Python 3.9+, Ollama, done.
How I Built It
Built with AI assistance in OpenCode, with Google's open-weight Gemma 3 running locally through Ollama.
Details that took the time:
-
Verdicts stream in. The status line reads
3 of 5 looked at · model gemma3:4b · no rushbecause on a CPU each image is ~20s of real work, and a spinner would be lying about it. - Apply is idempotent: a second request never re-moves anything.
-
/thumb?f=resolves inside the scanned folder and rejects../outright. - Every test request carries a timeout — after I hit a real deadlock mid-build (a serializer called while holding its own lock), that bug now fails the suite instead of hanging it.
Why Does Open Innovation Matter?
Because screenshots are the most private files on a machine — bank cards,
medical portals, half-written messages, a chat you weren't supposed to capture.
Sending 400 of them to a cloud vision API would be the wrong answer even if it
were free, and at per-call pricing it's the answer you keep postponing — which
is exactly how the graveyard got to 400 images.
With an open-weight model on localhost:
-
Nothing leaves the laptop. The client POSTs to
127.0.0.1:11434and nowhere else. - Works with the Wi-Fi off. Plane, train, locked-down work machine.
- Costs nothing per look, so filing the whole backlog is a few minutes of GPU — not a decision you defer forever.
-
You can swap or fine-tune the brain.
--modeltakes any local vision model; fine-tune Gemma on your desktop and it gets better at your screenshots. A closed API will never let you do either.
The Lazy Payoff
The demo graveyard is five synthetic screenshots and takes about 90 seconds to
file — but the real target is my own camera roll and Downloads/, where files
are named IMG_20261021_180329.jpg and nothing is ever found again. Before
snapfile, "organise screenshots" was a chore I had postponed for roughly two
years. Now it's snapfile web ./Downloads and a decision I make with a
thumbs-up while the kettle boils.
Prize Categories
-
Best Use of Gemma —
gemma3:4b(andgemma3:1b) via Ollama is the sole engine: classification, titles, junk detection and destination naming all come from the model, running locally as the load-bearing core.
Top comments (0)