Open source · Apache 2.0

Four rules on every write. Enforced by the server, not the prompt.

OpenLedger checks each entry before it's saved. An entry that breaks a rule is refused with the reason, and nothing is written.

Updated

Why a prompt isn't enough.

  1. 01

    Agents make arithmetic slips

    A swapped digit or a missing line leaves the books out of balance, and nothing downstream notices.

  2. 02

    Decimals drift

    Money stored as floating point picks up fractions of a cent that never add back up.

  3. 03

    Edits erase evidence

    Fixing a number in place removes the record of what was wrong and who fixed it.

The rules

Checked on every write. Inside one database transaction.

Balance

Debits must equal credits.

Every entry needs at least two lines, and the debit total must equal the credit total. The check runs in the write path, in the same database transaction as the insert.

  • At least two lines per entry
  • Every account must exist and be open
  • A refusal names the rule and the amounts

Whole cents

No floating-point money.

Amounts are stored as integer minor units. A line of 125.5 cents is refused, so rounding errors can't enter the books.

  • amount_minor must be a positive integer
  • Reports turn cents into dollars on the way out
  • One base currency per deployment

Reversals

Posted entries never change.

No tool updates or deletes an entry. reverse_transaction posts a new entry that flips every line, dated like the original, and marks the original reversed. A reason is required.

  • The original stays on the record
  • The reversal points back to what it reverses
  • An entry can be reversed once, and a reversal can't be reversed

Audit

Every change writes an audit row.

The audit row commits in the same database transaction as the change it describes, so the log can't get ahead of the ledger or fall behind it.

  • Entries, transfers, reversals and new accounts
  • Read it with get_audit_log, filtered by action or actor
  • Rejected calls write nothing, so they leave no row

What else the ledger does.

  • Chart of accounts

    Assets, liabilities, equity, income and expenses, each with its normal side.

  • Account ledgers

    Every line on an account, with a running balance.

  • Transfers

    A two-line entry between accounts in one call.

  • Three statements

    Trial balance, profit and loss, and balance sheet, as of any date.

  • Search

    Find entries by text, date range, account or status.

  • Read-only SQL

    run_query accepts SELECT only, on a connection that can't write.

See the rules work.

All three run against the open-source server.

  1. Connect Claude

    Add the MCP server to Claude Code from the open-ledger folder.

    claude mcp add openledger -s user -- $PWD/.venv/bin/python $PWD/run_mcp.py
  2. Ask for an unbalanced entry

    The server refuses it and returns both totals.

    > Post rent: $4,200 debit, $4,000 credit.
  3. Run the smoke test

    It calls every tool against the seeded books and checks that the rules hold.

    .venv/bin/python scripts/smoke_test.py

What each table holds.

Read from scripts/schema.sql in the open-ledger repository.

TableWhat it holdsHow it changes
accountsCode, name, type, normal side and an archived flagAdded with create_account
transactionsDate, description, reference, status, source and who created itNever edited. A reversal marks the original reversed
entry_linesAccount, debit or credit, and a positive whole number of centsNever edited or deleted
audit_logActor, action, object and details, in sequenceAppended with every change
org_settingsBusiness name and base currencyOne row per deployment

The balance rule is enforced by the server's write path, not by a database constraint. Writing to the SQLite file directly bypasses it.

Questions.

Can an agent edit or delete an entry?

No. No tool updates or deletes an entry. Corrections are reversals, and run_query accepts SELECT statements only.

Does it stop an account going negative?

No. The rules cover balance, whole cents, immutability and audit. There's no overdraft or insufficient-funds check.

Is the audit log tamper-evident?

Not yet. Rows are written with each change and the tools only append, but a hash-chained log you can verify is planned for v0.3.

Which agent made a change?

Today every MCP write is recorded with the actor mcp. API keys, with the audit actor taken from the key, are planned for v0.2. Attri adds per-agent identity in managed deployments.

Can it close a month?

Not yet. Fiscal periods and closing entries are planned for v1.0.

Let your agents keep the books. Keep the rules on the server.

Run OpenLedger on sample books in minutes, or have Attri deploy it inside your environment with access control and approval rules.