# OpenMed: on-device clinical NER and PII de-identification in Python

> OpenMed is an Apache-2.0 SDK that runs clinical entity extraction and HIPAA-oriented de-identification on hardware you control. It installs from PyPI, ships an MLX path for Apple Silicon, and leaves model and dataset licensing to the deployer.

**maziyarpanahi/openmed** — Local-first healthcare AI: clinical NER & HIPAA PII de-identification that runs 100% on-device. 2,200+ medical models, 21 languages, Apple MLX + Python, no cloud, no patient data leaving your network. Apache-2.0.

- Repository: https://github.com/maziyarpanahi/openmed
- Website: https://openmed.life/
- Stars: 5,413 · Forks: 690
- Language: Python
- License: Apache-2.0
- Published: 2026-08-08 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/maziyarpanahi-openmed

## What OpenMed does, and who actually needs it

OpenMed is a Python SDK for two jobs: pulling structured clinical entities out of free text, and removing personally identifiable information from it. The README frames the whole project around one constraint, that patient text should not have to leave the network to be processed. The 30-second example in the README is a single function call, `analyze_text`, that returns entities with a label, the matched span, and a confidence score.

The intended user is not a clinician clicking a button. It is an engineer or data platform team that has clinical notes, discharge summaries, or intake forms sitting in a warehouse and needs either structured signals or a de-identified copy before anything downstream touches it. The repository layout supports that reading: there are example directories for dbt, Dagster, Dataflow, DHIS2 and OpenMRS integrations, plus a Gradio app and a Flutter example. This is infrastructure, not an application.

The scope claim worth noticing is the model catalog, described as 2,200+ medical models across 21 languages in the project description, while the README banner says 33 model-backed PII languages. Those two numbers measure different things, and the README does not reconcile them. Treat the catalog as a directory to search, not as a guarantee that your language and entity type are both covered.

## The local runtime boundary and where network calls still happen

The README is unusually careful about what "local" means, and that care is the most useful thing in the document. It states that the core local runtime performs extraction and de-identification after required model artifacts are available, and then lists the paths that may still use a network: model downloads, remote-provider adapters, telemetry-enabled paths, and user-configured integrations. The deployment table repeats the same split.

That distinction matters because "no patient data leaving your network" is only true once the artifacts are on disk. The first run of any model will fetch weights, and the Docker setup makes this explicit by mounting a shared `hf-cache` volume and accepting an `HF_TOKEN`. If your environment has no outbound access, you need to populate that cache ahead of time; the README does not describe an offline bundle for doing so.

The second boundary is licensing. The README says the SDK source is Apache-2.0, and then says model and dataset terms vary, and that deployment owners validate them. That is not boilerplate. A curated catalog of thousands of models pulled from different sources will contain checkpoints with different redistribution and commercial-use terms. The SDK licence tells you nothing about the model you actually load.

## Installing OpenMed and running a first de-identification

The package is on PyPI and requires Python 3.10 or newer, per `pyproject.toml`. A plain install pulls only four runtime dependencies (pysbd, faker, jieba, pyyaml), which is a deliberate choice: the heavy ML stack lives behind extras. The README gives the MLX extra as `pip install --upgrade "openmed[mlx]"` for Apple Silicon, and the Dockerfile installs `.[hf,service]` for the container image.

```bash
pip install openmed
```

After that, the README's own example is the fastest way to confirm the runtime works. It loads a disease detection model and prints one entity per line.

```python
from openmed import analyze_text

result = analyze_text(
    "Patient started on imatinib for chronic myeloid leukemia.",
    model_name="disease_detection_superclinical",
)

for entity in result.entities:
    print(f"{entity.label:<12} {entity.text:<28} {entity.confidence:.2f}")
```

The README shows the expected output as a DISEASE span for "chronic myeloid leukemia" at 0.98 and a DRUG span for "imatinib" at 0.95. Your first call will also trigger the model download, which is the network step described above.

If you would rather not manage Python environments, the repository ships a compose file with two services. The application service listens on port 8080 and the MCP service on 8081, bound to localhost by default.

```bash
docker compose up
```

The app container exposes a `/health` endpoint and runs uvicorn against `openmed.service.app:app`; the MCP container runs a streamable-http transport at the `/mcp` path. Both mount the same Hugging Face cache volume, so the second start does not re-download.

## Apple Silicon, Android and browser paths are not equivalent

OpenMed advertises several execution surfaces, and the README is honest that they vary by environment and artifact. On Apple hardware there is a Swift package, OpenMedKit, added through Swift Package Manager at version 2.2.0, plus an MLX runtime for PII token classification, the Privacy Filter family, experimental GLiNER-family zero-shot tasks, and MLX-LM text generation with Laneformer. There is a CoreML fallback for supported token-classification artifacts. The README also notes that an MLX model name can fall back to a matching PyTorch checkpoint when that mapping exists, which is a portability convenience rather than a guarantee.

The performance claim in the README is specific and bounded: MLX on Apple Silicon is described as 24 to 33 times faster than CPU PyTorch for the Privacy Filter, measured as median latency per inference step. That number is for one model family on one class of hardware. The README does not publish a comparable figure for CUDA, for the ONNX path, or for the general NER models, so do not generalize it.

Android is a separate story. The Kotlin library goes through JitPack, requires a scoped repository entry in `settings.gradle.kts`, and depends on ONNX Runtime Mobile with model repositories that carry stable tensor names, dynamic sequence axes, tokenizer files, labels, and fp32, fp16, INT8 or optional `.ort` outputs. The README links a browser path through Transformers.js as well. Each of these is a different artifact pipeline, and a model that works in Python will not automatically exist in the mobile or browser formats.

## Where OpenMed is the wrong tool

The README states plainly that use of the SDK does not itself establish HIPAA compliance, and that expert deployment review remains required. The Safe Harbor configuration can target the 18 identifier categories, but targeting a category list is a configuration, not an audit. If your compliance team needs a vendor who will sign a business associate agreement and accept liability for redaction errors, a self-hosted Apache-2.0 SDK is not that vendor. You are the vendor.

There is a second failure mode in the design of NER-based de-identification generally, and nothing in the README claims otherwise: recall is bounded by the model. A name or identifier pattern that the model was not trained on will pass through. The README's own demo uses synthetic values, which is the right way to show a screenshot but tells you nothing about miss rates on your data. Anyone planning to release de-identified text downstream needs their own held-out evaluation, and the repository does ship an `eval/` directory and a `gates/` directory that suggest the maintainers think about this.

Finally, the language coverage claim deserves scrutiny. The banner says 33 model-backed PII languages while the project description says 21 languages overall. If your notes are in a language where only the general NER models exist and no PII model does, the de-identification half of the pitch does not apply to you.

## How it compares to Presidio and to hosted clinical NLP APIs

The closest open alternative in this space is Microsoft Presidio, and the difference is architectural rather than cosmetic. Presidio is a detection framework built around pattern recognizers, checksum validators, and pluggable NLP engines, with spaCy or transformers as the underlying model. It is strong on structured identifiers such as phone numbers, account numbers, and dates, where a regex plus a checksum is more reliable than a neural tagger. OpenMed inverts that emphasis: the default path is a domain-tuned clinical model, and the catalog is organized around medical entity types such as disease and drug alongside PII labels. If your problem is mostly finding MRNs and phone numbers in English text, Presidio's deterministic recognizers are easier to reason about. If your problem is finding patient names and clinical concepts inside narrative notes, a fine-tuned clinical model is the more direct route, and OpenMed packages that route with an MLX and mobile story that Presidio does not have.

The other comparison is hosted clinical NLP services. Those give you an endpoint, an SLA, and a compliance posture, at the cost of sending text off your network. OpenMed's entire reason for existing is to avoid that trade. The cost you accept instead is operational: you own the model cache, the GPU or Apple Silicon capacity, the artifact versions, and the evaluation.

## Maintenance cadence, licence and upgrade cost

The repository is not archived, and the last push was on 2026-08-21, which coincides with the v2.2.0 release. Two earlier releases, v2.1.0 and v2.0.0, landed in the same six-week window in July and August 2026. That is a fast release cadence, and fast cadences have a cost: the 2.x line moved three times in about a month, so pinning a version is advisable before you build anything on top of it.

The SDK is Apache-2.0, which permits commercial use and modification. The licence does not extend to the models. The README says model and dataset terms vary and that deployment owners validate them, and the model catalog is hosted on Hugging Face under a separate organization. In practice this means a legal review of the SDK is quick and a legal review of your chosen checkpoint is not. Nothing here is legal advice; the point is that the two artefacts carry different terms.

Upgrade cost is dominated by the model cache rather than the code. The Docker compose file centralizes the cache in a named volume, so image rebuilds do not invalidate downloaded weights, but a model rename or a format change between versions will. The `models.jsonl` file at the repository root is the catalog index, and it is the file to diff when you upgrade.

## Conclusion

Adopt OpenMed if you need clinical entity extraction or PII redaction to run on hardware you control and you accept that model and dataset terms are your responsibility. Do not adopt it if you expect the SDK alone to make you HIPAA compliant, or if you need a hosted endpoint with a support contract. Before committing, verify three things: that the specific model you plan to use is available and licensed for your use case, that your target language is actually covered by a model rather than by the language list in the README, and that your deployment path (CPU, CUDA, MLX, Android, browser) has a working artifact for the task you need.

## FAQ

### How do I install OpenMed?

Install the package from PyPI with pip, which requires Python 3.10 or newer. Apple Silicon users can add the MLX extra, and a Docker compose file is provided for the service and MCP containers.

### Does OpenMed keep patient data on my own hardware?

The README states that the core local runtime performs extraction and de-identification after required model artifacts are available. It also lists model downloads, remote-provider adapters, telemetry-enabled paths and user-configured integrations as paths that may use a network.

### Which languages does OpenMed support for PII de-identification?

The README banner says 33 model-backed PII languages, while the project description says 21 languages overall. The two figures measure different things and the README does not reconcile them, so check the catalog for your specific language.

### Does using OpenMed make my deployment HIPAA compliant?

No. The README states that Safe Harbor-aligned configuration can target the 18 identifier categories but that use of the SDK does not itself establish HIPAA compliance and expert deployment review remains required.

## Sources

- [Official documentation](https://openmed.life/)
- [Official README](https://github.com/maziyarpanahi/openmed#readme)
- [Project repository](https://github.com/maziyarpanahi/openmed)
- [Release notes](https://github.com/maziyarpanahi/openmed/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/maziyarpanahi-openmed
