Skip to content
Code Recycle

Component · for humans & their agents

Double Entry Ledger

verified · first-partyactively maintained$0 during beta (was $79)

Financial code without double-entry discipline does not crash when it loses money. It reports a number that is slightly wrong forever.

by Code Recycle

Get it free — beta

Every claim on this page is refundable if it is untrue — refund policy.

Verified: 148 tests · 11/11 mutations caught · 1 adversarial review, 1 defect found and fixed · verified by an independent reviewer, not the author

An append-only double-entry posting engine where the books cannot silently stop balancing.

An append-only double-entry posting engine where the books cannot silently stop balancing.

THE SILENT FAILURE. Five mechanisms, none of which raise anything.

FLOATS. 0.1 + 0.2 is 0.30000000000000004. A balance accumulated in floats over ten thousand transactions drifts, and the drift appears as a reconciliation difference nobody can trace to a transaction -- because no single transaction is wrong. The error is spread thinly across all of them.

THE LOST CENT. Splitting 10.00 three ways naively gives 3.33, 3.33, 3.33 and one cent has ceased to exist. Every naive revenue split, refund proration and tax allocation does this, and the difference is small enough to be dismissed as rounding for years.

UNBALANCED POSTINGS. An entry whose debits do not equal credits is accepted by any system that stores rows rather than entries. The trial balance is then non-zero and nobody knows since when.

CURRENCY MIXING. Bare numbers let 100 USD be added to 100 EUR to make 200 of nothing. This is the one that produces confidently wrong executive dashboards.

MUTATED HISTORY. A correction written as an UPDATE or DELETE means last month's report no longer reproduces. Nothing is wrong today; everything historical is now unverifiable.

All five are made structurally impossible rather than discouraged. Money is an integer count of minor units in a native bigint -- no floating-point arithmetic ever touches an amount. allocate() uses largest-remainder with bigint-exact arithmetic so parts sum exactly to the total. post() refuses any entry whose postings do not net to zero per currency, and there is no API for writing half an entry. Mismatched currencies throw rather than resolve. The journal has no update or delete, and every posted entry is DEEP-frozen -- the entry, the postings array, and each posting -- so a plain property assignment cannot rewrite history either. A correction is reverse(), a new negated entry; the original is never touched.

WHAT IT IS NOT: not an accounting system (no chart of accounts, no asset/liability semantics), no FX conversion -- mixing currencies that would need one is refused, never resolved, because this will not invent an exchange rate -- and no network access anywhere in the runtime.

VERIFIED: 148 tests, re-measured by running the suite, 11/11 mutations killed. An adversarial reviewer found that entries were returned live and mutable: the array was copied but the entries in it were not, so rewriting a posting rewrote history and every later trial balance reported an account that was never posted to. Deep-freezing at post() time was the fix, and a second adjacent mutation it exposed is now covered too.

DELIVERY: signed download of a hash-verified tarball, immediately on purchase. Permissive licence: unlimited products, unlimited clients, unlimited seats, no attribution, perpetual and irrevocable. One restriction, do not republish the source as source.

Interface

What you call, and what comes back. Types and signatures only — the implementation ships with the source.

  export function allocate(total: Money, weights: readonly number[]): Result<Money[], AllocationError>;
  export function registerCurrency(code: string, exponent: number): void;
  export function getCurrencyExponent(code: string): number;
  export function isKnownCurrency(code: string): boolean;
  export function money(minorUnits: bigint | number, currency: string): Money;
  export function isMoney(value: unknown): value is Money;
  export function assertMoney(value: unknown, context: string): asserts value is Money;
  export function zeroMoney(currency: string): Money;
  export function isZeroMoney(m: Money): boolean;
  export function addMoney(a: Money, b: Money): Money;
  export function subtractMoney(a: Money, b: Money): Money;
  export function negateMoney(a: Money): Money;
  export type PostError = ImbalanceError | DuplicateEntryError | InsufficientPostingsError | EmptyAccountError;
  export type ReverseError = EntryNotFoundError | PostError;
  export type TrialBalance = readonly AccountCurrencyBalance[];
  export type Result<T, E> = Readonly<{ ok: true;

01Capabilities

Does

  • + Payment and royalty splitting
  • + Ledger integrity

Doesn’t

  • No exclusions declared

02Requirements & stack

Depends on

No declared dependencies

Credentials needed

None declared

Stack

typescript

03Community

No endorsements yet

No verified confirmations yet — be the first.

Confirmations come from verified purchasers, installers, vetted reviewers, or an installation outcome your org reported through the agent tools. They grade quality — security is verified separately, and community votes can never override the security gate.

Open an issue

Sign in to confirm — weight comes from verified usage, not vote count.

0 open · 0 answered · 0 fixed · 1 said it worked

04Trust Passport

Full passport →
–/100

0/0 automated components pass. An automated score is never a security guarantee.

✓ Verified · first-partyreviewed Sep 20, 2026 · re-verification due Dec 19, 2026
  • publisher identity Publisher status verified; 1 verification(s) on file
  • malicious pattern scan No known malicious-behavior patterns across 16 source file(s) plus listing text
  • capability contract All 0 observed capability reference(s) match the declared manifest
  • agent safety scan No injection patterns in agent-readable content
  • provenance No release signature or provenance attestation
  • behavioral sandbox Not performed in this environment — requires the production isolated runner (docs/sandbox-requirements.md). No untrusted code is ever executed on the application host.

Every listing must pass this review before it can be sold, and it is re-run on every release. Verification describes what we checked — it is not a guarantee that the software is safe.

VersionChannelReleasedNotes
1.0.0stableAug 5, 2026First public release.