Suggest ICD-10-CM diagnosis codes (and ICD-10-PCS for inpatient procedures) for the diagnosis and procedure spans OpenMed extracts. This is decision support for a certified coder, not autonomous billing: OpenMed + this skill narrow the candidate set and explain why; a human validates the final, billable code.
ICD-10-CM and ICD-10-PCS are public domain. CMS publishes the complete annual code files, addenda, and indexes for free. (CPT/HCPCS procedure codes are AMA-licensed and restricted — out of scope here; obtain those separately under the user's own AMA license.)
references/icd10-chapters.md for code ranges).For clinical-meaning codes use mapping-to-snomed; for HCC/risk capture use
coding-hcc-risk-adjustment; this skill is for the ICD-10 classification.
Two complementary paths, both license-clean:
A) CMS files, loaded locally (public domain; you download once):
# CMS publishes the order/addenda file; load the code->description table.
# Columns: code (no dot), description; you insert the dot for display.
icd10cm = {} # "E1122" -> "Type 2 diabetes mellitus with diabetic chronic kidney disease"
with open("icd10cm_order_2025.txt", encoding="latin-1") as fh:
for line in fh:
code = line[6:13].strip()
billable = line[14] == "1" # '1' = valid billable code
long_desc = line[77:].strip()
if billable:
icd10cm[code] = long_desc
def search_local(term: str, limit: int = 5):
t = term.lower()
hits = [(c, d) for c, d in icd10cm.items() if t in d.lower()]
return sorted(hits, key=lambda cd: len(cd[1]))[:limit]
B) A FHIR terminology server that hosts ICD-10-CM (public servers exist; e.g. an NLM Clinical Tables endpoint or your own HAPI/Ontoserver):
import requests
# NLM Clinical Tables (public, no key) — ICD-10-CM autocomplete/search:
def search_icd10cm(term: str, count: int = 7):
r = requests.get(
"https://clinicaltables.nlm.nih.gov/api/icd10cm/v3/search",
params={"sf": "code,name", "terms": term, "maxList": count}, timeout=10,
)
r.raise_for_status()
_total, codes, _extra, display = r.json()
return list(zip(codes, [d[1] for d in display])) # [(code, name), ...]
print(search_icd10cm("type 2 diabetes nephropathy"))
references/icd10-chapters.md (e.g. endocrine → E00–E89, circulatory →
I00–I99). This shrinks the search space and catches obvious mis-hits.{system: "http://hl7.org/fhir/sid/icd-10-cm", code, display}
marked status: needs-coder-review, with OpenMed source offsets.openmed.analyze_text(..., output_format="dict") returns entities, each a dict
with text, label, confidence, start, end. Consume Disease/Pathology
spans:
import openmed
note = "Assessment: type 2 diabetes with diabetic nephropathy; CAP."
result = openmed.analyze_text(
note,
model_name="disease_detection_superclinical", # Disease category
output_format="dict",
)
DX_LABELS = {"DISEASE", "CONDITION", "PATHOLOGY"}
for ent in result["entities"]:
if ent["label"] in DX_LABELS:
candidates = search_icd10cm(ent["text"], count=5)
print(ent["text"], ent["start"], ent["end"],
f"(conf {ent['confidence']:.2f}) ->", candidates)
# surface as SUGGESTIONS for a coder — never auto-bill
Keep OpenMed's start/end offsets next to each suggested code so the coder can
jump to the exact supporting text. Store offsets and codes only — never the raw
note in your suggestion log.
.9/unspecified code.references/icd10-chapters.md