Wallet
Personal finance system with an integrated AI layer.
TypeScript · Expo / React Native · Kotlin · SQLCipher
01Problem
A mobile app for personal finance. Money is recorded in a ledger on the device, and an AI layer sits beside it — never inside it.
I wanted something more serious than a basic expense tracker: to understand personal finance as a system — how transactions, balances and budgets should actually fit together — and then see where AI could help without being allowed to decide anything on its own.
02My role
Solo
03What I built
You
Record, confirm, decide
Every change is a user action
Finance system
Double-entry ledger · deterministic engines · encrypted on the device
Read-only: the AI never writes
AI layer
Explains, suggests, abstains when unsure
- A double-entry ledger: append-only, corrected only by reversals, with time-sortable IDs.
- Tested, deterministic engines for cash-flow projection and spending analysis.
- Offline-first: data lives on the device, in an encrypted SQLite database.
- An Android payment-capture module in Kotlin: incoming bank SMS are matched against templates and held in an encrypted staging queue.
In the lab
On-device categorisationexploring
Not built yet. Today’s categoriser is a rule cascade that abstains when unsure.
Forecasts as rangesexploring
A proposal only. The deterministic forecast stays the authority.
04Engineering decisions
Option A
A mutable balance column
Option BChosen
A double-entry ledger
- Trade-off
- A balance column is simpler to write. A ledger costs more code and storage, but every number can be rebuilt and checked.
- Decision
- Append-only double-entry ledger. Corrections are reversals, and the books are checked after every change.
- Why
- Every balance traces back to source rows, so it can’t silently drift — and a ledger is very hard to retrofit later.
Option A
AI computes the figures
Option BChosen
AI only explains them
- Trade-off
- Letting a model compute is faster to build. Keeping it out of the arithmetic means more layers, but the numbers stay exact.
- Decision
- The AI layer computes nothing. It can suggest, but it never writes to the ledger without a user action.
- Why
- Increasing model intelligence must never increase model authority.
Option A
Make its best guess
Option BChosen
Abstain
- Trade-off
- Guessing always gives an answer. Abstaining sometimes gives none.
- Decision
- Category suggestions abstain, forecasts refuse to invent an exchange rate, and safe-to-spend has explicit refusal states.
- Why
- In finance, a wrong number costs more than a missing one.
Option A
The whole SMS inbox
Option BChosen
Only new messages, as they arrive
- Trade-off
- Inbox access allows backfilling history. New-only access sees less, but asks for far less.
- Decision
- Receive new SMS only, never read the inbox, and process everything on the device.
- Why
- Least privilege — and it is the strongest argument in a Play Store review.
Option A
Real time and real randomness
Option BChosen
Injected time, seeded randomness
- Trade-off
- Real inputs are simpler to wire. Injected ones take discipline, but results reproduce exactly.
- Decision
- The forecasting engine guarantees no clock and no randomness.
- Why
- A test that can’t reproduce a number can’t protect it.
05What I learned
I built two complete engines before any screen could reach them. Breadth reads like progress; users only get value from what they can reach.
06Links
No public repository or demo.