No description
  • Rust 99.7%
  • Just 0.3%
Find a file
Kerry Hatcher 1afff12607
docs(claude-md): point the superproject link at Forgejo, not the stale GitHub mirror
The GitHub repo is deliberately kept as a mirror, but its main is frozen at
b08f1f0 (pre-thor-deployment) with a .gitmodules that still points every
submodule back at GitHub — the same trap finding 3 caught in install.md.
An agent following this link lands on stale code, not the current tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FGisjtKSjUcVGw1jX1Hf8M
2026-08-07 13:39:28 -04:00
src fix: revoke on logout without claiming a client_id 2026-08-06 01:18:23 -04:00
.gitignore feat: ratatui TUI with a scriptable CLI mode 2026-08-03 15:18:11 -04:00
Cargo.lock feat(auth): store tokens in the OS keyring, file as fallback 2026-08-05 14:32:54 -04:00
Cargo.toml feat(auth): store tokens in the OS keyring, file as fallback 2026-08-05 14:32:54 -04:00
CLAUDE.md docs(claude-md): point the superproject link at Forgejo, not the stale GitHub mirror 2026-08-07 13:39:28 -04:00
justfile feat: just run to start the TUI 2026-08-03 15:26:01 -04:00
LICENSE Initial commit 2026-08-03 14:23:45 -04:00
README.md refactor: default to the api's new port 38081 2026-08-03 15:42:15 -04:00
rustfmt.toml feat: ratatui TUI with a scriptable CLI mode 2026-08-03 15:18:11 -04:00

openbooks-cli

Terminal client for openbooks-api. Run it with no arguments and you get a TUI; give it a subcommand and it becomes a quiet, scriptable CLI.

Run it

From this repo, with the API already up:

just run                      # the TUI
just run balances --json      # arguments pass straight through
just test                     # unit and render tests, no API needed
just check                    # fmt and clippy, as CI would

From the openbooks superproject, which starts postgres and the API first if they're down:

just cli
just cli balances --json

Point it elsewhere with --api or OPENBOOKS_API (default http://localhost:38081).

The TUI

Four tabs in fixed positions, the money on hand always in the header:

Dashboard balance of every account
History every transaction, newest first
Reports money in and out, plus what we hold and owe, for any month/quarter/year
Record log money in, money out, or a transfer

Keys — ? shows them all:

Tab / Shift-Tab   next / previous tab        j k / ↓ ↑   move
1 2 3 4           jump to a tab              g G         first / last row
r                 reload                     q           quit
Reports:  m Q y   monthly / quarterly / annual      [ ]   previous / next period
History:  d       delete the selected transaction
Record:   Tab     next field    ← →  change    Enter  save    Esc  clear

Needs at least 80x24; below that it says so rather than drawing a broken layout. Respects NO_COLOR, and the selected row uses reverse video so it stays visible with no colour at all.

The CLI

Text by default — aligned columns, no escape sequences, safe to pipe. --json emits the API's own JSON untouched, so jq sees exactly what the server said.

openbooks accounts
openbooks balances
openbooks transactions --from 2026-01-01 --to 2026-03-31
openbooks income --from 2026-04-01 --to 2026-06-30
openbooks balance-sheet --as-of 2026-06-30
openbooks record out --amount 45.00 --account checking --category Food \
    --date 2026-03-05 --description "Meeting pizza"

record takes in, out, or transfer and works out the double-entry split itself. Accounts resolve by name, by unambiguous prefix, or by id — an ambiguous prefix is an error rather than a guess. Anything wrong exits non-zero with the reason on stderr, so a script can trust the exit code.

Amounts

Dollars in, 45 or 45.50, parsed to integer cents without ever touching a float — 19.99 * 100.0 is 1998.9999… in binary floating point, and truncating that loses a penny every time. cargo test covers that case specifically.

Tests

cargo test

19 tests, no network needed: money parsing and formatting, the debit/credit split, account resolution, period arithmetic across year boundaries and leap Februaries, and the whole render path against ratatui's TestBackend — including the too-small-terminal gate and the warning shown if a balance sheet ever fails to balance.