If you run a budget in a spreadsheet, you already know the worst part. It is not setting up the formulas, or even the monthly review. It is sitting there tagging each transaction with a category so your actuals line up with your budget.
I do this for my household, and for a long time it was the single most annoying chore in our finances. So I built a system that does almost all of it for me. Here is exactly how it works, including the parts that are not magic.
The setup, and the real problem
My wife and I run all of our spending through one credit card, because it earns the best points. The catch: it is her personal card and I am an authorized user, so I cannot log in to see the transactions myself. For months, “doing the budget” meant asking her to export a CSV so I could import it. Not a great system.
I now sync those transactions directly with SheetLink, which connects the card through Plaid and drops the transactions into our Google Sheet without needing her bank login. That solved the access problem. But it surfaced the real one.
SheetLink gives me everything the bank exposes, including Plaid’s category for each transaction. The trouble is that Plaid’s categories are not my budget categories. Plaid says GENERAL_MERCHANDISE. My budget says Groceries, or Kids, or Misc, depending on what we actually bought. Bridging that gap, transaction by transaction, was the chore.
The insight: most of it is not a judgment call
When I looked at the transactions we had already categorized, a pattern jumped out. I had tagged about 890 transactions by hand over the past year. Across them were roughly 400 unique merchants. And here is the thing: about 95 percent of those merchants map to exactly one budget category, every single time.
- Spectrum is always Spectrum.
- Netflix is always Netflix.
- Our grocery store is always Groceries.
- The mortgage payment is always Mortgage.
These are not judgment calls. They are the same decision, repeated forever. A lookup table handles them perfectly, with no AI required.
Only about 5 percent of merchants are genuinely ambiguous, and they are ambiguous for real reasons that a human would also have to think about. Amazon could be Kids, Household, Entertainment, or Misc, depending on what was in the box. 7-Eleven could be Gas or a snack run. Kohl’s and Michaels could be Kids or Entertainment. That 5 percent is the only place judgment actually adds value.
The system: lookup first, AI only for the gaps
The system has three layers, and they run in order.
1. Lookup table (about 95 percent). Learn a merchant-to-category map from the transactions I have already tagged. Every repeat merchant gets categorized instantly, with zero effort.
2. AI judgment (the new merchants).When a merchant shows up that the lookup table has never seen, that is where an AI like Claude earns its place. Give it the merchant name, the amount, the bank’s category, and my list of budget categories, and it reasons it out. A run of charges at a stadium plus concessions is clearly an Entertainment outing. A resort plus a museum plus a ballgame is the family trip we took. Crucially, every decision the AI makes becomes a new lookup rule, so it never has to decide that one again.
3. A quick human glance (the truly ambiguous). The Amazon-type charges get a best guess and a flag. I glance at those, and only those.
When I ran this on a recent batch of my real transactions, the lookup table handled the bulk instantly, the AI categorized the new merchants and turned each into a permanent rule, a handful got flagged for a two-second confirm, and transfers and card payments were correctly left alone because they are not budget expenses. The transactions that genuinely needed me to think? Two. Down from a screen full.
Why this beats “let AI do everything”
It would be easy to point an AI at every transaction and let it categorize the whole list. People do this. I think it is the wrong design, for two reasons.
First, it is wasteful. You do not need a language model to know that Netflix is Netflix. A lookup table is faster, free, and never wrong on the repeats.
Second, and more importantly, the system gets lazier over time, not more dependent on AI.Every new merchant the AI categorizes becomes a rule. Next month, those merchants are pure lookup. The slice that needs AI shrinks every cycle. That is the opposite of most “AI does your budget” tools, which re-guess everything every time.
The right mental model is: a lookup table for the 95 percent that repeat, AI for the few that need a brain, and your own eyes on the genuinely ambiguous handful.
The real unlock: structured output Claude can ingest
Here is the part that makes this more than a spreadsheet trick. SheetLink does not only write to a Google Sheet. On the MAX plan, the CLI can output your transactions as structured data in formats built for machines, not just spreadsheets. That is what turns your bank history into something an AI can reason over directly.
Install the CLI and authenticate once. sheetlink auth prompts for your MAX API key (it starts with sl_) and stores it locally, so you never pass it again:
npm install -g sheetlink
sheetlink authJSON: pipe your transactions straight to a script or Claude
JSON is the default. It streams to stdout, so you can pipe it anywhere. This is the format I hand to Claude for categorization.
# all transactions as JSON
sheetlink sync --output json
# count them with jq
sheetlink sync --output json | jq '.items[].transactions | length'
# pipe straight into your categorizer (or Claude via a script)
sheetlink sync --output json | python3 categorize.pyThe shape is predictable: a top-level items array (one per connected bank), each with a transactions array. Clean, structured, easy for any AI or script to walk.
Here is the part that makes it click. I run this inside Claude Code, so the CLI and Claude share the same terminal. I never export a file, upload anything, or paste a wall of JSON into a chat window. I just tell Claude to run sheetlink sync and it reads the output directly, then builds and runs the categorization against it. The data goes from my bank, through SheetLink, into a model that can act on it, without ever leaving my machine.
SQLite: a local database Claude can run SQL against
Output to a SQLite file and you have a real, queryable database of your finances on your own machine. Point Claude at it and ask questions in plain English; it writes the SQL.
# upsert all transactions into a local SQLite db
sheetlink sync --output sqlite:///~/finances.db
# then, for example:
# "how much did we spend on groceries each month this year?"
# Claude writes and runs the query against finances.dbCSV: portable and AI-readable
Want a flat file to drop into a sheet, a notebook, or an AI tool? CSV is one flag.
# snapshot CSV (overwrites each run)
sheetlink sync --output csv --file ~/finances.csvPostgres: for when this grows up
If you are building something real on top of your transactions, sync straight into Postgres. Same command, a connection string instead of a file.
sheetlink sync --output postgres://localhost/financesThis is the difference between a sync button and a programmable data feed. The spreadsheet is one destination. JSON, SQLite, CSV, and Postgres are the destinations that let Claude, a script, or a dashboard ingest your money and act on it. You own the data, and you choose the shape.
Why this beats a budgeting app
A budgeting app would have categorized my transactions too, using its own categories, showing me its own views. And that would have been the end of it. I could not have asked it my own questions, or built the lookup system, or pulled the data into a tool of my own.
The difference is ownership and format. When you control your transactions in a form an AI can read, the budgeting is just one thing you do. The categorization, the analysis, the tools you build next: all of it is available, because nobody put a ceiling on it. If you want the longer version of how I got here, I wrote up the whole story.
This is the manual, terminal-driven version. Next, I bring the same Claude categorization into the spreadsheet itself, as a one-click menu button you can run from Google Sheets (no terminal, works from your phone). After that, I have Claude build a personal finance web app that runs entirely on my own machine, against a local copy of my own transactions, so the data is fully private and fully mine. Same data, same ownership, more automation each step.
How to do this yourself
You do not need anything fancy.
- Get your transactions out of your accounts. I use SheetLink so I can sync the card directly, including one I can only access as an authorized user. If you already export CSVs, that works too.
- Learn your rules from your own history. If you have already categorized transactions, that is your training data. Build the merchant-to-category lookup from it.
- Apply the lookup, then handle the gaps. Repeats get tagged automatically. New merchants get an AI suggestion or a quick decision from you, and become rules.
- Glance at the flagged ambiguous ones. That is the only real work left.