Agent Skillsmaziyarpanahi/openmed › mapping-to-snomed

mapping-to-snomed

GitHub

将OpenMed提取的临床概念映射到SNOMED CT。通过用户提供的术语服务器(如Ontoserver、Snowstorm)执行SCTID查找、ECL查询及代码转换,严禁捆绑任何受版权保护的词汇数据。

skills/mapping-to-snomed/SKILL.md maziyarpanahi/openmed

Trigger Scenarios

SNOMED CT SNOMED concept id ECL ConceptMap $translate $lookup Ontoserver Snowstorm SCTID post-coordination terminology server

Install

npx skills add maziyarpanahi/openmed --skill mapping-to-snomed -g -y
More Options

Use without installing

npx skills use maziyarpanahi/openmed@mapping-to-snomed

指定 Agent (Claude Code)

npx skills add maziyarpanahi/openmed --skill mapping-to-snomed -a claude-code -g -y

安装 repo 全部 skill

npx skills add maziyarpanahi/openmed --all -g -y

预览 repo 内 skill

npx skills add maziyarpanahi/openmed --list

SKILL.md

Frontmatter
{
    "name": "mapping-to-snomed",
    "license": "Apache-2.0",
    "metadata": {
        "pairs": "after",
        "project": "OpenMed",
        "version": "1.0",
        "category": "terminology-coding"
    },
    "description": "Maps clinical concept spans extracted by OpenMed to SNOMED CT concepts through a USER-SUPPLIED terminology server (the user's own Ontoserver, Snowstorm, or UMLS\/UTS), never a bundled vocabulary. Use when the user wants to code findings, disorders, procedures, body structures, or substances to SNOMED CT, run an ECL query, translate via a ConceptMap, or resolve a span to a concept id with FHIR $lookup\/$translate\/$validate-code. Trigger keywords: SNOMED CT, SNOMED concept id, ECL, ConceptMap, $translate, $lookup, Ontoserver, Snowstorm, SCTID, post-coordination, terminology server. Pairs after OpenMed NER: consume Disease\/Anatomy\/Pharmaceutical entities from openmed.analyze_text and map each span out-of-process. SNOMED CT is license-restricted — it is NEVER bundled; the user calls their own affiliate-licensed server."
}

Mapping OpenMed spans to SNOMED CT

Ground clinical concept spans that OpenMed extracts — disorders, findings, procedures, body structures, substances — to SNOMED CT, the comprehensive clinical reference terminology. The atom is the SCTID (a SNOMED CT concept identifier), organized into a description-logic hierarchy you can query with ECL (Expression Constraint Language).

Hard licensing boundary — read first. SNOMED CT is license-restricted. OpenMed and this skill never bundle, ship, cache, or redistribute any SNOMED CT content. All mapping happens out-of-process against a terminology server the user supplies and is licensed for — their own Ontoserver, Snowstorm, the NLM's UTS/UMLS FHIR endpoint, or a national release server. SNOMED International requires an Affiliate License (free in member territories like the US via the NLM; check your country). Your code receives a base URL + credentials from the user; it must work with any compliant FHIR terminology server and store nothing but the returned codes.

When to use

  • You need rich, hierarchy-aware clinical codes (more granular than ICD-10) for problems, procedures, or body sites.
  • You want to translate an existing code (ICD-10-CM, local code) to SNOMED CT via a ConceptMap/$translate.
  • You need subsumption/ECL queries ("is this a descendant of Diabetes mellitus?") for cohorting or decision support.

For billing codes use coding-icd10; for drugs normalizing-rxnorm; for labs mapping-loinc. SNOMED CT is the clinical-meaning layer.

Quick start (user-supplied FHIR terminology server)

Configuration is injected, never hardcoded. The operations are standard FHIR R4.

import os, requests

# Provided by the USER — their licensed server. Nothing bundled.
TX = os.environ["FHIR_TX_URL"]              # e.g. https://snowstorm.example.org/fhir
TOKEN = os.environ.get("FHIR_TX_TOKEN")     # if the server requires auth
SNOMED = "http://snomed.info/sct"
HDRS = {"Accept": "application/fhir+json"}
if TOKEN:
    HDRS["Authorization"] = f"Bearer {TOKEN}"

def lookup(code: str) -> dict:
    """$lookup: fully specified name + properties for an SCTID."""
    r = requests.get(f"{TX}/CodeSystem/$lookup",
                     params={"system": SNOMED, "code": code},
                     headers=HDRS, timeout=15)
    r.raise_for_status()
    return r.json()

def find_concepts(text: str, ecl: str = "<<404684003", count: int = 10):
    """Text search constrained by ECL (default: descendants of Clinical finding)."""
    vs = f"{SNOMED}?fhir_vs=ecl/{ecl}"
    r = requests.get(f"{TX}/ValueSet/$expand",
                     params={"url": vs, "filter": text, "count": count},
                     headers=HDRS, timeout=20)
    r.raise_for_status()
    return r.json().get("expansion", {}).get("contains", [])

def translate(code: str, source_system: str, conceptmap_url: str):
    """$translate an existing code to SNOMED CT via a ConceptMap."""
    r = requests.get(f"{TX}/ConceptMap/$translate",
                     params={"url": conceptmap_url, "system": source_system,
                             "code": code, "targetsystem": SNOMED},
                     headers=HDRS, timeout=20)
    r.raise_for_status()
    return r.json()

# ECL examples: 64572001=disease, 71388002=procedure, 123037004=body structure
print(find_concepts("type 2 diabetes", ecl="<<64572001"))

Workflow

  1. Extract spans with OpenMed (Disease, Anatomy, Pharmaceutical models).
  2. Pick a semantic constraint (ECL) from the OpenMed label so you search the right hierarchy: disorder span → <<64572001; anatomy span → <<123037004; substance/drug → <<105590001; procedure → <<71388002.
  3. Search with ValueSet/$expand?filter=<span> under that ECL.
  4. Rank & disambiguate by display match and confidence; prefer the most specific concept whose meaning is fully entailed by the text (do not over-code).
  5. Validate with $validate-code; $lookup to capture the FSN and any needed properties.
  6. Translate instead of searching when you already hold an ICD-10/local code and the user's server has the relevant ConceptMap.
  7. Emit {system: "http://snomed.info/sct", code, display} — the SCTID plus the OpenMed source offsets for traceability.

Hand-off from OpenMed

openmed.analyze_text(..., output_format="dict") returns entities, each a dict with text, label, confidence, start, end. Route each label to an ECL hierarchy and map out-of-process:

import openmed

note = "Assessment: type 2 diabetes mellitus with diabetic nephropathy."
result = openmed.analyze_text(
    note,
    model_name="disease_detection_superclinical",   # Disease category
    output_format="dict",
)

ECL_FOR_LABEL = {
    "DISEASE":   "<<64572001",     # | Disease |
    "CONDITION": "<<64572001",
    "PATHOLOGY": "<<64572001",
    "ANATOMY":   "<<123037004",    # | Body structure |
    "ORGAN":     "<<123037004",
}

for ent in result["entities"]:
    ecl = ECL_FOR_LABEL.get(ent["label"], "<<404684003")  # fallback: Clinical finding
    candidates = find_concepts(ent["text"], ecl=ecl, count=5)
    print(ent["text"], ent["start"], ent["end"], "->",
          [(c["code"], c["display"]) for c in candidates[:3]])

Carry OpenMed's start/end offsets next to each SCTID so every code is auditable back to its span. Persist codes and offsets only — never the raw note, and never a local copy of SNOMED content.

Edge cases & gotchas

  • Never bundle SNOMED CT. Do not vendor a release, embed an export, or cache descriptions to disk for reuse. If you find yourself shipping SNOMED data, stop — the design must call the user's licensed server live, out-of-process.
  • Affiliate licensing. Confirm the user holds (or their territory grants) a SNOMED International Affiliate License. In the US it is free via the NLM/UMLS; elsewhere it varies. Surface this requirement; do not assume entitlement.
  • Pre- vs post-coordination. Some clinical meanings need a post-coordinated expression (e.g. finding + body site + severity). Prefer a single pre-coordinated concept when one exists; only post-coordinate when your server and downstream systems support SNOMED CT expressions.
  • Edition/version drift. SCTIDs are stable but content differs across editions (International vs US vs UK) and monthly releases. Record the edition the server reports; do not mix codes across editions silently.
  • Negation/uncertainty stays in OpenMed. A span "no evidence of pneumonia" must not be coded as present pneumonia. Resolve assertion/negation with OpenMed's clinical-context layer before mapping.
  • Don't over-specify. Map to the concept actually supported by the text; inventing severity or laterality the note never stated is a coding error.
  • Local-first. OpenMed NER runs on-device; only de-identified concept strings reach the terminology server. No PHI over the wire.

Standards & references

Version History

  • f213557 Current 2026-07-23 00:45

Same Skill Collection

skills/building-with-openmed/SKILL.md
skills/loading-openmed-models/SKILL.md
skills/annotating-variants/SKILL.md
skills/assembling-fhir-bundles/SKILL.md
skills/auditing-deid-leakage/SKILL.md
skills/auditing-deidentification-runs/SKILL.md
skills/auditing-part11-trails/SKILL.md
skills/auditing-safe-harbor-checklist/SKILL.md
skills/auditing-subgroup-fairness/SKILL.md
skills/authoring-model-cards/SKILL.md
skills/batch-processing-clinical-text/SKILL.md
skills/benchmarking-clinical-ner/SKILL.md
skills/bridging-presidio-and-spacy/SKILL.md
skills/building-gold-corpus/SKILL.md
skills/building-patient-timelines/SKILL.md
skills/checking-hipaa-compliance/SKILL.md
skills/choosing-openmed-models/SKILL.md
skills/coding-hcc-risk-adjustment/SKILL.md
skills/coding-icd10/SKILL.md
skills/computing-ecqms/SKILL.md
skills/configuring-privacy-policies/SKILL.md
skills/defining-cohort-phenotypes/SKILL.md
skills/deidentifying-clinical-text/SKILL.md
skills/deidentifying-multilingual-text/SKILL.md
skills/deploying-openmed-mcp/SKILL.md
skills/detecting-pv-signals/SKILL.md
skills/enforcing-nophi-logging/SKILL.md
skills/etl-to-omop-cdm/SKILL.md
skills/evaluating-with-leakage-gates/SKILL.md
skills/exporting-bulk-fhir/SKILL.md
skills/exporting-to-fhir/SKILL.md
skills/extracting-clinical-entities/SKILL.md
skills/extracting-dicom-metadata/SKILL.md
skills/extracting-lab-tables/SKILL.md
skills/extracting-pii-entities/SKILL.md
skills/extracting-sdoh/SKILL.md
skills/fetching-fhir-resources/SKILL.md
skills/gating-deid-leakage/SKILL.md
skills/generating-synthea-data/SKILL.md
skills/generating-synthetic-surrogates/SKILL.md
skills/ingesting-clinical-documents/SKILL.md
skills/linking-umls-concepts/SKILL.md
skills/mapping-loinc/SKILL.md
skills/mining-pubmed-literature/SKILL.md
skills/normalizing-rxnorm/SKILL.md
skills/parsing-ccda-documents/SKILL.md
skills/parsing-hl7v2-messages/SKILL.md
skills/parsing-lab-values/SKILL.md
skills/parsing-trial-eligibility/SKILL.md

Metadata

Files
0
Version
f213557
Hash
b8833f98
Indexed
2026-07-23 00:45

ホーム - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-07-29 13:11
浙ICP备14020137号-1 $お客様$