# ⚙️ AIR ### The Language of Accounting **LLVM for the ledger** — LLMs understand your documents, a deterministic compiler keeps your books. [![CI](https://github.com/spboucher-ai/air/actions/workflows/ci.yml/badge.svg)](https://github.com/spboucher-ai/air/actions/workflows/ci.yml) [![Python](https://img.shields.io/badge/python-3.11%2B-3776AB?logo=python&logoColor=white)](pyproject.toml) [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE) [![Tests](https://img.shields.io/badge/tests-99%20offline%20%2B%202%20live-brightgreen)](tests/) [![Golden cases](https://img.shields.io/badge/golden%20cases-21-gold)](tests/golden/cases/) [![Amounts](https://img.shields.io/badge/floats-forbidden-red)](docs/adr/0003-monetary-amounts.md) [![Double entry](https://img.shields.io/badge/A%20%3D%20L%20%2B%20E-verified%20after%20every%20pass-blueviolet)](core/invariant.py) [![Ledger](https://img.shields.io/badge/ledger-append--only%20%7C%20hash--chained-orange)](kernel/ledger.py) [![Offline first](https://img.shields.io/badge/works%20offline-no%20ERP%2C%20no%20API%20key%20required-informational)](docs/cli-reference.md) *by [Simon-Pierre Boucher](mailto:contact@spboucher.ai)*
--- ## The idea Every ERP reinvents the same accounting model. LLMs are brilliant at *understanding* ("this invoice = 3 chairs paid by Visa") and unreliable at *applying* hundreds of tax and accounting rules. **AIR separates the two** — exactly like LLVM separated language frontends from machine backends: ```mermaid flowchart LR A[📄 Invoice / Email
Bank / POS / API] --> B["🧠 LLM
understanding"] B -->|"AIR events
(never journal entries)"| C["⚙️ AIC Compiler
deterministic rules"] P["📜 ALSL Policies
taxes · thresholds · rounding
versioned & cited"] --> C C -->|"balanced entries
+ full provenance"| D["📗 Native Ledger
hash-chained, standalone"] C --> E["📤 CSV · QuickBooks
Xero · Odoo · SAP*"] D --> F["📊 Trial balance · Balance sheet
Income statement · GL"] style B fill:#f9e79f,stroke:#b7950b style C fill:#aed6f1,stroke:#2471a3 style D fill:#a9dfbf,stroke:#1e8449 style P fill:#f5b7b1,stroke:#c0392b ``` > **The one rule that never bends:** an LLM (or any frontend) only ever produces > **AIR** — a description of *what happened economically*. It never writes a journal > entry, an account code, or a debit. The compiler does that, deterministically, > with the double-entry invariant `Assets = Liabilities + Equity` verified after > **every** pass and clang-style diagnostics when anything is wrong. ## What you get | | | |---|---| | 🗣️ **A universal language** | `EconomicEvent` (REA-based): sales, purchases, refunds, payments, FX — perspective-neutral, schema-validated, no debits anywhere | | ⚙️ **A real compiler** | Pass pipeline (validation → classification → tax → FX → posting), pass manager with verify-after-every-pass, diagnostics with location + cause + `help:` fix | | 📜 **Rules as data (ALSL)** | GST 5%, QST 9.975%, HST, capitalization thresholds, rounding modes — all in versioned YAML policy sets with **mandatory source citations** (the loader rejects uncited rates) | | 🏠 **Standalone books** | No ERP required: managed AIR home with an append-only, tamper-evident ledger, content-addressed document archive, and all financial statements in text/markdown/CSV/JSON | | 🔁 **Git-style corrections** | Changed invoice? `air recompile` diffs by content fingerprint and posts reversal + replacement entries — history is never edited | | 🤖 **An agent SDK** | AI agents get syscalls (`CreateEconomicEvent`, `Post`, `Reverse`, `ClosePeriod`, `Merge`, `Reconcile`…) — never the ledger. Every call, including refusals, lands in a hash-chained audit log | | 🧾 **LLM ingestion** | Invoice text → Claude (structured outputs) → schema-validated AIR → confidence routing → human approval inbox. Fully offline mock for tests | | 🚀 **Optimizations** | 50 identical payments → 1 batch entry (fusion), refund↔sale netting, duplicate detection — provenance preserved through every transformation | | 🏦 **Bank reconciliation** | camt.053 + MT940 (with statement integrity check) + CSV → matched against the books, differences reported on both sides | | 🔍 **Total traceability** | Every posted cent walks back through the provenance graph (accounting SSA) to its source event, document, OCR/LLM confidence, policy version, and rounding mode | ## Quickstart ```bash git clone https://github.com/spboucher-ai/air && cd air python3 -m venv .venv && .venv/bin/pip install -e ".[dev]" source .venv/bin/activate # 1) Your books live in a managed AIR home — one command air init --home books --policies alsl/policies/ca-qc-2026.yaml # 2) Compile economic events into the books (document archived, ledger chained) air compile tests/fixtures/demo_document.yaml --home books \ --report trial-balance --report balance-sheet # 3) A source invoice was corrected? Post only the delta (reversal + replacement) air recompile old.yaml corrected.yaml --home books # 4) Statements any time, any format air report income-statement --home books --format markdown # 5) Ingest a real document (offline extractor; add --llm for Claude) air ingest tests/fixtures/invoice_high_confidence.txt --home books air inbox --home books # 6) Month end air reconcile statement.mt940 --home books air audit --home books ``` Full command reference: **[docs/cli-reference.md](docs/cli-reference.md)** ## Sixty seconds of AIR An economic event — *what happened*, nothing else: ```yaml events: - id: evt_01H8XGJWBW type: Sale date: 2026-07-20 parties: {seller: "company:acme", buyer: "customer:cust_123"} items: - {sku: chair-std, qty: "3", unit_price: {amount: "333.33", currency: CAD}} payment: {method: card.visa, immediate: true} tax: {jurisdiction: CA-QC} # ← where. Rates live in policies, never here ``` The compiler applies the cited CA-QC policy set (GST 5%, QST 9.975% on the pre-GST price, half-up per Excise Tax Act s.165.2(2)) and emits a balanced entry: ``` DR 1000 Cash 1149.74 CR 4000 Sales revenue 999.99 CR 2310 GST payable 50.00 tax:GST@0.05~half_up CR 2320 QST payable 99.75 tax:QST@0.09975~half_up ``` Same input + same policies = **byte-identical output, always** (property-tested, and CI compiles the demo twice and `diff`s the results). When something is wrong, you get a compiler error, not a wrong number: ``` error[AIR-E400]: no tax policy in set 'ca-qc' matches jurisdiction 'CA-BC' --> event evt_x, field tax.jurisdiction pass: tax help: add an ALSL tax policy for this jurisdiction or mark the event tax.exempt: true ``` ## Agents keep books through syscalls — and only syscalls ```python from sdk.syscalls import AirKernel k = AirKernel("books", actor="agent:alice") k.create_economic_event({...}) # schema-validated draft k.post() # deterministic compile → books (idempotent) k.reverse("je_evt_x") # corrections are contra entries, never edits k.close_period("2026-01") # posting into it now fails with AIR-E700 k.merge() # post with netting + payment fusion k.reconcile("statement.mt940") # bank matching ``` ``` $ air audit --home books #0000 OK agent:alice CreateEconomicEvent {"event_id": "evt_x", "type": "Sale"} #0001 OK agent:alice Post {"drafts": 1} #0008 ERR agent:alice Post {"drafts": 1} <- error[AIR-E700]: period 2026-01 is closed 10 syscalls, hash chain VALID ``` Refused actions are audited like successful ones. Editing any record breaks the chain. ## The seven guarantees 1. **Determinism** — no LLM, network, or clock inside the compiler. 2. **Double entry** — the invariant is verified after *every* pass; violations abort compilation. 3. **Traceability** — provenance graph from every posted line to its source (accounting SSA). 4. **No floats** — exact decimals end to end; floats rejected at every boundary. 5. **No rules in code** — every rate/threshold lives in cited, versioned ALSL policies. 6. **Append-only** — reversals, never edits; ledger and audit log are hash-chained. 7. **Human in the loop** — low-confidence or schema-invalid extractions always route to a person. ## Repository map | Path | Role | LLVM analogy | |---|---|---| | [`schemas/`](schemas/) | AIR JSON Schema | the IR definition | | [`core/`](core/) | events, Money, provenance, invariants | IR + verifier | | [`aic/`](aic/) | pass manager, passes, diagnostics, incremental | opt/llc | | [`alsl/`](alsl/) | rule language + cited policy sets | TableGen | | [`backends/`](backends/) | native, CSV, QuickBooks (offline-tested) | targets | | [`kernel/`](kernel/) | ledger, reporting, workspace, audit, reconciliation | runtime | | [`sdk/`](sdk/) | CLI, agent syscalls, demo agent | libclang | | [`ingestion/`](ingestion/) | extractors, confidence routing, approval queue | frontend | | [`docs/spec/`](docs/spec/) | **the AIR/ALSL specification** | LangRef | | [`docs/adr/`](docs/adr/) | architecture decision records | — | | [`docs/research/`](docs/research/) | 9 cited research reports (tax law, formats, APIs) | — | | [`tests/`](tests/) | golden cases, property tests, unit + live tests | lit | ## Documentation - 📖 **[The AIR Specification](docs/spec/air-spec-v0.1.md)** — the language, the compiler, diagnostics, syscalls, reconciliation - 🧭 **[CLI Reference](docs/cli-reference.md)** — every command with examples - 🏛️ **[ADRs](docs/adr/)** — why Python, why REA events, why rounding is policy - 🔬 **[Research](docs/research/)** — GST/QST from official sources, camt.053/MT940 specs, ERP API surveys, LLVM architecture lessons - 🤝 **[Contributing](CONTRIBUTING.md)** — the non-negotiable rules CI enforces ## Development ```bash .venv/bin/python -m pytest tests/ -q --ignore=tests/test_llm_live.py # 99 tests, fully offline python3 scripts/check_headers.py # author-header gate # opt-in live LLM tests (cost a few cents) ANTHROPIC_API_KEY=sk-ant-... .venv/bin/python -m pytest tests/test_llm_live.py -v ``` Everything — including the QuickBooks backend and the LLM ingestion — develops and tests **fully offline**: mock transports simulate the real APIs' documented behaviors (idempotency replay, duplicate errors), so no account or key is ever required to work on AIR. ## Roadmap - [x] Phases 0–6: research → core → compiler → backends → ingestion → agent SDK → optimizations & reconciliation *(complete)* - [ ] beancount/hledger export backend - [ ] Xero & Odoo backends (offline mock pattern) - [ ] Reference-first bank matching (`EndToEndId`) - [ ] More jurisdictions as cited ALSL policy sets (US sales tax, EU VAT) - [ ] AIR v0.2: REA commitments (pending deliveries, IFRS 15 performance obligations) ---
**AIR** — *because your books deserve a compiler.* MIT © 2026 [Simon-Pierre Boucher](mailto:contact@spboucher.ai)