Technology & AI
Governed intelligence on a canonical finance model.
Six layers, each with one job and hard boundaries between them. The result is a system where a plain-English question becomes a validated plan, a computed answer and a traceable row — and where nothing irreversible happens without a person.
The stack
Six layers. One job each.
Bottom to top: where data comes from, where it lives, where it is posted, how it is governed, how it is reasoned about, and how it is controlled.
1 · Connectors
One stateless service per source, holding only its own credentials. Fetch and normalize; never persist. Nightly sync, webhooks, backfills — all idempotent.
8 live services2 · Canonical store
A normalized finance model in Postgres: accounts, transactions, invoices, parties, products, shipments, payouts. Row-level security on every tenant table.
RLS · AES-GCM secrets3 · Ledger of record
Double-entry postings live in ERPNext behind a connector. Finanly drafts, a human approves, an idempotent export posts once; statements are re-derived and parity-checked hourly.
19k+ entries in parity4 · Semantic layer
Governed cubes, measures and dimensions over the canonical store. Statements, Report Studio, dashboards and the model all plan against the same definitions.
26 cubes · 124 measures · 756 dimensions5 · Model layer
A private model behind an internal-only gateway proposes semantic plans and categorizations. core-api validates; the engine executes; the model never touches a connector.
Internal-only gateway6 · Controls
Approvals and export batches, idempotency keys on every side-effect call, append-only audit events enforced by a database trigger, rate limits, undo.
Append-only audit trailMost finance AI is a model with database access. Finanly is a governed model with a validator in front of it, an engine behind it and a person at the end.
Governed intelligence
How a question becomes a number you can audit.
Scroll through the four steps. Every frame is the real shape of the data at that step, with demo figures.
1 · The request
A plain-English question from the Business Intelligence page. Suggestion chips cover the questions founders ask most; anything else is fair game.
2 · The model proposes a plan
The private model receives the request and the governed vocabulary — measure names, dimensions, the chart of accounts — and returns a semantic plan. Three tools stop it inventing accounts, fields or dates.
3 · core-api validates
Every measure, dimension and period is checked against the semantic registry: 26 cubes, 124 measures, 756 dimensions. Unknown fields fail closed. The tenant is bound from the session, never from the model.
4 · The engine answers
Cube executes the validated plan on the canonical store and returns rows, totals and the plan. Save it, schedule it, pin it to a dashboard — or drill to the ledger rows.
Separation of powers
What proposes, what validates, what computes, who approves.
The model proposes
Reads the request and the governed vocabulary; returns a semantic plan or a categorization suggestion with a confidence.
Never reads raw ledger rows. Never calls a connector.
The platform validates
Checks every measure, dimension and period against the registry; binds the tenant from the session; fails closed on anything unknown.
Never trusts a field the model invented. Never widens a tenant boundary.
The engine calculates
Executes the validated plan on the canonical store and returns rows, totals and the plan that produced them.
Never computes outside governed measures. Never returns a figure without its rows.
A human approves
Accepts, edits, splits or rejects; approves export batches to the ledger. Every decision is reversible and audited.
Nothing irreversible happens without this step.
Three-tier classification
The model is the last resort, not the first guess.
Categorization runs exact history first, similarity second, and asks the model only to disambiguate — with the chart of accounts as a tool so it cannot invent an account. Every accepted line becomes history for the next two tiers.
The normalized description matches a line you categorized before. Amount-aware: if two histories match, the closest amount wins.
Weighted token similarity against your tenant's history, with an amount tie-break when two candidates are near-equal.
Only when tiers 1–2 are unsure: the description plus the top 5 candidates go to the Finanly model to disambiguate. It picks; it does not invent accounts.
Data architecture
One canonical model, one ledger of record.
Finanly keeps its own normalized store for every source and every workflow, and posts double-entry results to a ledger of record through a connector. Both sides are checked against each other.
Canonical Postgres store
Accounts, transactions, invoices and lines, parties, products, shipments, payouts, disputes, GL entries. Row-level security on every tenant table; the application filters by tenant too — two layers, not one.
ERPNext as ledger of record
Postings, invoices, parties and stock live in a real double-entry ledger. Finanly is the surface and the brain; it does not pretend to be an independent ledger yet.
Parity, not trust
Balance sheet, P&L and trial balance are re-derived from the canonical store and compared with the ledger every hour. Drift is a visible gate, not a silent assumption.
Semantic layer (Cube)
Measures and dimensions are defined once and used by statements, Report Studio, dashboards and the model. The number agrees everywhere because it is computed in one place.
Jobs and schedules
Celery workers and a beat schedule: nightly sync, webhooks, backfills with explicit ranges, exports, report runs, parity checks, dispute tracking.
Append-only audit
A database trigger rejects updates and deletes on audit_events. Every irreversible action writes who, what, when and its idempotency key.
The model layer, honestly
What serves today. What is in development.
Production runs an open-weights language model privately on your hardware behind the internal gateway. Finanly's own finance-tuned model is in development and will drop into the same gateway — the plan-validate-execute contract around it does not change.
- Serving today
- An open-weights language model, hosted privately on your hardware behind the internal gateway
- In development
- Finanly's own finance-tuned model (ledgers, chart-of-accounts vocabulary, reconciliation patterns, statements); drops into the same gateway
- Input
- Natural language — ask the way you would ask your controller — plus the governed vocabulary as tools
- Output
- Semantic plans (validated by core-api), categorization suggestions, narrative over computed figures
- Runtime
- Your own hardware; internal network only
- Reachability
- Called by core-api with a short-lived, tenant-scoped JWT
- Tools
- get_chart_of_accounts · get_cube_measures · resolve_period
- Web
- Self-hosted search for vendor enrichment lookups — search, not inference
Security controls
Concrete controls, not badges.
The short list. The full treatment — deployment model, data handling, certification status — is on the security page.
Tenant isolation
Postgres row-level security on every tenant table, forced for the application role; tenant context set per request from the session.
Secrets
Connector credentials encrypted with AES-GCM; associated data binds each ciphertext to its tenant and key so it cannot be swapped.
Audit & idempotency
Append-only audit events; Idempotency-Key required on side-effect endpoints; replays return the stored response, changed payloads are rejected.
Private network
Only the edge, UI and core-api are exposed. Connectors, the model gateway, workers and the compliance engine have no host ports.
Roles & entitlements
Memberships carry roles per company; every feature is a registered key checked at the endpoint and in the UI; plans assign them.
Certification status
Not SOC 2 certified. Controls are in place and documented; certification is on the roadmap. We say it plainly.
FAQ
Straight answers
What happens when a question can't be answered?
Unsupported or ambiguous requests receive an explanation or a supported, clearly scoped alternative. Available answers depend on the current measures, source coverage and reviewed definitions; missing data is not a guessed zero.
Where does the model run?
On the same host as the stack, behind an internal-only gateway with no host port. core-api calls it with a short-lived token bound to one tenant. Nothing is sent to a public AI API.
Which model is it?
Today an open-weights general-purpose model; Finanly's own finance-tuned model is in development. We name the exact model in conversation rather than in marketing copy.
Is the semantic layer the same for every surface?
Yes. Statements, Report Studio, dashboards and the model all plan against the same cubes and measures, so a number does not change depending on where you look at it.
How is a company kept apart from another?
Row-level security in Postgres enforces tenant isolation underneath the application; the application also filters explicitly. Secrets are encrypted per tenant. The model sees one tenant per call.
What is idempotent, exactly?
Every side-effect endpoint — categorize, export, sync, revalue — requires an Idempotency-Key. A replay returns the stored response; the ledger connector uses the same key so a posting is created once; a changed payload under the same key is rejected.
What are the known limits?
Financial meanings depend on reviewed definitions and source coverage. Missing cost or history can make margins and duration metrics unavailable. Complex AI questions can take tens of seconds; a successful example is not a guarantee for every question.
