Working with the HomeBudget Python wrapper for programmatic access to HomeBudget financial data
The HomeBudget Python wrapper is a library and CLI for programmatic access to HomeBudget personal finance data. It enables full CRUD operations for expenses, income, and transfers with automatic sync to mobile devices.
Official Documentation: https://yayfalafels.github.io/homebudget/
.dev\env (Python 3.12.10) for all HomeBudget CLI work and helper scripts. Activate with .dev\env\Scripts\Activate.ps1. The env\ directory is a separate legacy context and must not be used for HomeBudget helper-script work.HomeBudgetClient methods over direct client.repository access for normal automation.data-sources-inspect for cross-source inspection methodology.data-sources-inspect for cross-source inspection methodology and evidence capture.For detailed troubleshooting and edge cases, refer to:
For all HomeBudget CLI work and helper scripts in this repo, use .dev\env (Python 3.12.10). .env is reserved for environment variables. env\ is a separate legacy context and must not be used for helper-script work.
# Activate environment (Windows PowerShell)
.dev\env\Scripts\Activate.ps1
# Verify hb resolves to .dev\env
(Get-Command hb).Source # should show ...financial-statements\.dev\env\Scripts\hb.exe
# Install package
pip install homebudget
Test scripts should follow the existing HomeBudget wrapper test pattern used in this repo:
db_path parameterencoding="utf-8" when reading/writing filesDate handling:
import datetime as dt
# Use date objects, not strings
start = dt.date(2026, 1, 1)
end = dt.date.today()
expenses = client.list_expenses(start_date=start, end_date=end)
Expense handling:
import datetime as dt
from decimal import Decimal
from homebudget import ExpenseDTO
# Expenses are always booked in TWH - Personal (the cost center)
# A matching transfer from the real payment account is also required
expense_dto = ExpenseDTO(
date=dt.date(2026, 2, 16),
category="Food (Basic)",
subcategory="Groceries",
amount=Decimal("43.50"),
account="TWH - Personal", # always the cost center, never the payment account
notes="NTUC FairPrice"
)
Income handling:
import datetime as dt
from decimal import Decimal
from homebudget import IncomeDTO
income_dto = IncomeDTO(
date=dt.date(2026, 2, 28),
name="Interest Income",
amount=Decimal("0.93"),
account="TWH DBS Multi SGD",
notes="Monthly bank interest"
)
Batch operations:
from homebudget import BatchOperation, HomeBudgetClient
operations = [
BatchOperation(
resource="expense",
operation="add",
parameters={
"date": "2026-02-16",
"category": "Food (Basic)",
"subcategory": "Cheap restaurant",
"amount": "25.50",
"account": "TWH - Personal",
"notes": "Lunch",
},
)
]
with HomeBudgetClient() as client:
result = client.batch(operations, continue_on_error=False)
This section defines HB-specific booking rules used in this repo. These rules govern how transactions must be structured in HomeBudget to reflect actual financial activity correctly.
| id | HB type | example | role |
|---|---|---|---|
| 01 | Budget | TWH - Personal | personal expense cost center; closes to zero monthly |
| 02 | Cash | TWH DBS Multi SGD | real wallet or bank account |
| 03 | Credit | TWH UOB One SGD | credit card or line of credit; holds negative balances |
| 04 | External | IB POSITION USD | investment positions and non-personal accounts |
Key accounts:
TWH - Personal — primary personal expense cost center; month-end balance must be zeroTWH DBS Multi SGD — primary personal income account; all SGD non-capital-gains income books hereTWH CITI — USD income account; non-capital-gains USD income not in investment accounts books hereTWH IB USD — IBKR cash account; positive balance = classified as Cash, negative balance = classified as CreditIB POSITION USD — IBKR position account; books capital gains and M2M adjustmentsEvery personal expense requires two transactions in HomeBudget:
TWH - PersonalTWH - Personal with the applicable category and subcategoryThis applies regardless of payment method — cash, bank account, or credit card.
# Cash payment
hb transfer add --date 2026-02-16 --from-account "Cash TWH SGD" --to-account "TWH - Personal" --amount 25.50
hb expense add --date 2026-02-16 --category "Food (Basic)" --subcategory "Cheap restaurant" --amount 25.50 --account "TWH - Personal" --notes "Lunch"
# Credit card payment
hb transfer add --date 2026-02-20 --from-account "TWH UOB One SGD" --to-account "TWH - Personal" --amount 52.80
hb expense add --date 2026-02-20 --category "Food (Basic)" --subcategory "Groceries" --amount 52.80 --account "TWH - Personal" --notes "NTUC FairPrice"
All personal income is booked in the account where cash lands:
TWH DBS Multi SGDTWH CITIhb income add --date 2026-02-28 --name "Salary and Wages" --amount 7400.00 --account "TWH DBS Multi SGD" --notes "Flintex Feb salary"
hb income add --date 2026-02-28 --name "Interest Income" --amount 0.93 --account "TWH DBS Multi SGD" --notes "DBS monthly interest"
IBKR uses two linked accounts:
TWH IB USD — IBKR cash; books interest, dividends, realized P&L, and forex cash effectsIB POSITION USD — IBKR position; books capital gains and M2M adjustmentsTrades are transfers between cash and position — they are not income or expense:
# IBKR deposit: bank account to IBKR cash
hb transfer add --date 2026-03-01 --from-account "TWH CITI" --to-account "TWH IB USD" --amount 5000.00 --notes "IBKR deposit"
# Stock purchase: IBKR cash to position account
hb transfer add --date 2026-03-10 --from-account "TWH IB USD" --to-account "IB POSITION USD" --amount 10000.00 --notes "AAPL buy"
# Capital gain or M2M booked as income on the position account
hb income add --date 2026-03-31 --name "Capital Gain/Loss" --amount 1880.00 --account "IB POSITION USD" --notes "AAPL M2M March"
When a foreign-currency purchase is made on a credit card, three transactions are required:
TWH - Personal at spot exchange rate in SGDTWH - Personal at the actual posted SGD chargeTWH - Personal for the difference, category Professional Services:Currency Conversion# USD 50.00 at spot 1.35 = SGD 67.50
hb expense add --date 2026-03-08 --category "Travel" --subcategory "Accommodation" --amount 67.50 --account "TWH - Personal" --notes "Airbnb NYC"
# Actual posted charge: SGD 68.20
hb transfer add --date 2026-03-08 --from-account "TWH UOB One SGD" --to-account "TWH - Personal" --amount 68.20 --notes "Airbnb NYC USD FX"
# Forex fee reconciliation: 68.20 - 67.50 = 0.70
hb expense add --date 2026-03-08 --category "Professional Services" --subcategory "Currency Conversion" --amount 0.70 --account "TWH - Personal" --notes "Airbnb NYC FX fee"
Uniqueness is defined by: account + date + amount + description.
When two legitimate transactions share all four fields, append a sequential suffix to the description:
hb expense add --date 2026-02-16 --category "Transport" --subcategory "Taxi" --amount 12.00 --account "TWH - Personal" --notes "Grab taxi -01"
hb expense add --date 2026-02-16 --category "Transport" --subcategory "Taxi" --amount 12.00 --account "TWH - Personal" --notes "Grab taxi -02"
When reconciling a bank account, transactions fall into three groups relative to the reconciliation date:
| id | group | in statement | in HB | date | action |
|---|---|---|---|---|---|
| 01 | captured | yes | yes | before | reconcile HB amount to match statement |
| 02 | pending | no | yes | before | move transaction date to after reconciliation date |
| 03 | forecast | no | yes | after | leave as-is, out of scope for reconciliation |
For pending transactions moved past the reconciliation date, add the actual transaction date in the notes field, for example "13 Mar". After two reconciliation periods have passed, update the transaction to its actual date.
pip install homebudget
pip install homebudget-2.1.1-py3-none-any.whl
Use this skill as the source of truth for HomeBudget inspection procedures and implementation details.
docs/develop/data-sources/.The Business Logic section in this skill is a derived, HB-scoped summary. The authoritative source for accounting rules and account classification is:
docs/requirements/accounting-logic.md — booking patterns, double-entry rules, forex, M2M, reconciliationdocs/requirements/account-classification.md — account types, asset categories, balance rules, income restrictionsWhen the two conflict, the requirement docs take precedence. Update this skill to stay in sync when those docs change.
HomeBudget requires a configuration file to locate your database.
Default path:
%USERPROFILE%\OneDrive\Documents\HomeBudgetData\hb-config.json
Create hb-config.json with:
{
"db_path": "C:\\Users\\YOUR_USERNAME\\OneDrive\\Documents\\HomeBudgetData\\Data\\homebudget.db",
"sync_enabled": true,
"base_currency": "SGD",
"forex": {
"cache_ttl_hours": 1
}
}
Key fields:
db_path - Absolute path to your HomeBudget database (required)sync_enabled - Controls SyncUpdate creation for direct wrapper usage; default is truebase_currency - Base currency code like "SGD", "USD" (default: from database)forex.cache_ttl_hours - Forex rate cache validity (default: 1)Default database path per official documentation:
%USERPROFILE%\OneDrive\Documents\HomeBudgetData\Data\homebudget.db
db_path= for methods and --db for CLI.db_path or CLI --db when you need predictable behavior across environments.homebudget --db "C:/path/to/homebudget.db" expense list
When using this skill in this repository, do this first before any HomeBudget CLI inspection:
.dev\env so hb resolves to the correct workspace interpreter.hb * list before writing examples or making assumptions.# Always use .dev\env for HomeBudget CLI and all helper-script work
.dev\env\Scripts\Activate.ps1
hb account list
hb category list
hb category subcategories --category "Food (Basic)"
Two virtual environments exist in this repo:
| path | Python | purpose |
|---|---|---|
.dev\env | 3.12.10 | development, inspection, helper scripts |
env\ | 3.11.0 | main app context for commissioning and app operations |
use .dev\env for inspection, requirements, design and development tasks
Why it matters:
hb may point at the wrong Python installation and fail on missing dependencies.Use this workflow before adding or editing examples in this skill:
.dev/env/ so hb resolves to the helper-script interpreter.hb account list.hb category list.hb category subcategories --category "<category>".hb income list --limit 20 and treat the income classification field as name, not category.Reference commands:
.dev\env\Scripts\Activate.ps1
hb account list
hb category list
hb category subcategories --category "Food (Basic)"
hb income list --account "TWH DBS Multi SGD" --limit 20
Live examples observed in this repo:
Cash TWH SGD, TWH DBS Multi SGD, TWH CITI, TWH IB USD, CPF MAFood (Basic), Transport, Utilities, Professional Services, TravelFood (Basic): Groceries, Cheap restaurant, Food Court, Tingkat, meal prepSalary and Wages, Interest Income, Refund and Promotion, Dividend, Capital Gain/Loss, Other Incomeimport datetime as dt
from homebudget import HomeBudgetClient
# Loads config automatically from default location
with HomeBudgetClient() as client:
# Browse categories and accounts
categories = client.get_categories()
subcategories = client.get_subcategories("Food (Basic)")
accounts = client.get_accounts()
# Query personal expenses for a closing period
expenses = client.list_expenses(
start_date=dt.date(2026, 2, 1),
end_date=dt.date(2026, 2, 28)
)
# Query income booked in the primary personal income account
incomes = client.list_incomes(
start_date=dt.date(2026, 2, 1),
end_date=dt.date(2026, 2, 28)
)
# Query account balance for reconciliation
balance = client.get_account_balance("TWH DBS Multi SGD")
from homebudget import HomeBudgetClient
# Use explicit path, ignore config file
with HomeBudgetClient(db_path="C:/path/to/homebudget.db") as client:
expenses = client.list_expenses()
Browse Data:
client.get_categories() - List all expense categories ordered by sequence numberclient.get_subcategories(category_name) - List subcategories for a category nameclient.get_accounts(currency=None, account_type=None) - List accounts with optional filtersclient.get_account_balance(account_name, query_date=None) - Compute balance from reconcile dataQuery Transactions:
client.list_expenses(start_date=None, end_date=None) - Query expensesclient.list_incomes(start_date=None, end_date=None) - Query incomeclient.list_transfers(start_date=None, end_date=None) - Query transfersCreate/Update/Delete:
client.add_expense(expense_dto) - Add expenseclient.update_expense(key, **fields) - Update expenseclient.delete_expense(key) - Delete expenseBatch Operations:
client.batch(operations, continue_on_error=False) - Execute mixed add/update/delete operationsclient.add_expenses_batch(expenses) - Batch-add expensesclient.add_incomes_batch(incomes) - Batch-add income recordsclient.add_transfers_batch(transfers) - Batch-add transfersDTOs and Records:
ExpenseDTO, IncomeDTO, and TransferDTO for create operations.ExpenseRecord, IncomeRecord, TransferRecord, and BalanceRecord.See official Methods documentation for complete API reference.
Use the CLI for interactive inspection, ad hoc CRUD, and operations where automatic UI coordination matters.
In this repo, activate .dev/env/ first so hb uses the correct interpreter for helper-script usage.
hb category list
hb category subcategories --category "Food (Basic)"
hb account list
hb income list --account "TWH DBS Multi SGD" --limit 20
hb account balance --account "TWH DBS Multi SGD" --date 2026-02-01
hb expense list --start-date 2026-02-01 --end-date 2026-02-28 --limit 50
Personal expenses always require a paired transfer and expense. The transfer moves funds from the real payment account into the cost center; the expense is then booked in the cost center.
# Cash payment: transfer from cash account, then book expense in cost center
hb transfer add --date 2026-02-16 --from-account "Cash TWH SGD" --to-account "TWH - Personal" --amount 25.50
hb expense add --date 2026-02-16 --category "Food (Basic)" --subcategory "Cheap restaurant" --amount 25.50 --account "TWH - Personal" --notes "Lunch"
# Credit card payment: transfer from credit card, then book expense in cost center
hb transfer add --date 2026-02-20 --from-account "TWH UOB One SGD" --to-account "TWH - Personal" --amount 52.80
hb expense add --date 2026-02-20 --category "Food (Basic)" --subcategory "Groceries" --amount 52.80 --account "TWH - Personal" --notes "NTUC FairPrice"
# Personal income: book in TWH DBS Multi SGD
hb income add --date 2026-02-28 --name "Salary and Wages" --amount 7400.00 --account "TWH DBS Multi SGD" --notes "Flintex Feb salary"
hb income add --date 2026-02-28 --name "Interest Income" --amount 0.93 --account "TWH DBS Multi SGD" --notes "DBS monthly interest"
# Update and delete
hb income update 1041 --notes "DBS visa cashback"
hb transfer delete 21007 --yes
homebudget batch run --file operations.json
homebudget batch run --file operations.json --continue-on-error
homebudget batch run --file operations.json --error-report batch_errors.json
Batch JSON entries use resource, operation, and parameters fields matching single-record CLI commands.
SyncUpdate rows so changes propagate to devices in the sync group.HomeBudgetClient() manages the database connection, but UI control is only enabled when explicitly requested.DeviceInfo and SyncUpdate tables and confirm all apps point at the same database.For inspection work, the most relevant tables are Account, Category, SubCategory, Expense, Income, Transfer, AccountTrans, DeviceInfo, and SyncUpdate.
Problem: Script cannot locate hb-config.json
Solutions:
%USERPROFILE%\OneDrive\Documents\HomeBudgetData\hb-config.jsondb_path parameter explicitly: HomeBudgetClient(db_path="C:/path/to/homebudget.db")homebudget --db "C:/path/to/homebudget.db" expense listProblem: Config file exists but missing db_path field
Solutions:
"db_path" key"db_path": "C:\\Users\\..."Problem: db_path points to non-existent database
Solutions:
Problem: Changes made via Python don't sync to mobile device
Solutions:
sync_enabled: true in config fileDeviceInfo table exists in database (HomeBudget creates this)Problem: Unicode characters fail to print in cmd.exe (cp1252 encoding)
Solutions:
set PYTHONIOENCODING=utf-8hb Executable / Missing Dependency ErrorProblem: hb resolves to a different Python installation and fails with import errors such as missing requests
Solutions:
.dev/env before running hb commandsProblem: Updated category list doesn't reflect recent changes
Solutions:
client.get_categories() and client.get_subcategories(category_name)Problem: get_account_balance() or homebudget account balance fails for an account
Solutions:
Problem: Transfer amounts do not match the expected sending or receiving amount
Solutions:
currency and currency_amount describe the from-account or to-account sideexchange_rate when you need deterministic resultsdocs/requirements/homebudget.md for requirement boundary and scope.