DEV Community

Aman Kumar Dewangan
Aman Kumar Dewangan

Posted on

Shoebox: a freelancer's receipt sorter that never leaves the laptop

Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle Submission 💸

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:

  1. Hashes each file, so re-running only reads new documents.
  2. Sends the text (or the photo) to a local open-weight model and asks for vendor, date, total, tax, currency, category and document type.
  3. Re-validates everything the model said, because models get dates and decimal commas wrong.
  4. Copies the file into sorted/2026-03/travel/2026-03-09_delta-air-lines_304.00.pdf.
  5. Writes ledger.csv and a summary.md with 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
Enter fullscreen mode Exit fullscreen mode

Code

GitHub logo amandewatnitrr / shoebox

Local-first receipt & invoice sorter for freelancers. Open-weight model (Gemma 3 via Ollama), zero cloud. Hacktoberfest AI Challenge W2.

Shoebox: receipts in, ledger out

license python deps model cloud hacktoberfest

🥿 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
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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)