A tiny command-line tool to track the Papercusp 2026 engineering offsite budget.
Act 1 of the demo plans the offsite. This is the software the coding hive builds in Act 2: a tool the planners can run to roll up the budget and see, at a glance, whether we're under or over the $45,000 target.
Goal (the one-line ask): Build a small CLI that reads a budget file (line items by category) and prints a budget report — per-category totals, the grand total, and a clear flag of how far over or under the $45,000 target we are. Exit non-zero when over budget.
This repo is zero-dependency: it runs on Node ≥ 18 with the built-in test runner. No
npm install, no build step. node --test and node src/cli.js are all you need.
- A reusable budget engine — a pure function, no I/O — that rolls up line items and computes the verdict against a target. This is the contract C-1 below.
- A CLI that reads a budget JSON file, runs the engine, prints a readable report, and
sets its exit code (
0within budget,1over budget). - Tests ship with the code.
node --testis green and covers both the engine (totals, variance, status, bad input) and the renderer/CLI (the rendered report, the exit code). Code without tests is not done. - Running
node src/cli.js budget.sample.jsonprints the report for the sample budget (which is intentionally over the $45k target) and exits1.
The engine is the seam every other piece builds against. Owner lane lands this first; consumers stub against it immediately.
// summarizeBudget(lineItems, targetUsd) -> BudgetReport
//
// lineItems: Array<{ category: string, label: string, amountUsd: number }>
// targetUsd: number (the budget target, e.g. 45000)
//
// BudgetReport = {
// byCategory: { [category: string]: number }, // summed amountUsd per category
// total: number, // sum of every line item
// targetUsd: number, // echoed back
// varianceUsd: number, // total - targetUsd (positive = over)
// status: 'under' | 'at' | 'over', // total <target / ==target / >target
// }
//
// Throws a clear Error on invalid input (not an array; missing category;
// non-finite or negative amountUsd).src/budget.js— the engine (owns C-1).src/render.js—renderReport(report) -> string(the human-readable table).src/cli.js— reads argv → parse file →summarizeBudget→renderReport→ print + exit code.test/*.test.js— one test file per component.
node --test # run the test suite
node src/cli.js budget.sample.json # print the sample budget report (exits 1: over budget)See budget.sample.json. A budget file is:
{
"targetUsd": 45000,
"lineItems": [
{ "category": "venue", "label": "…", "amountUsd": 12000 }
]
}