← All case studies
05 · PERSONAL AUTOMATION · SHIPPED 2024 · 6 min read

A ledger the household actually reads

Every consumer finance app answers the wrong question. They show you what you spent. They do not tell you what changed. The bot was built to close that gap for one household, and architected so it could close it for many.

4accounts unified
2currencies reconciled
~390transactions / month
1digest the household reads
01 · CONTEXT

CONTEXT

A household runs on a handful of accounts across two currencies, a shared card, a personal card, and a small pile of recurring charges nobody has audited in years. The bank apps render this as four disconnected timelines. Nothing aggregates. Nothing categorizes beyond a crude merchant tag. Nothing flags when a subscription renews at triple last year's rate.

The operator wanted one artifact per month. One page. Readable at the kitchen table. Accurate enough to act on.

02 · WHY

WHY THIS, WHY NOW

Categorization is the foundation of every useful finance question a household asks. What did we spend on food. Are the subscriptions still earning their keep. Did anything unusual happen this month. Without clean categories, every answer is a guess.

Consumer apps do not solve this. They cannot. Their categorizer has to work for everyone, so it works properly for no one. A household-specific ledger with a household-specific rule set is a different object entirely, and it is cheap to build once the primitives exist.

03 · HOW

HOW IT WORKS

Each night, a cron job pulls the day's transactions from every account into a single Postgres ledger. Duplicates are collapsed on a hash of amount, merchant, and date. Currencies are normalized at the transaction-date rate, not the reporting-date rate, so historical comparisons stay honest.

Categorization runs in two passes. A rules engine handles the ninety percent of merchants that are unambiguous — the supermarket, the utility, the mortgage line. The remainder, the messy long tail of one-off merchants and cryptic card descriptors, is routed to an LLM pass with a tight prompt and the household's own category taxonomy. Ambiguous results are quarantined, not guessed.

MONTHLY DIGEST · PREVIEW MONTH .............. OctoberTRANSACTIONS ....... 387 across 4 accountsTOP CATEGORY ....... Groceries · 24%ANOMALIES .......... 4 flagged · subscription creep · 2 services unused 60d+ · duplicate charge · merchant XYZ · €18.40
04 · SYSTEM

THE SYSTEM, IN THREE PARTS

The categorizer is the first part. It owns the taxonomy, the rules, and the LLM fallback. It knows nothing about accounts, anomalies, or how anything is rendered. Given a transaction, it returns a category and a confidence.

The anomaly engine is the second part. It watches the ledger for four specific shapes: subscription creep, duplicate charges, category overruns against a rolling baseline, and merchants in unusual geographies. Each anomaly is a structured record, not a free-text warning.

The digest renderer is the third part. Once a month it composes a single readable page — top categories, deltas against the trailing three months, flagged anomalies, and a short plain-language summary — and pushes it to the household over email and Telegram. The three parts talk through the ledger and nothing else. Any of them can be replaced without touching the others.

Categorizing your own spending properly is the highest-leverage financial tool a household owns. No consumer app will ever do it for you, because doing it properly requires knowing you. — on why this had to be built
05 · RESULTS

What it changed

The household reads the digest. That is the quiet result, and it is the only one that matters. Subscriptions that stopped earning their keep were cut the month they were flagged. Duplicate charges were recovered. A slow drift in one category — the kind no bank app surfaces because it happens below the alert threshold — was caught and corrected.

The architectural result is that none of this is bound to one household. The categorizer, the anomaly engine, and the renderer are independent services over a shared ledger schema. Onboarding a second household is a configuration exercise, not a rebuild. The bot was shipped for one kitchen table. It was designed for many.

06 · STACK
PythonPostgresGPT-4ocronTelegram digest

Python ingestion into a unified Postgres ledger, two-pass categorization with an LLM fallback, a dedicated anomaly engine, and a monthly digest rendered to email and Telegram on cron.

NEXT CASE STUDY

A productized outbound stack — 663 sends, 0 replies, one expensive truth

Read next →

If this maps to a system you need built or fixed — tell me about it.

WhatsApp → Telegram → Email →