Skip to content

Repository files navigation

💰 Monay

A modern terminal app for zero-based budgeting — with monthly rollover, pockets, and a flexible section model.

Built with Python 3.14 · a pure budgeting engine behind a Textual terminal UI.

Python Textual License


Monay brings zero-based, envelope-style budgeting to the terminal — give every dollar a job, then watch what you don't spend roll forward in its pot. You define your own sections and fields, log spending as you go, and at month-end close the month — unused money rolls forward, pots carry over, and the next month is created for you automatically.

 Monay  ┃ Budget ┃ Transactions │ Pockets │ Settings      Docs │ History
─────────────────────────────────────────────────────────────────
 January 2025   ● open                           Profile: alex
─────────────────────────────────────────────────────────────────
 SECTIONS                              avail        rest
 ▍Bills      pre · 500                500.00        0.00
 ▍Needs      post · 50%               750.00      350.00
 ▍Wants      post · 30%               450.00      300.00
 ▍Savings    post · 20%               300.00       60.00
                                  ──────────
 income 2000.00 · post pool 1500.00 · Σ% = 100 ✓
─────────────────────────────────────────────────────────────────
 ✓ Groceries −17.06 → LEFT 332.94 (Needs REST 350.00)
 > _

✨ Features

  • Zero-based by design — every dollar of income gets a job: tax-sections skim a % off fresh income first, pre-sections come off the top, post-sections split the rest and must sum to 100%. Define your own tax/pre/post sections and fields — no two budgets look alike.
  • Envelope rollover — close a month and unspent budget rolls forward into each field's envelope (its pot), capped at a per-field max (finite or ∞); section leftovers route to next month's income, back into themselves, or into another section.
  • Pockets — per-account "how much should I have here right now?" counters, so you can reconcile against reality.
  • Borrowing, modeled honestly — fields and sections can go negative (red) and heal over future months; supports one-time "advance" budgets.
  • Expressions everywhere — type 15.71+1.35 or (7.81)/2+6.5 for any amount.
  • Command-driven — everything happens by typing bare-verb commands in one bar; arrows are only for navigation.
  • Money done rightDecimal, 4-decimal storage with banker's rounding; no floats ever touch a value.
  • Multiple profiles — fully independent budgets in one app.

🚀 Install & run

Standalone binary (no Python needed)

Download the binary for your OS/arch from the Releases page, then run it from a terminal:

# Linux / macOS
chmod +x monay-linux-x86_64
./monay-linux-x86_64

# Windows (PowerShell)
.\monay-windows-x86_64.exe

Monay stores your data in a monay.db file in the current working directory, so run it from a folder you'll remember.

From source (developers)

Monay uses uv for environment and dependency management.

uv sync                      # create the venv + install deps (fetches Python 3.14)
uv run python -m monay       # launch the app
uv run pytest                # run the test suite

🧩 Concepts

A quick mental model — five ideas:

  • Income enters the month as one or more named entries.
  • Sections each receive a slice of income, called AVAILABLE:
    • Tax-sections come off the very top — a % of fresh income only (leftovers carried from last month were already taxed, so they're excluded).
    • Pre-sections are taken off the top next, in order — a fixed amount or a % of what income remains (e.g. rent, savings, charity).
    • Post-sections split whatever's left by percentage; their percentages must sum to 100% (e.g. Needs 50 / Wants 30 / Savings 20).
  • Fields are the budget lines inside a section. Each has a BUDGET (what you feed it this month — a fixed amount, or a % of the section's AVAILABLE remaining after its fixed budgets), a CURRENT pot (carried from last month), and a MAX rollover cap (a number, or ).
  • Pockets are where money physically sits (Main, Bank, Broker…). Each field belongs to one; a pocket's counter is the sum of its fields' balances — what you should actually have in that account.
  • Closing a month rolls everything forward and locks it.

The core formula, per field:

LEFT     = min(CURRENT + BUDGET − PAID, MAX)     ← your pot after this month

Underspend and the pot grows (capped at MAX); overspend and it goes red and is repaid by future budgets. A section's unused slice is its REST, which on close routes to next month's income, back into the section, or into another one.

📖 Using Monay

Everything is a typed command. Names are case-insensitive; quote names with spaces ("Emergency Fund"); amounts accept arithmetic.

First month, from scratch

profile add alex                  # create + select a profile (auto-creates the month + a Main pocket)
income add Salary 2000            # add income (have as many entries as you like)

section add tax  Income-Tax 1.5%  # tax-section: a % of fresh income, off the very top
section add pre  Bills 500        # pre-section: a fixed amount off the top (or a %)
section add post Needs 50%        # post-sections split the remainder; must sum to 100%
section add post Wants 30%
section add post Savings 20%

field add Needs Groceries 300 400  # field with budget 300, max 400 (use `inf` for ∞)
field add Savings Emergency 50%    # % budget: half of Savings' AVAILABLE after its fixed budgets
field set  Groceries current 100   # type your carried-over pot (first month only)

add Groceries 15.71+1.35 d5 weekly shop   # log a transaction (d5 = day 5; day defaults to today)

Navigating

The screen has two panes: working tabs on the left (Budget, Transactions, Pockets, Settings) and helper tabs on the right (Docs, History).

On the Budget tab, click a section row — or expand <section> — to reveal its fields inline; any number of sections can be open at once. expand with no name opens them all, collapse <section> closes one, collapse closes them all · goto <tab> switches tab (either pane) · Tab cycles tabs · Ctrl+B toggles the helper pane · drag the divider between the panes, or Ctrl+←/Ctrl+→, to resize it (the keyboard shortcuts are shown along the bottom of the helper pane).

Closing a month

close          # shows a summary, asks Type Yes or No, then locks the month and creates the next

Field pots carry forward as next month's current; section RESTs route per their setting; a single Leftovers income entry is created. Closed months are read-only in History (month 2025-01 to view, month to return).

Full command reference
Command Effect
add <field> <amount> [d<day>] [desc…] Record a transaction
transfer <amount> <from> <to> [d<day>] [note…] Move pot money between fields
tx [filter] · tx edit <#> <attr> <val> · tx del <#> View / edit / delete transactions
section add tax|pre|post <name> <pct%|amount> Create a section (tax/post are %-only)
section set <name> pct|amount|name|rest <value> Edit a section (rest = income/self/<section>)
section order <name> <pos> · section del <name> Reorder / delete a section
field add <section> <name> [budget] [max|inf] Create a field
field set <name> budget|max|pocket|name|current <value> Edit a field
field del <name> Delete a field (only when empty)
income add|set|del … Manage income entries
pocket add|rename|del <name> · pocket main <name> Manage pockets
month [<yyyy-mm>] · close View a month / close the open one
expand [section] · collapse [section] · goto <tab> Expand/collapse a section (or all) · navigation
profile add|switch|rename|del <name> Manage profiles
help [command] Open the Docs tab — the full command reference (filter by command)
quit Exit

🏗️ Building a standalone binary

PyInstaller produces a one-file binary; it bundles the host interpreter, so build on the OS/arch you're targeting (no cross-compiling).

uv sync --no-dev --group build
uv run --group build pyinstaller monay.spec    # → dist/monay  (or dist/monay.exe)

The .github/workflows/build.yml workflow builds Linux and Windows binaries for both x86_64 and arm64, and publishes them as a stable versioned release on each v* tag (see docs/RELEASING.md).

📁 Project layout

monay/
  domain/      pure engine: value objects, Month aggregate + recompute, closing, ports
  data/        SQLAlchemy Core adapters, schema, migrations, unit of work
  app/         use-case services + the spec-driven command registry
  tui/         Textual app: shell, command bar, theme, screens, widgets
  bootstrap.py composition root (dependency-injector container)
tests/         unit + engine + adapter + headless-TUI tests
docs/          DEVELOPING (code guide)

Contributors: see CONTRIBUTING.md for the development loop and docs/DEVELOPING.md for how the code is organized.

📜 License

MIT — see LICENSE.

About

Keyboard-driven terminal budget app for zero-based, envelope-style budgeting. A pure Python engine behind a Textual TUI.

Topics

Resources

Contributing

Stars

2 stars

Watchers

1 watching

Forks

Releases

Contributors

Languages