Financial transaction categorisation your auditor can follow.

Plain-text .fin rules. Same input, same output, every time. Every match names the rule that produced it and the audit reason behind it — from a hundred-row spreadsheet to a 20-million-row integrity check.

$pip install finlang
See Workbench
No network calls in the engineRule-attributed audit trailSHA-256 verify
youtube.com / FinLangHQ · Deterministic financial categorisation
Overview
What is FinLang? Transaction categorisation you can explain
Product loop · four beats

Read, categorise, audit, reconcile.

The four moves a FinLang run makes — the same loop the docs describe, the same loop a regulated workflow expects.

Beat 01 · Read

Read your data and your rules.

Bank CSV in. Plain-text rules in. Human-readable and Git-friendly — your finance team can read them, own them, version them. Locale-aware: US, UK, EU, Commonwealth.

rule "GROCERIES: Tesco" { match: counterparty ~ "*TESCO*" set: category = "Groceries"}
Beat 02 · Categorise

Categorise deterministically.

Rules apply top-to-bottom. Last matching rule sets the category; flags accumulate as the engine moves through the row. No ML, no randomness, no network calls.

$ finlang \ --input bank.csv \ --rules my_rules.fin \ --output out.csv
Beat 03 · Audit + verify

Audit and verify integrity.

Every decision logged with the rule that fired and the matched condition. SHA-256 fingerprints over the immutable fields before and after the engine, compared field-by-field.

--audit audit.json --audit-mode full --verify-full --verify-output-dir verify/
Beat 04 · Reconcile

Reconcile against your ML pipeline.

Run FinLang against the same raw data your ML system processes. Every disagreement is flagged with the FinLang rule that fired. Your ML pipeline keeps running as-is.

--reconcile ml_output.csv --reconcile-key date,amount --reconcile-html # row-level CSVs + orphans, # self-contained HTML to archive
Validation

Evidence, not promises.

The supporting record — what shipped, what's been verified, what the engine can produce in front of a regulator or model-risk reviewer.

Test suite
204tests
Across 10 gates, plus 43 API and 27 Workbench tests — every release runs this gate.
Verified rows
20M
Verified field-by-field across three runs, zero mismatches.
Throughput · integrity harness
217Krows/s
FastIO backend, integrity harness. Standard backend ~180K rows/s.
Release pipeline
PyPI
Cleanroom validation — every release re-installs from PyPI in a fresh venv and re-runs a smoke gate.
Verify shows the engine didn't corrupt the data. Reconcile gives the categorisation an independent challenge. Audit names the rule behind every decision. The three feed the same evidence chain a regulated workflow expects.
Workbench · new in v0.9

Your rules. On screen.

Point it at your CSV. Build rules in plain English and see the engine read them back. Tick what you want checked (verify, or reconcile against a model's output), and every match names the rule that decided it. It runs on your machine, served from 127.0.0.1; nothing leaves it. Every run also shows the equivalent command, so anything you click, you can script.

The FinLang Workbench Run screen: key results with each match naming the rule that decided it, and 8 rows left uncategorised.
The Run screen. Eight rows sit uncategorised — no rule matched them, so none is claimed.
terminal · workbench
$ pip install finlang
$ finlang-ui

→ serving http://127.0.0.1:8484/ui/
Integrate · four ways in, one engine

Four ways in. One engine.

No second engine. No drift. Same deterministic rules, same audit trail — whichever way you reach it.

01 · Workbench · point and click

Point and click, on your machine.

The whole loop on screen — rules, run, results — served from 127.0.0.1. Every run shows the equivalent command, so anything you click, you can script.

terminal · workbench
$ pip install finlang
$ finlang-ui

→ opens 127.0.0.1:8484/ui/
02 · CLI · batch

Categorise a CSV in one line.

Runs locally, no network. The original batch-processing path — hard-won enterprise-harness throughput, audit trail by default.

terminal · cli
# 1. install from PyPI
$ pip install finlang

# 2. v0.7.7 benchmark, 5M × 50
$ finlang \
    --input bank.csv \
    --rules my_rules.fin \
    --output categorised.csv \
    --audit audit.json \
    --audit-mode full --fastio

→ read  5,000,000 rows     [OK]
→ apply rules                 [OK]
→ write categorised.csv        [OK]
→ audit · full                [OK]
→ time ~3m · ~28K rows/s
03 · Python · pipeline

Drive the engine from Python workflows.

Same engine, called from your Python data pipeline. Subprocess-isolated and deterministic — the same execution path the HTTP wrapper uses.

python · pipeline
import subprocess
import sys

subprocess.run([
    sys.executable, "-m", "finlang.cli.run_finlang",
    "--input", "bank.csv",
    "--rules", "my_rules.fin",
    "--output", "categorised.csv",
    "--audit", "audit.json",
    "--audit-mode", "full",
], check=True)
04 · HTTP API · service

Run the FinLang HTTP wrapper inside your own infrastructure.

Runs where your data lives — local machine, your VPC, or controlled internal environment. No hosted endpoint, by design.

http · self-host
$ pip install finlang
$ finlang-api    # starts on 127.0.0.1:8000

$ curl -X POST \
    http://127.0.0.1:8000/process \
    -F "input_csv=@bank.csv" \
    -F "rules=@my_rules.fin"
Compare · labels you already have

Already categorising transactions?

Compare those labels with rules your team owns and review the differences.

15 rows13 agree2 to review
  1. Your dataSHELL TRADING INTERNATIONAL2026-01-15 · −245,000.00
    Where the labels differYour modelUtilitiesFinLangEnergy & Commodities
    The rule that decidedEnergy: Shellcounterparty ~ "*SHELL*"
  2. Your dataCAYMAN ISLANDS TRUST2026-01-18 · −250,000.00
    Where the labels differYour modelTreasury OperationsFinLangCompliance: Offshore Jurisdictions
    The rule that decidedCompliance: Offshore Jurisdictionscounterparty ~ "*CAYMAN*"

FinLang explains its own output; it does not reveal a provider's hidden reasoning or, by itself, validate a lending decision.

Real output from finlang 0.9.1 on the public example files. The full reconcile report, including orphan rows, is below.

Demo · real output

The reconcile report a review can archive.

Real output from finlang --reconcile --reconcile-key --reconcile-html against an ML pipeline's output. Key alignment matches by content, not row position — so alongside disagreements it lists rows in the ML output that FinLang did not produce, and rows FinLang produced that the ML output lacks. Self-contained HTML, prints to PDF, archives cleanly.

reconcile_report.html · finlang 0.8.0

FinLang Reconciliation — out.csv ↔ ml_output.csv

2026-06-30T11:08:14Z · key:date,amount,counterparty alignment · field: category · finlang 0.8.0 · audit_entries_loaded=12 · orphans: 1 FinLang / 1 ML
Status: REVIEW REQUIRED9/11 match (81.82%) · 2 mismatches · 2 orphan rows · perfect_match=false
Key-matched
11
Agreed
9
Mismatched
2
Orphans
2
#
Counterparty
ML says
FinLang says
Rule matched
01
SHELL TRADING INTERNATIONAL
−245,000.00 · 2026-03-02 · "Q1 gas supply"
Utilities
Energy & Commodities
Energy: Shell
counterparty ~ "*SHELL*"
02
CAYMAN ISLANDS TRUST
−250,000.00 · 2026-03-03 · "Investment management fee"
Treasury Operations
Compliance: Offshore Jurisdictions
Compliance: Offshore
counterparty ~ "*CAYMAN*"
Orphans — FinLang rows with no ML match (1)
Rows FinLang categorised that the ML output does not contain — dropped, unscored, or filtered upstream.
#
Counterparty
Date
Amount
Category
06
HSBC TREASURY DESK
"FX settlement GBPUSD"
2026-03-07
−1,200,000.00
Treasury Operations
Orphans — ML rows with no FinLang match (1)
Rows in the ML output that FinLang did not produce — for example duplicated or mis-keyed upstream.
#
Counterparty
Date
Amount
Category
12
BARCLAYS MERCHANT SVCS
2026-03-15
−990.00
Bank Charges
Verbatim output from a v0.8.0 key-mode reconcile run · 2026-06-30
Preview · before you ship

Change a rule without flying blind.

Run your data through your current rules and a proposed change, and see exactly what moves — which transactions re-categorise, the indicative amount that shifts, and which changes are real behaviour versus a rule rename with no effect. Preview the blast radius before it ships, not after the quarter's numbers are wrong.

impact_report.html · finlang 0.8.0

FinLang Impact Analysis — baseline.fin → candidate.fin

2026-06-30T11:08:15Z · two-pass · field: category · finlang 0.8.0 · 12 rows compared · writes no categorised output
Status: REVIEW REQUIRED2 behavioural · 1 attribution-only · 9 stable (75%)
Rows compared
12
Behavioural
2
Attribution-only
1
Stable
9
#
Counterparty
Change
Indicative £
Class
04
BRITISH GAS BUSINESS
−4,200.00 · 2026-03-05 · "Office utilities"
Utilities → Energy
Utilities: Gas → Energy: Gas
£4,200
behavioural
12
VODAFONE BUSINESS
−1,890.00 · 2026-03-13 · "Telecoms line rental"
Utilities → Telecoms
Utilities: Telecoms → Telecoms
£1,890
behavioural
07
TESCO STORES 4471
−310.50 · 2026-03-08 · "Staff catering"
Staff & Catering → Staff & Catering
Catering: Retail → Hospitality: Retail
—
attribution-only
Verbatim output from a v0.8.0 impact run · 2026-06-30
For institutional buyers

An independent validation layer for ML-driven finance.

For finance teams operating ML-driven categorisation pipelines under regulatory scrutiny — banking, insurance, fund administration, wealth management. FinLang sits as an independent challenge layer beside your existing model, producing rule-attributed disagreement evidence that can support SR 26-2 / EU AI Act-style validation workflows.

SR 26-2 is US banking guidance from the Federal Reserve, OCC and FDIC (April 2026). It is non-binding, expected to be most relevant to banking organisations with over $30bn in total assets, and it places deterministic rule-based processes outside its definition of a model. So your ML system may be in scope; FinLang, as a rule-based engine, is the challenger beside it. It is not a UK requirement.

For ML teams that need an independent audit alongside categorisation — embed via Python or self-host the API inside your pipeline.

Early Access Programme · open

Help shape the FinLang DSL.

We're inviting a small number of organisations into an Early Access programme where teams can help shape the FinLang DSL and contribute rulepack patterns.

What you get
  • 6 months free Team licence
  • Priority support
  • Direct input on the roadmap
  • Early access to commercial rulepacks
  • Optional: co-authored case study
Who it's for
  • Fintech platforms
  • Accounting & reconciliation vendors
  • Banks and compliance teams
  • Data teams building finance automation
What we ask
  • 30-minute feedback session each month
  • Real-world usage insights
  • (Optional) workflow review

No IP transfer. No revenue sharing. Just early access in exchange for real-world feedback.

Apply to the programme