Zack Design has published ledger — a terminal-first personal finance tool that ingests bank statements from multiple Australian banks, categorises transactions with regex-based rules, and renders an ATO-ready tax return view plus a net worth dashboard. Local-first, SQLite under the hood, no cloud dependency.
The itch
Every mid-year I rebuild the same Excel spreadsheet: paste in ING transactions, paste in PayPal, paste in the Bankwest credit card, then hand-categorise everything, then try to remember which expense was for which business, then double-count a $200 transaction that appeared on both the credit card and the bank account it was paid from. Then I hand it to my accountant and we do it all over again. Ledger is the version I should have built five years ago.
Sources supported today
| Source | Formats | Parser |
|---|---|---|
| ING Australia | PDF statements, CSV export | etl/parsers/ing_pdf.py, ing_csv.py |
| PayPal | CSV activity download | etl/parsers/paypal_csv.py |
| Bankwest | PDF eStatements, CSV | etl/parsers/bankwest_pdf.py, bankwest_csv.py |
| HSBC | PDF statements | etl/parsers/hsbc_pdf.py |
| Coles Mastercard | PDF statements | etl/parsers/coles_pdf.py |
| Amex | CSV download | etl/parsers/amex_csv.py |
Drop a statement into staging/<source>/, run ledger ingest, and the right parser picks it up. PDF parsing is per-bank because every Australian bank has a different statement layout and none of them offer a clean machine-readable export.
What it does
- Multi-source ingestion. The above parsers, with dedup rules to prevent double-counting when a transaction appears on both a bank account and a credit card.
- Auto-categorisation. Regex-based merchant rules assign categories automatically and learn from manual overrides.
- Business splits. A percentage of any expense can be allocated to a business — essential for anyone running a sole-trader side or a company with home-office overlap.
- ATO tax return view. Output structured to match the sections of an Australian individual tax return: salary, rental schedule, business schedule, deductions.
- Financial year view. Outgoing / incoming / rental / work-trip sub-tabs replacing the Excel sheet I had been rebuilding by hand every year.
- Net worth dashboard. Accounts, credit cards, property, vehicles — balances pulled from the same statements.
- Tags. Orthogonal to categories. A transaction can be in category “Travel” and tagged
flight,biz-hosting,rental-incomefor finer reporting without having to invent a deeper category tree.
Why local-first
Because my financial data is mine. No cloud dependency, no third-party aggregator pulling read-only access to my bank accounts, no “we are deprecating the Xero integration” email six months from now. SQLite sits in a folder, the dashboard runs on localhost, and if I want to back it all up I copy a single file.
Quick start
git clone https://github.com/isaacrowntree/ledger.git
cd ledger
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
cp config/accounts.yaml.example config/accounts.yaml
cp config/categories.yaml.example config/categories.yaml
cp config/tax.yaml.example config/tax.yaml
ledger init
mkdir -p staging/ing staging/paypal
# Drop PDFs/CSVs into those folders
ledger ingest
python -m api
# Open http://localhost:5050
Who it is for
Anyone in Australia with more than one bank account, a side business or two, and an accountant who currently gets a hand-assembled spreadsheet every July. Source on GitHub.