← all projects

Spendly — finance tracker

2026 · python (stdlib only), sqlite, regex · live

A finance tracker that never leaves my Mac. It reads the bank and UPI debit SMS my iPhone forwards to my Mac, parses them locally with regex, and shows where the money went on a localhost dashboard. The only thing that ever crosses the wire is a deduplicated list of merchant names.

Spendly dashboard — spend by category bars, payment-method donut, and spend-over-time chart, with amounts blurred
The unlock

The problem with every finance app in India is the input: they want SMS permissions on your phone and your data on their servers. The unlock here was realizing iOS already solves the extraction: text message forwarding mirrors bank SMS into the Mac's Messages app, and Messages stores everything in a plain sqlite file (chat.db). Grant Terminal full disk access, open the database read-only, and every debit alert is just a SQL query away. No app on the phone, no cloud, no permissions beyond my own machine.

Privacy by design

Raw SMS never goes to an LLM. Amount, merchant, and date are extracted locally with regex. OTPs are dropped at the filter before storage: the database never holds one. Credits are dropped too: salary and refunds are never recorded, expenses only.

The single network call in the whole system is categorization: a deduped list of merchant name strings goes to an LLM that's constrained to a fixed category enum. Merchant names are treated as untrusted input: the model can label them, it can't act. A categorize-once cache means the steady state is zero network calls. And with the provider set to none, it falls back to keyword categorization and runs fully offline.

The pipeline

Six small stages, pure Python standard library, no pip install: ingest reads chat.db, filter applies the debit allowlist and drops OTPs and credits, extract turns text into structured transactions with regex, store writes deduped rows to sqlite, categorize is the one redaction boundary, and a stdlib http server serves the dashboard on 127.0.0.1.

The dashboard

Spend by category, by payment method (UPI / card / cash), and over time, plus top merchants and recent transactions. There's a manual cash-entry form for the spends that never hit SMS, and the whole thing is an installable PWA. And it's on my phone now: Tailscale puts the Mac and the iPhone on a private encrypted mesh (MagicDNS + HTTPS certs, `tailscale serve` on the dashboard port), so the phone installs it from a private URL as an app. Still no cloud: the Mac is the server.

Spendly on the phone — total spent, transaction count, and spend by category (demo data)
Spendly on the phone — category bars and the payment-method donut (demo data)
next project
Liquid Glass