~/finance/2026/journal.ledger
APR 17 2026 · DECK 01
*2026-04-17 opening entry

Plain-text
accounting

$∞
$∞
$0
-$∞
transaction balanced
A talk by Claude · 20 min · Q&A to follow
L.0001 — L.0042
[definition]

>So, what is it?

Plain-text accounting is bookkeeping done in text files, with command-line tools. Your ledger is source code — diffable, scriptable, and yours to keep.

// instead of
  • ×Spreadsheet cellsFragile formulas, hidden state, no history
  • ×SaaS dashboardsVendor lock-in, black-box math, subscriptions
  • ×Proprietary files.qbo, .mny — unreadable in ten years
// you get
  • +A single text fileGrep-able, diff-able, scriptable, portable
  • +Version controlEvery change tracked in git, forever
  • +Real double-entryEvery transaction balances or it doesn't compile
§ 02

Meet
beancount.

An open-source, double-entry accounting system in plain text — started in 2007 by Martin Blais. You write a .beancount file; the compiler validates every balance, every currency, every posting.
main.beancount
[a minimal ledger]

>Three lines of setup.
One transaction.

;; -*- mode: beancount -*-
;; A minimal personal ledger.

2026-01-01 open Assets:Checking       USD
2026-01-01 open Equity:Opening-Balances

2026-01-02 * "Deposit"
    Assets:Checking              100.00 USD
    Equity:Opening-Balances
L.0100 — L.0180
[the five roots]

>Everything is an account.

Account names are colon-separated hierarchies, each segment capitalized. The first segment must be one of five roots.

Beneath that, organize however you like — by bank, by country, by card, by purpose. The hierarchy is your chart of accounts.

Assets:US:Chase:Checking
Assets:Broker:Stock

Liabilities:US:Amex:Platinum
Liabilities:Mortgage

Income:US:Acme:Salary
Income:Interest

Expenses:Food:Groceries
Expenses:Travel:Hotel

Equity:Opening-Balances
L.0181 — L.0260
[the core rule]

>Every transaction balances.

2026-02-14 * "Whole Foods" "Valentine's groceries"
    Liabilities:US:Amex:Platinum     -82.40 USD
    Expenses:Food:Groceries           65.00 USD
    Expenses:Home:Flowers             17.40 USD
sum of postings
−82.40 + 65.00 + 17.40
=
must equal
0.00 USD ✓
L.0261 — L.0340
[more than transactions]

>Assertions keep you honest.

  • open Declare an account Every account must be opened before it can accept postings.
  • balance Assert a balance "Check that Checking has exactly $1,204.17 on this morning."
  • pad Auto-fill to meet the next assertion Reconcile a history you didn't enter by hand.
  • price Record a market quote Used for currency conversion and holdings valuation.
  • close Retire an account Bank changed? Close the account; postings after that date error.
2026-01-01 open    Assets:Checking  USD

2026-03-01 balance Assets:Checking
                     1204.17 USD

2026-03-01 pad     Assets:Checking
                     Equity:Opening-Balances

2026-04-15 price   EUR  1.08 USD

2026-06-30 close   Assets:OldBank
L.0341 — L.0410
[multi-currency, lots, cost basis]

>It's not just dollars.

Anything countable is a commodity: currencies, shares, crypto, vacation hours, airline miles. Lot prices {…} track what you paid; market prices @… track what it's worth today.

; Buying 10 shares of AAPL at $150 — cost basis recorded as a lot.
2026-01-15 * "Buy stock"
    Assets:Broker:Stock     10 AAPL {150.00 USD}
    Assets:Broker:Cash   -1500.00 USD

; Spending euros from a USD account — @ records the exchange rate.
2026-03-20 * "Coffee in Paris"
    Assets:USD             -4.50 USD @ 0.92 EUR
    Expenses:Food:Coffee   4.14 EUR
L.0411 — L.0480
[a lot = a remembered cost]

>Same ticker. Different lots.

When you buy an asset, beancount remembers each lot — its price and date. Sell later, and you must say which lot.

; Three separate purchases — three separate lots.
2024-03-10 * "Buy AAPL"
    Assets:Broker:Stock     10 AAPL {150.00 USD, 2024-03-10}
    Assets:Broker:Cash   -1500.00 USD

2025-01-08 * "Buy AAPL"
    Assets:Broker:Stock     5 AAPL {220.00 USD, 2025-01-08}
    Assets:Broker:Cash   -1100.00 USD

; Sell 5 shares — identify the lot, and record today's price.
2026-04-20 * "Sell AAPL"
    Assets:Broker:Stock    -5 AAPL {150.00 USD, 2024-03-10} @ 210.00 USD
    Assets:Broker:Cash    1050.00 USD
    Income:Gains                                      USD
                             ;  auto-balanced → −300.00 USD realized gain
L.0481 — L.0540
[two kinds of price]

>Braces vs. at-sign.

{150 USD}
cost — the lot

Stuck to the asset. This is what you paid. It creates a new, distinct inventory lot and stays with the shares until they leave.

Used for: cost basis, realized gains, tax lots.

@ 0.92 EUR
price — the conversion

A passing rate. Tells beancount how to convert one commodity to another in this transaction. Informational — it doesn't create a lot.

Used for: FX conversions, current market value.

Combined: 5 AAPL {150.00 USD} @ 210.00 USD  — selling a lot I bought at $150, at today's price of $210.
L.0541 — L.0620
[a price database in your ledger]

>Tracking what it's worth, today.

Every transaction contributes prices; price directives add quotes directly. Beancount builds a time-series — one point per commodity per day — and interpolates when you ask for a holding's value.

; Weekly quotes.
2026-01-06 price AAPL   188.50 USD
2026-01-13 price AAPL   192.10 USD
2026-01-20 price AAPL   201.75 USD
2026-01-27 price AAPL   208.40 USD
2026-02-03 price AAPL   212.00 USD

2026-01-06 price EUR    1.088 USD
2026-02-03 price EUR    1.094 USD

2026-01-06 price BTC   42100.00 USD
2026-02-03 price BTC   46580.00 USD
AAPL — USD/share
188.50 212.00 Jan 06 Feb 03

Fava and BQL use this series for net worth over time, unrealized gains, and performance vs. cost basis — all from one text file.

L.0411 — L.0490
[the tools around it]

>A file is just the start.

web UI
Fava
A slick browser interface on top of your ledger — charts, account browser, budget views, queries. The usual reason people pick beancount first.
query
BQL
SQL-ish query language built in. Ask SELECT account, SUM(position) and get answers in milliseconds.
import
Importers
Write Python that reads your bank's CSV, emits transactions. Review in a diff, commit. Scripts replace data entry.
storage
git
Your ledger lives in a repo. Every change has an author, a message, and a timestamp. Blame on line 4,213 of journal.beancount.
edit
Editor plugins
Emacs, Vim, VS Code, Sublime — syntax highlighting, autocomplete, and account completion. Write your books with the same tools you write code.
extend
Plugins
Tag rules, deduction splitters, cost reconcilers. If you can write a Python function, you can extend the compiler.
EOF
[takeaway]

>Your books,
  in your editor,
  forever.

~2007
first release
v3since 2024
current version
1file
all you really need
$ bean-check journal.beancount
✓ 0 errors.  Your ledger compiles. Ship it.