Skip to content

Latest commit

 

History

3,042 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FerroEHR

A pure-Rust openEHR® Clinical Data Repository. Every conformance claim is measured.

Pronounced "FER-ro-E-H-R" — from ferrum, iron. Rust is just iron oxide, so we went straight to the element.
(Saying "ferro-air" is unsupported, but we can't stop you.)

ITS-REST 1.1.0  ·  AQL 1.1  ·  RM 1.2.0 + 1.1.0  ·  ADL 1.4 + 2.4  ·  PostgreSQL 18  ·  Rust 1.96

Try it live: sandbox.ferroehr.eu (ferroehr / ferroehr, demo data, reset nightly)

CI Containers CodeQL GitHub Release Image pulls FOSSA Status FOSSA Status

Coverage Quality gate status OpenSSF Scorecard OpenSSF Best Practices GHCR Artifact Hub DOI License: BUSL-1.1

openEHR CNF conformance CNF performance SLSA Build L3

Live sandbox · Documentation · Why this exists · Do you need a commercial licence? · Quick start · Features · Spec versions · Rust crates · Architecture · Conformance · Deployment · Roadmap · Contributing


openEHR separates clinical knowledge from software: applications store and query structured health records through a vendor-neutral REST API and the Archetype Query Language, against a shared clinical information model. FerroEHR implements that standard natively in Rust: a headless, API-first Clinical Data Repository shipped as a single self-contained binary on PostgreSQL 18. No JVM, no language runtime. Every compliance claim it makes is machine-verified: the full conformance catalogue is executed against a live server by a committed runner, the run records are committed alongside the code, and the published Conformance Statement, Certificate and every quoted number derive from those records. None of them are hand-typed.

Why this project exists

openEHR is one of the few places in health IT where clinical meaning is written down as a shared, computable, vendor-neutral model. That is what lets a record outlive the application, the vendor and the procurement cycle that produced it. A specification that good deserves an implementation anyone can actually run: complete, openly developed, source-available, and measured against the specification itself. That is what FerroEHR is for.

The whole thing is source-available under the Business Source License 1.1, with no open-core tier. Multi-tenancy, RBAC/ABAC, ATNA audit, signatures, FHIR, events and the viewer are all in this repository under the same licence, and nothing is held back to be sold back to you. Reading, building, modifying and redistributing the source is free, and so is every non-production use. Production use is free for Non-Commercial Purposes and needs a commercial licence otherwise: the table below says which applies to you.

What we ask in return, and cannot require, is that improvements come back. A private fork inherits the entire maintenance surface (spec releases, advisories, database upgrades, conformance re-runs, a re-merge every release) and pays for it alone; upstreamed, the same work is maintained once for everyone. In clinical software a defect found once should be fixed everywhere, and interoperability is a property of the population of implementations, not of any one of them. When the same fix is made privately in five places, the standard is no stronger and five teams have paid for it.

Contributions are not only code: a reproducing bug report, a conformance case for uncovered behaviour, a specification ambiguity you had to resolve (we report the genuine ones upstream), documentation, or measurement from your own hardware all count. The full statement is Why FerroEHR exists on the documentation site.

What makes it different

  • Compliance you can verify. An independent CNF 2.0 conformance instrument executes the complete machine-readable catalogue across the claimed wire formats and computes the openEHR profile verdicts as pure functions of the run records. The conformance badges above render straight from the committed run artifacts of real runs; none are hand-edited. Every badge on this page is computed by something that can disagree with us: the conformance ones by an instrument built as its own project, the workflow ones by GitHub, and the security score by OpenSSF Scorecard, which grades this repository's supply chain (digest-pinned actions, minimal workflow token permissions, code scanning, signed releases) independently of anything we claim here. The SLSA badge is the one static image on the page, and its claim is falsifiable: it links to the verification guide whose pinned-signer command either passes or does not. There is no self-asserted "hardened" badge, because it would prove nothing. The Conformance Report carries the full per-case record.
  • Performance classes are earned by measurement. Volumetric deployment classes are earned by open-loop measured runs (population-anchored offered-load floors held for at least the normative hour, extendable to half-day holds), with re-checkable latency histograms embedded in the committed results; a separate step-load stress instrument finds the maximum sustainable throughput. Every published chart regenerates from those committed records, guarded in CI.
  • Two openEHR specification generations, and you choose which one runs. The specification layer is generated from the official machine-readable models. Both the latest RELEASED generations and the development ones are generated, side by side, as complete peers. One configuration key picks the set the server serves, so staying on released specifications is a setting, not a fork. See Choose your openEHR specification generation.
  • A specification update means regenerating the crates, and a CI drift-check makes silent divergence impossible: REST API 1.1.0, AQL 1.1, RM, BASE, Archetype Model 1.4 + 2.4, Terminology 3.1 all come from the vendored machine-readable models, pinned per component.
  • Both generations of the archetype language, end to end. ADL 2.4 source templates are parsed, validated against the full AOM2 validity catalogue, specialisation-flattened, and compiled to operational templates. ADL 1.4 OPTs and source archetypes are validated against their own 1.4 rules and can be migrated to ADL 2 in-CDR. Every template, either dialect, generates spec-valid example compositions that pass the server's own validation.
  • One static Rust binary. Predictable memory, fast cold starts, a minimal distroless container image, no garbage-collection pauses in the write path.
  • PostgreSQL 18-native clinical storage. Temporal versioning with database-enforced non-overlap, time-ordered UUIDv7 keys, and canonical openEHR JSON stored verbatim. What you store is exactly what the API serves.

Features

openEHR platform

  • REST API (ITS-REST 1.1.0): EHR, EHR_STATUS, COMPOSITION, DIRECTORY, CONTRIBUTION, query, template, and admin resources, with canonical JSON and XML on the wire
  • AQL 1.1 engine: typed path analysis over a spec-generated Reference Model, compiled to efficient SQL; including ALL_VERSIONS, terminology-backed TERMINOLOGY() expansion inside matches, and stored parameterised queries
  • Full versioning semantics: contribution-atomic commits, indelible version history, logical delete, attestations, per-version digital signatures, point-in-time reads
  • Templates & validation, both ADL generations: ADL 2.4 source templates (full ADL2/cADL/ODIN parser, the AOM2 validity catalogue with typed rule codes on the wire, specialisation flattening, OPT2 compilation) and OPT 1.4 ingestion with artefact validity checking; WebTemplate, FLAT and STRUCTURED formats from either dialect; deep archetype-constraint validation plus the RM invariant catalogue (including the terminology-backed invariants) on every write
  • Example generation: every stored template, ADL 1.4 or 2.4, serves deterministic example compositions that pass the server's own full validation, in canonical JSON/XML and the simplified formats
  • ADL 1.4 → ADL 2 migration: stored 1.4 archetypes convert to ADL 2 source in-CDR, with a reproducible conversion log
  • EHR Extract & messaging: whole-EHR export/import with preserved distributed version identity, EHR cloning across systems, TDD import
  • Demographics: a versioned party store (person, organisation, group, agent, role) with relationships
  • Terminology: the bundled openEHR terminology plus pluggable external FHIR terminology servers (validate, expand, subsume)

Integration

  • Change events: a transactional outbox publishes every commit to AMQP/RabbitMQ with per-EHR ordering, filterable server-side subscriptions, and PHI-free payloads by default
  • FHIR R4B connectors: bidirectional and mapping-driven: ingest FHIR resources as validated compositions with full provenance, expose committed data through a FHIR read façade, emit FHIR resources on change
  • Binary & object storage: large multimedia is content-addressed into any S3-compatible store with cryptographic integrity verification; SeaweedFS works out of the box for self-hosted setups

Security & operations

  • Authentication: Basic and OAuth2/OIDC (Keycloak, Active Directory, any standards-compliant identity provider)
  • Authorization: role-based access control plus attribute-based policies, via the embedded policy engine or an external policy decision point
  • Multi-tenancy: fully integrated: each tenant is an isolated logical openEHR system, enforced by PostgreSQL row-level security
  • ATNA audit logging: IHE ATNA-compliant system log (DICOM audit messages over TLS syslog), alongside the openEHR contribution audit trail; identified data never enters telemetry
  • Hardened by default: layered database roles, a pure-Rust TLS stack, and built-in observability: Prometheus metrics, OpenTelemetry traces, structured logs, health probes

Deployment

  • Docker Compose for development and evaluation, with an optional Grafana observability overlay
  • Distroless, non-root, shell-less multi-arch containers (amd64 + arm64), published to GHCR
  • Helm chart with security-hardened defaults (non-root, read-only filesystem, network policies) for Kubernetes
  • Operations guide covering database roles, backup/PITR, and upgrades

Quick start

The fastest path is the live sandbox: it opens the viewer over a running FerroEHR, with the same server's Swagger UI at /ferroehr/rest/swagger-ui (credentials ferroehr / ferroehr, demo data, wiped nightly). So everyone knows what it runs on and what it costs:

Server one Hetzner Cloud CX33 — 4 shared vCPU, 8 GB RAM, 80 GB NVMe SSD — at €8.49/month net
Location Nuremberg, Germany (eu-central), dual-stack, behind a Caddy proxy terminating TLS
Database a second CX33 running the project's own ferroehr-postgres image (PostgreSQL 18), reachable only over a Hetzner private network

The whole posture is committed at deploy/hosted/. One step up, open a GitHub Codespace and the published stack (server, PostgreSQL 18, viewer) boots in your browser. Details in Try it in Codespaces.

Or run it locally with Docker Compose: one downloaded file, no checkout (needs Compose 2.23.1+). Grab docker-compose.yml from the latest release and start it:

docker compose up
# Probe the status endpoint
curl http://localhost:8080/ferroehr/rest/status

# Create an EHR (development credentials: ferroehr / ferroehr)
curl -u ferroehr:ferroehr -X POST -i \
  http://localhost:8080/ferroehr/rest/openehr/v1/ehr

# Query it with AQL
curl -u ferroehr:ferroehr -H 'Content-Type: application/json' \
  -d '{"q":"SELECT e/ehr_id/value FROM EHR e"}' \
  http://localhost:8080/ferroehr/rest/openehr/v1/query/aql

Interactive OpenAPI documentation is served at http://localhost:8080/ferroehr/rest/swagger-ui, and the hosted sandbox runs the same UI at https://sandbox.ferroehr.eu/ferroehr/rest/swagger-ui if you want to look before installing anything. The viewer is opt-in: docker compose --profile viewer up, then http://localhost:3000 with the same credentials.

To try OAuth2/OIDC instead of Basic auth, download the docker-compose.keycloak.yml overlay from the same release beside the base file: it adds a Keycloak with a ready-made demo realm and points the server's bearer validation at it (Basic keeps working).

docker compose -f docker-compose.yml -f docker-compose.keycloak.yml up
# realm ferroehr on :8081 — client ferroehr / ferroehr-quickstart-secret,
# user ferroehr / ferroehr (password grant enabled for curl)

Published images: ghcr.io/rubentalstra/ferroehr, ghcr.io/rubentalstra/ferroehr-postgres (PostgreSQL 18 with roles, schemas, and extensions pre-created; the server runs its own migrations at boot), and ghcr.io/rubentalstra/ferroehr-viewer (the viewer). The Compose file pins the release's exact image versions. Configuration is environment-driven (FERROEHR_*) on top of the config the Compose file carries inline; that config ships one development user with role-based access control disabled: dev defaults that must be replaced outside development. In a checkout, docker compose up --build builds everything from source and uses the fuller development configuration in docker/ferroehr.dev.toml instead (three users, RBAC on).

Optional: local observability stack (Grafana LGTM)

One overlay adds an OTLP collector, Prometheus, Tempo, Loki, and Grafana with a provisioned service-overview dashboard (it provisions from files in this repository, so run it from a checkout):

docker compose -f docker-compose.yml -f docker-compose.observability.yml up
# Grafana → http://localhost:3000

The Grafana dashboard and Prometheus scrape config travel inline in the overlay itself (it works standalone, downloaded beside docker-compose.yml); a tunable alert-rule starter pack lives in docker/observability/.

Choose your openEHR specification generation

openEHR publishes released specification versions and keeps developing the next ones. Most implementations pick one and hard-wire it. FerroEHR generates both: every generation is a complete peer with its own type model, canonical JSON/XML codecs, Reference Model attribute model, invariant cores and validation behaviour. One configuration key decides which set the server runs:

# ferroehr.toml  (or FERROEHR__SPEC_PROFILE=stable)
spec_profile = "development"   # the default
spec_profile RM BASE LANG Use it when
development (default) 1.2.0 1.3.0 1.1.0 You want the generations this build is developed against
stable 1.1.0 1.2.0 1.0.0 You need to run on RELEASED openEHR specifications only

The key is documented in full on the configuration page. It is one coupled choice, not three independent knobs: the components' generations are modelled against each other (RM 1.1.0's own model declares that it includes BASE 1.2.0), so incoherent combinations are not representable. The active profile appears on the boot banner and at /management/info.

Changing it later is a documented contract. stable → development is always safe, because openEHR minor releases are additive by the Foundation's own release strategy: everything stored under the released generations is valid under the development ones. The reverse direction is supported only for data that never used a development-only construct; anything that did is refused loudly at read, naming the profile conflict, never silently down-converted or hidden. Under stable, a request that addresses surface the released generations do not define is refused with an error naming the profile, and released surface the development line later dropped stays accepted, so the boundary is exact in both directions.

The openEHR specification layer, as Rust crates

You do not need the whole CDR to get the openEHR specifications in Rust. The generated specification layer is published on crates.io as eight independently usable crates, the same code this server runs on:

Crate What it gives you
Crates.io Version The Reference Model — COMPOSITION, EHR_STATUS, OBSERVATION, the data structures and data types, change control
Crates.io Version BASE: the foundation + base types (identifiers, intervals, the terminology-facing types)
Crates.io Version The Archetype Model, both generations: AOM 1.4 and AOM 2.4
Crates.io Version The ADL engine: ADL2/cADL/ODIN parser, AOM2 validity catalogue, specialisation flattener, OPT2 generator, ADL 1.4 → 2 conversion
Crates.io Version Canonical JSON + XML codecs, the ITS-REST contract, and the Simplified Formats (WebTemplate, FLAT, STRUCTURED)
Crates.io Version The AQL 1.1 lexer, parser and AST
Crates.io Version The terminology model plus the bundled openEHR terminology
Crates.io Version The BMM/P_BMM object model and the ODIN instance reader

The multi-generation crates expose their generations as version-named modules (openehr_rm::v1_2, openehr_rm::v1_1, openehr_am::v2_4, …), with the current generation re-exported from the crate prelude and the others reachable by full path. Each crate's emitted Generation enum is the single authority on which openEHR version a generation implements: Generation::default() is the current one, and spec_version() tells you its version string.

These crates version on their own SemVer line, deliberately decoupled from the openEHR specification versions they implement: the implementation can keep improving while a vendored specification stands still, and adopting a new specification generation does not force a semantic version on your code. The implemented specification version is always a runtime datum, never guessed from the package version.

Architecture

Three directories, one strict dependency direction: the application consumes the generated specification layer (app/* → crates/*), and the tools verify from outside (the conformance runner drives the deployed server purely over HTTP):

flowchart TB
    specs["openEHR machine-readable specs<br/>(BMM · XSD · OpenAPI — vendored + pinned)"]

    subgraph crates ["crates/* — the specification layer (generated where the specs are machine-readable)"]
        openehr["openehr-base · openehr-rm · openehr-am · openehr-term · openehr-lang (BMM · ODIN · BEL)<br/>openehr-its (native canonical JSON/XML codecs + ITS-REST contract + Simplified Formats: WebTemplate · FLAT · STRUCTURED)<br/>openehr-adl (ADL 1.4 + 2.4 engine: parser · AOM2 validation · flattener · OPT2)<br/>openehr-query (AQL parser)"]
    end

    subgraph app ["app/* — the application (five crates, five roles)"]
        rest["ferroehr-rest<br/>ITS-REST 1.1.0 protocol adapter (axum)<br/>+ access (authn · RBAC/ABAC) + wire mapping"]
        core["ferroehr<br/>the platform library: PG18 node storage · versioning ·<br/>AQL→SQL engine · validation · signing · templates ·<br/>audit — one service module<br/>per SM Platform Service Model chapter"]
        bin["ferroehr-server<br/>the wiring-only binary"]
        viewer["ferroehr-viewer<br/>the Leptos SSR viewer (own OCI image,<br/>consumes the CDR strictly over ITS-REST)"]
        ext["ferroehr-ext<br/>optional integrations behind additive features:<br/>FHIR conversion · AMQP events · multimedia store"]
    end

    subgraph tools ["tools/* — generation + verification (not shipped)"]
        codegen["openehr-codegen<br/>(BMM/XSD/OAS → Rust)"]
        testkit["testkit<br/>(shared PG18 harness)"]
    end

    conf["Veredictum<br/>(the independent CNF 2.0 conformance instrument,<br/>pinned in scripts/lib/veredictum.sh)"]

    specs -- "openehr-codegen (deterministic, drift-checked in CI)" --> crates
    bin -- "wires" --> rest
    rest -- "calls the concrete service" --> core
    core -- "optional, feature-forwarded" --> ext
    app --> crates
    conf -. "drives the deployed server over HTTP" .-> rest
    testkit --> core
Loading

The service layer follows the openEHR SM Platform Service Model: one service module per SM component, whose concrete methods carry the spec's call names and error vocabulary: the "native API behind protocol adapters" architecture the SM itself prescribes. The specification layer carries no serde: canonical JSON and XML are native codecs generated alongside the types, so the wire contract is explicit, tested code. The full design is documented in docs/architecture.md.

Conformance, measured

CNF CORE CNF STANDARD CNF OPTIONS CNF SEC-BASIC

bash scripts/conformance.sh

One command builds the current sources into a container, runs the complete machine-readable openEHR conformance catalogue against it across the claimed wire formats, and writes the report, the Conformance Statement, and the Certificate. Profile verdicts are computed by the runner — never hand-asserted — and the badges at the top of this page are generated from real runs.

Performance is graded the same way. A volumetric deployment class is earned by holding its population-anchored offered-load floor for the sustained window (the normative hour by default, extendable to longer demonstrations, never shorter), with every latency histogram embedded in the committed results so the verdict re-derives from the artifact alone:

# the measured class stage (hour-plus, on the exclusively composed server)
CONF_PERF_CLASS=POC bash scripts/conformance.sh

# an extended sustained hold (a stricter demonstration of the same class)
CONF_PERF_CLASS=POC CONF_PERF_HOURS=8 bash scripts/conformance.sh

# the step-load stress instrument — exploration only, never a conformance record
source scripts/lib/veredictum.sh
"$(veredictum_bin)" stress --root "$(veredictum_artifacts)" \
  --ixit docs/conformance/party/ferroehr/ixit.json \
  --out docs/conformance/ferroehr/stress.json

The published performance visuals (the class ladder, per-operation latency percentiles, and the latency-throughput stress curve) regenerate from the committed records (bash scripts/render/perf-assets.sh) and are diff-guarded in CI, exactly like the conformance numbers.

The committed stress run's latency-throughput curve (the knee, the p99 budget line, and the class floors as context) renders straight from docs/conformance/ferroehr/stress.json (exploration only; the chart carries the measured numbers so none are typed here):

The latency-throughput stress curve

Every measured class run and every stress step also records resource telemetry: per-container CPU, resident memory, and block/network I/O for the server and the database separately. A class run also records the database volume's disk anchors, down to the storage cost per committed composition. The committed record shows what a run cost the machine and where saturation lives; telemetry is measured context only and never influences a verdict:

Resource telemetry across the measured class run

Disk growth across the measured run's four anchors

Measured against EHRbase

One instrument, two servers, byte-identical requests: both systems run the same committed CNF catalogue for conformance and the same step-load stress ladder for throughput — the hospital-simulation workload on official openEHR CKM templates, seeded fresh through the public API on each side's own composed stack. Both directions are always published, and every number derives from committed run artifacts — nothing here is hand-typed.

The stress ladder climbs geometrically until the system leaves the envelope (p99 over budget or errors past tolerance), then bisects to the maximum sustainable throughput: every load step embeds its own re-checkable histograms and per-container resource telemetry, and a breached step is reported with the exact violation. Where EHRbase sustains a higher rate, its curve is drawn exactly like one where it doesn't:

Both systems' latency-throughput curves

Both systems' capability conformance, rendered from each party's own committed verdicts (one cell per claimed capability, evidence as color and glyph):

FerroEHR capability conformance

EHRbase capability conformance

And the per-chapter outcomes side by side:

FerroEHR outcomes by chapter

EHRbase outcomes by chapter

The full, generated comparison — profile verdicts, capability-by-capability evidence, failures in both directions, and the stress overlay once both committed reports exist — is the comparison page on the website and docs/conformance/COMPARISON.md in the repo, with each system's committed measurement records under docs/conformance/. Reproduce either side with the pinned instrument: bash scripts/conformance.sh (CONF_SUT=ehrbase for EHRbase) and veredictum stress / veredictum aql-probe (Veredictum, pinned in scripts/lib/veredictum.sh).

Deployment

The Helm chart is published to GHCR as an OCI artifact, beside the images it deploys, and listed on Artifact Hub:

helm install ferroehr oci://ghcr.io/rubentalstra/charts/ferroehr \
  --version 6.0.13 --set database.existingSecret=my-db-secret

There is no HTTP chart repository, so helm repo add does not apply — OCI is the only publication path. The chart version and the image tag are separate SemVer lines: --version pins the chart, --set image.tag= pins the server. Your values file is checked against the chart's values.schema.json before anything is applied. The chart and the images are published with signed keyless provenance (gh attestation verify oci://ghcr.io/rubentalstra/charts/ferroehr:<chart-version> -R rubentalstra/FerroEHR), and the chart additionally carries a keyless cosign signature.

See the Kubernetes chapter and the documentation website for the production checklist: database role separation, TLS, backup and point-in-time recovery, and audit logging.

Building from source

Requires the pinned toolchain (installed automatically by rustup), Docker for the PostgreSQL integration tests, and xmllint for the canonical-XML tests.

cargo build --workspace
cargo nextest run --workspace

CI gates every commit: the full test suite against real PostgreSQL 18, clippy -D warnings, rustfmt, the rustdoc lints, supply-chain policy (cargo deny — same advisory database as cargo audit, plus yanked-crate, license, ban and source policy), MSRV, unused-dependency checks, spec-codegen drift, comment style, and a container smoke test. See CONTRIBUTING.md for the developer workflow.

Documentation

Documentation website The user guide, versioned per release
API reference The live sandbox's Swagger UI (demo login ferroehr/ferroehr)
Architecture How the system is built, and why
Conformance report The latest measured results, per test case
Version matrix Every pin: openEHR spec generations, Rust toolchain, PostgreSQL
openehr-* crates The specification layer as standalone Rust libraries
Roadmap board The plan and its live status
Developer documentation Contributing, design decisions, specifications
Vendored openEHR specifications The oracle every spec-facing decision cites

For the openEHR standard itself, see the openEHR specifications. The specification text this project treats as its oracle is vendored in-repo and pinned per component, so every conformance decision cites a file you can read.

Contributing, governance and security

Contributions are welcome — see CONTRIBUTING.md and the Code of Conduct. Please report suspected vulnerabilities privately per the security policy, not in public issues.

Document Answers
SUPPORT.md where to ask a question, report a defect, or report a vulnerability — they are not the same place
GOVERNANCE.md who decides, how a change gets in, and how to become a maintainer
MAINTAINERS.md who the maintainers are, which publishing identities exist, and what happens if they are unavailable
SECURITY.md how to report a vulnerability, what you can expect back, and which versions receive security fixes
Threat model the trust boundaries, the control at each, the residual risk that survives it, and what is explicitly not defended against

Two of those are worth reading before a procurement decision rather than after: the project has one maintainer, and only the newest release receives security fixes. Both are stated plainly in the documents above rather than left to be discovered.

Do you need a commercial licence?

FerroEHR is source-available under the Business Source License 1.1, which is not an OSI-approved open-source licence. LICENSE is the authority and names the Licensor, the Licensed Work, the Additional Use Grant and the Change Date; this table is the same boundary in the order people ask about it.

What you are doing What you need Why
Reading, building, modifying or redistributing the source Free The licence grants it without a fee and without asking anyone.
Development, testing, evaluation, prototyping Free All non-production use is granted.
Production use for Non-Commercial Purposes Free Personal use, academic or scientific research, teaching, and use by a non-profit organisation or public body that is not in the course of a business, does not deliver a service for payment, and is not for commercial advantage.
A hospital, clinic or care provider running it for its patients Commercial licence Delivering health care, or any other service for payment, is production use outside the grant.
A vendor or integrator, or any company running it in production Commercial licence Production use in the course of a business is outside the grant.
Offering it, or a work derived from it, to third parties as a hosted, managed or embedded service Commercial licence Excluded from the grant in every case, whoever you are.
Selling, sublicensing or otherwise distributing it for a fee Commercial licence Excluded from the grant in every case, whoever you are.

The last two rows hold whatever else you are: they need a commercial licence even for an organisation the rows above would otherwise leave free.

Each version becomes Apache License 2.0 four years after that version is published. Companies and care providers building on FerroEHR are wanted here, and the commercial licence is the normal path for them. It starts with a short conversation with the maintainer named in MAINTAINERS.md.

The eight openehr-* crates on crates.io are a separate question. The five generated model crates (openehr-base, openehr-rm, openehr-am, openehr-lang, openehr-term) are Apache-2.0, so any Rust project can use them without a licence conversation; the three hand-written engines (openehr-query, openehr-adl, openehr-its) carry the same Business Source License as the application. The full picture, including every vendored third-party tree, is on the documentation site's Licensing & legal page.

Acknowledgments and license

FOSSA Status

Acknowledgments

  • EHRbase: FerroEHR began as a fork of EHRbase, developed by vitasystems GmbH and the Peter L. Reichertz Institute, and records that lineage in the labelled import commit at the root of this repository's history. It is not affiliated with or endorsed by the EHRbase project; EHRbase itself remains Apache-2.0, and no code from it is present in this tree.
  • openEHR Foundation: publishes the openEHR specifications and the machine-readable models this project generates from. openEHR® is the registered trademark of the openEHR Foundation; FerroEHR is an independent implementation of the openEHR® specifications and is not endorsed by the Foundation.
  • Cabolabs EHRServer — the viewer's feature set (the Template Manager, the point-and-click Query Builder, saved/grouped/cohort queries) is inspired by EHRServer by Pablo Pazos / CaboLabs Health Informatics (Apache-2.0). The UX is reimplemented fresh in Rust over this project's own AQL engine — no code is copied — but the design lineage is gratefully credited.

Licensing

Material License
FerroEHR's own code: the application, the tooling, the viewer and the documentation BUSL-1.1
The five generated openehr-* model crates on crates.io (openehr-base, openehr-rm, openehr-am, openehr-lang, openehr-term) Apache-2.0 (openehr-term also CC-BY-SA-3.0 for the terminology XML)
The three hand-written openehr-* engines on crates.io (openehr-query, openehr-adl, openehr-its) BUSL-1.1 (openehr-its also Apache-2.0 for the openEHR-derived codecs, contract and schema it embeds)
openEHR machine-readable artifacts (BMM, XSDs, OpenAPI, JSON Schemas — the specifications-ITS-* repos) and the vendored test corpora (archie, Better web-template-tests, the EHRbase SDK) Apache-2.0
openEHR specification text (vendored for conformance work) CC-BY-SA 3.0
CKM-derived clinical models (test corpora) per-file licence metadata — a mix of CC-BY-SA 4.0 and CC-BY-SA 3.0

Each vendored tree documents its exact origin and license in a PROVENANCE.md, with the upstream LICENSE vendored alongside — and the whole tree is additionally declared in the machine-readable REUSE 3.3 form (REUSE.toml + LICENSES/), so licensing survives a file being copied out of the repository. Two positions the summary table above deliberately does not flatten — an MPL 1.1 election under a tri-licensed corpus, and one upstream file whose own header contradicts its repository's license — are set out with the rest on the documentation site's Licensing & legal page.

How this is built

Substantial parts of FerroEHR are written with AI coding tools, directed and reviewed by the maintainer, with every change gated by the machine-enforced checks this page describes. The full statement — what that means, what bounds it, and what you can verify instead of trusting it — is AI_STATEMENT.md.

About

A pure-Rust openEHR Clinical Data Repository: ITS-REST 1.1.0, AQL 1.1, PostgreSQL 18-native storage.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

90 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages