# BusyMobile: GST bookkeeping for small Indian shops, with an AI that never leaves the shop

> Source: <https://dev.to/abhinav_garg_05/busymobile-gst-bookkeeping-for-small-indian-shops-with-an-ai-that-never-leaves-the-shop-1bdb>
> Published: 2026-10-18 08:39:35+00:00

*This is a submission for the [Hacktoberfest Open-Source AI Challenge Week 2: Side Hustle](https://dev.to/challenges/hacktoberfest-week2-2026-10-12)*

My father runs a small cement trading business. Like millions of Indian shopkeepers, he keeps GST books, and every month he does the same tedious job: going through the bank statement line by line.

```
UPI/DR/412345678901/RAMESH KUMAR/YESB/ramesh@ybl/Payment        -5,000.00
NEFT CR-HDFC0000123-MODERN HARDWARE STORE-INV 12              +26,880.00
ACH D- BAJAJ FINANCE LTD-P400XXXX                               -8,450.00
```

For each line he works out who paid whom, whether it was a customer, a supplier, a loan EMI or the electricity bill, and types it in as a voucher. Then he does the same for every supplier's paper bill.

**BusyMobile** is an offline-first Android/iOS app for GST bookkeeping: invoices with CGST/SGST/IGST, party ledgers, stock, GSTR-1/3B summaries, and PDF invoices to share on WhatsApp. It has an AI assistant built on an **open-weight model that runs on a laptop in the shop**:

**Who would pay for it:** small traders, kirana and hardware shops, and the accountants who keep books for twenty of them. They already pay for desktop software like BUSY or Tally, and they pay with hours every month for data entry. They won't upload their bank statements to a foreign AI service, and they won't accept a per-call bill they can't predict. A flat monthly fee for an app that runs on hardware they already own is an easy sell. 

The whole video is real: a Pixel 6 emulator talking to `gemma3:4b` in Ollama on my laptop over the local network. Waits for the model are sped up and labelled with the real time.

| AI Quick Entry | Bank Import — Categorised | Local AI Configuration | 
|---|---|---|

`src/services/ai.js`: the local model client (Ollama `/api/chat` with a JSON schema, or any OpenAI-compatible server), plus the rule layer around it`src/utils/bankParser.js`: CSV parsing for HDFC, SBI, ICICI, Axis, Kotak and others, and the rules for deterministic lines`src/utils/ledger.js`: balances computed from entries, so they can't drift` tests/`: `npm test` runs 22 logic tests, and `npm run test:live` runs the real prompts against your own model server
**Stack:** React Native + Expo on the phone, and **[Ollama](https://ollama.com) serving Google's open-weight `gemma3:4b`** on any laptop on the shop Wi-Fi. One 3.3 GB model handles both text and bill photos. The app also speaks the OpenAI-compatible API, so llama.cpp's server or LM Studio work too.

```
ollama pull gemma3:4b
OLLAMA_HOST=0.0.0.0 ollama serve      # then: Settings → Local AI → http://<laptop-ip>:11434
```

**My first version didn't work.** I sent the 4B model 8 bank lines at a time and asked for an array back. It **misaligned the answers**: Suresh's name ended up on the Bajaj EMI line, and two lines came back empty. It also recorded "UPI se mile" as cash, invented a party called "Bank", and in one run read "1.5 lakh" as ₹1.5.

The fix was not a bigger model. It was a different split of work:

After that, all 10 lines of my test statement were correct, and it ran **2× faster** (53 s vs 116 s on CPU). Small prompts with one job each beat one big prompt for a 4B model.

**Measured on my laptop CPU (16 GB RAM, no GPU):** about 5–10 s per bank line, ~20 s for a typed note, and 35–95 s for a bill photo. That's slow next to a cloud API, but this job runs once a month, and it's far faster than typing.

**While building it I also fixed the bookkeeping underneath.** Balances are now computed from the vouchers instead of being mutated in place. That fixed a sign bug, and it means editing or deleting an entry can't leave a stale balance. Without this, the AI would only have posted wrong numbers faster.

**1. The data can't leave the shop.** A bank statement shows every customer, supplier, loan and payment of the business, and GSTINs and party ledgers are just as sensitive. Most traders I know would never upload that to a US AI API, and they shouldn't have to. With a local model, the privacy promise is simple and easy to check: unplug the router and it still works. The app shows where each request goes ("Processed on 192.168.1.x — never sent to the cloud").

**2. The unit economics work.** A shop's statement has hundreds of lines a month, plus bills and daily entries. With an open-weight model on a laptop the shop already owns, the marginal cost per line is **zero**. I can charge a flat, small monthly fee without a busy customer wiping out my margin. A closed API would turn every bank line into a cost I'd have to pass on.

**3. I could build for a niche general tools handle badly.** Indian bank narrations, Hinglish ("jama kiya", "nikale", "kal"), lakh and crore amounts, and GST rules are a narrow domain. Owning the whole stack let me wrap the model in rules exactly where it was weak and run it with a schema I control. When a better small model comes out, I can test it with `npm run test:live` in minutes.

**4. No lock-in.** Swapping `gemma3:4b` for Qwen, Llama or next year's small model is a settings change, not a migration. Nobody can change my pricing, deprecate my model or read my customers' books.

**Where closed would have won, honestly:** a frontier API would be more accurate on messy narrations out of the box, and much faster. For this customer, though, "private, free per use, works offline, good enough with guardrails" beats "a bit smarter, sends your books abroad, bills per call".

I built this with Claude Code as a pair programmer. The most useful part of the session was running the real prompts against the local model, seeing the batched version fail, and redesigning around one line per call plus rules.

`gemma3:4b` runs locally through Ollama and does all three AI jobs (bank narrations, Hinglish notes and bill-photo reading) on a laptop CPU, with structured JSON outputs.
