Agent Skillsmaziyarpanahi/openmed › parsing-trial-eligibility

parsing-trial-eligibility

GitHub

将临床试验自由文本 eligibility 解析为结构化规则,并与 OpenMed 提取的患者数据进行匹配。用于判断患者是否符合入排标准,生成可解释的决策支持结果,而非自动执行入组。

skills/parsing-trial-eligibility/SKILL.md maziyarpanahi/openmed

Trigger Scenarios

eligibility criteria inclusion exclusion trial matching patient screening criteria parsing eligibilityModule age/sex gates

Install

npx skills add maziyarpanahi/openmed --skill parsing-trial-eligibility -g -y
More Options

Use without installing

npx skills use maziyarpanahi/openmed@parsing-trial-eligibility

指定 Agent (Claude Code)

npx skills add maziyarpanahi/openmed --skill parsing-trial-eligibility -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": "parsing-trial-eligibility",
    "license": "Apache-2.0",
    "metadata": {
        "pairs": "after",
        "project": "OpenMed",
        "version": "1.0",
        "category": "research-genomics"
    },
    "description": "Parses free-text clinical-trial eligibility criteria into structured inclusion and exclusion logic, then matches them against patient facts that OpenMed extracted. Use when the user wants to turn a ClinicalTrials.gov eligibility block into machine-readable rules, screen a synthetic patient for trial fit, or explain why a patient does or does not meet criteria. Trigger keywords: eligibility criteria, inclusion, exclusion, trial matching, patient screening, criteria parsing, eligibilityModule, age\/sex gates. Pairs after OpenMed and after searching-clinicaltrials: consume the eligibilityModule text from a study, structure it, and match against conditions, medications, labs, and demographics from openmed.analyze_text. Decision-support only — never autonomous enrollment."
}

Parsing trial eligibility & matching patients

A ClinicalTrials.gov study exposes its eligibility as a single free-text block (protocolSection.eligibilityModule.eligibilityCriteria) plus a few typed fields (sex, minimumAge, maximumAge, healthyVolunteers). This skill turns that prose into structured inclusion / exclusion criteria and matches each rule against patient facts that OpenMed extracted — producing an explainable eligible | ineligible | unknown verdict per criterion.

This is decision support, not enrollment. The output is a candidate list and a rationale for a clinician to review, never an automated eligibility decision.

When to use

  • You pulled a study with searching-clinicaltrials and need its eligibility as machine-readable rules.
  • You have a (synthetic) patient profile and want to screen it against one or many trials, with a per-criterion reason.
  • You want to highlight which patient facts are missing to decide a criterion.

Quick start

The typed gates are deterministic — apply them first. The free-text criteria need parsing into bullet-level inclusion/exclusion items.

# Study from ClinicalTrials.gov v2 (see searching-clinicaltrials)
elig = study["protocolSection"]["eligibilityModule"]

raw = elig["eligibilityCriteria"]            # free text, often markdown bullets
sex = elig.get("sex", "ALL")                 # ALL | FEMALE | MALE
min_age = elig.get("minimumAge")             # e.g. "18 Years"
max_age = elig.get("maximumAge")             # e.g. "75 Years"
healthy_ok = elig.get("healthyVolunteers")   # bool

def split_criteria(text: str) -> dict[str, list[str]]:
    """Split the prose into inclusion / exclusion bullet lists."""
    sections, current = {"inclusion": [], "exclusion": []}, None
    for line in text.splitlines():
        low = line.strip().lower()
        if "inclusion criteria" in low:
            current = "inclusion"; continue
        if "exclusion criteria" in low:
            current = "exclusion"; continue
        bullet = line.strip(" -*•\t")
        if bullet and current:
            sections[current].append(bullet)
    return sections

criteria = split_criteria(raw)

Each bullet is a candidate rule. Structure it into a comparable predicate: condition present/absent, lab threshold, age/sex, prior-therapy, performance status (e.g. ECOG ≤ 2), pregnancy status, etc.

from dataclasses import dataclass

@dataclass
class Criterion:
    kind: str            # "condition" | "lab" | "age" | "sex" | "medication" | "other"
    polarity: str        # "include" | "exclude"
    text: str            # original bullet
    target: str | None   # e.g. "ECOG", "diabetes", "metformin"
    op: str | None = None  # "<=", ">=", "==", "present", "absent"
    value: float | str | None = None

Matching against OpenMed-extracted patient facts

Build the patient profile from openmed.analyze_text outputs plus structured demographics, then evaluate each criterion to a three-valued result.

patient = {
    "age": 61, "sex": "FEMALE",
    "conditions": {"type 2 diabetes", "hypertension"},   # OpenMed Disease spans
    "medications": {"metformin", "lisinopril"},          # OpenMed Pharmaceutical
    "labs": {"hba1c": 8.1, "ecog": 1},                   # from a labs extractor
}

def evaluate(c: Criterion, p: dict) -> str:
    if c.kind == "sex" and c.target:
        return "pass" if p["sex"] == c.target or c.target == "ALL" else "fail"
    if c.kind == "condition" and c.target:
        has = c.target.lower() in {x.lower() for x in p["conditions"]}
        ok = has if c.polarity == "include" else not has
        return "pass" if ok else "fail"
    if c.kind == "lab" and c.target and c.target.lower() in p["labs"]:
        v = p["labs"][c.target.lower()]
        cmp = {"<=": v <= c.value, ">=": v >= c.value, "==": v == c.value}
        return "pass" if cmp.get(c.op, False) else "fail"
    return "unknown"   # fact not present → needs human review, never assume pass

Aggregate: a patient is a candidate only if every inclusion criterion is pass (or unknown, flagged) and every exclusion criterion is not fail. Surface the unknown items prominently — missing data is the most common reason a real screen needs a human.

Workflow

  1. Apply the typed gates (sex, minimumAge, maximumAge) — cheap, exact.
  2. Split the free text into inclusion / exclusion bullets.
  3. Structure each bullet into a Criterion (kind, polarity, target, op, value). NER on the bullet via openmed.analyze_text finds the condition / drug / lab targets; numeric thresholds come from a regex/units pass.
  4. Evaluate each criterion against the OpenMed-derived patient profile to pass | fail | unknown.
  5. Report a verdict with a per-criterion rationale and an explicit list of unknown facts that block a confident decision.

Hand-off to / from OpenMed

  • From OpenMed (patient side). Run openmed.analyze_text over the patient note to populate conditions (Disease), medications (Pharmaceutical), and oncology context; normalize via coding-icd10 / normalizing-rxnorm so comparisons are code-based, not string-based.
  • From OpenMed (trial side). Run openmed.analyze_text over each eligibility bullet to identify the condition / drug / lab the rule references, improving target extraction beyond keyword spotting.
  • From searching-clinicaltrials. Studies arrive with their eligibilityModule already populated — this skill is the next stage.
  • Keep everything local: matching runs on-device against the patient profile; no PHI leaves the process. Examples here use a synthetic patient.

Edge cases & gotchas

  • Three-valued logic is mandatory. Treating unknown as pass enrolls ineligible patients; treating it as fail drops eligible ones. Surface it.
  • Negation & temporality. "No prior chemotherapy" vs "prior chemotherapy" flips polarity; "active infection" vs "history of infection" differs in time. Use openmed.clinical (see resolving-clinical-context) so negated/historical mentions are not counted as present.
  • Units & ranges. "Creatinine clearance ≥ 60 mL/min", "platelets > 100,000/µL" — normalize units before comparing; LOINC grounding (mapping-loinc) helps.
  • Compound bullets. One sentence may carry several predicates ("age 18-75 and ECOG 0-1"). Split into atomic criteria.
  • Inconsistent headings. Some studies omit explicit "Inclusion/Exclusion" labels or use "Key Inclusion Criteria". Default unlabeled bullets to inclusion and flag for review.
  • Not a medical device. Output is a ranked candidate list with rationale for a clinician — never an autonomous enrollment or exclusion decision.

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/mapping-to-snomed/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

Metadata

Files
0
Version
f213557
Hash
2fddebb4
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 $お客様$