easa-erules
Deterministic, local toolkit for EASA Easy Access Rules — built for LLM agents.
Turns the official EAR XML exports (CS-*, AMC, GM) into structured data an agent can quote from. An experimental FAA branch serves 14 CFR through the public eCFR API using the same interface.
- fetch a regulation, or a pinned version, into a local cache
- parse into a canonical Regulation AST (Flat OPC / OOXML, or eCFR XML)
- export Markdown, JSON and HTML
- extract one rule, query with SQLite FTS5, walk cross-references
- validate conversions so nothing is dropped silently
Regulatory text is never rewritten by an LLM during conversion. Conversion is deterministic; models reason on tool output, not on recall.
Every machine-readable result states which publication and amendment it came from, and distinguishes "searched, found nothing" from "never looked" — the usual way an agent pipeline goes quietly wrong.
Install
Requires Python ≥ 3.11.
# PyPI (recommended for users)
pip install easa-erules
# or with uv
uv pip install easa-erules
From source / development:
git clone https://github.com/mrSpringpeace/easa-erules.git
cd easa-erules
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
# or: pip install -e ".[dev]"
Pinned git tag (if PyPI is unavailable):
pip install "git+https://github.com/mrSpringpeace/easa-erules.git@v0.2.0"
Optional MCP server (for agent hosts that speak MCP rather than shell):
pip install "easa-erules[mcp]"
Entry points: easa-erules, easa-erules-mcp.
Disclaimer: Unofficial toolkit, not endorsed by EASA or the FAA. Always verify critical interpretations against the official publication. The MIT licence covers this software only — see
NOTICEfor the attribution and licensing of regulatory text.
Quick start
# Catalog
easa-erules list
easa-erules info vla
# Download latest XML into the cache
easa-erules fetch cs-vla
easa-erules fetch cs-vla --version "Amendment 1"
# Inspect / convert / extract / search / refs
easa-erules inspect cs-vla
easa-erules convert cs-vla -o ./out --split
easa-erules convert ./local.xml -o ./out --format html
easa-erules extract cs-vla CS-VLA.303 --format json
easa-erules query cs-vla "factor of safety" --json
easa-erules refs cs-vla CS-VLA.303 --json
easa-erules validate ./out
# FAA parts work the same way (experimental)
easa-erules fetch far-23
easa-erules extract far-23 "14 CFR 23.2005" --format json
Local path or registry id/alias is accepted for most commands. Use --fetch on convert/extract/query when the id is not cached yet.
Output contract
Every --json result carries the same envelope, so an agent can branch on it
without guessing:
{
"schema_version": "1.0",
"status": "ok",
"source": {"regulation_id": "cs-vla", "amendment": "Amendment 1", "sha256": "…"},
"warnings": [],
"rule": { "…": "…" }
}
status |
exit | Meaning |
|---|---|---|
ok |
0 | Succeeded, results present |
no_match |
0 | Searched, nothing matched |
not_cached |
3 | Not downloaded — run fetch or pass --fetch |
index_missing |
4 | Search index damaged — retry with --rebuild |
fetch_failed |
5 | Download failed |
source_drift |
6 | Landing page no longer matches the catalog entry |
parse_error |
7 | Source could not be parsed |
error |
1 | Unknown id, bad path, everything else |
no_match is not evidence that a requirement does not exist. Amendment and
issue are never silently null: when they cannot be established the field reads
unknown and a warning says so.
Cache layout
~/.cache/easa-erules/ # override: EASA_ERULES_CACHE
cs-vla/
source.xml # latest convenience copy
meta.yaml
search.sqlite # FTS index (built on first query)
versions/<slug>/
source.xml
meta.yaml # sha256, download_url, retrieved_at, …
original.zip
Split convert output
out/
├── index.md
├── metadata.yaml
├── document.json
├── conversion-report.json
├── rules/
│ └── cs-vla-303.md
└── assets/
└── cs-vla-303-fig-01.png
CLI reference
| Command | Purpose |
|---|---|
list |
Built-in regulation catalog |
info |
Metadata + cache presence for an id/alias |
fetch |
Resolve landing page → download XML → cache + integrity |
inspect |
Structure stats, warnings, unknown elements |
convert |
Markdown / JSON / HTML (--split, --format) |
extract |
Single rule (JSON preferred for agents) |
query |
Local FTS5 search (--json, --rebuild) |
refs |
Outgoing / incoming cross-reference graph |
validate |
Check a conversion output directory |
Design principles, adapters and the full output contract: docs/MANUAL.md.
Architecture
EASA landing page ──fetch──► cache (XML + meta + sha256)
eCFR API ──fetch──► │
│
Local XML/DOCX ───────────────────┤
▼
OpcPackage / eCFR XML
▼
EasaDocumentParser | FaaEcfrAdapter
▼
Regulation AST ──normalize──►
▼
┌───────────────┼───────────────┐
▼ ▼ ▼
Markdown JSON HTML
│
├── SQLite FTS5 (query)
├── Reference graph (refs)
└── Validation / conversion-report.json
Built-in sources
EASA — sources/easa.yaml, keyed on stable landing pages rather than
fragile direct URLs:
cs-vla, cs-lsa, cs-22, cs-23, cs-25, cs-27, cs-29, cs-e, part-21, uas-rules
cs-p and cs-etso are catalogued but PDF-only — EASA publishes no XML
export for them, so commands fail with an explanation instead of a confusing
parse error.
FAA — experimental — sources/faa.yaml, served by the public eCFR API:
far-21, far-23, far-25, far-27, far-43, far-91
This branch is a prototype: it mirrors regulation text only, its shape may change, and it is not a source for the FAA certification basis. EASA is where this project is maintained.
A weekly workflow resolves, downloads and parses every entry, and reports drift without failing the build:
python scripts/catalog_health.py --deep
For LLM agents
Two integration routes, same results:
- Shell — the thin skills under
skills/(generic / Codex / Claude Code / OpenCode) - MCP —
easa-erules-mcp, exposinglist_regulations,regulation_info,extract_rule,query_regulation,rule_references,fetch_regulation
Cookbook: examples/agent-cookbook.md
Full manual: docs/MANUAL.md
Rules of engagement:
- Prefer
query/extract/refswith--jsonover stuffing full regulations into context. - Never hand-write or "fix" regulatory text from model memory.
- After bulk
convert, runvalidate. - Ground answers only on tool output, and cite the
designation+amendmentfrom thesourceblock. - This is an EASA source. It is not a source for the FAA certification basis — the FAA branch mirrors eCFR text only, with no Advisory Circulars or policy material.
Development
pytest # offline; real-sample tests skip
python tests/real_samples/fetch_samples.py # pull the pinned publications
pytest -m real_sample -v
EASA_ERULES_LIVE=1 pytest -k live -v # network smokes
ruff check src tests scripts
- Unit fixtures:
tests/fixtures/ - Golden renders:
tests/golden/ - Real documents: pinned, not committed — see
tests/real_samples/README.mdanddocs/LEGAL-REVIEW.md
Development state: docs/STATUS.md
Design principles
- Deterministic conversion — same source + parser version → same AST/ids/exports
- No silent content loss — unknown elements and failed structures are reported
- AST in the middle — no direct XML → Markdown hacks
- Agent-first CLI — versioned, self-describing JSON for extract/query/refs
- Explicit over empty — a result never leaves an agent guessing why it is empty
License
MIT for the software — see LICENSE.
The MIT grant does not extend to regulatory text retrieved through this
tool. EASA Easy Access Rules are reproduced with acknowledgement per
EASA's copyright policy;
14 CFR is US Government work in the public domain. See NOTICE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file easa_erules-0.2.1.tar.gz.
File metadata
- Download URL: easa_erules-0.2.1.tar.gz
- Upload date:
- Size: 141.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ae9c5ecb9d63dacd772ded7d776f7043532b0072a0a2fd6633f878a1777b36d0
|
|
| MD5 |
96f6fd32189c26f55f410839acd8b331
|
|
| BLAKE2b-256 |
59ccf4e3af36710003b7ce0e1f7ecaa6ff1a343e2c812516cedd30b5062e495b
|
Provenance
The following attestation bundles were made for easa_erules-0.2.1.tar.gz:
Publisher:
publish.yml on mrSpringpeace/easa-erules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
easa_erules-0.2.1.tar.gz -
Subject digest:
ae9c5ecb9d63dacd772ded7d776f7043532b0072a0a2fd6633f878a1777b36d0 - Sigstore transparency entry: 2407428590
- Sigstore integration time:
-
Permalink:
mrSpringpeace/easa-erules@8d9839f7ac955d31ec3fef823371e11dbdb45c50 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/mrSpringpeace
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8d9839f7ac955d31ec3fef823371e11dbdb45c50 -
Trigger Event:
release
-
Statement type:
File details
Details for the file easa_erules-0.2.1-py3-none-any.whl.
File metadata
- Download URL: easa_erules-0.2.1-py3-none-any.whl
- Upload date:
- Size: 117.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8ce6ff09e287420f23608271f4984bfe28b7ef90d26c991a10e1d59b79561037
|
|
| MD5 |
998945dce97f212c08eb5ab1a5b4a1ac
|
|
| BLAKE2b-256 |
501a0c2cee5d7ab408750fb78c0ee340f3e84c3531bac74e438c5c6aebdab3ca
|
Provenance
The following attestation bundles were made for easa_erules-0.2.1-py3-none-any.whl:
Publisher:
publish.yml on mrSpringpeace/easa-erules
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
easa_erules-0.2.1-py3-none-any.whl -
Subject digest:
8ce6ff09e287420f23608271f4984bfe28b7ef90d26c991a10e1d59b79561037 - Sigstore transparency entry: 2407428606
- Sigstore integration time:
-
Permalink:
mrSpringpeace/easa-erules@8d9839f7ac955d31ec3fef823371e11dbdb45c50 -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/mrSpringpeace
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@8d9839f7ac955d31ec3fef823371e11dbdb45c50 -
Trigger Event:
release
-
Statement type: