annotating-variants
Annotates VCF variants and normalizes HGVS nomenclature with public, license-free annotators…
Fetches and pages FHIR R4 resources (Patient, DocumentReference, DiagnosticReport, Observation, Condition) from a FHIR REST server, decodes base64 attachments, and extracts clinical narrative for OpenMed. Use before OpenMed processing when pulling charts from an EHR FHIR API
$ npx -y skills add maziyarpanahi/openmed --skill fetching-fhir-resources --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/fetching-fhir-resourcesContext preview
The summary Claude sees to decide when to auto-load this skill.
Fetches and pages FHIR R4 resources (Patient, DocumentReference, DiagnosticReport, Observation, Condition) from a FHIR REST server, decodes base64 attachments, and extracts clinical narrative for OpenMed. Use before OpenMed processing when pulling charts from an EHR FHIR API
name: fetching-fhir-resources description: "Fetches and pages FHIR R4 resources (Patient, DocumentReference, DiagnosticReport, Observation, Condition) from a FHIR REST server, decodes base64 attachments, and extracts clinical narrative for OpenMed. Use before OpenMed processing when pulling charts from an EHR FHIR API (Epic, Cerner/Oracle, HAPI, or any US Core server) and you need the note text de-identified and analyzed, then results rejoined by patient. Hand narrative to openmed.deidentify and openmed.analyze_text; openmed.interop.fhir_operations implements a $de-identify operation over Bundles. Trigger keywords: FHIR, R4, US Core, DocumentReference, DiagnosticReport, Bundle, _revinclude, presentedForm, base64, EHR API." license: Apache-2.0 metadata: project: OpenMed category: data-ingestion pairs: before version: "1.0"
FHIR R4 is the modern EHR API: a RESTful, JSON-or-XML interface over resources like `Patient`, `Encounter`, `Condition`, `Observation`, `DiagnosticReport`, and `DocumentReference`. The unstructured clinical text you want for NLP lives in **`DocumentReference.content.attachment`** and **`DiagnosticReport.presentedForm`** — usually **base64-encoded** PDF, RTF, or plain text. This skill pulls those resources, pages through results, decodes the attachments, and hands the narrative to OpenMed.
Azure/Google/AWS HealthLake) and want note text for de-id and NER.
patient and encounter.
Search is `GET [base]/[Type]?param=value`. Results come back as a **searchset `Bundle`**; the next page is the URL in `Bundle.link` where `relation == "next"`. Use `_count` to size pages, `_revinclude` to pull related resources in one round trip, and `_since`/`_lastUpdated` for incremental sync.
GET /Patient?identifier=http://hospital.org/mrn|12345 GET /DocumentReference?patient=Patient/abc&category=clinical-note&_count=50 GET /DiagnosticReport?patient=Patient/abc&_revinclude=Observation:related
Page a search, decode attachments, hand narrative to OpenMed:
import base64
import requests
import openmed
BASE = "https://fhir.example.org/r4"
HEADERS = {"Accept": "application/fhir+json", "Authorization": "Bearer <token>"}
def iter_bundle(url, params=None):
"""Yield resources across all pages following Bundle.link[next]."""
while url:
bundle = requests.get(url, params=params, headers=HEADERS, timeout=30).json()
for entry in bundle.get("entry", []):
yield entry.get("resource", {})
params = None # next links are fully-qualified
url = next(
(l["url"] for l in bundle.get("link", []) if l.get("relation") == "next"),
None,
)
def attachment_text(att):
"""Decode a FHIR Attachment to text (handles base64 and inline text/plain)."""
if att.get("data"):
raw = base64.b64decode(att["data"])
if att.get("contentType", "").startswith("text/"):
return raw.decode("utf-8", "replace")
return "" # PDF/RTF: route to OpenMed multimodal/OCR intake instead
return ""
# Pull a patient's clinical notes and analyze each.
for doc in iter_bundle(f"{BASE}/DocumentReference",
{"patient": "Patient/abc",
"category": "clinical-note", "_count": 50}):
for content in doc.get("content", []):
text = attachment_text(content.get("attachment", {}))
if not text.strip():
continue
deid = openmed.deidentify(text, method="replace", policy="hipaa_safe_harbor")
result = openmed.analyze_text(deid.text, output_format="dict")
patient_ref = doc.get("subject", {}).get("reference") # rejoin key1. **Authenticate.** Most production FHIR endpoints use SMART-on-FHIR OAuth2 (client-credentials for backend services). Scope to the minimum (`system/DocumentReference.read`, `system/DiagnosticReport.read`). 2. **Search narrowly.** Filter by `patient`, `category`, `type` (LOINC), `date`, and `_count`. Prefer server-side filtering over client-side. 3. **Page** via `Bundle.link[next]` until exhausted. Never assume one page. 4. **Extract narrative:** `DocumentReference.content.attachment` and `DiagnosticReport.presentedForm`. Decode base64; for PDF/RTF/scanned content, route bytes to OpenMed's document intake (`multimodal`/`ocr`) rather than decoding as UTF-8. 5. **De-identify → analyze** each narrative with OpenMed. 6. **Rejoin** results to `subject.reference` (patient) and `context.encounter` so downstream consumers can group by patient/encounter — storing hashed, not raw, identifiers.
`openmed.analyze_text`. Carry `subject.reference` as the rejoin key.
the FHIR `$de-identify` *operation logic* over the OpenMed privacy pipeline:
reports modified element paths as an `OperationOutcome`. It de-identifies free-text strings, identifier values, and `text.div` narrative while never altering codes, references, systems, or temporal values. Use this to de-identify a whole fetched Bundle before storage:
from openmed.interop.fhir_operations import de_identify_bundle
safe_bundle = de_identify_bundle(bundle, policy="hipaa_safe_harbor",
method="replace")Local-first healthcare AI: clinical NER and HIPAA PII de-identification on hardware you control. 2,200+ medical models, 35 model-backed PII languages, and Python, MLX, Android and browser runtimes. Apache-2.0 SDK.
Repo: maziyarpanahi/openmed
Annotates VCF variants and normalizes HGVS nomenclature with public, license-free annotators…
Choose the first OpenMed workflow skill for an intake, privacy, extraction, exchange, or…
Package multiple FHIR R4 resources produced from OpenMed output into a single valid…
Adversarially scan already-de-identified clinical text for residual identifiers and emit a…
Produce a signed, reproducible, no-PHI audit trail for an OpenMed de-identification run via…
Generates and verifies 21 CFR Part 11-style audit trails — who/what/when, electronic…