Sumner Evans's personal finances have travelled through Mint, Rocket Money, Markdown files, Origin, and eventually something that looks suspiciously like a step backwards: lines of text stored in Git.1
What looks like a backward step mostly changes which layer owns the complexity.
Plain text accounting keeps the journal itself readable as text, while programs such as Ledger, hledger and Beancount provide the checks, imports and reports that would otherwise live behind an application interface.2
Evans chose hledger. His more interesting motivation was not terminal nostalgia: after unreliable account connections and several limitations in consumer finance products, he wanted to understand his flows and learn double-entry bookkeeping.1
We tried breaking the model with hledger 1.52.1, a fake bank account and a few imaginary euros.
Four layers
An hledger transaction can be almost aggressively ordinary:
2026-08-08 * Hosting
expenses:hosting 24.00 EUR
assets:bank -24.00 EUR
Two postings say where value appeared and where it came from; their sum is zero, and hledger rejects an explicitly unbalanced transaction while reading the journal.3
That tiny scene already contains four separate systems.

The journal answers “what did we record?”; hledger answers “is it coherent under the rules we supplied?”; Git answers “what changed, and when?” Around those layers remain things that do not magically fit inside them: statements, invoices, receipts, bank exchange, tax obligations and team processes.
None of those responsibilities disappears; what changes is that they no longer sit invisibly behind one interface, and the user can see which mechanism is responsible for which guarantee.
One euro
Our first test begins with a balanced journal and 1,500 EUR in the bank account at month end. A balance assertion explicitly says the ledger should match the statement:
assets:bank 0.00 EUR = 1500.00 EUR
We change a hosting expense from 24 to 25 EUR on one posting only, leaving the bank side untouched.
hledger check stops immediately: the transaction now sums to +1 EUR.
Nothing dramatic needs to happen here: the point is precisely that a structural mistake becomes difficult to ignore before it can contaminate later reports.
A more plausible and troublesome error appears when we change 24 to 25 on both postings, because the transaction remains perfectly balanced even though the underlying amount is wrong.
Double entry has no way to know whether the hosting provider charged 24 or 25 EUR; it only knows that what we wrote agrees with itself. The month-end assertion, by contrast, compares the resulting ledger with outside information, so hledger calculates 1,499 EUR where we declared an expected 1,500 and rejects the journal.3

The test captures much of the subject in one line: an accounting rule checks what that rule is capable of knowing, not reality in its entirety.
The diff
The same balanced mistake also produces an almost comically readable diff:
- expenses:hosting 24.00 EUR - assets:bank -24.00 EUR + expenses:hosting 25.00 EUR + assets:bank -25.00 EUR
At that point Git starts doing work that is directly useful to the accounting exercise rather than merely looking like a developer accessory attached to personal finance.
Inside an opaque database, “the balance changed” may require a dedicated audit interface. In this journal the change is two lines; a commit can explain why they changed, reviewers can inspect the diff, and previous states can be compared directly.
Evans also stores his finance data in a Git repository, while the wider Plain Text Accounting ecosystem treats human-readable, version-controllable source files as a central property of the approach.12
A personal Git repository obviously does not become a regulated accounting audit system through this trick; what it gains is a technical history that is unusually easy to inspect, compare and explain.
Export, no prison
We next asked hledger to emit the journal as CSV:
hledger -f journal.journal print -O csv
The 1.52.1 build we tested directly produced rows containing dates, descriptions, accounts, amounts, commodities, debits and credits. The manual also documents CSV reading and rules files for translating bank exports into journal entries.3
Less photogenic than a dashboard, this matters because the source file is not the only way out of the system: humans can inspect the original while the program generates other representations for downstream tools. When a chart, notebook or spreadsheet becomes more convenient, the numbers need not be manually retyped, a ritual our species continues to perform despite having invented computers several generations ago.
Two humans
Git becomes less graceful as soon as two people write in the same place. In our test, two branches started from the same journal; Alice appended a travel expense, Bob appended a food expense at the same end of the file, and the merge produced a content conflict.
Both transactions were valid, but Git had no basis for ordering concurrent edits made to the same region of one file.
We repeated the exact experiment with a main journal containing:
include journals/*.journal
Alice wrote journals/alice.journal, Bob journals/bob.journal. Git merged the branches automatically and hledger check then validated the composed journal.

Calling that a solution to collaboration would overstate the result, since two people can still edit the same split file and conflict again; the experiment demonstrates a narrower architectural lever, namely that smaller shared edit surfaces reduce some Git collisions.
As a team grows, permissions, review conventions, concurrent reconciliation, locking and change control arrive as well. At some point a purpose-built business interface becomes considerably nicer than asking accounting staff to interpret <<<<<<< markers.
The secret returns
The most important failure in our lab has nothing to do with double entry: we added a fake sensitive identifier to the journal, committed it, then tried to remove it as though deletion from the current file were enough.
TEST-ACCOUNT-1234
After the second commit the identifier disappears from the current file, yet git show on the earlier commit still retrieves it without difficulty.
That is normal version-control behavior, yet it sharply reverses a common intuition: Git improves traceability precisely by making forgetting harder.
GitHub consequently has a dedicated procedure for removing sensitive information from repository history and recommends revoking or rotating exposed credentials before history rewriting.5
Accounting files rarely contain only harmless categories; names, account references, payment notes, income and suppliers may all be sensitive, which means privacy requires more thought than simply marking the repository private.
Not the invoices
A ledger excels at describing accounting events, whereas an invoice PDF belongs to a different documentary layer with different requirements.
A posting can certainly point to a receipt path in a comment, a neighbouring document tree can be organized by convention, and the PTA ecosystem lists many surrounding tools for invoicing, imports, reporting and interfaces.2
That is exactly the boundary, though: those capabilities sit around the journal.
The text ledger does not, by itself, guarantee that an invoice satisfies the rules in your jurisdiction, that evidence is retained for the required period, that a tax return is correct, or that imported bank data has been reconciled. Those obligations depend on location, activity and workflow.
For a business, “our entries live in Git” is therefore very different from “our accounting system is complete”.
Visible complexity
Evans's post also demonstrates that the simple file survives surprisingly rich situations: several payment methods in one transaction, securities and market prices, transfers, employee reimbursements, balance assertions and multiple journals.1
Keeping the representation readable while the model underneath becomes considerably more sophisticated is a genuine strength of the approach.
The learning curve simply moves toward accounting itself. Whether a reimbursement belongs as a negative expense, a receivable or something else depends on accounting judgement rather than syntax; cost basis, lots, currencies and transit accounts likewise require understanding the model that the text exposes.
hledger 1.52 continued developing features around cost annotations and their export, while the project was already publishing previews of its future 2.0 line.4
The file remains simple. The world it describes is under no such obligation.
Understand it
This makes plain text accounting more interesting as an instrument of understanding than as retro computing theatre.
Consumer finance software generally tries to hide mechanics. That is often comfortable: connect a bank, recognize merchants, display a chart, ask the user to fix exceptions.
A text journal moves in the opposite direction. It makes you name accounts, see both sides of movement and decide where ambiguity belongs, while hledger automates validation and reporting without hiding the source.13
Beancount follows a related philosophy with its own double-entry language, another indication that the idea extends beyond one particular executable.6
For somebody who wants to learn what their money is doing, that friction can be the main feature.
Where it fits
Our small lab cannot decide anything for a 200-person business, but it does sketch a practical boundary between a transparent ledger workflow and a full multi-user accounting product.
The model is particularly attractive when:
- one person or a few technically comfortable people keep the books;
- readable, owned data matters strongly;
- custom imports and scripts need to remain possible;
- Git history genuinely adds value;
- the surrounding document and compliance workflow can be chosen separately.
It becomes less obvious when the interface must completely hide Git, when dozens of people edit the same books, or when the required product needs business validation, documents, fine-grained permissions, banking automation and local compliance from day one.
Plain text has not failed at that boundary; the representation has simply stopped being enough to serve as the complete product.
The trouble
After our test, the strongest promise is not really “your accounting can fit in a .journal file”.
It is this: you can see where each guarantee starts and where it ends.
Our first one-euro mistake is caught by double entry, the second by the balance assertion; Git exposes the diff and also preserves the fake secret we thought we had deleted, while splitting files changes merge behaviour and CSV comes back out without negotiating with a proprietary API.
Fortunately, none of this requires plain text to be magical: its value lies in leaving the mechanisms exposed enough that we can understand them, test them and even watch them fail.