Personal Finance as Code: 2 Months of Plain-Text Budgeting with AI

#yos#ai#finance Читать на русском

I wanted to see where my money goes. Not in a “check the banking app” way — in a “full picture, trends over time, forecast the next 12 months” way.

Every budgeting app I tried either did too little (just categories) or too much (connect all your accounts, trust us with your data, pay monthly). I wanted something in between: powerful enough to forecast, simple enough to understand, and fully mine.

So I built it from plain text files. It lives inside YOS — my personal life OS — alongside everything else: journal, tasks, habits, projects. Turns out, a few scripts and a text-based ledger get you surprisingly far.

The stack

Three components, nothing fancy:

  • hledger — plain-text double-entry accounting. Think spreadsheets, but in a text file, with 30 years of tooling behind it. One command gives you balance sheets, income statements, monthly breakdowns.
  • A Python import script — takes a bank export file (XLSX or CSV), parses transactions, categorizes them by rules, and appends to the hledger journal.
  • Markdown forecasts — monthly files with tables: income, fixed expenses, variable expenses, projected balance. Updated each month as new data comes in.

No database. No cloud sync. Everything in git, versioned alongside the rest of my life data.

The import pipeline

Here’s where it gets interesting. My bank (BBVA, but any bank with CSV/XLSX export works) lets me download transaction history. The import script does three things:

1. Parse. Read the file, extract date, description, amount. Handle format quirks — date formats, currency symbols, encoding issues. Boring but necessary.

2. Categorize. This is the fun part. A JSON rules file maps description patterns to accounts:

[
  {"patterns": ["mercadona", "lidl", "carrefour"], "account": "expenses:groceries"},
  {"patterns": ["netflix", "spotify", "youtube"], "account": "expenses:subscriptions"},
  {"patterns": ["farmacia", "clinic", "dentist"], "account": "expenses:health"}
]

If nothing matches — the transaction lands in expenses:uncategorized. After each import, I review these, figure out what they are, and add new rules. The coverage grows organically. First import: maybe 60% recognized. Two months in: over 90%.

3. Write. Append hledger journal entries:

2026-02-21 Mercadona
    expenses:groceries    EUR 42.86
    assets:bank:checking

That’s it. Run a command, review the uncategorized ones with AI (“what’s this merchant?”), add rules, done. The whole process takes about 10 minutes per import now.

Building forecasts

Raw accounting tells you where money went. Forecasting tells you where it’s going. After the first full month of data, I built a simple model:

Split expenses into fixed and variable.

  • Fixed: rent, utilities, subscriptions, taxes, insurance — predictable, recurring.
  • Variable: groceries, dining, entertainment, shopping — fluctuates month to month.

Project forward. Take the monthly averages, add known periodic expenses (quarterly taxes hit hard — more on that below), and extend the table 12 months ahead.

Track the balance. Each row shows: income minus expenses = net, running balance. You immediately see which months are tight and which build cushion.

The first forecast was rough — based on a single month. Some categories looked alarming (cash withdrawals seemed huge) and others misleadingly low (shopping was zero in month one, definitely not the norm).

The accuracy test

This is the part I find most valuable. After month two, I could compare the forecast against reality.

The variable expenses forecast was almost exactly right — within 1% of actual. That was honestly surprising for a one-month baseline.

Fixed expenses came in slightly higher than predicted — an annual subscription I’d forgotten about, and utilities that vary seasonally. Off by about 7%.

Overall, the net prediction missed by less than 10%. For a model built on a single month of data, that’s workable.

But here’s the real insight: the forecast gets better automatically. Each month of new data tightens the averages. The breakdown by category shows you which estimates are stable (groceries barely moved between months) and which are volatile (health expenses swung by 50%). You know exactly where your model is weak.

What AI actually does here

AI isn’t running the finances — I am. But it accelerates every step:

  • Writing the import script. I described what I needed, provided a sample export file. Working parser in one session.
  • Categorizing unknowns. “What’s this merchant?” — AI often recognizes businesses from the description and suggests the right category.
  • Building forecasts. We go through the numbers together. AI pulls the data from hledger, computes averages, flags outliers, formats the table. I make decisions about what to include and what assumptions to use.
  • Spotting risks. “Your balance drops to X after quarterly taxes in April — that’s your tightest month.” Useful context that’s easy to miss when you’re staring at a spreadsheet.

The pattern is consistent: AI handles the mechanical work (parsing, computing, formatting), I handle the judgment calls (is this expense recurring? should I budget for it?). Neither of us could do it as well alone.

What works, what doesn’t

Works well:

  • The import pipeline is genuinely useful. Ten minutes per import, and I have clean, categorized data.
  • Plain text means I can query my finances with hledger’s powerful reporting: monthly breakdown, category trends, period comparisons — all one-liners in the terminal.
  • The forecast, even after two months, already gives me confidence about the year ahead. I can see the tight spots coming.
  • Everything is in git. I can see how my forecasts evolved, when I added which rules, how actuals compared to predictions.

Still rough:

  • Two months of data means some averages are unreliable. Categories with high variance (health, shopping) need more history.
  • Cash withdrawals are a black box. Money goes out, I don’t know where it goes. This is the biggest blind spot.
  • Quarterly tax payments create predictable stress — the model shows it clearly, but knowing it’s coming and being comfortable with a low balance are different things.
  • The import is semi-manual. I download the file, run the script, review. Fully automated bank sync would be nice, but I actually like the review step — it forces me to look at every transaction.

The plain-text philosophy

There’s a reason this lives in a text file next to my journal and habit tracker. Personal finance isn’t separate from the rest of life — it’s connected to goals, projects, decisions.

When I’m planning whether to invest in a course, I can look at the forecast. When I’m doing a weekly review, the financial summary is right there. When something changes — a new recurring expense, a raise, a big purchase — I update the forecast in the same commit as the journal entry about the decision.

No app switching. No data export. One repo, one history, one context.


Two months in. The system is simple, the data is growing, and each forecast gets a little more honest. That’s all I wanted.

Project
YOS — Your Operating System
View project