FinLang — The Financial Rules Engine
Deterministic. Auditable. Global.
Designed for explainable processing in regulated environments.
🌐 Overview
FinLang is a domain-specific language (DSL) and vectorised CLI engine for financial transaction processing.
It replaces opaque machine-learning categorization with transparent, deterministic rules — delivering explainability, auditability, and global compatibility.
Built for audit-friendly logic and deterministic processing.
A deterministic alternative where explainability and reproducibility matter.
What this is for
FinLang is a deterministic rules engine for financial transaction categorisation.
It is especially useful as a challenge layer alongside ML categorisers: the --reconcile workflow compares FinLang's rule-attributed output against an external classification, row by row.
Same input + same rules = reproducible output, with rule-attributed audit trails.
The v0.7.9 FastAPI wrapper makes the same engine reachable over a self-hosted HTTP surface for service/integration workflows; the v0.9.0 Workbench puts it in a local browser.
Four surfaces. One engine:
- Workbench — a local browser interface via
finlang-ui(served from127.0.0.1only) - CLI for batch processing
- Python workflows via subprocess-isolated CLI execution
- Self-hosted HTTP wrapper via
finlang-api
📝 The FinLang DSL
FinLang rules are human-readable, Git-friendly, and designed for precision.
The engine processes rules top-to-bottom; the last matching rule sets the category, while flags accumulate.
# Example: Basic categorization and flagging
rule "GROCERIES: Tesco" {
match:
- counterparty ~ "*TESCO*"
set:
- category = "Groceries"
- flags += "Supermarket"
}
# Example: Numeric range and exact match
rule "TRAVEL: High Value Flight" {
match:
- counterparty == "BRITISH AIRWAYS"
- amount in -5000.00 .. -500.00
set:
- category = "Travel"
- flags += "HighValue"
}
⚙️ Key Features (v0.9.1)
| Feature | Description |
|---|---|
| Deterministic DSL | Human-readable .fin rules language — explainable logic, Git-friendly. |
| Vectorised Engine | Vectorised core (Pandas + NumPy + PyArrow) — ~217K rows/sec FastIO validated throughput on the integrity harness (20M × 6 cols). |
| Dual Backend | Standard (Engine: c) or FastIO (Engine: pyarrow) with automatic fallback. |
| Growth Loop | Automated Discover → Suggest → Categorize workflow — 97.8% average coverage gain across 5 validation runs (source). |
| Global I18n Support | US/UK/EU/Commonwealth formats, £ € $ ¥ ₹ stripping, localized decimals/dates/delimiters. |
| Audit Trail System | Every decision logged (before/after state diffs); stateless for reproducibility. |
| Exclude Marker | Boolean exclude column — rule-driven, auditable, supports blacklist/whitelist exception patterns. |
| CR/DR Semantics | Case-insensitive CR/DR (with or without space), accounting negatives (123.45), trailing minus 123.45-. v0.7.7 fixes a latent bug on no-space CR/DR formats. |
| Amount Synthesis | Auto-computes amount = abs(credit) – abs(debit) across 9 edge cases. |
| Strict Parsing | Locale-aware normalization with configurable thresholds (--strict-parse). |
| Flag Integrity | Append-only (flags +=) with deterministic deduplication. |
| Integrity Verification | Built-in --verify and --verify-full — SHA-256 fingerprinting of immutable fields with optional artifact output; --verify-html (v0.8.3) can render a self-contained plain-English report. See docs/verify.md. |
| ML Reconciliation (v0.7.8) | --reconcile produces a row-by-row mismatch report against an external (typically ML) categorisation, with rule attribution and audit reason. Optional self-contained HTML report via --reconcile-html; the ML side's date convention is inferred from the data (or stated via --reconcile-date-format, v0.8.3) and recorded in the report. See docs/reconciliation.md. |
| FastAPI Wrapper (v0.7.9) | A self-hosted HTTP surface (finlang-api) over the same CLI engine — nine endpoints incl. /process, /reconcile, /impact, /discover, /suggest, /rulepacks, /rules/validate. Subprocess-dispatched (no second engine surface); included in the base install since v0.9.0. 43 standalone integration tests + CLI/API parity contract test. See docs/api.md. |
| Workbench (v0.9.0) | finlang-ui opens a local browser interface over the same engine — pick a CSV and rules, tick verify/reconcile, and get every row back with the rule that decided it, plus a rule builder that reads rules back in plain English. Served from 127.0.0.1 only; every run shows its CLI equivalent. See docs/workbench.md. |
📦 Installation
Requirements: Python 3.10—3.14
From PyPI (Recommended):
pip install finlang
With Fast I/O (PyArrow):
pip install "finlang[fastio]"
(Enables --fastio for accelerated CSV I/O.)
The Workbench (local browser UI):
finlang-ui # serves 127.0.0.1:8484 and opens your browser
(In the base install — no extras needed. See docs/workbench.md.)
HTTP API wrapper:
finlang-api # binds 127.0.0.1:8000 — interactive docs at /docs
(Thin FastAPI wrapper over the CLI for HTTP-based integration and demos. In the base install since v0.9.0 — pip install "finlang[api]" remains valid as a no-op. See docs/api.md.)
From Source (Development):
git clone https://github.com/FinLang-Ltd/finlang.git
cd finlang
pip install -e .[fastio]
🚀 Quick Start — The 5-Step Growth Loop
1️⃣ Initial Categorization
finlang --input transactions.csv --output baseline.csv \
--rules my_rules.fin --include-pack retail,transport
2️⃣ Discover Gaps
finlang-discover --input baseline.csv \
--candidates candidates.csv --all-candidates all_candidates.csv \
--min-count 5
3️⃣ Suggest Rules (Exact Mode Recommended)
finlang-suggest --input candidates.csv --output suggested_rules.fin \
--rules my_rules.fin --emit-match exact
4️⃣ Merge and Re-run
cat my_rules.fin suggested_rules.fin > merged.fin
finlang --input transactions.csv --output improved.csv \
--rules merged.fin --include-pack retail,transport
✅ Expected Result: 5–10% coverage improvement; zero duplicates in exact mode.
📊 Performance Benchmarks (v0.7.7)
Measured with --audit-mode none (max throughput) on Intel i7-12700T, 48GB RAM, Windows 11, Python 3.13.7, PyArrow 21.0.
| Dataset | Test | Time (s) | Rows/sec | Notes |
|---|---|---|---|---|
| 100K (UK Synthetic) | Growth Loop | 2.54 | 39,370 ✅ | Baseline (121 rules) |
| 100K (after Growth Loop) | Growth Loop | 4.96 | 20,161 ✅ | +6.3× rules → ≈ 2× slower (764 rules) |
| 5M × 50 cols | Benchmark Harness | 179.27 | 27,900 ✅ | Enterprise validation, 3-run average |
| 20M × 6 cols | Integrity Test (FastIO) | ~90 | 217,068 ✅ | Engine throughput, full SHA-256 verified |
v0.7.7 improvement: Hot-path bug fix in
_to_numberremoved an unnecessary\bword boundary that was both producing wrong results on no-space CR/DR formats AND costing measurable runtime. The fix delivered +30-50% throughput on the integrity harness vs v0.7.6, taking standard mode to ~180K rows/sec and FastIO to ~217K rows/sec.Cumulative v0.6.4 → v0.7.7: -14% runtime, +16% throughput on the enterprise harness (5M × 50).
Audit Overhead: Enabling
--audit-mode lite/fullreduces throughput by ≈38% due to diff calculation; provides full decision provenance.Note: These figures are validated benchmark results from controlled tests. Actual performance varies depending on dataset, ruleset, and audit mode.
Seedocs/benchmarks.mdfor full details.
🔐 Integrity Verification (v0.7.7+)
SHA-256 fingerprint verification benchmarked on large datasets:
| Rows | Engine (Standard) | Engine (FastIO) | Result |
|---|---|---|---|
| 5M | 178,903 rows/s | 198,448 rows/s | ✅ All fingerprints match |
| 10M | 178,511 rows/s | 214,136 rows/s | ✅ All fingerprints match |
| 20M | 181,566 rows/s | 217,068 rows/s | ✅ All fingerprints match |
What this benchmark validated: Every row's immutable fields (
date,amount,counterparty) were verified via SHA-256 hash before and after engine processing. Zero cross-row contamination detected. Zero data corruption detected. 60M rows verified field-by-field across three runs, zero mismatches.Note: As of v0.7.7, SHA-256 integrity verification is available as a CLI feature via
--verify(fast fingerprint) and--verify-full(fingerprint + field comparison). Use--verify-output-dirto save audit artifacts (JSON report + proof CSV). Seedocs/cli_reference.mdfor details.
🌍 Internationalization Matrix
| Region | Example Number | Date Order | CLI Flags |
|---|---|---|---|
| 🇺🇸 US / 🇨🇦 Canada | 1,234.56 | MM/DD | (defaults) |
| 🇬🇧 UK / 🇦🇺 Commonwealth | 1,234.56 | DD/MM | --dayfirst |
| 🇪🇺 Continental Europe | 1.234,56 | DD/MM | --decimal "," --thousands "." --dayfirst |
| 🇨🇭 Switzerland | 1'234.56 | DD/MM | --thousands "'" --dayfirst |
Auto-Detection and Normalization: BOM-safe UTF-8 encodings, , ; | \t delimiters, and automatic currency symbol stripping.
🧠 The Growth Loop Explained
Discover → Suggest → Categorize → Repeat
FinLang's Growth Loop accelerates rule creation through data-driven discovery.
- Discover uncategorized counterparties
- Suggest new rules in seconds (1:1 mapping in exact mode)
- Merge + Re-run for incremental coverage gains
- Validated Result: 97.8% average coverage gain across 5 runs (source)
📄 See: docs/growth_loop_best_practices.md
🧾 Known Limitations (v0.7.x)
- ⚠️
--emit-match fuzzy(default) filters corporate stopwords (LTD, LLC, PLC, INC, GROUP, COMPANY, CO, SAS, GMBH, CORP) and deduplicates patterns within a batch (v0.7.7). Edge cases with very short counterparty names may still produce broad patterns. → Use--emit-match exactfor production workflows. - ⚠️ Hyphenated/apostrophe names may affect fuzzy matching (< 1% impact).
- ⚠️ No support for non-Gregorian calendars or non-Western numerals.
📘 Documentation
docs/release_notes/v0_9_0.md— the Workbench (finlang-ui), one-install dependencies,/processverify status changedocs/release_notes/v0_7_9.md— FastAPI wrapper (finlang-api), three surfaces / one enginedocs/release_notes/v0_7_8.mddocs/release_notes/v0_7_7.mddocs/release_notes/v0_7_6.mddocs/workbench.md— the Workbench local browser UI (finlang-ui, v0.9.0)docs/reconciliation.md—--reconcileML validation layer (v0.7.8)docs/verify.md—--verifyintegrity verificationdocs/api.md— FastAPI wrapper (finlang-api; base install since v0.9.0)docs/api_reference.md— full API endpoint referencedocs/runtime_contract.mddocs/cli_reference.mddocs/rulepacks.mddocs/benchmarks.mddocs/growth_loop_best_practices.mddocs/amount_synthesis.mddocs/i18n_examples.mddocs/stateless_processing.md
Command-line help:
finlang --help
finlang-discover --help
finlang-suggest --help
🧩 Example CLI Usage
finlang --input bank.csv --output categorized.csv \
--rules examples/rules.demo.fin \
--include-pack retail,transport,subs \
--fastio --audit audit_log.json --audit-mode lite
📜 License & Commercial Use
FinLang is open source under the GNU Affero General Public License (AGPL-3.0).
Commercial licenses and enterprise support are available via FinLang Ltd.
📧 info@finlang.io
🌐 https://finlang.io
Contributing
Contributions are welcome! Before submitting a PR, please review and accept our Contributor Licence Agreement (CLA).
📌 Version Summary
| Component | Version | Validation |
|---|---|---|
| Core Engine | v0.8.3 | Hardening: FINLANG_AUDIT_MAX/audit_max validation; categorisation output unchanged |
| CLI Suite | v0.9.1 | 204 tests across 10 gates (daily); 7-gate full pre-release suite |
| FastAPI Wrapper | v0.9.1 | 43 standalone integration tests + CLI/API parity contract test; /rulepacks + /rules/validate; verify mismatch on /process → HTTP 200 |
| Workbench | v0.9.1 | 17 UI-contract tests + 10 Playwright end-to-end tests (real browser, live server, real CLI) |
| Discover/Suggest | v0.8.2 | 97.8% average coverage gain across 5 validation runs |
| Integrity Test | v0.8.2 | 20M rows verified field-by-field, ~227K rows/sec FastIO on the integrity harness (re-validated 20 Jul 2026) |
| Verify | v0.8.3 | --verify / --verify-full / --verify-html (SHA-256 fingerprint + field comparison + readable report), vectorised — ~570s → ~15s on the 500K full-mode benchmark |
| Reconcile | v0.8.3 | --reconcile / --reconcile-html / --reconcile-date-format (row-by-row mismatch + audit reason; ML date convention inferred and recorded) |
| Cleanroom | v0.9.0 | 5-gate disposable-venv PyPI validation (incl. API surface) |
| CI | v0.9.0 | GitHub Actions matrix: Python 3.10 / 3.11 / 3.12 / 3.13 / 3.14 |
| Docs | v0.9.1 | Coverage across CLI, rule language, API, reconcile, verify, i18n, growth loop |
| Python Support | 3.10—3.14 | Tested across all five versions via CI matrix |
Metadata
Release files for finlang 0.9.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| finlang-0.9.1.tar.gz | 153.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| finlang-0.9.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 323.8 kB
Release files / finlang-0.9.1.tar.gz
| Download URL | finlang-0.9.1.tar.gz |
|---|---|
| Size | 153.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ba1b0e8223e9b350057ff0502551472d40c94f2fad7a6422702c3997b735c746
|
|
BLAKE2b-256 checksum How to use checksums |
8ddecf32608057e03b9a4284e1f536f6f02d68decc12342381be077e8c88fd2e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / finlang-0.9.1-py3-none-any.whl
| Download URL | finlang-0.9.1-py3-none-any.whl |
|---|---|
| Size | 170.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0a74391331ffc6e1251d99884dfd39686477c909fe78e48017e45139553a5a73
|
|
BLAKE2b-256 checksum How to use checksums |
e6633d1b2c35a43b4e9521d9c6c7611148fb3050ab6841e23a6b0730afd8714b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|