aeoi
Open toolkit for Automatic Exchange of Information reporting: CRS (OECD XML Schema 2.0 and 3.0), CARF (1.5) and, later, FATCA. Swiss ESTV AIA portal first; other portals as rule packs.
Status: pre-alpha, week 2. What exists today:
-
Typed Python models generated from the pinned OECD XSDs (
src/aeoi/schemas/): CRS 2.0, CRS 3.0, CRS Status Message 2.0, CARF 1.5, CARF Status Message 1.1. Regenerate withpython tools/generate_models.py. -
Flat input format (
docs/FLAT-FORMAT.md): an Excel workbook or CSV folder with the sheets ReportingFI, Accounts, ControllingPersons, Payments; generated template with drop-downs and aCodessheet (aeoi crs template). -
Domain model and checks (
aeoi.crs.model): every 3.0 field, version-aware validation with talking errors (location + ESTV rule number) for both 2.0 and 3.0. -
Builder (
aeoi.crs.build): domain -> CRS XML 2.0 or 3.0, valid against the OECD XSD; 3.0 written inurn:oecd:ties:crs:v3only; ESTV header rules (5.3.2) applied. -
ESTV transfer package (
aeoi.estv.packaging):CRS_Payload.xml-> zip -> AES-256-CBC -> RSA PKCS#1 v1.5 key blob ->CRS_Payload+CRS_KEYzip, with the 100 MB / 10 MB limits and theTest*.ziprule (Technische Wegleitung AIA, Ziffer 3.3.1 and 4.1.1). -
ESTV identifiers and character set (
aeoi.estv.ids): MessageRefId, DocRefId, Anhang 7.2. -
Test corpus: the five annex examples of the Technische Wegleitung (2.0), validated against the OECD schema and round-tripped through the models; a complete 3.0 example built by construction.
-
Rule engine: 59 of the 65 ESTV rules enforced before the file leaves the machine (
docs/ESTV-RULES.md), partner states by year from the pinned SIF list, IBAN/ISIN checksums. -
Submission registry (
aeoi.registry, SQLite on the FI's machine) and workflow (aeoi.crs.submit): new messages, corrections (OECD2), deletions (OECD3), correction chains, nil reports, outcomes;aeoi crs correct,aeoi crs registry,aeoi estv status --registry. -
Outcome parser (
aeoi.estv.status): OECD CRS Status Message 2.0 or pasted portal text, every code explained from the catalogue. -
Validator for any file (
aeoi crs validate report.xml): schema, header and DocSpec rules, character set, content rules - for XML produced by this or another tool, 2.0 and 3.0. -
German user pages for reporting FIs and fiduciaries:
docs/de/ANLEITUNG.md,docs/de/WAS-AENDERT-SICH-MIT-3.0.mdand the one-pagedocs/de/KURZFASSUNG.mdfor associations, the latter also in Italian (docs/it/RIASSUNTO.md) and French (docs/fr/RESUME.md), quoting the official editions of the ESTV guidance in those languages.
Not yet: the pilot's first test upload (needs a registered FI), CARF.
Why
From 1 January 2027 the amended CRS applies and every reporting financial institution must use the OECD CRS XML Schema 3.0 (ESTV: 2.0 accepted until 14.12.2026, only 3.0 from 16.01.2027). There is no open implementation of CRS, CARF or FATCA reporting; the closed ones are priced per named user.
Quick start (development)
python -m venv .venv
.venv/Scripts/python -m pip install -e ".[dev]"
.venv/Scripts/python -m pytest
From an Excel workbook to an ESTV test package (public key: ESTV-PublicKey.pem from the AIA
application):
aeoi crs template --out template.xlsx # empty template (add --example for invented data)
aeoi crs check --input filled.xlsx --version 3.0
aeoi crs build --input filled.xlsx --version 3.0 --out report.xml --test --key ESTV-PublicKey.pem --package Test-report.zip
aeoi estv inspect Test-report.zip --key ESTV-PublicKey.pem --test
Until 14.12.2026 the ESTV accepts only schema 2.0 (--version 2.0); from 16.01.2027 only 3.0.
With a registry (recommended: it is what makes corrections possible):
aeoi crs build --input filled.xlsx --version 3.0 --out m1.xml --registry fi.sqlite
aeoi estv status outcome.txt --registry fi.sqlite --message CH2026CH... # after the portal answered
aeoi crs correct --input fixed.xlsx --version 3.0 --out m2.xml --registry fi.sqlite --cancel A7
aeoi crs registry --registry fi.sqlite
The registry file contains the account data needed to build deletions: keep it next to the workbook, back it up, never send it.
Browser validator
Online at https://aeoi-com.github.io/aeoi/ once GitHub Pages is enabled.
web/index.html is a static page that runs the validator in the browser with Pyodide: drop a
CRS XML file or a filled workbook and get the same checks as aeoi crs validate / aeoi crs check,
rendered as a verdict card, an overview of the message (holders, residence countries, balances)
and one card per finding with a title and a remedy in German, French or Italian
(src/aeoi/estv/rule_titles.json), the technical message and the official ESTV wording behind
a disclosure. Built-in samples, report download, light/dark theme, self-hosted Inter font.
Everything the page needs - the Pyodide runtime, the packages, the wheels, the fonts - is served
from the page's own origin (tools/build_web.py vendors it; nothing else is ever contacted), a
service worker keeps it available offline after the first visit, and the page can be installed
as an app from the browser.
The page also runs the whole reporting flow without an installation: download the empty
template, check the filled workbook, open or create the registry file (the state - on Chrome
and Edge it is rewritten in place through the File System Access API, elsewhere it is downloaded
after every change), choose the ESTV public key once (remembered in the registry), build the
message(s) the registry implies (new records, corrections, deletions - aeoi.crs.workflow),
download the encrypted package for the AIA portal, and record the portal's answer. Productive
messages need an open registry; test messages do not.
The file never leaves the browser; the page has no analytics and no server side. Build it with
python -m build && python tools/build_web.py (downloads the runtime once into .local/vendor-cache); node tools/web_smoke.mjs runs the same code
headlessly (see the script header for the one-time Pyodide setup);
PW_CHANNEL=chrome node tools/web_browser_test.mjs drives the real page in an installed Chrome
or Edge with the page's Content-Security-Policy enforced and asserts that no request leaves the
browser after the file selection. CI publishes the page to GitHub Pages once Pages is enabled
for the repository.
Sources
All schemas and guidance documents are pinned with SHA-256 in docs/SOURCES.md. Open questions for the pilot institution are in docs/OPEN-QUESTIONS.md.
Data protection
The toolkit runs on the reporting institution's machine. No account-holder data leaves it; the browser validator runs client-side with no analytics and no server-side logs.
Licence
Apache-2.0. Contributions require a Developer Certificate of Origin sign-off (git commit -s).
Metadata
Release files for aeoi 0.0.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 | Provenance | |
|---|---|---|---|---|
| aeoi-0.0.1.tar.gz | 497.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aeoi-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 705.9 kB
Release files / aeoi-0.0.1.tar.gz
| Download URL | aeoi-0.0.1.tar.gz |
|---|---|
| Size | 497.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0064ca3a055488c0a86c9a7658b05409bb9cd8d5165704f08b340a793e4f7d10
|
|
BLAKE2b-256 checksum How to use checksums |
a143df0a5c9719832d952a098e6995258eb21dad15219f5f43ab288106849eca
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / aeoi-0.0.1-py3-none-any.whl
| Download URL | aeoi-0.0.1-py3-none-any.whl |
|---|---|
| Size | 208.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
03c6f659a5fcb03ee5c0ae476582e2a15d7837a93f664cf323b8844786162b5b
|
|
BLAKE2b-256 checksum How to use checksums |
f8cdd9b7df636866c63a0cd446fe8ab503103dcae1abbdac98bf82d5062a4337
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logSecurity for aeoi 0.0.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for aeoi-0.0.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.