{"id":"0dbf883f-791a-4167-a87b-ee32836357d4","slug":"coolerp","kind":"mcp","name":"CoolERP","summary":"Agent-native ERP: the AI operates the ledger over a typed MCP surface, and PostgreSQL enforces double-entry, append-only history and idempotency — so a wrong posting is impossible to create, not merel","owner":"Pher217","repoUrl":"https://github.com/Pher217/CoolERP","license":"AGPL-3.0","licenseTier":"strong-copyleft","trust":"community","stars":1,"match":null,"fewStars":true,"format":"mcp","createdAt":"2026-05-29T17:10:23.000Z","addedAt":"2026-10-21T06:10:58.870Z","logoUrl":"https://avatars.githubusercontent.com/u/61641590?v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["databases","memory-knowledge","utilities"],"tags":["accounting","agent-native","ai-agents","axum","bookkeeping","double-entry","erp","llm"],"runtime":"binary","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-21T06:11:17.536Z","sample":false,"url":"https://conduits.dev/tools/coolerp","language":"Rust","transports":["stdio"],"install":{},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"<div align=\"center\">\n\n# CoolERP\n\n**The ERP whose primary operator is an AI agent — and whose books cannot be wrong by construction.**\n\n[![CI](https://github.com/Pher217/CoolERP/actions/workflows/ci.yml/badge.svg)](https://github.com/Pher217/CoolERP/actions/workflows/ci.yml)\n[![License: AGPL-3.0](https://img.shields.io/badge/license-AGPL--3.0-blue.svg)](LICENSE)\n[![SDK: MIT/Apache-2.0](https://img.shields.io/badge/SDK-MIT%2FApache--2.0-green.svg)](crates/ol-sdk)\n[![Built in Rust](https://img.shields.io/badge/core-Rust-orange.svg)](https://www.rust-lang.org/)\n[![MCP](https://img.shields.io/badge/MCP-native-purple.svg)](https://modelcontextprotocol.io)\n[![Status](https://img.shields.io/badge/status-early%20%C2%B7%20building%20in%20the%20open-yellow.svg)](#what-works-today)\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](#build-it-with-us)\n\n*Double-entry-correct by construction · every state change a typed, idempotent capability · every figure traceable to an append-only event log.*\n\n**A duplicate journal entry here is not a bug to catch — it is impossible to create.**\n\n</div>\n\n## Demo\n\n![CoolERP walkthrough](docs/demo/coolerp-walkthrough.gif)\n\n*Overview KPIs → post a balanced journal entry through the UI → the ledger, cash and\nrevenue update → the six business processes, each a state machine generated from its\nYAML source.* Recorded against a live `ol-api` and Postgres; the entry posted in the\nclip is real and the figures move because the ledger actually changed.\n\n<p align=\"center\">\n  <b>▶ <a href=\"docs/claude-desktop.md\">Drive the same ledger from Claude Desktop</a></b> — the agent-native demo\n  · <sub><a href=\"docs/adr/README.md\">Architecture &amp; design rationale</a></sub>\n</p>\n\n---\n\n## The inversion\n\nEvery legacy ERP — SAP, Oracle, even Odoo — works the same way: a human clicks through a UI, and the database *trusts the UI* to keep the books straight. Decades of bugs, reconciliation nightmares, and audit theatre flow from that single misplaced trust.\n\n**CoolERP inverts it.** The **AI agent is the primary operator**, driving the ledger through a typed [MCP](https://modelcontextprotocol.io) capability surface — and correctness is enforced *in the database*, where it cannot be bypassed by any client, human or machine.\n\nYou don't *hope* the books balance. They **cannot** not-balance.\n\n## Correctness you cannot violate\n\nThese aren't features. They're invariants — physically enforced, not politely requested:\n\n- ⚖️ **Double-entry, enforced in PostgreSQL.** Every entry has ≥2 lines and `Σdebits = Σcredits`, checked by a deferred constraint trigger at commit. The application layer is *defense in depth*, never the only guard.\n- 🔒 **Append-only.** No `UPDATE`, no `DELETE` on the ledger — triggers forbid it. Corrections are reversing entries. History is immutable.\n- 🔁 **Idempotent posting.** Journal posting, inventory receipt and starting a process instance are idempotent via a client `idempotency_key` bound to a canonical hash of the request: a `UNIQUE (operation, idempotency_key)` constraint makes a duplicate *physically impossible*, and reusing a key with a **different** payload is rejected rather than silently replayed. **Ran twice ≠ paid twice.** Advancing a process is the one state-changing capability still without a client key — `advance_process`'s key is server-derived, so a retried advance is not deduped by idempotency; it is caught only incidentally by the illegal-transition guard once the instance has moved on.\n- 📜 **Audit-log-first.** An append-only `events` table records actor, capability, inputs hash, and resulting entries — the actor is client-asserted on the ledger path and a per-surface constant (`api`/`mcp`/`ai-chat`) on process advances until auth lands ([#9](https://github.com/Pher217/CoolERP/issues/9)) — machine-legible, replayable, training-corpus-grade.\n- 💶 **Money is integer cents.** No floats. Ever.\n\nThe posting engine is property-tested *and* hammered with concurrent races (12 writers on one idempotency key → exactly one entry; 15 writers contending the same accounts → not one lost post). Correctness is the entire credibility surface, so we treat it that way.\n\n## Agent-native, human-respected\n\nThe agent acts; the human watches, approves, and steps in — both over the same typed API and the same audit trail. Scoped OAuth for the MCP and REST surfaces is designed in [docs/adr/0006-mcp-auth-cimd-over-rfc7591.md](docs/adr/0006-mcp-auth-cimd-over-rfc7591.md) but not yet wired; the API currently runs unauthenticated in dev mode. See [SECURITY.md](SECURITY.md). Every business workflow is a version-controlled state machine in plain YAML, so \"what is this invoice allowed to do next?\" has one answer, and it's diffable:\n\n```mermaid\nstateDiagram-v2\n    [*] --> draft\n    draft --> posted: post_invoice 💶 [lines_nonempty, totals_balance]\n    posted --> paid: register_payment\n    draft --> void: void_invoice\n    paid --> [*]\n    void --> [*]\n```\n\n💶 marks a transition that writes to the append-only ledger; `--> [*]` marks a terminal state. Both\nare derived from the YAML, not annotated by hand.\n\nEach arrow is an MCP capability the agent calls — not a UI click — and each one carries the\nguards and posting rule from the same YAML, enforced again by a database trigger at commit:\n\n| capability | guards | posts |\n|---|---|---|\n| `post_invoice` | `lines_nonempty`, `totals_balance` | DR `accounts_receivable` / CR `sales_revenue` + `tax_payable` |\n| `register_payment` | — | **none declared** — `customer_invoice.yaml` sets no `posting_rule`, and the engine posts only where one exists ([`ol-engine/src/lib.rs:469`](crates/ol-engine/src/lib.rs)), so this transition marks the invoice paid without clearing AR ([#110](https://github.com/Pher217/CoolERP/issues/110)) |\n| `void_invoice` | — | none — reachable only from `draft`, before money has moved |\n\nThat diagram isn't hand-drawn — it's the literal output of [`Process::to_mermaid`](crates/ol-process/src/lib.rs),\n**generated from the workflow's YAML source of truth** ([`processes/customer_invoice.yaml`](processes/customer_invoice.yaml)),\nso the human view of a process can never drift from what the engine actually enforces.\n\n## Rust at the core, polyglot at the edges\n\nThis is a deliberate contributor bargain, not a purity test:\n\n- 🦀 **Rust where it earns its place** — the posting engine, the invariant-enforcing core, the event store. Performance, memory safety, and compile-time correctness are non-negotiable *there*.\n- 🐍🟦 **Python & TypeScript where you live** — the MCP server speaks a language-agnostic protocol, the OpenAPI 3.1 spec is published at `/api-docs/openapi.json`, and the web UI is React. Integrating with CoolERP, scripting it, and adding new business processes (plain YAML in [`processes/`](processes/)) **never requires writing Rust** — adding a new server-side capability still does. The Python and TypeScript SDKs are meant to be generated from that spec; **neither exists yet**, and they are the two flagship good-first-issues ([#60](https://github.com/Pher217/CoolERP/issues/60), [#59](https://github.com/Pher217/CoolERP/issues/59)).\n\nThese architectural choices are recorded in [docs/adr/README.md](docs/adr/README.md).\n\nIt's the pattern the best open engines already use — a fast, safe core wrapped in accessible clients (AppFlowy's Rust core + Flutter UI; Zoo/KittyCAD's Rust core + TypeScript app). **Contributions in Python and TypeScript are first-class.** Bring your stack.\n\n## What works today\n\nHonest status — this is early, and we're building in the open:\n\n| Component | State |\n|---|---|\n| `ol-domain` — double-entry invariants | ✅ implemented + property-tested |\n| `migrations` — schema + DB-enforced invariants | ✅ done (balance + append-only triggers) |\n| `ol-ledger` — posting engine (`post_journal_entry`, balances) | ✅ done, concurrency- & adversarially-reviewed |\n| `ol-process` — workflow engine (`processes/*.yaml` → state machine + Mermaid) | ✅ done |\n| `ol-api` — REST + OpenAPI | ✅ works |\n| `ol-mcp` — MCP server | ✅ works; authentication is designed but not wired — it runs unauthenticated, and there is no authenticated mode to switch on (see [SECURITY.md](SECURITY.md)) |\n| `apps/ol-ui` — React web app | ✅ works |\n| `ol-engine` — process instances, transitions, posting rules | ✅ done |\n| `ol-auth` — EdDSA JWT, Argon2id, scopes | ⚠️ implemented and unit-tested, but **no crate depends on it** — the auth primitives exist, the flow does not ([#9](https://github.com/Pher217/CoolERP/issues/9)) |\n| `ol-sdk` — shared error envelope (Rust) | ✅ used by `ol-api`/`ol-mcp`; the Python/TS client SDKs do not exist yet ([#59](https://github.com/Pher217/CoolERP/issues/59), [#60](https://github.com/Pher217/CoolERP/issues/60)) |\n| `ol-events` — event store + replay | 🚧 **empty stub, nothing depends on it.** The append-only `events` table is real, but it is written directly by `ol-ledger`; replay is not implemented and the table has no read endpoint ([#57](https://github.com/Pher217/CoolERP/issues/57)) |\n\nYou can run the app locally today; the core is solid and the quickstart below will get you a ledger, API, and UI in minutes.\n\n## Quickstart\n\n```bash\ndocker compose up -d db\nmake demo\nmake api\n```\n\nThen, in a second terminal:\n\n```bash\nmake ui\n```\n\n## Build it with us\n\nThis is the moment to get in — the foundation is laid, the hard correctness problems are solved, and the surface area where **you** can ship something visible is wide open.\n\n**Good first issues** (no Rust required for several):\n- 🌍 i18n scaffold (FR / DE / EN)\n- 🧩 Build the Python / TypeScript SDKs from the OpenAPI spec\n\n→ Browse [`good first issue`](https://github.com/Pher217/CoolERP/labels/good%20first%20issue) · read [CONTRIBUTING.md](CONTRIBUTING.md) (DCO sign-off) · meet the [maintainers](MAINTAINERS.md) · see the [roadmap](ROADMAP.md).\n\n```bash\ngit clone https://github.com/Pher217/CoolERP && cd CoolERP\ncargo test --all          # the core, green\nDATABASE_URL=postgres://… cargo run -p ol-cli -- migrate   # apply the schema\n```\n\nWe're looking for **≥3 maintainers**, especially anyone with real double-entry / accounting depth. If correctness-by-construction and agent-native software is your fight, [open an issue and say hi](https://github.com/Pher217/CoolERP/issues).\n\n## Scope (v0.1)\n\n**Working end-to-end:** journals & general ledger, the posting engine, account balances (including per-currency), inventory receipts and stock queries, the trial-balance / AR-aging / subledger-reconciliation reports, and the full process surface — list processes, start an instance, list instances, read one, advance it — over both REST and MCP.\n\nAudit trails are **partly readable**: every advance appends an immutable `process_steps_log` row and those come back on `GET /instances/{id}`, but the ledger's append-only `events` table has no read endpoint yet. The chart of accounts is seeded and read-only (no CRUD endpoint).\n\n**Tables only, no direct API surface:** AR/AP and invoicing. The `parties`, `invoices`, `invoice_lines`, `bills`, `bill_lines` and `payments` tables exist and are exercised through the `customer_invoice`, `order_to_cash` and `purchase_to_pay` processes — but there is **no REST endpoint and no MCP tool** that creates an invoice, bill, payment or party directly, and inventory valuation is recorded (`unit_cost`) but never computed. If you want an ERP resource API, that gap is the work.\n\n**Deliberately out:** manufacturing/MRP, payroll, HR, CRM, multi-entity consolidation, VAT/e-invoicing regimes. Per-currency balancing *is* implemented (`migrations/0004_currency.sql`); FX rates and settlement are not ([#63](https://github.com/Pher217/CoolERP/issues/63)). We ship the 20% that covers 80% — correct — before we ship breadth.\n\n## Workspace layout\n\n```\ncrates/\n  ol-domain/    double-entry invariants (AGPL-3.0)\n  ol-ledger/    posting engine, SQLx hot path, idempotency (AGPL-3.0)\n  ol-events/    event store + projections/replay — REPLAY IS A STUB (AGPL-3.0)\n  ol-process/   workflow YAML → state machine + Mermaid (AGPL-3.0)\n  ol-engine/    process engine — instances, transitions, posting rules (AGPL-3.0)\n  ol-api/       Axum REST + OpenAPI (AGPL-3.0)\n  ol-mcp/       MCP server — OAuth 2.1 PKCE designed (ADR-006), not wired (AGPL-3.0)\n  ol-auth/      EdDSA JWT, Argon2id, scopes — BUILT AND TESTED, NOTHING DEPENDS ON IT YET (AGPL-3.0)\n  ol-sdk/       shared error envelope + typed structs — Rust only today (MIT OR Apache-2.0)\n  ol-cli/       `ol migrate|post|balance` (`serve`/`replay` not implemented) (AGPL-3.0)\napps/ol-ui/     React + Vite web app — observe & operate (AGPL-3.0)\nmigrations/     SQL schema + double-entry triggers\nprocesses/      business-process source-of-truth (YAML)\n```\n\n## Stack\n\nRust · Axum 0.8 / Tokio · SQLx 0.8 (throughout — ADR-004 anticipated SeaORM for CRUD; it is not used today) · `rmcp` MCP server · PostgreSQL · React + Vite web UI · OpenAPI 3.1 (utoipa); Python/TS clients planned.\n\n## Kin & prior art\n\nNot foils — fellow travellers on the ledger-as-event-log thesis: [TigerBeetle](https://github.com/tigerbeetle/tigerbeetle), [Formance Ledger](https://github.com/formancehq/ledger), Modern Treasury, Beancount. Our edge is the **agent-native capability surface + idempotency-by-construction + a polyglot contributor base.**\n\n## Licensing\n\nCore / server / API / MCP / UI / CLI: **AGPL-3.0**. SDK: **MIT OR Apache-2.0**. Contributions require a [DCO](CONTRIBUTING.md) sign-off.\n\n---\n\n<div align=\"center\">\n<sub>Correct by construction. Agent-native by design. Open by default.</sub>\n</div>\n"}