This is a submission for the Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle
What I Built
Shoebox is a command-line tool that turns a messy folder of receipts and invoices into a sorted archive, a CSV ledger, and a tax-time summary. Everything runs on the freelancer's own machine.
Every freelancer I can think of has the same quarterly ritual: dig through Downloads, email attachments and phone photos, rename files, and type amounts into a spreadsheet. It eats an afternoon, and it is the kind of chore people will pay to skip.
Point Shoebox at a folder and it:
- Hashes each file, so re-running only reads new documents.
- Sends the text (or the photo) to a local open-weight model and asks for vendor, date, total, tax, currency, category and document type.
- Re-validates everything the model said, because models get dates and decimal commas wrong.
- Copies the file into
sorted/2026-03/travel/2026-03-09_delta-air-lines_304.00.pdf. - Writes
ledger.csvand asummary.mdwith totals by category and month.
Who would pay for it:
- Freelancers and solo consultants who want a "tax pack" at the end of each quarter, without sending client invoices to a third-party API.
- Bookkeepers with many small clients, where a per-document cloud bill would eat the margin on a flat-fee service.
- Small shops and studios that would run it on a spare mini PC and never mention it in a privacy policy.
I haven't tested any of those pricing ideas with a real customer. They are hypotheses, and I say more about that in the first-user section.
Demo
There is no hosted demo, and I'm not going to fake a screenshot. This tool reads private financial documents, so a public web demo would defeat the point. Anyone can reproduce it in a few minutes with the sample receipts in the repo (steps below), and the README shows the expected output layout.
git clone https://github.com/amandewatnitrr/shoebox.git && cd shoebox
python -m unittest discover -s tests -v # unit tests, no model needed
ollama pull gemma3:4b # one-time model download
python -m shoebox doctor # checks Ollama and the model
python -m shoebox scan examples/sample_receipts --out shoebox-out
cat shoebox-out/summary.md
Code
amandewatnitrr
/
shoebox
Local-first receipt & invoice sorter for freelancers. Open-weight model (Gemma 3 via Ollama), zero cloud. Hacktoberfest AI Challenge W2.
🥿 Shoebox
A receipt and invoice sorter for freelancers that runs on your laptop. Point it at a messy folder. It reads every receipt with an open-weight model, files each one by month and category, and hands you a CSV and a tax-time summary. Client data never leaves your machine.
Built for the Hacktoberfest Open-Source AI Challenge, Week 2: Side Hustle.
Honest status: this is a first-draft prototype. It was written without being run, so expect rough edges. Nothing here has been tested against a real model yet, and it has no users yet. The steps below are how you check it.
The side hustle
Every freelancer has a shoebox (or a Downloads folder) full of receipts, and every quarter they lose an afternoon to it. That afternoon is worth paying to skip.
| Who pays | What they pay for | Why local matters |
|---|---|---|
| Freelancers and solo consultants | A quarterly "tax |
MIT licensed. Runtime dependencies: none (PDF support is an optional pypdf extra).
How I Built It
Open pieces: Gemma 3 as the default open-weight model, served locally by Ollama. Photos of receipts need a vision-capable model, so a larger Gemma works better there. The model is one flag: --model.
The whole thing is plain Python standard library. The Ollama client is about 60 lines over urllib.
folder of receipts ──► hash + dedupe ──► text / image
│
Ollama on localhost (Gemma 3)
│ JSON constrained by a schema
â–¼
normalise dates, amounts, currency
│ │ │
sorted/YYYY-MM/category/ ledger.csv summary.md
Three design decisions did most of the work:
1. Constrain the model's output instead of begging for JSON. Ollama's format field accepts a JSON schema. Shoebox passes one with an enum of categories, so the model cannot invent "stuff" as a category. If the JSON is still malformed, reader.py retries once and then reports the file as failed rather than guessing.
2. Never trust the model's numbers. schema.py re-parses every field:
parse_amount("$1,234.50") # 1234.5
parse_amount("1.234,50 €") # 1234.5 (last separator is the decimal)
parse_amount("1,50") # 1.5
parse_amount("1,234") # 1234.0
parse_date("09/03/2026") # "2026-03-09"
Anything it can't parse becomes empty, and empty fields land in a "Needs a human look" list in the summary. A bookkeeping tool that silently invents a number is worse than no tool.
3. No currency conversion. Totals stay per currency. Guessing an exchange rate is how books go wrong, and a freelancer billing in two currencies would rather see two honest numbers.
Originals are copied, not moved, unless you pass --move. Progress is written to ledger.json after every document, so a crash halfway through a folder loses nothing.
Honest status. I built this without running it. The build ran in a setup where executing code and downloading models was off the table, so Shoebox is untested against a real model. The unit tests cover the parsing, sorting and summary logic and don't need a model, but I haven't run them either. Expect bugs, especially around how a small model handles blurry photos. Fixing those is the first item on the roadmap, not a footnote.
Why Does Open Innovation Matter?
This project only works as a business because the model is open.
- Cost. A cloud vision API charges per page. With a local model, the marginal cost of the 5,000th receipt is electricity. That's what makes a flat-fee service for bookkeepers plausible at all.
-
Privacy. Receipts and invoices carry client names, day rates and bank details. "Your documents never leave this machine" is a sentence a freelancer can say to a client. With Ollama the request goes to
localhost. - No lock-in. Swapping Gemma for another model is one flag. Fine-tuning a model on one country's receipt formats (VAT layouts, GST invoices) is possible because the weights are mine to adapt, which a closed API wouldn't allow.
- Offline. It works on a train or in an air-gapped office.
My First User
I don't have one yet, and I'm not going to invent a quote. The honest next step is to hand Shoebox to a freelancer friend, watch them run it on a real quarter of receipts, and write down what they ask for next and whether they'd pay.
Prize Categories
Best Use of Gemma: Gemma 3 is the default model, called through Ollama for both text receipts and (with a vision-capable variant) receipt photos, with schema-constrained output so the results are machine-checkable.
Top comments (0)