Part of gharasathi, a private household AI. Start here for all the series. This one follows on from gharasathi: Building a Household AI, which set out the idea on a $200 mini PC. This one is about the part I use every week: money.
Hishob (हिशोब) is Marathi for "accounts", as in keeping account of things. It's the money dashboard of gharasathi, and its job is simple to state: show me where the household's money goes, and point at the places where we're paying more than we need to.
What changed since the first series
The first series ran everything on a 6 GB mini PC with a 3B model, and part 2 ended with "a better LLM requires better hardware". That hardware arrived: a Mac Studio (M3 Ultra, 96 GB unified memory). It now hosts most of the household's private services:
- Immich: our photo library, off iCloud and Google Photos (a post of its own later)
- Nextcloud: documents, plus the bills and statements this series is about
- llama.cpp serving Qwen3.5-122B-A10B: the model behind everything "AI" here
- A k3d cluster running the gharasathi services
The mini PC still runs the media server and other services with little to do. The finance stack moved because the model had to be big enough to reason about money, and close enough to the data that nothing has to leave the house.
The architecture
As before, every service has a Marathi name:
| Service | Meaning | What it does |
|---|---|---|
| aapla-dhan (Go) | "our wealth" | Syncs bank accounts through Australia's Consumer Data Right into Neo4j. I start each sync by hand, about once a week. |
| aapla-patrakar (Go) | "our reporter" | Reads bills and statements from labelled Gmail folders and a Nextcloud drop folder, and files the PDFs. |
| aapla-olakh (Go) | "our recognition" | Hand-written PDF parsers that pull out fields and check each document's own arithmetic. |
| aapla-hushar (Python, FastAPI, LangGraph) | "our clever one" | Rule-based detectors, the overnight AI analyst, and anna, the chat assistant. |
| aapla-hishob (React) | "our accounts" | The dashboard. |
Only two things reach outside the house, and both only read: the bank feed (through an accredited CDR intermediary) and Gmail over IMAP. All inference runs on the Mac Studio.
All the accounts, not just one
Most budgeting apps see a single transaction account. Hishob sees the whole household balance sheet, pulled through Australia's Consumer Data Right (open banking): read-only, consented per account, and revocable from the bank's app.
| Account | Type | What it adds |
|---|---|---|
| Everyday account | transaction | Day-to-day spending, bills, salary |
| Offset account | transaction, offsets the loan | Savings that reduce mortgage interest every day |
| Home loan | mortgage | Balance, repayments, and the interest actually charged |
Having all three in one graph is what makes the dashboard more than a spending tracker:
- Spending is counted once. Moving money between our own accounts, or into the offset, isn't spending. Mortgage principal counts as saving (it builds equity), and mortgage interest counts as a real cost.
- Interest is connected to cash. With the offset balance and the interest charged side by side, the effect is visible: in the months the offset held the most cash, interest per day fell by about a fifth. A rule flags cash sitting in the everyday account that could be reducing interest instead.
- The mortgage can be modelled. Balance, offset, repayments and an estimated rate all come from the data, so "what if we kept $10k more in the offset?" is a calculation, not a guess.
- Refunds and reversed debits are matched to the original payment instead of looking like extra income and extra spending.
- No fake "complete" months. Each bank feed syncs separately. The dashboard only treats data as complete up to the oldest account's last transaction, so one lagging feed can't make a month look cheap.
How the data gets in: semi-automatic, on purpose
Hishob isn't fully automatic, and that's deliberate. Each kind of data comes in the way that keeps the most control in our hands.
| Data | How it arrives | Who does what |
|---|---|---|
| Bank transactions | Pulled once a week | I start the sync by hand. Nothing touches the bank feed unless I ask. |
| Bills and statements | Forwarded to a dedicated mailbox | Gmail filters label each one by type (gharasathi/utilities, gharasathi/childcare). The nightly job reads only those labels, read-only, and the parsers take it from there. |
| Anything else | Dropped into a Nextcloud folder | The same nightly job picks it up and files it. |
So the routine is: forward a bill when it arrives, and press sync once a week. Everything after that, from parsing and filing to matching, the rules and the analyst, runs overnight on its own.
One graph: the bank and the paperwork
Everything lands in a Neo4j knowledge graph, so a debit, the bill it paid and the line on that bill are connected, not just sitting in separate tables.
-
The bank side: each
Account(everyday, offset, home loan) is theSOURCE_OFitsTransactions, about 1,900 of them so far. -
The paperwork side: an email
HAS_ARTIFACTa PDF, the PDF isPARSED_ASaDocument, and the documentASSERTSFacts (usage, unit rates, the subsidy, the absence count). Each fact isEVIDENCED_BYthe PDF it came from. A bill also creates anObligation: an amount, a due date, and who it'sOWED_TO. - The join: code matches each obligation to the transaction that paid it, on the exact amount within a date window. For now that match is computed when the data is read; writing it back into the graph as an edge is next.
The graph is what lets anna answer "what did this debit pay for?" by walking from the transaction to the bill and quoting the line, instead of guessing from a merchant name. Postgres keeps the original records, and the graph is the connected view the assistant and the analyst query.
A small ontology, not a pile of nodes
Those labels and relationship names aren't ad hoc. They form a small ontology: a fixed vocabulary of the kinds of things in a household and the ways they can relate. Only the listed relationships are allowed, so nothing like a generic LINKED_TO edge. Three things follow from that:
- The model can query it reliably. With a short, known list of node types and relationships, the Cypher that anna writes stays predictable: there's one way to say "this document asserts this fact", not five.
-
Evidence is part of the structure. Every
Factpoints to the PDF it came from. A link the system guessed, such as a document mentioning an organisation, carries a confidence and a status, so it can be confirmed or rejected instead of being treated as true. - It isn't specific to money. Communication → Artifact → Document → Fact → Entity describes any household paperwork. The schema already defines entity types such as Person, Property, Policy, Vehicle and Event, so an insurance renewal or a medical letter fits the same shape without a redesign.
What the dashboard shows
Every dollar figure in these screenshots is hidden with the dashboard's own "Hide $" switch. Percentages and charts stay visible, so I can show the dashboard without showing our finances.
- The month so far against a typical month for the same number of days. Comparing the 14th of the month with a whole previous month made every month look cheap until the last week.
- Six months of spending by category, with income as a line and one-off payments marked rather than counted.
- What changed against the usual, and which merchants drove it.
- Bills & statements: every utility bill and childcare statement, matched to the bank debit that paid it (part 3).
- Things anna noticed: the part that matters most, covered next.
The star of the show: "Things anna noticed" and Explain
Charts tell you what happened. The bottom of the dashboard tells you what to do about it.
Every morning there is a short, ranked list of findings. Some come from deterministic rules (a price rise, a bill that wasn't paid, a subsidy gap) and some from the overnight AI analyst. Each one carries its evidence: the transactions, or the exact line from a bill. Each one has two buttons:
- Explain: anna, the assistant running on the local model, reads the finding, pulls the underlying data with her tools and explains it in plain words: what happened, the evidence, and what to do.
- Resolve: "not an issue". The finding disappears, and the overnight editor learns to rank similar ones lower.
Under every explanation there's a box for follow-up questions, so it reads like a conversation with someone who has all the statements open in front of them.
Three things it caught, with our own data:
"Did we pay that bill twice?" No. The same energy bill amount left our account twice, a week apart. On the bank feed alone, that looks exactly like a double charge. Hishob had the bill itself (read from email, part 3) and matched it to the bank. The first debit was returned by the bank, and the second was the real payment: one bill, paid once. The finding said so in one line.
Childcare subsidy we didn't know we were losing. Australia's Child Care Subsidy covers up to 42 absent days per child per year, and our statements showed we went past it. Explain walked through it: the statement's own count showed the limit was passed in February, and every absent day after that was charged the full fee. My follow-up, "how many absence days have we used this year, and what would one more cost?", got this year's count and the price of an extra day. Now a rule warns us before we reach the limit.
Advice that changed when I gave it context. A finding suggested negotiating the mortgage rate. My follow-up added what the data couldn't know: the loan is on a fixed rate, and our loan-to-value ratio means a new lender would charge Lenders Mortgage Insurance (LMI). The answer changed: refinancing would mean paying LMI again, and repricing a fixed loan means break costs. The real lever was keeping more cash in the offset account. Part 2 shows how this context now reaches the analyst every night.
None of this needed a cloud service. The question, the statements and the answer all stayed on a machine in the house.
How it runs: overnight, like a colleague who reads everything
- 01:30: new bills and statements are read and filed.
- Hourly: about twenty deterministic detectors run, but only when the data has changed. They cover recurring charges, price rises, duplicates, offset balance, unpaid or returned bills, and childcare subsidy gaps.
- 02:30: the AI analyst reads exact "fact packs" built by code and writes findings, which are then fact-checked (part 2).
- Morning: the dashboard and anna show the results.
The rule that shaped everything: code counts, the model explains
The first series learned this on a 3B model, and it still holds at 122B. The model never adds up money. Code computes every total, average and match. The model gets those exact figures and does the part code is bad at: noticing that two things are related, explaining why, and suggesting what to do. A fact-checker then rejects any finding that contains a dollar figure or percentage that doesn't trace back to the data.
Part 2 covers how that works with Qwen on the Mac Studio. Part 3 covers bills and statements, which turned out to hold the most valuable findings.
What's next in this series
- Part 2: Running Qwen3.5-122B on a Mac Studio as a household finance analyst, and keeping it honest
- Part 3: Reading bills and statements without AI, and what they revealed
Money is just where it starts. Once the data stays home, a capable model runs next to it, and the ontology has room for more than money, the possibilities are wide open. Any part of household life that leaves a record can get the same treatment: code does the counting, and the model explains.

Top comments (0)