Three requirements define a useful personal health record. Nothing in open source satisfies all three, and the reasons why turn out to be a map of the whole landscape.
You are building a PHR. Not a viewer — a comprehensive longitudinal record for a person, that other things can be built on top of. So you go looking for prior art, because surely this is solved.
What you find is a genuinely strong landscape: real standards, peer-reviewed validation, mature ecosystems, projects with more institutional weight behind them than most commercial products. You wire two or three of them together and the pile of work in front of you has not shrunk much.
The reason is that the requirement has three parts, and every project in this space satisfies one or two of them:
- It has to be a PHR. A complete longitudinal record for a person, with everything a PHR system is actually obliged to do — consent, audit, provenance, terminology lifecycle, patient-facing record semantics.
- It should be built on OMOP, not FHIR. FHIR is an exchange format and an excellent one. As the basis for a comprehensive record you intend to analyze — which is what foundations and HIEs want — it is the wrong substrate.
- It needs a flat projection for decision-readiness. Clinical decision support, trial matching, and predictive models all need to know what is true about one person now, cheaply and repeatedly.
That is the whole thesis, and the rest of this post is the three pillars argued properly, then the landscape measured against them.
Pillar 1 — It has to actually be a PHR
"Comprehensive longitudinal record" is the easy half. The other half is the set of obligations that come with being a record about a person rather than a dataset about a population, and they are more demanding than most builders expect.
The HL7 Personal Health Record System Functional Model, Release 2 (PHR-S FM R2) is the most complete statement of them: 748 mandatory criteria spanning personal health functions, security, audit, terminology management, and data interchange. Nobody conforms to all of it, and the standard says so — conformance is profile-based by design. You select a coherent subset and implement it fully.
Read what it asks for and notice how little of it is "features":
- Authentication hardening — account lockout, password reuse prevention, admin-triggered force-change enforced on every request.
- Audit that survives scrutiny — records in FHIR
AuditEventformat, per-row tamper-evidence, delete-restriction, break-glass access with an elevated trail, and auditing of audit-log reads themselves. - Terminology lifecycle — not just using SNOMED and LOINC, but version tracking, deprecation workflows, and concept replacement in the coded store.
- Interchange integrity — content digest verification on ingest, non-repudiation signatures on export.
- Patient-facing record semantics — consent-driven demographic redaction, advance directive in-effect status, entered-in-error status, field-level revision history.
The trap is that several of these are not a layer you add on top. Consent-driven redaction, entered-in-error, revision history, terminology versioning, and advance-directive state all reach into how records are stored and read. Build your record first and discover the functional model second, and you are retrofitting redaction and provenance into a schema designed without them — a rewrite, not a sprint.
This is also worth reading early because it finds real holes. When we ran our own PHR-S FM audit we expected paperwork. It found that our audit trail had no tamper-evidence, no delete-restriction, and no chain integrity, and that our authentication had no lockout, no reuse prevention, and no force-change. We had believed both were fine.
Keep this pillar in mind as you read the rest: most of the projects in this landscape are not PHR systems and do not claim to be. They are analytics and ML substrates. Holding them to a functional model for a PHR would be unfair — but if you assemble a PHR out of them, none of this arrives with the data.
Pillar 2 — It should be built on OMOP, not FHIR
This is the pillar we think is genuinely unusual, and the one most likely to be argued with, so here is the argument in full.
FHIR is superb at what it was designed for: moving a patient's record between two systems, and giving applications a consistent API to read it. If you are acquiring data from providers, exchanging it, or building an app against it, FHIR is the answer and there is no serious competitor. We ingest FHIR R4 and we will keep doing so.
But acquisition format and storage substrate are different decisions, and defaulting the second to the first is the most consequential mistake in this space. As the basis for a comprehensive record you intend to analyze, FHIR has four structural problems:
Vocabularies are permitted, not enforced. A FHIR CodeableConcept can carry any coding system, and outside of a few constrained bindings nothing obliges a source to use one you recognize. Two feeds can describe the same drug in two vocabularies and both are valid FHIR. OMOP's load process requires source codes to be mapped to standard concepts — SNOMED, RxNorm, LOINC — so comparability is established once, at the door, rather than negotiated by every downstream query.
There is no concept hierarchy to query through. This one is underrated and it is where analytics actually lives. "Any anthracycline," "any platinum agent," "any beta blocker" are single predicates in OMOP because concept_ancestor encodes the hierarchy. In FHIR you have a code, and the traversal is a terminology service call you write, maintain, and hope everyone else wrote the same way.
The grain is a resource, and resources nest and unroll. Population questions require flattening a nested document model into tables, which is precisely why an international working group spent eighteen months producing SQL-on-FHIR. That work is excellent — it just tells you the substrate was not built for this.
It is versioned for exchange, not for a decade of stored history. R4 to R5 is a migration for data you have already persisted. OMOP's model is deliberately stable and its vocabulary releases are versioned content rather than schema churn.
Now the positive case, which matters more. Choosing OMOP means an entire analytic ecosystem applies to your record with no adapter: ATLAS for cohort definition, Achilles for characterization, the Data Quality Dashboard for checks, PatientLevelPrediction for models, and the OHDSI network's accumulated study packages. None of that is something you build. It is something you inherit by having earned the format.
For foundations and HIEs this is the whole ballgame. Their job is aggregating across many sources and asking questions of the aggregate. Comparability across sources is the product. OMOP was designed for exactly that problem — multi-site observational research across heterogeneous source systems — and FHIR was designed to move one record between two systems. A foundation that stores FHIR and hopes to analyze it later has deferred the hardest work to the point where it is most expensive and least likely to be done consistently.
So the position is not "FHIR bad." It is FHIR at the edges, OMOP in the middle — and we think the second half of that is what almost nobody else is doing for a PHR.
Pillar 3 — It needs a flat projection for decision-readiness
OMOP solves comparability and it does not solve immediacy. It is normalized and event-oriented, which is right for populations and expensive for individuals. Asking "what is true about this person now" means joins, concept lookups, and most-recent-value subqueries, every time, in every application.
Three use cases drove us to do something about it:
- Clinical decision support and standard-of-care evaluation — guideline rules that need current line of therapy, stage, and latest labs, evaluated per patient, continuously.
- Trial matching — eligibility criteria evaluated across a whole population, repeatedly, against thousands of trials.
- Predictive models and cohort analytics — feature assembly that otherwise re-derives the same clinical state from raw events every run.
All three need the same thing, and all three would otherwise build it separately. Be specific about what that work is, because it is not schema translation:
- Line of therapy. Not a field on any resource — temporal reasoning across drug exposures, regimen definitions, gaps, and intent. In production we needed structural rules, OHDSI's ARTEMIS regimen detection, our own logic, and the ability to read physicians' notes to get this right on real-world data.
- Current disease status. Staging, progression, response — assembled from observations, notes, and episodes recorded at different times by different people.
- Most-recent-value resolution. Trivially stated, annoyingly expensive: every lab criterion needs a correlated subquery, and there are usually ten of them.
- Biomarker normalization. The same marker arrives as text, as a code, as a percentage, as a ratio, under three different names.
- Source reconciliation. Two feeds disagree. Something has to decide, once, and record why.
That is clinical reasoning, not transformation, and it gets re-implemented slightly differently by a different developer in your CDS engine, your matcher, and your analytics layer — until the three quietly disagree about the same patient.
A lot of projects flatten health data. The useful question is whether they flatten along the axis you need, and four sub-questions settle it: grain (what is one row — a resource, an event, an encounter, a patient at a study index date, or a person as they are now?), derivation (are clinical composites computed, or just raw values reshaped?), currency (rebuilt nightly, per study run, or on write?), and consumer (a model's tensor, a population report, or a row a coordinator can read and a rule can cite?).
The landscape, measured against the three pillars
Flat projections over FHIR
SQL-on-FHIR v2, Pathling, Aidbox, FHIR Data Pipes
SQL on FHIR v2 is the strongest work in this family and you should know it well. An international working group produced a standard, implementation-agnostic way to define tabular views over FHIR resources using FHIRPath, published in npj Digital Medicine in 2025 and validated by replicating a clinical study over 580 million FHIR resources on two independent implementations with identical results. Implementations include Pathling (CSIRO), Aidbox (Health Samurai), and Google's FHIR Data Pipes.
Pillar 1 — no. It is a view definition standard, not a record system. Consent, audit, and provenance are elsewhere.
Pillar 2 — no, by definition. It is the best available answer to "I chose FHIR as my substrate and now I need tables," which is a different problem from not choosing FHIR as your substrate.
Pillar 3 — partly. A ViewDefinition is resource-grain, bound to a single resource type, and it unrolls rather than collapsing to one row per patient. FHIRPath cannot express line of therapy. You can assemble a person-grain layer by joining a dozen ViewDefinitions — but then the clinical logic lives in your SQL, unversioned, re-implemented per consumer.
Use it when you need a tabular extract another organization can execute unchanged. Nothing else comes close.
Analytics-ready models with precomputed clinical concepts
Tuva, i2b2/ACT, PCORnet, Sentinel
The Tuva Project is an open-source healthcare data model and analytics framework built as a dbt package, taking raw claims, clinical, eligibility, and pharmacy data through an input layer, preprocessing, a core data model, and data marts — with data quality tests, terminology sets, and source connectors, running inside your own warehouse. Crucially it ships real derived content: chronic conditions, HCC risk, readmissions, quality measures. Its chronic conditions mart implements two groupers, one from CMS and one Tuva wrote after finding gaps in the CMS logic.
Worth saying plainly: Tuva already makes the derive-once argument and has been shipping it for years. So have i2b2, PCORnet, and Sentinel, for well over a decade. Nobody should present flattening as an invention.
Pillar 1 — no. An analytics model, not a record system.
Pillar 2 — a peer, not a match. It is a genuine analytic substrate with enforced terminology, which is the right instinct; it is simply a different one, tuned to claims rather than to clinical observation, and outside the OHDSI ecosystem.
Pillar 3 — partly. Its natural grain is the member-month, encounter, or episode, and its derivations are population- and financial-grade. It answers "what is the risk-adjusted burden of this population" extremely well, and is not built to answer "what is true about this person, right now."
Use it if your data is claims and your questions are about populations. Adopt it rather than re-deriving it. Its ceiling for oncology is that staging, biomarkers, and response assessment are not in the claim.
ML-ready event streams
MEDS, MEDS-Tab, FEMR
MEDS — the Medical Event Data Standard — is a deliberately minimal, event-centric schema for machine learning over EHR data, described in NEJM AI in 2026. As of March 2026 it was in use across 21 institutions, in at least 27 papers and preprints, supporting 17 datasets. Alongside it sit MEDS-Tab, which tabularizes event streams into model features, and FEMR from Stanford's Shah lab, which ingests OMOP into patient timelines for foundation-model training.
Pillar 1 — no, and explicitly not trying.
Pillar 2 — complementary. MEDS positions itself as complementary to OMOP rather than a replacement, and is deliberately semantics-light; FEMR reads OMOP as an input. Neither wants to be your record.
Pillar 3 — different axis. The output is a feature matrix, which is right for a model and wrong for a decision: a tensor is not auditable by a coordinator, cannot be shown to a patient, and does not have to explain itself.
Use it if you are training models on patient timelines — and note that a projection collapsing history into current state is the wrong shape for a sequence model. You want both, over the same source of truth.
OHDSI-native derivation
FeatureExtraction, PatientLevelPrediction
OHDSI's FeatureExtraction generates covariates for a cohort directly from CDM data — a large predefined set spanning conditions, drugs, procedures, age, and comorbidity indices, plus custom covariate builders — feeding PatientLevelPrediction and CohortMethod.
Pillar 1 — no. Study-execution tooling.
Pillar 2 — yes. This is the OMOP-native family, and we are inside it rather than adjacent to it.
Pillar 3 — close, and instructive about the difference. It is index-date scoped — the premise is a cohort and a defined t = 0, not "now." It emits a sparse long format of (covariateId, personId, value) triples for a model to consume, not named columns a person reads. It is R and batch, not event-driven serving. And its covariates are generic rather than clinical composites: you could write a custom builder that infers lines of therapy, but it would be per-study code rather than a shared, versioned derivation.
Use it for observational studies and prediction models on OMOP. We depend on parts of this ecosystem ourselves.
Person-grain summary documents
C-CDA CCD, FHIR International Patient Summary, $everything
This family rarely comes up and it should. The C-CDA Continuity of Care Document, the FHIR International Patient Summary, and the Patient/$everything and $summary operations are all explicitly person-grain: one artifact, one patient, curated. It is useful proof that person-grain summarization is a recognized need with decades of standards work behind it.
Pillar 1 — partly. Person-grain and standards-backed, but a document rather than a system.
Pillar 2 — no. FHIR- and CDA-based, with the vocabulary looseness that implies.
Pillar 3 — no. Document-grain rather than column-grain: built for exchange and human reading, not for a WHERE clause. There is no derived state in an IPS — no current line of therapy, no "is this patient on treatment." And $everything returns the full transactional history, which is the layer you want underneath a projection rather than the one you serve decisions from.
PHR platforms and FHIR application backends
Fasten Health, Medplum, HAPI FHIR, OpenMRS, OpenEMR
Fasten Health is an open-source, self-hosted personal and family health record connecting to a very large number of provider endpoints via SMART-on-FHIR. Medplum is an Apache-2.0, FHIR-native developer platform: FHIR R4 datastore, REST and GraphQL APIs, TypeScript SDK, React components, SMART-on-FHIR auth, access policies, subscriptions, serverless bots, with US Core and Bulk Data conformance.
Pillar 1 — the closest anyone gets. These are real record systems, and Medplum in particular is strong on the trust-infrastructure half — declarative access policies, audit, SOC 2 and ONC certification. What a platform gives you is the access half; the half that touches the data model is still yours.
Pillar 2 — no. They are FHIR datastores by design, which is exactly the substrate choice Pillar 2 argues against for an analytic record.
Pillar 3 — no. They store and serve; they do not derive. A FHIR datastore's answer to "what line of therapy is this patient on" is "write some code."
Use them for the hardest and least glamorous parts of a PHR: endpoint connectivity, OAuth and token refresh, storage, access control, audit, compliance posture. This is permanently-maintained work and you should not write it yourself.
The scorecard
| Family | Representative | A PHR system? | Analytic substrate | Person-grain decision projection? | Best at |
|---|---|---|---|---|---|
| Flat FHIR views | SQL-on-FHIR v2, Pathling, Aidbox | no | FHIR | no — resource-grain, unrolls | portable tabular extracts |
| Analytics-ready models | Tuva, i2b2/ACT, PCORnet | no | own model, claims-anchored | no — member-month / encounter grain | population analytics on claims |
| ML event streams | MEDS, MEDS-Tab, FEMR | no | event stream, semantics-light | no — feature matrix, not a readable row | model training on timelines |
| OHDSI derivation | FeatureExtraction, PLP | no | OMOP | no — index-date scoped, sparse long format | observational studies |
| Summary documents | C-CDA CCD, FHIR IPS, $everything | partly — document, not system | FHIR / CDA | no — curated, not derived | exchange & human reading |
| PHR / FHIR platforms | Fasten, Medplum, HAPI | yes | FHIR | no — storage and access | connectivity, storage, apps |
| PRomop | PatientRecord over OMOP 5.4 | yes | OMOP | yes — 304 columns, refreshed on write | per-patient decisions |
The three pillars are the middle three columns. Every family clears one or two. The combination — a real record system, on an analytic substrate, with a decision-ready person-grain projection over it — is the empty slot.
What PRomop hands you
Taken in pillar order.
It is a PHR. PRomop is audited against a published HL7 PHR-S FM R2 functional profile for oncology patient health records — 26 functions across personal health, security and audit, and terminology and interoperability, verified criterion by criterion against the source code. Of the profile's 78 mandatory SHALL criteria, 75 are met and none are unmet; every Essential function is fully conformant. Concretely: hash-chained HMAC-signed audit records in FHIR AuditEvent format with delete-restriction, account lockout and password-reuse prevention, terminology version tracking with deprecation and concept replacement, content digests on ingest and signed export bundles, consent-driven demographic redaction on the read path. The full conformance write-up is here.
It is built on OMOP. OMOP CDM 5.4 with oncology extensions is the source of truth — everything that ever happened, with source codes mapped to standard concepts at load. FHIR R4 comes in at the edge via ingestion, and C-CDA is converted upstream. Because the store is genuinely conformant, ATLAS, Achilles, and the Data Quality Dashboard apply to your data unchanged, and multi-site work stays possible. This is the pillar that makes a foundation's or an HIE's analytics ambitions realistic rather than aspirational.
It offers a flat projection. PatientRecord collapses a patient's entire longitudinal history into a single 304-column row representing what is true now. Line of therapy, current disease status, normalized biomarkers, latest values, reconciled sources — computed once, at projection time, and materialized. Refresh is event-driven: a change to the underlying record regenerates that patient's row, so the view stays current without a nightly job. It can be invoked on demand and disabled during bulk backfills with a single rebuild at the end.
What that means for the three use cases that drove it:
| What you're building | What it reads |
|---|---|
| CDS and standard-of-care evaluation | Guideline rules become predicates over named columns — current line, stage, most recent labs — instead of a state-reconstruction pipeline per rule. |
| Trial matching | A 20-criterion eligibility search that takes 27–39 joins over raw OMOP becomes zero joins against one row per patient — an estimated ~30×–200× on a representative workload. |
| Predictive models and analytics | The flattened feature row already exists with clinical composites in it, so feature engineering starts from derived state rather than raw events, and cohort selection runs over one table. |
The structural property that ties Pillars 2 and 3 together: the projection is a projection, not a fork. The OMOP tables remain the source of truth and stay conformant. Delete every PatientRecord row and the whole thing rebuilds from the CDM. You are not trading the ecosystem for the convenience.
It runs in production across the HealthTree Foundation (~14,000 blood-cancer patients) and CancerBot (~3,500), matching against roughly 6,000 actively recruiting trials in five cancer types — offered as evidence the pattern survives real-world data, which is the only test that counts.
These compose. Use all of them.
None of this is either/or. A reasonable stack:
- Fasten or Medplum at the front door — patient connectivity, auth, storage, the app surface. Do not write this yourself.
- OMOP CDM 5.4 as the source of truth — FHIR at the edges, OMOP in the middle.
- The
PatientRecordprojection over it — clinical state computed once, refreshed on write, read by every application you build. - SQL-on-FHIR when you need to hand tables to someone else, MEDS or FEMR when you are training on the transactional layer, FeatureExtraction when you are running a study.
Nothing about a projection layer requires that we also be your FHIR server, your connector network, or your ML pipeline — and we are not trying to be.
What building on it actually costs you
- The projection is a living artifact. Because it pre-computes what consumers need, it stays coupled to evolving clinical demand. A new trial criterion or decision rule sometimes means a new column. Plan for that as an ongoing obligation, not a one-time build.
- The valuable derivations need clinical reasoning, not just ETL. Lines of therapy resisted purely structural normalization on real-world data. Expect the highest-value fields to require rules, and sometimes unstructured text.
- Mapping to OMOP is real work. The comparability Pillar 2 buys is paid for at load time, in vocabulary mapping. That cost is why people default to storing FHIR — and deferring it does not remove it, it just moves it somewhere more expensive.
- Validation so far is in oncology. The OMOP foundation is disease-agnostic and the projection pattern is general, but our extensions and derived fields have been proven in blood cancers and breast cancer.
Where to start
The three pillars are also the sequence.
Decide you are building a PHR, and read the PHR-S FM functional model before you finalize how records are stored and read — consent, provenance, and redaction reach into the schema, and they are cheap early and expensive late.
Choose OMOP as the substrate and FHIR as the edge. If anyone downstream will want analytics — and for a foundation or an HIE that is the entire reason the data was gathered — this is the decision that determines whether those questions are answerable at all. Storing FHIR and planning to normalize later is deferring the hardest work to the point of maximum cost.
Then decide who owns clinical-state derivation. Every application, separately and inconsistently — or once, in a projection everything reads. CDS, trial matching, and predictive models all need the same derived state, and they are the reason the projection exists.
Everything else in this landscape is excellent at the job it was built for. The job that keeps getting left over is all three at once: a real record system, on a substrate that supports analysis, with a person-grain projection that makes it decision-ready.
PRomop and the rest of PHRAME are open source at github.com/healthkey-ai, with a live analytics demo on synthetic data at prism.healthkey.ai. Precision trial matching — what EXACT does that ranked-list matchers don't — is its own subject, and its own post.



