Skip to content
Security
Skill

/extracting-sdoh

Extracts social determinants of health (SDOH) — housing instability, food insecurity, unemployment, transportation barriers, social isolation, financial strain — from clinical narrative and maps the spans to ICD-10-CM Z-codes (Z55–Z65). Use after running OpenMed NER when the

BOOST
From plugin
openmed
5.7k74 skills
Install
$ npx -y skills add maziyarpanahi/openmed --skill extracting-sdoh --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/extracting-sdoh

Context preview

The summary Claude sees to decide when to auto-load this skill.

Extracts social determinants of health (SDOH) — housing instability, food insecurity, unemployment, transportation barriers, social isolation, financial strain — from clinical narrative and maps the spans to ICD-10-CM Z-codes (Z55–Z65). Use after running OpenMed NER when the

SKILL.md

extracting-sdoh.SKILL.md
name: extracting-sdoh
description: "Extracts social determinants of health (SDOH) — housing instability, food insecurity, unemployment, transportation barriers, social isolation, financial strain — from clinical narrative and maps the spans to ICD-10-CM Z-codes (Z55–Z65). Use after running OpenMed NER when the user wants SDOH surfacing, Z-code suggestion, health-equity analytics, or to recover SDOH that is documented in free text but not coded. Pairs with OpenMed analyze_text output. Standards: ICD-10-CM Z55–Z65, Gravity Project value sets, n2c2 2022 SDOH track. Trigger keywords: SDOH, social determinants, Z-codes, housing, food insecurity, health equity, Gravity Project."
license: Apache-2.0
metadata:
  project: OpenMed
  category: clinical-nlp
  pairs: after
  version: "1.0"

Extracting SDOH and Mapping to ICD-10-CM Z-Codes

Social determinants of health (SDOH) — the conditions in which people live, work, and age — drive an estimated 80% of health outcomes, yet they live almost entirely in free-text narrative. Multiple chart-review studies find SDOH **documented in notes but coded with a Z-code under ~2% of the time**. The information is there; the structured signal is not. This skill recovers it: run OpenMed NER over de-identified notes, then map the resulting spans to the ICD-10-CM **Z55–Z65** family.

When to use

  • A note clearly describes a social risk ("lives in her car", "skips meals to

afford insulin", "no ride to dialysis") and you want a coded, queryable signal.

  • You are building health-equity dashboards, risk stratification, or

closed-loop referral feeds and need SDOH as discrete data.

  • You want to reconcile what the chart *says* against what was *coded*, and flag

Z-code gaps for a coder or care team to confirm.

This is a **decision-support** step. It proposes Z-codes; a human assigns them. SDOH coding is sensitive — never expose individual SDOH inferences outside the care/coding workflow, and never feed them to coverage or pricing decisions.

Quick start

De-identify first, run NER, then map spans to Z-codes:

import openmed
from sdoh_zcode_map import SDOH_ZCODES  # see references/sdoh_zcode_map.md

note = (
    "62F with CHF. Reports she lost her apartment last month and is "
    "staying in a shelter. Often runs out of food before month-end. "
    "No car; misses appointments because the bus does not run to clinic."
)

# 1) Strip PHI before any downstream processing or storage.
deid = openmed.deidentify(note, method="replace", policy="hipaa_safe_harbor")

# 2) Run clinical NER. Use an SDOH/clinical model from the registry; discover
#    available keys with openmed.get_models_by_category(...).
result = openmed.analyze_text(deid.text, output_format="dict")

# 3) Map each entity span to a candidate Z-code.
for ent in result["entities"]:
    code = SDOH_ZCODES.get(ent["label"].lower())
    if code:
        print(f"{ent['text']!r:40}  {ent['label']:18}  -> {code}")

`analyze_text` returns entities shaped as `{"text", "label", "confidence", "start", "end", "metadata"}`. The `start`/`end` offsets index into the text you passed in, so you can anchor every suggested Z-code back to its exact source span for human review.

Workflow

1. **De-identify** the note with `openmed.deidentify` (HIPAA Safe Harbor or a stricter policy). SDOH text is dense with PHI (addresses, employer names). 2. **Extract entities** with `openmed.analyze_text`. Pick a model whose label set covers social concepts; if your model only emits clinical findings, run a second pass with a zero-shot model (`openmed zero`) using SDOH labels such as `housing_instability`, `food_insecurity`, `unemployment`, `transportation_barrier`, `social_isolation`, `financial_strain`. 3. **Map spans to Z-codes** using a curated lookup keyed by label (`references/sdoh_zcode_map.md`). Keep the **span offsets** and the model `confidence` on every suggestion. 4. **Stage for confirmation.** Emit `(span, label, suggested_code, confidence)` tuples for a coder or the Gravity Project pipeline to accept or reject. Do not auto-bill a Z-code from an inference alone. 5. **Normalize to value sets.** Align labels to the **Gravity Project** SDOH domains so codes are interoperable with FHIR (`Condition`, `Observation`, `Goal`) and USCDI v3 SDOH elements.

Z-code families you will hit most (ICD-10-CM Z55–Z65)

| Domain | Range | Example | | --- | --- | --- | | Education / literacy | Z55 | Z55.0 illiteracy | | Employment | Z56 | Z56.0 unemployment | | Occupational exposure | Z57 | — | | Housing / economic | Z59 | Z59.0 homelessness, Z59.41 food insecurity, Z59.82 transportation insecurity | | Social environment | Z60 | Z60.2 living alone, Z60.4 social exclusion | | Upbringing | Z62 | — | | Family / support circumstances | Z63 | Z63.4 disappearance/death of family member | | Psychosocial circumstances | Z64–Z65 | Z65.1 imprisonment |

The full curated label→code table lives in [references/sdoh_zcode_map.md](references/sdoh_zcode_map.md).

Hand-off to / from OpenMed

  • **From OpenMed:** this skill consumes `openmed.analyze_text(...)` output

(`PredictionResult` dict). Each `entity["start"]/["end"]` anchors a Z-code suggestion to source text.

  • **To OpenMed:** always run `openmed.deidentify` upstream so no raw PHI reaches

the SDOH store, logs, or coder queue.

  • **Onward:** emit suggestions into a FHIR `Condition`/`Observation` with the

Z-code as `code.coding` (system `http://hl7.org/fhir/sid/icd-10-cm`). OpenMed's `openmed.clinical.exporters.fhir` helpers (`to_bundle`, `to_operation_outcome`) assemble the envelope; ICD-10-CM itself is public-domain in the US release.

Edge cases & gotchas

  • **Negation and history.** "Denies food insecurity" or "previously homeless,

now housed" must not produce an active Z-code. Run negation/temporality resolution (`openmed.clinical`, `resolving-clinical-context`) before mapping.

  • **Hypotheticals and screening prompts.** T
Read more
Ships withopenmed

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.

Get the whole plugin

Other skills on openmed.