<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Prosper Ossaiku </title>
    <description>The latest articles on DEV Community by Prosper Ossaiku  (@prosperiko).</description>
    <link>https://dev.to/prosperiko</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972962%2F836c48c3-d629-42d9-b063-a294ea8b16de.png</url>
      <title>DEV Community: Prosper Ossaiku </title>
      <link>https://dev.to/prosperiko</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prosperiko"/>
    <language>en</language>
    <item>
      <title>I Built a Receipt Bookkeeper That Runs AI Fully Offline. The Business Math Only Works Because the Model Is Open.</title>
      <dc:creator>Prosper Ossaiku </dc:creator>
      <pubDate>Fri, 16 Oct 2026 04:24:59 +0000</pubDate>
      <link>https://dev.to/prosperiko/i-built-a-receipt-bookkeeper-that-runs-ai-fully-offline-the-business-math-only-works-because-the-58c5</link>
      <guid>https://dev.to/prosperiko/i-built-a-receipt-bookkeeper-that-runs-ai-fully-offline-the-business-math-only-works-because-the-58c5</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week2-2026-10-12"&gt;Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;Every month I run the same tedious ritual: a wallet full of paper receipts and a phone full of payment screenshots (PalmPay transfers, data subscriptions, supermarket runs) that have to become accounting records for my freelance work. It eats hours.&lt;/p&gt;

&lt;p&gt;Cloud AI could do the extraction, but read the fine print: you pay per receipt forever, you need reliable internet, and you hand a stranger's API your financial data. Receipt OCR text contains real names and phone numbers. I watched mine get extracted on day one.&lt;/p&gt;

&lt;p&gt;So I built the tool I would actually pay for: &lt;strong&gt;KoboKeeper&lt;/strong&gt;. Snap a receipt, and an open-weight model running on your own machine turns it into structured books. You review it, confirm it, and export an accountant-ready CSV or PDF. The side hustle math: charge freelancers around ₦2,000/month, keep inference costs at zero. That math is impossible with closed APIs and trivial with open weights.&lt;/p&gt;

&lt;p&gt;First real extraction, day one: a PalmPay money transfer. Vendor, date, ₦500.00 total, currency, line item, all correct, in about 27 seconds on my CPU. Total API spend: ₦0, forever.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://youtu.be/w-egLeekuvo" rel="noopener noreferrer"&gt;https://youtu.be/w-egLeekuvo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo: &lt;strong&gt;&lt;a href="https://kobokeeper.onrender.com" rel="noopener noreferrer"&gt;https://kobokeeper.onrender.com&lt;/a&gt;&lt;/strong&gt; (the instance sleeps when idle, so the first load takes 30 to 60 seconds to wake; extraction on the shared CPU takes 1 to 3 minutes)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3b7jatruulhg65bbcyn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3b7jatruulhg65bbcyn1.png" alt=" " width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Prosperiko" rel="noopener noreferrer"&gt;
        Prosperiko
      &lt;/a&gt; / &lt;a href="https://github.com/Prosperiko/kobokeeper" rel="noopener noreferrer"&gt;
        kobokeeper
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;KoboKeeper&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;KoboKeeper is an offline-first receipt bookkeeper for freelancers and small businesses.
It extracts structured receipt data locally with OCR + Gemma running through Ollama.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Quickstart&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;python -m venv .venv
&lt;span class="pl-c1"&gt;source&lt;/span&gt; .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
ollama pull gemma3:4b
uvicorn app.main:app --reload&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Then open &lt;a href="http://127.0.0.1:8000/dashboard" rel="nofollow noopener noreferrer"&gt;http://127.0.0.1:8000/dashboard&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Prosperiko/kobokeeper" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;The interesting files: &lt;code&gt;app/services/extractor.py&lt;/code&gt; (the Gemma prompt and JSON handling), &lt;code&gt;app/services/ocr.py&lt;/code&gt; (rapidocr + PyMuPDF), &lt;code&gt;app/services/vendor_memory.py&lt;/code&gt; (the learning loop), &lt;code&gt;app/services/export.py&lt;/code&gt; (CSV/PDF), &lt;code&gt;AGENT_SESSION_TRANSCRIPT.md&lt;/code&gt; (the annotated Copilot build log, linked from My Agent Session below). 19 automated tests, mocked at the model boundary so CI runs green without Ollama.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;Stack: Python, FastAPI, SQLAlchemy with SQLite, Jinja and HTMX (no build step, no CDN, because the offline story has to be real), reportlab for PDFs, Ollama serving Gemma locally.&lt;/p&gt;

&lt;p&gt;Pipeline: receipt photo or PDF, then rapidocr (local OCR), then Gemma 3 via Ollama (strict JSON), then a human review form, then vendor memory, then SQLite, then CSV or PDF export. The extraction prompt is deliberately strict: temperature 0, JSON output format, one bounded repair attempt, and a rule that makes this a bookkeeping tool instead of a chatbot: "If a field is not present, use null. Never invent values." A guard rejects OCR text under 20 characters before any model call, and a wrapped validation layer turns bad model output into a manual-entry form instead of a crash.&lt;/p&gt;

&lt;p&gt;My favorite piece is vendor memory: confirm a receipt once and KoboKeeper fuzzy-matches that vendor next time and pre-selects the category. Every receipt makes the next one faster.&lt;/p&gt;

&lt;p&gt;About 70% of the code was written by the GitHub Copilot coding agent from a 6-phase spec, phase by phase, with my local verification between each phase (see My Agent Session). I wrote the remaining 30% (exports, seed script, Docker and Render deployment) by hand after the agent's quota died.&lt;/p&gt;

&lt;p&gt;For the hosted demo I use a model split worth stealing: Ollama and gemma3:1b (about 0.8GB) run inside the Render container, so the demo literally performs inference on Render, on a 2GB instance paid with the $50 Hacktoberfest promo credit. Locally you run gemma3:4b (3.3GB). Same codebase, a MODEL_NAME environment variable picks the brain. Four honest deploy failures on the way (Ollama moved their download URL, zstd missing in the slim image, a background process hung the build layer, opencv's system libs missing at runtime), each a one-line fix, all in the commit history.&lt;/p&gt;

&lt;p&gt;Measured results:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;First real receipt (PalmPay transfer)&lt;/td&gt;
&lt;td&gt;all fields correct&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image receipts&lt;/td&gt;
&lt;td&gt;~27s on CPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF receipts&lt;/td&gt;
&lt;td&gt;~66s (rasterization plus OCR)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Live demo, 1 shared CPU&lt;/td&gt;
&lt;td&gt;under 3 minutes including cold model load&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated tests&lt;/td&gt;
&lt;td&gt;19 passing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API cost per extraction&lt;/td&gt;
&lt;td&gt;₦0.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;The honest, architectural answer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It runs on a laptop with no internet.&lt;/strong&gt; OCR, Gemma via Ollama, and SQLite all run locally. Airplane mode is a feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It keeps data off servers nobody controls.&lt;/strong&gt; Receipts, including other people's names, phone numbers, and transaction IDs, never leave the machine. The hosted demo exists so you can click it; the product is the local one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It lets you swap and fine-tune.&lt;/strong&gt; Demo runs gemma3:1b, locally gemma3:4b. Tomorrow I can fine-tune on Nigerian receipts (PalmPay and OPay formats, naira amounts) and the model gets better at my market instead of averaging the world.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It costs nothing to run.&lt;/strong&gt; No API keys, no meter. The only line item is electricity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Open weights are not ideology here. They are the difference between a business and a wrapper. A closed API makes the ₦2,000/month price impossible; an open-weight model makes it profitable.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Agent Session
&lt;/h2&gt;

&lt;p&gt;Three Copilot coding agent sessions, three human checkpoints, 10 agent commits. The condensed log: Session 1 scaffolded the project from spec and fixed its own template bug unprompted. Session 2 built the extraction core (strict Gemma prompt, OCR guard, bounded JSON repair) with 4 mocked tests passing. Session 3 applied my code review (a ValidationError bug and category normalization), then built the entire vendor memory and review-form workflow plus unrequested security hardening, and died on quota mid-hardening, right after committing the last important fix. My review checkpoints had already caught a hallucinated dependency pin (&lt;code&gt;rapidocr-onnxruntime==1.3.24&lt;/code&gt;, a version that does not exist) before it reached production.&lt;/p&gt;

&lt;p&gt;I believe agent-built software should ship with its build log, so the full annotated session transcript is in the repo: &lt;a href="https://github.com/Prosperiko/kobokeeper/blob/main/AGENT_SESSION_TRANSCRIPT.md" rel="noopener noreferrer"&gt;https://github.com/Prosperiko/kobokeeper/blob/main/AGENT_SESSION_TRANSCRIPT.md&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My First User
&lt;/h2&gt;

&lt;p&gt;Me, and that is not a dodge. The receipts in the dashboard are my actual freelance transactions, processed through the real pipeline, and the month-end CSV exported cleanly into my accounting spreadsheet. A freelancer friend tests it on their books this weekend, and I will update this section with their verdict, especially the answer to "would you pay ₦2,000 a month for this?" If they say no, that is the most valuable data this project will have produced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Overall&lt;/li&gt;
&lt;li&gt;Best Use of Gemma (Gemma 3 via Ollama runs the entire extraction, locally)&lt;/li&gt;
&lt;li&gt;Best Use of Render (Ollama and the model run inside the Render container; the demo performs inference on Render, paid with Hacktoberfest promo credits)&lt;/li&gt;
&lt;li&gt;Best Use of GitHub Copilot (built with the Copilot coding agent, supervised; see My Agent Session)&lt;/li&gt;
&lt;li&gt;Best Use of Entire (full annotated agent session shared in the write-up and repo)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>hf26challenge</category>
      <category>devchallenge</category>
      <category>gemma</category>
      <category>hacktoberfest</category>
    </item>
  </channel>
</rss>
