Update installation instructions
Add Python packaging tools
Add license metadata to `pyproject.toml`
A command-line envelope budgeter.
Executables:
Libraries:
pip install beancount-budget
budget
needs to know some things:
Running budget configure
will write a configuration file to the current directory,
or the directory you specify in budget -c /path/to/dir configure
.
If you
you are encouraged to try this software and email your experiences to the author.
First, I need some example Beancount data and a configuration for the budget:
$ bean-example --seed 0 --date-birth 2022-01-01 --date-end 2024-01-01 > main.beancount
$ budget configure
Example configuration written to `.bcbudget.toml`.
Use your preferred editor to finish configuration.
$ vi .bcbudget.toml
This is what the config file looks like after editing:
currencies = ["USD", "VACHR"]
[regexes]
cash = "^Assets:US:(BofA:Checking|Hoogle:Vacation)"
deductions = "^Expenses:(Taxes:|Health:.*:Insurance$)"
expenses = "^Expenses:"
income = "^Income:"
transfers = "^$"
liabilities = "^Liabilities:"
invest = "^(Assets|Income):US:ETrade:"
open = "^Equity:Opening-Balances$"
[paths]
beancount = "main.beancount"
budgets = "budgets"
quotas = "quotas"
And here is an empty budget.
$ budget show 2022-01
Category Budgeted Expenses Balances Deviations
Expenses:Financial:Fees 4.00 -4.00 -4.00
Expenses:Food:Groceries 219.35 -219.35 -219.35
Expenses:Food:Restaurant 329.62 -329.62 -329.62
Expenses:Home:Electricity 65.00 -65.00 -130.00
Expenses:Home:Internet 80.14 -80.14 -160.14
Expenses:Home:Phone 68.36 -68.36 -68.36
Expenses:Home:Rent 2400.00 -2400.00 -2400.00
Expenses:Transport:Tram 120.00 -120.00 -240.00
Total 3286.47 -3286.47 -3551.47
Available 6649.63
Net income 6649.63
In this example, all budget
commands that require a month will use
2022-01
. In daily usage you will likely use commands like budget show
unqualified.
The example data's first month contains an opening balance for a checking account ($3948.43), and two paychecks whose net balances are almost evenly split between the checking account and a 401k account ($1350.60 and $1200.00 respectively).
The budgeter's focus is on everyday spending, so 401k postings aren't counted
as income. That leaves 3948.43 + (1350.60 * 2) = 6649.63
.
budget fill
allocates money to categories until each has enough balance for
the month's expenses and quotas. It tries to eliminate negative deviations.
$ budget fill 2022-01 > /dev/null
$ xsv select 'category,"2022-01"' budgets/USD.csv
category,2022-01
Expenses:Financial:Fees,4.00
Expenses:Food:Groceries,219.35
Expenses:Food:Restaurant,329.62
Expenses:Home:Electricity,65.00
Expenses:Home:Internet,80.14
Expenses:Home:Phone,68.36
Expenses:Home:Rent,2400.00
Expenses:Transport:Tram,120.00
$ budget show 2022-01
Category Budgeted Expenses Balances Deviations
Expenses:Financial:Fees 4.00 4.00
Expenses:Food:Groceries 219.35 219.35
Expenses:Food:Restaurant 329.62 329.62
Expenses:Home:Electricity 65.00 65.00
Expenses:Home:Internet 80.14 80.14
Expenses:Home:Phone 68.36 68.36
Expenses:Home:Rent 2400.00 2400.00
Expenses:Transport:Tram 120.00 120.00
Total 3286.47 3286.47
Available 3363.16
Net income 6649.63
budget trim
does the opposite: it removes money from overbudgeted categories,
in order to eliminate positive deviations.
$ budget add Expenses:Transport:Tram 100 2022-01
Expenses:Transport:Tram (Balance now) 100.00
(Balance added) 100.00
[Available] 100.00
$ budget trim 2022-01
[Available] (Balance now) 3363.16
(Balance added) 100.00
Expenses:Transport:Tram 100.00
For more on the concept, see "Quotas" below.
Some of these categories cost a fixed amount per month, so it makes sense to
start planning for them. To start, create quotas/$YOUR_CURRENCY.toml
. (Unlike
budgets, quotas are entirely manually set up.)
["Expenses:Home:Electricity".this]
type = "monthly"
amount = 65
["Expenses:Home:Internet".self]
type = "monthly"
amount = 80
["Expenses:Transport:Tram".wow]
type = "monthly"
amount = 120
The names were chosen to reflect their arbitrary nature.
I use this
in whole-category quotas.
$ budget fill 2022-01
Expenses:Home:Electricity (Balance now) 65.00
(Balance added) 65.00
[Available] 65.00
Expenses:Home:Internet (Balance now) 80.00
(Balance added) 80.00
[Available] 80.00
Expenses:Transport:Tram (Balance now) 120.00
(Balance added) 120.00
[Available] 120.00
$ budget show 2022-01
Category Budgeted Expenses Balances Deviations
Expenses:Financial:Fees 4.00 4.00
Expenses:Food:Groceries 219.35 219.35
Expenses:Food:Restaurant 329.62 329.62
Expenses:Home:Electricity 130.00 65.00 65.00
Expenses:Home:Internet 160.14 80.14 80.00
Expenses:Home:Phone 68.36 68.36
Expenses:Home:Rent 2400.00 2400.00
Expenses:Transport:Tram 240.00 120.00 120.00
Total 3551.47 3286.47 265.00
Available 3098.16
Net income 6649.63
Quotas are amounts you intend to budget each month. For example, in United States dollars:
The numbers are strictly illustrative and I will brook no complaints about them.
Each of these quotas are assigned to a Beancount account, such as
Expenses:Gifts:NPO
. Multiple quotas may be assigned to the same account. If
none are assigned to an account, that account has a default quota of zero
(which conceptually reduces to "no overspending").
A goal or yearly quota expects the balance to be fulfilled during the month before the stated end date. For example:
Each quota is assigned a category and a name (both strings), and consists of the following fields, with TOML types in parentheses:
monthly
, yearly
, goal
, or fixed
.YYYY-MM
format.YYYY-MM
format.budget trim
.This is how the aforementioned quotas would look in quotas/USD.toml
:
["Expenses:Vacation"."Los Angeles"]
type = "goal"
start = "2019-01"
by = "2019-07"
amount = 1200 # from January to June, you'll budget $200/m
["Expenses:Basics:Groceries".this] # "this" is arbitrarily chosen
type = "monthly" # to represent whole-account quotas
amount = 200
["Expenses:Basics:Candles".this]
type = "fixed"
amount = 3600
["Expenses:Basics:Health".gym]
type = "monthly"
amount = 70
start = "2019-01"
["Expenses:Gifts:NPO"."Department of Redundancy Department"]
type = "monthly"
amount = 20
["Expenses:Gifts:NPO"."Benevolent and Proactive Order of Llamas"]
type = "monthly"
amount = 10
["Expenses:Gifts:NPO"."Feed the Childrens"]
type = "monthly"
amount = 10
["Expenses:Goals:Car".this]
type = "goal"
start = "2018-01"
by = "2019-01"
amount = 10000
hold = true
["Expenses:Subs:USPS".this]
type = "yearly"
month = 6
amount = 288 # = $24/m