After years of spending entire weekends reconciling my finances, I’ve finally gotten my monthly close down to about an hour. Here’s the system I’ve built that might help others escape the reconciliation time sink.
The Problem: Death by a Thousand Transactions
Before I optimized my workflow, month-end looked like this:
- Download statements from 8 different accounts
- Manually compare transactions to my ledger
- Hunt down missing receipts
- Fix categorization errors
- Run reports and hope the numbers made sense
This easily consumed 4-6 hours, usually spread across a weekend because it was so tedious.
The One-Hour Monthly Close System
Now my process looks like this:
Week 1-3: Continuous Entry (15 min/week)
- Import transactions daily or every few days
- Categorize as I go using smart defaults
- Attach receipts immediately via document linking
Month-End Day: The One-Hour Sprint
Minutes 0-15: Import & Validate
; Run all importers
; bean-extract config.py ~/Downloads/*.csv >> journal/2025/01-january.beancount
; Then validate
; bean-check main.beancount
Minutes 15-35: Balance Assertions
; For every account with a statement, add an assertion
; Use the FIRST day of the NEXT month (balances are checked at start of day)
2025-02-01 balance Assets:Bank:Checking 4,523.67 USD
2025-02-01 balance Assets:Bank:Savings 12,450.00 USD
2025-02-01 balance Assets:Bank:HYSA 25,000.00 USD
2025-02-01 balance Liabilities:CreditCard:Chase -1,234.56 USD
2025-02-01 balance Liabilities:CreditCard:Amex -567.89 USD
2025-02-01 balance Assets:Investment:Brokerage 89,234.12 USD
If any assertion fails, Beancount tells you exactly which account and date to investigate.
Minutes 35-50: Review & Adjust
- Fix any balance assertion errors
- Record month-end adjustments (depreciation, accruals if relevant)
- Review uncategorized transactions
Minutes 50-60: Reports & Archive
- Generate income/expense summary
- Export to Fava for visual review
- Archive statement PDFs with consistent naming
The Automation Stack
1. Smart Importers with Learned Defaults
My importers remember past categorizations:
# In my importer config
LEARNED_ACCOUNTS = {
"AMAZON": "Expenses:Shopping:Amazon",
"WHOLE FOODS": "Expenses:Food:Groceries",
"SHELL OIL": "Expenses:Auto:Gas",
"SPOTIFY": "Expenses:Subscriptions:Music",
# ... hundreds more learned from history
}
New transactions from known payees auto-categorize. I only manually review truly new merchants.
2. Document Auto-Linking
; Set documents directory
option "documents" "/home/fred/finances/documents"
; File naming convention: YYYY-MM-DD.payee.description.pdf
; Example: 2025-01-15.amazon.keyboard.pdf
; Beancount/Fava automatically links documents to matching transactions
2025-01-15 * "Amazon" "Wireless keyboard"
Expenses:Office:Equipment 45.99 USD
Liabilities:CreditCard:Chase -45.99 USD
3. The Reconciliation Script
I run this before adding balance assertions:
#!/bin/bash
# reconcile.sh - Quick account status check
echo "=== Account Balances (Beancount) ==="
bean-query main.beancount "
SELECT account, SUM(position) as balance
WHERE account ~ 'Assets:Bank' OR account ~ 'Liabilities:CreditCard'
GROUP BY account
ORDER BY account
"
echo ""
echo "=== Check these against your statements ==="
4. Monthly Close Checklist (Custom Directive)
2025-01-31 custom "monthly-close-checklist" "January 2025"
; IMPORT
checking-imported: TRUE
savings-imported: TRUE
credit-cards-imported: TRUE
investment-imported: TRUE
; RECONCILE
checking-balanced: TRUE
savings-balanced: TRUE
chase-balanced: TRUE
amex-balanced: TRUE
brokerage-balanced: TRUE
; REVIEW
uncategorized-cleared: TRUE
large-transactions-reviewed: TRUE
; ADJUST
depreciation-recorded: FALSE ; N/A for personal
accruals-recorded: FALSE ; N/A for personal
; ARCHIVE
statements-filed: TRUE
receipts-linked: TRUE
; METRICS
time-spent-minutes: 52
transactions-imported: 127
manual-categorizations: 8
balance-errors-fixed: 1
Key Principles
1. Fix Transactions, Not Balances
When your balance assertion fails, NEVER use pad to force a match. Find the actual error:
- Missing transaction?
- Duplicate import?
- Wrong amount?
- Wrong account?
The error is almost always in your transactions, not your assertion.
2. Continuous > Batch
The biggest time saver: don’t wait until month-end. Import weekly (or daily). Categorize immediately. The monthly close becomes verification, not data entry.
3. Consistent Naming = Automatic Linking
Documents named YYYY-MM-DD.payee.description.pdf auto-link in Fava. This alone saves me 15+ minutes of manual receipt hunting.
4. Trust But Verify
Automation handles 90% of transactions. But always eyeball:
- Large transactions (> $500)
- New payees
- Anything flagged as unusual
My Current Metrics
| Metric | Before | After |
|---|---|---|
| Monthly close time | 4-6 hours | 50-65 minutes |
| Transactions manually categorized | 80%+ | ~5% |
| Balance errors at month-end | 3-5 | 0-1 |
| Receipts successfully linked | ~30% | ~95% |
Questions for Discussion
-
What’s your monthly close time? Am I the only one who was spending entire weekends on this?
-
Import frequency? Daily feels like overkill but weekly sometimes lets errors pile up. What works for you?
-
Anyone using AI for categorization? I’ve seen ChatGPT-based workflows but haven’t tried them yet.
Would love to hear other people’s systems and what automation tricks have saved you the most time.