Shared-expense apps are useful until a small edge becomes important: a cent has to go somewhere, a result needs to be reproducible, or the group does not want to create another account just to settle one trip.
I built CentSettle for that narrow job. It turns one shared-expense ledger into exact balances and a compact deterministic payment plan. You can use it directly in the browser, run the CLI, or import the zero-dependency ESM core.
- Try it: https://miki.meowc.at/centsettle/
- Source: https://codeberg.org/automa-tan/centsettle
- Release: https://codeberg.org/automa-tan/centsettle/releases/tag/v0.1.0
A small example
{
"currency": "USD",
"participants": ["Alex", "Blair", "Casey"],
"expenses": [
{
"description": "Cabin",
"paidBy": "Alex",
"amount": "90.00",
"sharedBy": ["Alex", "Blair", "Casey"]
},
{
"description": "Groceries",
"paidBy": "Blair",
"amount": "24.00",
"sharedBy": ["Blair", "Casey"]
}
]
}
CentSettle calculates these balances:
- Alex receives USD 60.00
- Blair owes USD 18.00
- Casey owes USD 42.00
And produces this plan:
- Casey pays Alex USD 42.00
- Blair pays Alex USD 18.00
Why the result is deterministic
Amounts enter the core as decimal strings and become exact BigInt cents. Equal and weighted splits use largest-remainder allocation, with the declared participant order breaking ties. Settlement repeatedly pairs the largest remaining debtor with the largest remaining creditor, again using participant order for ties.
That means the same ledger always produces the same cent allocation and transfer order. The plan clears at least one balance per transfer and uses at most participants - 1 transfers. CentSettle deliberately does not claim to find the mathematically minimum number of transfers.
Local-first boundaries
The browser build has no account, upload, analytics, telemetry, external assets, browser storage, or network API. Its content security policy disables connections. The CLI reads stdin or one bounded regular file and can emit readable text or stable schema-versioned JSON.
The input format also keeps its promise narrow: one three-letter display label and exactly two decimal places. CentSettle does not convert currencies, apply ISO minor-unit rules, move money, or replace accounting advice.
Install the CLI
The package is published in the Codeberg npm registry:
npm install --registry=https://codeberg.org/api/packages/automa-tan/npm/ centsettle@0.1.0
Then:
centsettle trip.json
centsettle --json trip.json
Node.js 20 or newer is required. The package has no runtime dependencies and is MIT licensed.
If you regularly split travel, household, event, or club expenses, I would be interested in which ledger shape or workflow feels awkward in practice. Issues are open on Codeberg.
Disclosure: I maintain CentSettle. Development and this launch post were AI-assisted, with independent release-blocking review and automated tests.
Top comments (0)