Philosophy¶
kasas is a financial ledger that can power all kinds of apps.
That sentence is the whole design. Everything below is a consequence of taking it seriously.
What kasas is¶
kasas is a headless financial data platform. It does three things, and tries to do them exceptionally well:
- Ingest — pull in organizations, accounts, and transactions through pluggable sources. SimpleFIN is the first, but the ledger is source-agnostic by design: a source normalizes one provider, a generic engine persists every source the same way.
- Store — keep that data in a durable, queryable ledger (SQLite or Postgres) with a clean, stable shape and a complete record of how it changed.
- Expose — make it programmable through a REST API, an MCP server, a canonical event stream, webhooks, and sandboxed plugins.
It owns the boring, load-bearing parts of any personal-finance system: authenticating to a source, deduplicating transactions, refreshing a pending charge when it posts, preserving the metadata you added, recording an immutable history, and emitting an ordered event for every change. These are the parts that are tedious to build, easy to get subtly wrong, and identical across every app that touches your money.
What kasas is not¶
kasas is not a Mint replacement, a budgeting app, a tax tool, or a financial planner. It has no opinion about your spending, no budgets, no projections, no charts of your net worth over time.
That restraint is intentional. The moment a ledger grows a budgeting opinion, it starts shaping its data model around that opinion, and everything else becomes a second-class citizen. kasas stays unopinionated about the application layer so that the application layer can be anything.
The thesis
Don't build another finance app. Build the ledger that finance apps run on — then let a hundred apps bloom on top of it, yours and everyone else's.
The platform primitives¶
A backbone is only useful if it gives builders the right seams. kasas exposes five, and the rest of this documentation is mostly about how each one works:
| Primitive | What it gives an app builder |
|---|---|
| Event stream | An append-only, replayable log of every change. Read what changed and when instead of re-diffing state — the substrate for sync engines, automations, and event-sourcing. |
| Webhooks | The event stream pushed outward, HMAC-signed, so an external service reacts to changes without polling. |
| Plugins | The event stream consumed in-process, in a sandboxed VM, so logic that wants to live close to the data can. |
| Schema extensions | Arbitrary namespaced JSON any app attaches to a transaction — extend the model without a migration or coordination. |
| MCP server | The whole ledger as tools an AI agent can call directly. |
Around those sit the everyday building blocks — labels, search, rules, and transaction history — each available identically across every surface.
AI is a first-class citizen¶
An AI agent is not a bolted-on feature or a read-only window onto kasas — it is a first-class client, equal to any app or human operator. The MCP server exposes the whole ledger as tools, at full parity with the REST API: an agent can search and label transactions, write and run rules, enter transactions by hand, read the event stream and immutable history, and administer webhooks, API keys, and plugins. Anything a person can do from the dashboard, an agent can do through a tool call — backed by the same core logic and identical response shapes, never a reduced or separate API.
This is a deliberate consequence of the thesis. A ledger that can power all kinds of apps has to count agents among them — so the restraint that keeps kasas unopinionated for human apps is the same restraint that makes it legible to machines. Amounts are exact decimal strings an agent never has to second-guess, every change is a structured event it can react to, and search is a real query language rather than a fixed set of filters. kasas was built to be driven by software — and that software, increasingly, reasons.
Design principles¶
These show up again and again in the internals.
- Source-agnostic ingestion. Data arrives through a source that normalizes one provider into a neutral batch; a generic engine owns the persist. Model the archetype (pull, file, webhook…), not the provider, so each new provider is a thin adapter — and a buggy source can never corrupt the ledger.
- Lean on storage, comprehensive on exposure. Reuse existing tables and a JSON column before adding schema; but when a capability exists, wire it across every surface (REST, MCP, dashboard) with full parity. A feature that only exists in the UI isn't a platform feature.
- The data you add is sacred. A sync refreshes what the source owns and never touches what you own. Your labels and extensions survive every re-sync, correction, and re-pull.
- Every change is a fact. Changes are recorded as durable events and immutable history snapshots, written in the same database transaction as the change itself, so the record can never disagree with reality.
- Money is exact. Amounts are stored and compared as decimal strings, never parsed into a float.
- Boring to run. A single static binary, no CGO, an embedded database, an embedded dashboard, graceful shutdown, Prometheus metrics, and structured logs. It should be unremarkable to self-host and forget.
- Safe by construction. Slow or crashing extensions (webhooks, plugins) run
after commit and can never block or corrupt a sync; untrusted plugin code
runs sandboxed and capability-gated; secrets are stored hashed or
0600.
Where to go next¶
- See the principles realized in the System Overview.
- See how data gets in through Ingestion & Sources.
- See the shape of the data in the Data Model.
- See the seams you build on in Webhooks, Plugins, and the Event Stream.