DEV Community

Cover image for A Local AI Reads My Kid’s School Papers So I Don’t Have To
Nazar Boyko
Nazar Boyko

Posted on AI-assisted

A Local AI Reads My Kid’s School Papers So I Don’t Have To

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

Every Friday my kindergartner's folder comes home full. Most of it is worksheets and coloring pages, and somewhere in between there is sometimes a slip or a flyer. I have to look through all of it to find the one paper that matters.

What I Built

Backpack is a small app that reads those papers for you. You photograph each one with your phone, drop the photos on a page in your browser, and Gemma 4 reads them on your own laptop. A few seconds per paper later you have the week: every date in order with one button that puts them in your calendar, every to-do with a checkbox, and a single line for the papers that need nothing from you.

The parent who used to sort the pile is the one who gets to be lazy now.

The week in Backpack: dates with a Download calendar button, then the open to-dos

Some things are missing on purpose: no account, no sync, no settings page, no model picker. You get one binary, one page and one folder on your disk.

Demo

The landing page, with screenshots and the install steps: https://nazboyko.github.io/backpack/

Papers are read one at a time. One that can't be read says so and offers to try again:

Cards for a paper being read, one waiting its turn, and one that could not be read with a Read again button

A date the model had to work out is underlined and marked "check". Click it and it turns into a date field:

The list of dates with the reading log's guessed Friday open in a date field

Download calendar (.ics) gives you one file. Apple Calendar took all 14 events from the ten test papers, with their times and the two-day book fair:

Apple Calendar after importing the file Backpack made from ten papers

Code

GitHub logo nazboyko / backpack

Photograph the pile, get the week. Reads school papers with Gemma 4 on your own laptop.

Backpack

Photograph the pile, get the week.

The week in Backpack: dates with a calendar download, to-dos with checkboxes

Every week a school backpack comes home with paper: permission slips, picture day flyers, "sign and return by Friday", early release, pizza night. Backpack reads photos of those papers with Gemma 4, an open-weight model that runs on your own laptop through Ollama, and gives you one page with the dates, the to-dos and the papers you can throw away. Nothing leaves your computer.

Install

On a Mac with Homebrew:

brew install go ollama && brew services start ollama
ollama pull gemma4:e4b
go install github.com/nazboyko/backpack/cmd/backpack@latest
~/go/bin/backpack
Enter fullscreen mode Exit fullscreen mode

The last command opens the page in your browser. Next time, run only that one The model download is about 7 GB and happens once.

From a clone: make run.

How to use it

  1. Take a photo of each paper with your phone and send them to the laptop.
  2. Drop the photos on the…

brew install go ollama && brew services start ollama
ollama pull gemma4:e4b
go install github.com/nazboyko/backpack/cmd/backpack@latest
~/go/bin/backpack
Enter fullscreen mode Exit fullscreen mode

The last command opens the page at http://127.0.0.1:7313. The tests come in four layers: unit tests, an end-to-end test that drives the real server against a fake Ollama, make live-check, which reads ten invented school papers with the real model and scores the result, and a guard test that fails if the code ever names a host other than this computer.

How I Built It

The model is gemma4:e4b, the small open-weight Gemma 4, served by Ollama on the same laptop. Backpack sends each photo to Ollama's chat API with format set to a JSON schema, so the model can only answer in one shape. This is its answer for the field trip slip, trimmed:

{
  "title": "Field Trip to Science Museum",
  "nothing_to_do": false,
  "events": [{"title": "Field Trip to Riverside Science Museum", "date": "2026-11-04",
              "start_time": "09:00", "end_time": "14:15", "date_confidence": "read"}],
  "actions": [{"text": "Sign and return the slip", "kind": "return",
               "due": "2026-10-30", "date_confidence": "read"},
              {"text": "Send $8 per child", "kind": "pay",
               "due": "2026-10-30", "date_confidence": "read"}]
}
Enter fullscreen mode Exit fullscreen mode

The prompt gives the model today's date and the school year and tells it to turn "Friday" and "next week" into real dates. It spells out the difference between an event (a trip, a day off, a fair) and an action (sign, return, pay, bring). It asks for "guessed" whenever the paper printed only a weekday or the photo was unclear.

Then the Go side checks everything, because a small model gets things wrong in small ways. Every date has to be a real day. "Friday" or "Nov. 4" gets resolved and marked as a guess. A date more than six months in the past moves to the nearest year, because in my first run the model filed a November pizza night under 2024. "00:00" means no time, "5-7 PM" in one field becomes a range, and two all-day "Book Fair" events on consecutive days become one.

With the prompt from my plan, before any tuning, the model found 11 of 13 dates and 6 of 10 to-dos on the ten test papers. It also added 13 lines that were not on the papers, four of them events on a class newsletter, all dated today. Two rounds of prompt changes plus the checks above brought it to 13 of 13 dates, 8 of 10 to-dos and 4 extra lines, and the newsletter now comes back as "nothing to do". It still misses "pack a sack lunch" on the field trip slip and "send a little money" on the bake sale flyer.

The larger gemma4:26b found all 10 to-dos on the same papers, at 3.6 seconds a paper instead of about 2, with an 18 GB download instead of 7 GB. e4b stays the default; 26b is one environment variable away.

Everything else is one Go binary with the page embedded: plain HTML, CSS and about 640 lines of JavaScript, no framework and no build step, so a parent installs one thing. It listens on 127.0.0.1 only, rejects requests for any other host name, and rejects changes sent by other websites open in the same browser. Every word the model writes reaches the page as text, never as HTML.

Where it is weak: handwriting and faint photocopies. My test papers are printed. One has a handwritten-style note ("we need 2 dozen cookies") and the model got it, but a teacher's real handwriting on a faded copy is harder. That is what the "check" marks are for.

Why Does Open Innovation Matter?

Think about what a school paper can carry: a child's name, sometimes in the child's own handwriting, the school, the teacher and the room number. A form asks for a home address and a parent's phone number. Now and then there is a note about an allergy. I don't want any of that on someone else's server, and with an open-weight model it never goes there. Backpack talks to 127.0.0.1 and nothing else, and a test in the repo fails the build if the code ever names another host.

Open weights also mean there is nothing to pay next month and nothing to sign up for. There's no API key to paste and no usage limit, and nobody can change the terms under me. It works on a plane. When a better open model comes out, I change one variable: BACKPACK_MODEL=gemma4:26b.

A large closed model behind an API would probably read a crumpled handwritten note better than a 7 GB model on a laptop does today. I chose the laptop anyway. For my kindergartner's paperwork I'll trade some accuracy for keeping it in the house, and I built the page so that I see every guess before I trust it.

The Lazy Payoff

On an Apple M5 Max with 64 GB, with the model not even loaded, I dropped all ten test papers at once. 24 seconds later every one was read: the first took 5 seconds while the model loaded, the rest about 2 each. Backpack found all 13 dates and 8 of the 10 to-dos.

Then I tried this week's real folder. I photographed 11 papers, dropped them all at once, and 20 seconds later every card was read. All 11 came back "Nothing to do", and all 11 were right: a week of worksheets and coloring pages, with no notes, no slips and no dates. The one thing I did have to do this week, return a library book, was not written on any paper, so Backpack could not know about it. It reads paper. It doesn't know what nobody wrote down. One cosmetic miss: a summary stopped mid-sentence ("A coloring and pasting activity for a"). Nothing was invented, and I fixed nothing by hand.

I don't sort the pile anymore. I drop it, look at the "check" marks, and press one button for the calendar.

Prize Categories

Best Use of Gemma. Gemma 4 reads every paper. Without it, Backpack is a drop zone and nothing else.

The repo is open under MIT, with the test papers, the scores and the prompt in it.

Top comments (2)

Collapse
 
neithergalax profile image
neitherGalax •

Thanks for sharing. This is a really interesting use of local AI. I like how you took an everyday problem and turned it into something practical while keeping personal information local. I'm curious, does Backpack also support screenshots or digital PDFs of school announcements?

Collapse
 
nazar-boyko profile image
Nazar Boyko •

Thanks! Good question and I hadn’t actually tried it until now, so I did. 😊

Screenshots work. I took one of a school email on my laptop and another on my phone, and both came back with the right date, time and the thing I had to do. It even ignored the other emails in the inbox next to it.

The only thing it struggles with is a single very tall screenshot of a long newsletter. The text gets shrunk too much and it misread one date. If you take two or three screenshots as you scroll instead of one long one, it reads them fine. That’s a small fix on my side, and it’s the first thing I’ll do after the challenge.

PDFs don’t work yet. I kept it to images so I could finish in a week, but a one-page PDF is an easy add and will come with the same update.