OpenMed v2.1.0 is here, delivering the first feature release on the stable v2 line for local-first healthcare privacy and clinical AI.
This release expands clinical section and note-type routing, temporal and coreference graphs, calibrated relations, radiology and discharge-summary structures, dosing checks, span-grounded fact recall, offline terminology grounding, OMOP loading, FHIR and OpenEHR export, cohort phenotype resolution, structured privacy, multimodal intake, and typed MCP workflows.
OpenMed 2.1 also strengthens the deployment surface: Android now follows the documented Unicode-scalar offset contract and ships a fail-closed 753-entry on-device catalog derived from the committed 2,266-entry public manifest; the browser and Node.js package remains available as openmed; and the Python, Swift, Helm, service, and container version surfaces are synchronized on 2.1.0.
The public Python inventory grows from 20,538 to 31,619 symbols with 11,081 additions, no removed or narrowed public symbols, and no new deprecations. The REST contract grows additively from 15 paths and 12 component schemas to 17 paths and 15 schemas.
Install or upgrade:
pip install --upgrade "openmed==2.1.0"
npm install openmed@2.1.0Swift Package Manager:
.package(url: "https://github.com/maziyarpanahi/openmed.git", from: "2.1.0")Android through JitPack:
implementation("com.github.maziyarpanahi:openmed:v2.1.0")Container:
docker pull ghcr.io/maziyarpanahi/openmed:v2.1.0Release notes: https://openmed.life/docs/release/v2.1.0/
Migration guide: https://openmed.life/docs/migration/2.0-to-2.1/
Full changelog: v2.0.0...v2.1.0
Release scope
The current published v2.0.0 tag resolves to rewritten-history commit 94ace7d and is an ancestor of current master through merge boundary b9ab7a3d. Public API compatibility compares the tagged trees directly, while the release integration ledger follows changes after that boundary.
The integration ledger in CHANGELOG.md records 213 PR-associated integrations and seven direct integrations, plus the final release-hardening change set. It covers the Python package, tests, documentation, examples, website, Android, JavaScript, service, MCP, deployment, model manifest, evaluation, security, and release-engineering surfaces.
Highlights
- Clinical extraction: Note-type and section routing, temporal and coreference graphs, calibrated medication and problem relations, radiology and discharge structures, dosing sanity checks, clinical fact recall, and span-grounded faithfulness.
- Grounding and interoperability: Caller-supplied offline terminology snapshots, hybrid grounding, OMOP loading, FHIR and OpenEHR export, local cohort phenotype resolution, and typed clinical MCP workflows.
- Structured privacy: Declarative generalization, relational k-anonymity, streaming tabular anonymization, aggregate-only differential privacy, attacker-model reports, and review-first column semantics.
- Multilingual and multimodal intake: Unicode and grapheme-safe routing, Vietnamese model-backed coverage, Urdu and Indic routing, Belgian and Swiss national-ID validation, RTF and DICOM-SR extraction, OCR layout reconstruction, and opt-in YASBD sentence segmentation.
- On-device and distributed adapters: Android Unicode-scalar parity, grapheme repair, packaged R8 consumer rules, a 753-entry public on-device catalog, Flutter FFI support, and optional Beam, Ray Data, PySpark, Haystack, and LangGraph paths.
- Evaluation and release safety: DirectID evidence, deterministic safety sweeps, signed scorecards, cross-corpus and cross-lingual evaluation, staged promotion, last-green rollback, public-API checks, and fail-closed release readiness.
Clinical extraction and terminology grounding
OpenMed 2.1 expands deterministic clinical document processing across section and document-type routing, coreference, temporal ordering, medication and problem relations, radiology findings, discharge structures, dosing checks, and span-grounded fact recall.
Terminology workflows accept explicit local snapshots and preserve version, code-system, match, abstention, and provenance evidence. OncoTree and other restricted or externally governed terminology inputs remain caller-supplied; the SDK does not silently download or bundle them.
Clinical MCP tools expose typed grounding, FHIR export, risk, signed-audit, model-search, and staged pipeline operations. Existing MCP clients should refresh cached schemas before enabling the new tools.
Interoperability and structured privacy
New local workflows cover OMOP loading, cohort phenotype resolution, FHIR and OpenEHR export, streaming tabular processing, declarative generalization, relational k-anonymity, aggregate-only differential privacy, and attacker-model risk reporting.
Apache Beam, Ray Data, PySpark, Haystack, LangGraph, and sdcMicro integration paths remain optional. The interop-gpl extra installs no GPL code; R and sdcMicro remain separate, out-of-process, user-managed software.
DUA-gated corpora and licensed terminologies are never bundled. Loaders require caller-supplied paths, credentials, or snapshots and preserve explicit local provenance rather than treating data availability as permission to redistribute.
Multilingual and multimodal processing
Vietnamese is now a model-backed PII language route, while Urdu and additional Indic codes gain explicit routing and user-supplied-model behavior. Script segmentation is grapheme-aligned and keeps combining sequences, virama conjuncts, zero-width-joiner sequences, and regional-indicator pairs intact.
RTF extraction is stdlib-only and maps extracted characters back to source offsets. DICOM-SR, OCR layout, and other multimodal paths continue to require deployment-specific validation and optional dependencies where documented.
The release advertises 35 built-in PII routes: 33 are model-backed and the Russian and Tamil routes are explicit placeholders. Production Russian or Tamil extraction requires caller-qualified weights and deployment evidence.
Python, REST, CLI, and MCP
The documented Python imports remain available, including:
from openmed import OpenMedConfig, analyze_text, deidentify, extract_piiNew CLI groups cover model-cache management, batch-run resume and reporting, OMOP loading, cohort resolution, OpenEHR export, registry lineage, and release rollback. Existing commands remain available.
REST adds POST /cohort/resolve and POST /omop/load without replacing an existing route. Applications that generate clients from OpenAPI can regenerate to expose the new operations; applications using only existing routes do not need a compatibility shim.
Android, Swift, browser, and deployment
Android OpenMedKit now returns half-open Unicode-scalar offsets consistently from entity predictions, spans, token decoding, and policy de-identification. Applications that pass offsets to Kotlin UTF-16 string APIs for non-BMP text must convert with EntityPrediction.utf16SpanIn.
The Android AAR derives a 753-entry permissively licensed ONNX/TFLite catalog from the committed 2,266-entry public manifest and fails the build if that derivation is empty. Catalog metadata identifies discoverable artifacts; it is not downloaded model data or model-quality evidence.
Swift package sources are unchanged in this release range. The package version coordinates and demo bundle versions are synchronized to 2.1.0, and the existing Unicode-offset parity tests remain green.
The unscoped npm package openmed continues to ship ESM and CommonJS exports for browser and Node.js use. Helm chart metadata, default image selection, and the generated REST OpenAPI version are synchronized to 2.1.0.
Compatibility and migration
The static public Python comparison against the published v2.0.0 tree records 11,081 additions, no removals or renames, no narrowed callable signatures, and no newly deprecated symbols.
Android Unicode offsets are the only called-out behavioral migration. ASCII and Basic Multilingual Plane-only text retains the same numeric offsets; code that applies offsets to strings containing emoji or other non-BMP characters must convert scalar offsets to Kotlin UTF-16 indices first.
Applications using the Android model catalog should re-evaluate pinned or filtered entries against the refreshed catalog. Applications relying on the former dedicated Tamil default must configure and qualify explicit weights.
See the complete migration guide at https://openmed.life/docs/migration/2.0-to-2.1/.
Security and release hardening
- Core PHI processing remains local after explicitly required artifacts are available; telemetry remains off by default.
- Model, terminology, and dataset downloads remain explicit trust and network boundaries with separate license and integrity review.
- Release evidence records hashes, counts, offsets, thresholds, and provenance rather than raw identifiers or source clinical text.
- Repository, license, secret, action-reference, dependency-vulnerability, SBOM, provenance, API compatibility, package-content, and deterministic test policies are enforced by dedicated gates.
- Public model-manifest refreshes disable implicit Hub authentication, preserve reviewed metadata, and fail closed when Android catalog generation is empty.
- Release readiness treats missing evidence as failure; an absent staged report is never interpreted as a successful no-op.
Local validation completed before merge
- Python: 11,539 tests passed, 95 were skipped, one expected failure was recorded, and 20 warnings were reported by the complete suite.
- Release-focused tests: 276 API-compatibility, publication-workflow, provenance, release-gate, and readiness tests passed.
- End-to-end golden scope: 203 tests passed and three were skipped.
- Static API compatibility: 20,538 to 31,619 public symbols, 11,081 additions, zero breaking changes, and zero new deprecations; migration completeness passed.
- REST/OpenAPI: generated output is synchronized on
2.1.0, with 17 paths and 15 component schemas. - Documentation: strict multilingual MkDocs builds and the exact Pages staging pipeline passed route, asset, LLM-feed, metadata, and locale validation.
- Browser and Pages: 386 tests passed across Chromium, Firefox, and WebKit with 46 expected skips; the 300-file staged artifact passed ownership, hash, and byte-budget checks without local model or runtime payloads.
- Python artifacts: wheel and source distribution built successfully, passed
twine check, passed content inspection, and installed with working imports and CLI entry points in a clean Python 3.11 environment. - JavaScript: dependency audit found zero vulnerabilities; build, typecheck, nine Node/browser-runtime tests, and dry-run npm packaging passed.
- Swift: formatting, dependency resolution, package build, a generic iOS Simulator build, 70 package tests with 14 expected local MLX-resource skips, and the focused offset-parity test passed.
- Android: debug AAR assembly, 87 unit tests, the 753-entry catalog, release version validation, release AAR assembly, and consumer-rule verification passed for
2.1.0. - Helm: default and CI values passed lint and template rendering.
- Security: high-severity Bandit, secret scanning, license policy, GitHub Actions reference policy, pip-audit with zero known vulnerabilities, and a CycloneDX 1.6 SBOM for OpenMed 2.1.0 plus 135 runtime dependencies passed.
- Version preflight: every active release surface resolves to
2.1.0, and thev2.1.0tag was unused locally and on origin at validation time.
Required exact-commit and tag-time validation
The final merged release commit must still receive green hosted checks on that exact SHA. In particular, the Linux containerized browser job must compare the approved pixel snapshots, applicable Apple simulator jobs must pass, container build and smoke tests must pass on amd64 and arm64, and the secret-backed signed Android Central Portal bundle must be produced where configured.
Release readiness also requires real staged inputs at artifacts/release-candidate.json, artifacts/release-candidate-shield.json, and artifacts/staged-models.jsonl. Those inputs drive fresh golden and public SHIELD evaluation, signed release gates, evidence binding, and a final readiness decision of exactly READY. They are not fabricated or replaced by the synthetic unit-test results above.
Registry availability, immutable package and image coordinates, live documentation, checksums, attestations, and published release assets are verified only after the tag-driven workflows complete.
Privacy and clinical boundaries
OpenMed keeps local processing as the default, but no de-identification system can guarantee zero residual risk. Validate direct-identifier recall, critical leakage, span integrity, language and script coverage, policy behavior, quantized-model deltas, and device behavior against deployment-specific fixtures before production use.
Clinical extraction is assistive software, not a medical device or a source of clinical ground truth. Outputs require qualified review and must not automatically trigger diagnosis, treatment, billing, or other clinical decisions.
Build hashes and package checksums establish artifact identity; they do not prove model quality. Model-specific evidence must be evaluated independently for each selected model, language, quantization, runtime, and deployment.
Contributor and change inventory
Thank you to every contributor whose work is included in this release, with a special welcome to first-time contributors @speedyk-005 and @josephkehan-prog.
The complete pull-request and commit inventory, including direct integrations and final release hardening, is recorded in CHANGELOG.md.
What's Changed
- Keep skipped model publishes idempotent by @maziyarpanahi in #2001
- feat: add DirectID dataset assembly manifest by @maziyarpanahi in #1997
- Connect DirectID outputs to safety-sweep evidence by @maziyarpanahi in #2002
- Add incremental on-device grounding index shards by @maziyarpanahi in #2003
- Enforce span-grounded faithfulness for extracted facts by @maziyarpanahi in #2006
- feat: add DirectID tiny distillation run evidence by @maziyarpanahi in #2000
- feat: certify DirectID tiny checkpoint evidence by @maziyarpanahi in #2007
- Add cross-document linkage release gate by @maziyarpanahi in #2009
- feat: add DirectID tiny quantization evidence by @maziyarpanahi in #2004
- Add end-to-end pipeline error attribution by @maziyarpanahi in #2010
- Harden deidentification against adversarial input by @maziyarpanahi in #1953
- Add longitudinal linkage risk dashboard panel by @maziyarpanahi in #2011
- OM-798: Add pipeline-stage contract property tests by @maziyarpanahi in #2012
- Gate relation regressions against pinned baselines by @maziyarpanahi in #2013
- Add cross-modal subject surrogate consistency by @maziyarpanahi in #2008
- Add structured attacker-model re-identification risk report by @maziyarpanahi in #2018
- Wire relation suites into signed scorecards by @maziyarpanahi in #2017
- Document multilingual ConText lexicon contributions by @maziyarpanahi in #2019
- OM-800: Add per-request resource and timeout budgets by @maziyarpanahi in #2014
- OM-801: Add shared input-normalization and validation gateway by @maziyarpanahi in #2023
- Complete relation evaluation harness gates by @maziyarpanahi in #2021
- Add MCP clinical workflow contracts and stage-order validation by @maziyarpanahi in #2026
- Add multilingual ConText reporting summaries by @maziyarpanahi in #2024
- Add MCP clinical workflow handlers by @maziyarpanahi in #2043
- Align overlap resolution with canonical label risk policy by @maziyarpanahi in #2054
- Add Japanese multilingual ConText cue pack by @maziyarpanahi in #2022
- Execute composable clinical MCP pipelines by @maziyarpanahi in #2047
- Add OMOP replace-by-note loading by @maziyarpanahi in #2055
- feat: add human-in-the-loop review workflow by @maziyarpanahi in #2025
- Add Postgres OMOP DDL and constraint validation by @maziyarpanahi in #2057
- Fix multilingual recent ConText section priors by @maziyarpanahi in #2056
- Complete the section 4.2 package scaffold by @maziyarpanahi in #2041
- Mark model cards as manifest-generated by @maziyarpanahi in #2059
- Add typed TLINK candidate extraction primitives by @maziyarpanahi in #2060
- Complete OMOP CDM vocabulary-aware loading by @maziyarpanahi in #2061
- Wire daily release gates into staged promotion and rollback by @maziyarpanahi in #2045
- feat: add yasbd backend options for sentence segmentation and analysis by @speedyk-005 in #2005
- Add a canonical callable schema registry by @maziyarpanahi in #2050
- Preserve prediction spans in re-identification risk reports by @maziyarpanahi in #2065
- Decode temporal TLINKs into a consistent reduced graph by @maziyarpanahi in #2064
- Implement OncoTree tumor-type mapping by @mrfeathers in #2058
- Add MCP clinical workflow discovery and golden fixture by @maziyarpanahi in #2052
- Expose privacy-safe event timeline ordering by @maziyarpanahi in #2066
- Complete clinical MCP workflow validation by @maziyarpanahi in #2072
- Add clinical document type classification by @maziyarpanahi in #2074
- feat: anchor clinical events to DCT and TIMEX values by @maziyarpanahi in #2062
- feat: add temporal TLINK gold and consistency metrics by @maziyarpanahi in #2068
- Attach clinical event frames to coreference representatives by @maziyarpanahi in #2073
- Add privacy-safe clinical event coreference candidate clustering by @maziyarpanahi in #2071
- Complete leakage-first eval benchmark harness by @maziyarpanahi in #2063
- Add rules-first clinical section detection by @maziyarpanahi in #2078
- Add plugin example package and conformance kit by @maziyarpanahi in #2079
- Harden synthetic golden fixture validation by @maziyarpanahi in #2080
- Collapse coreferent clinical relation and FHIR outputs by @maziyarpanahi in #2075
- Wire discovered plugins into runtime registries by @maziyarpanahi in #2081
- Harden Indic NER checkpoint compatibility by @maziyarpanahi in #2086
- Complete clinical temporal relations and timeline composition by @maziyarpanahi in #2087
- Complete signed audit report provenance by @maziyarpanahi in #2067
- Add shadow-canary rollout orchestration with automatic rollback by @maziyarpanahi in #2070
- feat: expand Naamapadam robustness evaluation by @maziyarpanahi in #2088
- Add opt-in clinical assertion context by @maziyarpanahi in #2089
- Add redaction-preserving retrieval toolkit by @maziyarpanahi in #2076
- Add core plugin SDK protocols and registry by @maziyarpanahi in #2077
- Add language-family taxonomy and transfer graph config by @maziyarpanahi in #2090
- Complete clinical event coreference cluster indexing by @maziyarpanahi in #2104
- Add donor-to-target adapter fine-tuning recipe by @maziyarpanahi in #2103
- feat: add composite concept normalization and re-linking by @maziyarpanahi in #2106
- Add zero-shot family-transfer adapter routing by @maziyarpanahi in #2105
- feat: add family-transfer evaluation reporting by @maziyarpanahi in #2108
- Add medication-attribute relation extraction by @maziyarpanahi in #2084
- Add validated post-coordination expressions by @maziyarpanahi in #2110
- Add joint span-pair entity and relation decoder by @maziyarpanahi in #2111
- Detect and suppress boilerplate and copy-forward note spans by @maziyarpanahi in #2112
- feat: add offline model registry state and rollback pointers by @maziyarpanahi in #2091
- Restore shared vulnerability gates after the August review by @maziyarpanahi in #2182
- Enforce relational privacy across linked tables by @maziyarpanahi in #2119
- Emit grounded concepts as FHIR CodeableConcepts by @maziyarpanahi in #2120
- Parse clinical list and enumeration structure by @maziyarpanahi in #2116
- Add review-first clinical column semantic classifier by @maziyarpanahi in #2125
- Add per-language clinical normalization by @maziyarpanahi in #2122
- Graph-orchestration and modular-search-pipeline adapters for redaction-safe clinical flows by @maziyarpanahi in #2132
- Resolve cross-sentence document-level relations with evidence aggregation by @maziyarpanahi in #2126
- Orchestrate nightly model releases with an audit trail by @maziyarpanahi in #2128
- Unify clinical relation extraction facade by @maziyarpanahi in #2136
- Deterministic-output guarantees with a same-input-same-spans regression harness by @maziyarpanahi in #2137
- fix(eval): reject unseeded rollout transitions by @maziyarpanahi in #2183
- Order clinical events from supplied TLINK candidates by @maziyarpanahi in #2129
- Add SHAC-aligned SDOH finding schema and dispatcher by @maziyarpanahi in #2143
- OM-820: Graceful degradation when an optional model or extra is missing by @maziyarpanahi in #2131
- Qualify language-family adapter transfer efficiency by @maziyarpanahi in #2144
- Build the section and document-type training-label builder by @maziyarpanahi in #2146
- Build laterality and finding-site SNOMED expressions by @maziyarpanahi in #2188
- Propagate section-scoped clinical context across spans by @maziyarpanahi in #2190
- feat: add multilingual grounding for ICD-10-CN and Indic terms by @maziyarpanahi in #2124
- Calibrate relation confidence and enable abstention by @maziyarpanahi in #2198
- Add problem-attribute relation extraction by @maziyarpanahi in #2138
- Certify clinical model family releases by @maziyarpanahi in #2201
- Add canonical biomedical entity labels by @maziyarpanahi in #2139
- Add lab result structuring by @maziyarpanahi in #2145
- Add the data-driven ConText rule engine by @maziyarpanahi in #2117
- Add history-family section segmenter by @maziyarpanahi in #2189
- Add radiology findings NER domain by @maziyarpanahi in #2211
- Add validated clinical section detection orchestration by @maziyarpanahi in #2212
- Integrate biomedical NER family documentation by @maziyarpanahi in #2216
- Document biomedical NER families by @alberthammerich in #2186
- Integrate deterministic RTF text extraction by @maziyarpanahi in #2217
- feat(multimodal): add RTF text extraction with a char-offset map by @josephkehan-prog in #2107
- Integrate fail-safe rollout rollback decisions by @maziyarpanahi in #2219
- feat: add gate-regression to rollback decision function by @DrVelvetFog in #2109
- feat: expand multilingual evaluation and distributed batch processing by @maziyarpanahi in #2213
- Build the scheduler and batch multi-model release dispatch by @maziyarpanahi in #335
- feat: add aggregate-only DP synthetic table generation by @maziyarpanahi in #2121
- fix: make streaming table output boundary-invariant by @maziyarpanahi in #2184
- Package Android R8 consumer rules by @alberthammerich in #2218
- Layout block segmenter reconstructing multi-column reading order from OCR bboxes by @maziyarpanahi in #2222
- feat: map document classifier to LOINC document ontology by @maziyarpanahi in #2223
- feat: add terminology snapshot cache by @maziyarpanahi in #2224
- Add Belgian Rijksregister and Swiss AHV national-ID validators by @maziyarpanahi in #2231
- Add the n2c2 2018 Track 1 de-identification eval-only loader by @maziyarpanahi in #2232
- Add family-history relation attribution linking conditions to family members by @maziyarpanahi in #2235
- Add dataflow-tool processor for in-flow record redaction by @maziyarpanahi in #2236
- Add model download and cache management CLI by @maziyarpanahi in #2238
- feat: add lightweight clinical relation candidates by @maziyarpanahi in #2240
- Add an inter-annotator-agreement scorer with Cohen and Fleiss kappa by @maziyarpanahi in #2242
- Add Android artifact fields to the model manifest and model card by @maziyarpanahi in #2253
- Add a local FFI plugin for on-device de-identification by @maziyarpanahi in #2256
- Add credential-gated DUA relation corpus loaders by @maziyarpanahi in #2199
- feat: add Apache Beam de-identification transform by @maziyarpanahi in #2151
- Add a DICOM-SR content-tree structured-text extractor by @maziyarpanahi in #2205
- Add local cohort phenotype resolution by @maziyarpanahi in #2134
- Add burned-in OCR text synthetic generator by @maziyarpanahi in #2147
- Add Ray Data de-identification map operator by @maziyarpanahi in #2150
- Add sdcMicro out-of-process disclosure-risk bridge by @maziyarpanahi in #2153
- LOINC-informed document-type feature and label mapping for note-type classification by @maziyarpanahi in #2221
- Add a learned section-detection head with LOINC section codes for messy notes by @maziyarpanahi in #2270
- Complete longitudinal document linking and de-duplication by @maziyarpanahi in #2148
- Add offline drug-drug interaction flagging by @maziyarpanahi in #2209
- Add a structured discharge-summary extractor for diagnoses, procedures, discharge meds and follow-up by @maziyarpanahi in #2272
- feat: add RxNorm free vocabulary loader by @maziyarpanahi in #2114
- Add a LOINC free-vocabulary loader with part and answer-list awareness by @maziyarpanahi in #2115
- Add an ICD-10-CM free-vocabulary loader with code validity and hierarchy traversal by @maziyarpanahi in #2118
- OM-823: Memory-bounded streaming for very long documents by @maziyarpanahi in #2207
- Add an Eastern-digit and Unicode normalization layer for i18n PII detection by @maziyarpanahi in #2266
- Dosing-range sanity checker flagging out-of-range extracted doses for clinician review by @maziyarpanahi in #2273
- fix(structured): validate declarative date generalization inputs by @maziyarpanahi in #2203
- fix(structured): keep anonymization errors raw-value free by @maziyarpanahi in #2275
- Add structured tabular anonymization workflow by @maziyarpanahi in #2141
- Add a cross-corpus generalization report to the eval harness by @maziyarpanahi in #2180
- Complete extension SDK and registry acceptance by @maziyarpanahi in #2194
- Add a clinical fact recall metric for summary faithfulness by @maziyarpanahi in #2269
- Add note-type routing profiles for radiology and pathology by @maziyarpanahi in #2271
New Contributors
- @speedyk-005 made their first contribution in #2005
- @josephkehan-prog made their first contribution in #2107
Full Changelog: v2.0.0...v2.1.0