annotating-variants
Annotates VCF variants and normalizes HGVS nomenclature with public, license-free annotators…
Normalizes drug mentions extracted by OpenMed to RxNorm RxCUIs using the free public RxNav/RxNorm REST API. Use when the user wants to code, standardize, or de-duplicate medication names, resolve a brand/generic/ingredient to a stable RxCUI, link strength+dose-form to an
$ npx -y skills add maziyarpanahi/openmed --skill normalizing-rxnorm --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/normalizing-rxnormContext preview
The summary Claude sees to decide when to auto-load this skill.
Normalizes drug mentions extracted by OpenMed to RxNorm RxCUIs using the free public RxNav/RxNorm REST API. Use when the user wants to code, standardize, or de-duplicate medication names, resolve a brand/generic/ingredient to a stable RxCUI, link strength+dose-form to an
name: normalizing-rxnorm description: "Normalizes drug mentions extracted by OpenMed to RxNorm RxCUIs using the free public RxNav/RxNorm REST API. Use when the user wants to code, standardize, or de-duplicate medication names, resolve a brand/generic/ingredient to a stable RxCUI, link strength+dose-form to an SCD/SBD, attach NDCs, or build a US Core Medication resource. Trigger keywords: RxNorm, RxCUI, RxNav, drug normalization, medication coding, NDC, ingredient, SCD, SBD, brand vs generic, getApproximateMatch. Pairs after OpenMed NER: consume Pharmaceutical/Chemical entities from openmed.analyze_text and map each drug span to an RxCUI. RxNorm and RxNav are fully public and free — no API key, no license barrier, the lowest-friction terminology in this set." license: Apache-2.0 metadata: project: OpenMed category: terminology-coding pairs: after version: "1.0"
Map free-text medication mentions that OpenMed extracts to **RxNorm** — the U.S. National Library of Medicine's normalized drug nomenclature. The unit of meaning is the **RxCUI** (RxNorm Concept Unique Identifier): a stable integer that ties together brand, generic, ingredient, strength, and dose form.
RxNorm and the **RxNav REST API** are **fully public and free**: no API key, no license agreement, no rate-limit registration for normal use. Of every skill in this terminology batch, this one has the highest value-to-friction ratio — start here when grounding medications.
you need one stable code per drug for storage, analytics, or interoperability.
product — **SCD** (Semantic Clinical Drug, generic) or **SBD** (Semantic Brand Drug) — e.g. "metformin 500 MG Oral Tablet".
`Medication`/`MedicationRequest` coded with RxNorm.
If the source text is non-English or you need ATC/SNOMED links instead, see `mapping-to-snomed`; RxNorm itself is U.S.-centric.
Base URL: `https://rxnav.nlm.nih.gov/REST`. No auth. JSON via `?...&...` paths ending in nothing or `.json` depending on endpoint; the REST root returns XML by default, so request JSON explicitly.
import requests
BASE = "https://rxnav.nlm.nih.gov/REST"
def rxcui_for(name: str) -> str | None:
"""Exact-match RxCUI lookup for a normalized drug name."""
r = requests.get(f"{BASE}/rxcui.json", params={"name": name}, timeout=10)
r.raise_for_status()
ids = r.json().get("idGroup", {}).get("rxnormId", [])
return ids[0] if ids else None
def approximate(name: str, max_entries: int = 3) -> list[dict]:
"""Fuzzy match for misspelled or abbreviated drug text."""
r = requests.get(
f"{BASE}/approximateTerm.json",
params={"term": name, "maxEntries": max_entries},
timeout=10,
)
r.raise_for_status()
return r.json().get("approximateGroup", {}).get("candidate", [])
print(rxcui_for("metformin")) # -> '6809' (ingredient)
print(approximate("metformin 500")) # fuzzy -> candidate RxCUIsResolve a full prescribable product (ingredient + strength + form) to an SCD:
# getApproximateMatch / getRxConceptProperties give term type (TTY)
def properties(rxcui: str) -> dict:
r = requests.get(f"{BASE}/rxcui/{rxcui}/properties.json", timeout=10)
r.raise_for_status()
return r.json().get("properties", {})
# Find the SCD ("metformin 500 MG Oral Tablet") from the ingredient:
def related_by_tty(rxcui: str, tty: str) -> list[dict]:
r = requests.get(
f"{BASE}/rxcui/{rxcui}/related.json", params={"tty": tty}, timeout=10
)
r.raise_for_status()
groups = r.json().get("relatedGroup", {}).get("conceptGroup", [])
out = []
for g in groups:
out.extend(g.get("conceptProperties", []) or [])
return outAttach NDCs and check interactions (both public):
ndcs = requests.get(f"{BASE}/rxcui/{rxcui}/ndcs.json").json() # package codes1. **Extract** drug spans with OpenMed (`pharma_detection_superclinical`). 2. **Parse** each span into name + strength + dose form when present ("metformin 500 mg tablet" → ingredient `metformin`, strength `500 MG`, form `Oral Tablet`). 3. **Exact match** the cleaned name with `/rxcui.json?name=`. If empty, fall back to `/approximateTerm.json`. 4. **Pick the right term type (TTY)** for your use case:
5. **Validate** by reading `/rxcui/{rxcui}/properties.json` and confirming the `tty` and `name` match expectations; record the `score` from approximate matches as a confidence signal. 6. **Emit** `{system: "http://www.nlm.nih.gov/research/umls/rxnorm", code, display}`.
OpenMed's `analyze_text` returns a `dict` whose `entities` list contains, per span, the keys `text`, `label`, `confidence`, `start`, `end`. Consume the Pharmaceutical/Chemical entities directly:
import openmed, requests
note = "Patient on metformin 500 mg BID and atorvastatin 20 mg nightly."
result = openmed.analyze_text(
note,
model_name="pharma_detection_superclinical", # Pharmaceutical category
output_format="dict",
)
DRUG_LABELS = {"DRUG", "MEDICATION", "CHEM"} # OpenMed Pharmaceutical labels
for ent in result["entities"]:
if ent["label"] in DRUG_LABELS:
span = ent["text"] # e.g. "metformin"
rxcui = rxcui_for(span) or (
(approximate(span) or [{}])[0].get("rxcui")
)
print(span,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…