Reinventing the Wheel #1: Personal Finance Software
A fun little side project (inspired by matrimony) that has become my main personal finance tool
Today, we’re breaking from this blog’s usual topic (statistics, economics, etc) to indulge in a far more important topic: a hobby project I built seven years ago. Aside from being a trip down memory lane, it’s possible this blog has a point. Two of them, in fact:
Doing things just because is a perfectly good reason to do things, and
Extensible double-entry accounting apps are a valid form of artistic expression.
It was the Fall of 2018, and I was to be wed in the Spring. I did not have much in the way of savings in those ancient days, and weddings cost money. I needed to budget for it.
Naturally, I needed to write an extensible double-entry accounting system to do this. It had to be programmable in Scheme, of course. I cannot overemphasize how much all of these requirements were unavoidable design constraints. It is impossible to budget for a wedding without Lisp.
And so, leas was born. Leas is an extensible accounting system that you can use interactively in the terminal. It’s extensible with Scheme, a full programming language, embedded in the app.
[I wrote it without thinking about LLMs—it was 2018—but now that we are in the new world, these tools do make it even more useful. “Codex, write me a script in Guile Scheme to update my home value based on whatever Zillow says it is and record the incremental value as home equity gains” just works like magic. Try getting a web app to do that.]
The initial idea was to make a tool that fit in between two kinds of accounting tools.
ledger. A tool that produces reports from specially-formatted text files. It’s very UNIX-y. I like ledger. It is highly extensible because you just need a script that modifies a text file. Easy. I actually first toyed with the idea of making leas an interactive tool to modify ledger files, but I didn’t like the result, and I didn’t find ledger very convenient to use in its natural state. I wanted something more interactive that was still extensible.
GUI-tools like GNUCash. I used GNUCash in grad school, but it was a separate GUI app that I’d always forget to open. I wanted something quick and easy from the terminal. GNUCash had some extensibility (in Scheme, too) but not super easy to use.
I also just thought the idea of an Emacs-like personal finance tool was neat-o.
So, I came up with this little structure:
Interactive C-based command line app.
The prompt was just a Scheme interpreter that called various Scheme/C functions exposed to Scheme.
My first critical design decision: I realized right away that I did not want to type parentheses all the time:
(command arg1 arg2)So, I made the interpreter insert the outer parenthesis automatically so that this Just Works (tm):
command arg1 arg2But, I wanted the program to be more… interactive. I didn’t want to have to type full commands. So, I settled on a UX like this:
> spend
5: Groceries
6: Rent
...
To Account: 5
1: Checking
...
From Account: 1
Amount: 109.23
Description: Walgreens
Year: 2026
Month: 6
Day: 22
>Of course, I could just code this interaction in C, but I wanted to make the interactive system sort of “universal” and something you could use in Scheme extensions to add new interactive commands. So I came up with this system for making any Scheme function interactive, and also added some special data types like this:
(define add-record
(lambda ()
(leas/call "leas/at"
(list
(cons "Account" "current_account")
(cons "Amount" "real")
(cons "Description" "string")
(cons "Day" "day")))))
So you can use leas/call to provide arguments to any non-interactive function using data types like “real” and “string” but also with some leas specific datatypes like “day” (for a date), “current_account” for the currently selected account, “account” for an account, “expense_account” (for an Expense account), “liability_account” (for a Liability account), and so on. So now we have some actual accounting data types.
This little structure let me write a small set of core routines and data types in C and then most of the interactive structure in Scheme (the UI, more or less) which was nice.
The basic structure was:
Book
Account
Transaction
Each Account has a Type. One of:
Asset
Liability
Income
Expense
Buying a McDouble, taking out loans, paying them back, and earning money are all just transfers between accounts. You transfer funds from the Income account to the Asset account on payday. You transfer from a Liability to an Expense account when you pay with a credit card or from a Liability to an Asset account when you take out a loan.
There is this concept of the “current” account, a pointer that attaches to a certain account and marks it “active”. That makes it possible to use commands which just take the current account as their argument which makes it quicker to navigate around. For example, lt lists the last few transactions in the current account.
I use leas every day, so the thing has ended up having lots of niceties. There are commands for doing things like paying off a loan (two transfers: one from an asset account to an expense account to pay interest and one to the liability account to pay off the principal).
I’ve written Scheme scripts to automatically update the values of any funds/stocks/etc. I hold by scraping the internet.
I should point out that this whole “budgeting” thing actually worked. Go figure. Keeping track of spending did let me kind of thread the needle on the wedding. It reduced stress, increased confidence, and gave my skin a healthy glow.
The whole thing is only about 2000 lines of code. Simple, but I’ve used it daily for a long time now. I don’t commit much to the repo anymore. The software is finished, more or less. I fixed an edge case in it a couple of weeks ago. I’m averaging a commit every two years since 2020. That’s the nice part about non-SaaS software. You can finish it. Nothing changes in the environment, and it’s not like any bug is a big deal. It’s running on your machine. You can’t steal someone else’s info if I make an error in the controller.
Of course, there was really no point to this project. The number of budgeting and personal finance tools out there is endless. They are better documented, tested, and so on. I could’ve found something that worked well enough to not be worth the hours I spent on it.
But I had oodles of fun, and there’s the pride of making something useful.
I don’t know shit about fixing cars, so I have to find something else to do.
There’s this terrible piece of advice folks get. If someone’s already solved the problem, don’t re-solve it. Think about another problem worth solving. It’s bad advice. You can’t solve any problem until you learn enough about it.
The best way to learn how the wheel works is to reinvent it.
Oh, and here’s the Github for this project: leas.
Thanks for reading!
Zach
Connect at: https://linkedin.com/in/zlflynn

