Agent Skillsmaziyarpanahi/openmed › scaffolding-smart-on-fhir

scaffolding-smart-on-fhir

GitHub

用于生成嵌入EHR(如Epic/Cerner)的SMART on FHIR应用脚手架,涵盖OAuth2 PKCE认证、FHIR数据获取及本地脱敏处理流程。

skills/scaffolding-smart-on-fhir/SKILL.md maziyarpanahi/openmed

Trigger Scenarios

用户需要构建嵌入EHR的医疗应用 提及SMART on FHIR或EHR启动流程 涉及OAuth2授权码流与PKCE实现 需要配置FHIR作用域与Token管理

Install

npx skills add maziyarpanahi/openmed --skill scaffolding-smart-on-fhir -g -y
More Options

Use without installing

npx skills use maziyarpanahi/openmed@scaffolding-smart-on-fhir

指定 Agent (Claude Code)

npx skills add maziyarpanahi/openmed --skill scaffolding-smart-on-fhir -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": "scaffolding-smart-on-fhir",
    "license": "Apache-2.0",
    "metadata": {
        "pairs": "adjacent",
        "project": "OpenMed",
        "version": "1.0",
        "category": "fhir-interop"
    },
    "description": "Scaffold a SMART-on-FHIR app (SMART App Launch v2 — EHR launch and standalone launch, OAuth2 PKCE, scopes, token handling, fhirContext) so an OpenMed-powered tool can run inside Epic or Cerner\/Oracle Health. Covers the .well-known\/smart-configuration discovery, authorize\/token sequence, scopes like patient\/DocumentReference.rs and launch\/patient, and fetching clinical notes the app then de-identifies and runs NER on locally with OpenMed. Use when the user wants to embed OpenMed inside an EHR, mentions SMART on FHIR, OAuth2 launch, scopes, Epic\/Cerner app, or clinician-facing FHIR app. Pairs adjacent."
}

Scaffolding SMART on FHIR

To put an OpenMed-powered tool inside a clinician's EHR (Epic, Cerner/Oracle Health), you build a SMART on FHIR app: a web app the EHR launches with an OAuth2 flow, granting scoped, time-limited access to the patient's FHIR data. The app fetches the clinical notes, then runs OpenMed on-device (de-id + NER) — so PHI is processed locally and only de-identified output, if anything, leaves the browser/host.

When to use

Reach for this when the deliverable is a clinician-facing app embedded in an EHR, or a standalone app authorizing against an EHR's FHIR endpoint. Triggers: "SMART on FHIR", "EHR launch", "OAuth2 scopes", "Epic/Cerner app", "embed OpenMed in the chart". For pulling notes at cohort scale (no UI), use exporting-bulk-fhir instead.

Two launch flows

  • EHR launch — clinician clicks your app in the chart. The EHR opens your launch_uri?iss=<fhir-base>&launch=<opaque>; you complete OAuth2 and inherit the current patient/encounter context.
  • Standalone launch — user opens your app directly; it discovers the FHIR server and runs OAuth2, and the user/EHR picks the patient.

Both use SMART App Launch v2: OAuth2 authorization code flow with PKCE (required in v2), discovered via .well-known/smart-configuration.

Quick start: the launch sequence

1. EHR launch URL:
   GET https://app.example/launch?iss=https://ehr.example/fhir&launch=abc123

2. Discover endpoints:
   GET https://ehr.example/fhir/.well-known/smart-configuration
   -> { "authorization_endpoint": ".../authorize",
        "token_endpoint": ".../token",
        "code_challenge_methods_supported": ["S256"],
        "capabilities": ["launch-ehr","client-public","context-ehr-patient", ...] }

3. Redirect the browser to authorize (PKCE + the launch token):
   GET .../authorize?
       response_type=code&
       client_id=YOUR_CLIENT_ID&
       redirect_uri=https://app.example/callback&
       scope=launch openid fhirUser patient/DocumentReference.rs patient/Patient.r&
       state=RANDOM&
       aud=https://ehr.example/fhir&
       launch=abc123&
       code_challenge=BASE64URL(SHA256(verifier))&
       code_challenge_method=S256

4. Callback -> exchange code for token:
   POST .../token
       grant_type=authorization_code&code=...&redirect_uri=...&
       client_id=...&code_verifier=ORIGINAL_VERIFIER
   -> { "access_token": "...", "token_type": "Bearer", "expires_in": 3600,
        "scope": "patient/DocumentReference.rs ...",
        "patient": "Patient-123", "encounter": "Encounter-9",
        "id_token": "..." }

5. Call FHIR with the token:
   GET https://ehr.example/fhir/DocumentReference?patient=Patient-123&type=clinical-note
       Authorization: Bearer <access_token>

The token response carries the launch context (patient, sometimes encounter, and in v2 a fhirContext array). Use patient to scope every subsequent query.

Scopes you actually need

SMART v2 scopes are <level>/<Resource>.<permissions> where permissions are a subset of c r u d s (create/read/update/delete/search) — .rs = read + search. Request the minimum:

Scope Why
launch EHR launch context (omit for standalone; use launch/patient)
openid fhirUser Identify the launching user
patient/Patient.r The in-context patient demographics
patient/DocumentReference.rs Read + search the patient's clinical notes
patient/Condition.rs (optional) reconcile against existing problems
offline_access (optional) refresh token for background work

Prefer patient/… (current-patient) over user/… (everything the user can see) to keep the blast radius small. Granular v2 scopes (.rs) are stricter than the v1 .read/.write forms — use them.

Where OpenMed runs

Notes arrive as DocumentReferencecontent.attachment (often base64 or a url to a Binary). Decode, then process locally:

import base64, openmed

note_b64 = document_reference["content"][0]["attachment"]["data"]
note = base64.b64decode(note_b64).decode("utf-8")

# De-identify on-device before anything else touches it
deid = openmed.deidentify(note, method="replace", policy="hipaa_safe_harbor")

# Clinical NER on the (de-identified or raw, per your IRB) text
entities = openmed.analyze_text(deid.text, model_name="disease_detection_superclinical")
# -> render highlights in the SMART app UI, or export FHIR (exporting-to-fhir)

OpenMed models run on-device after a one-time download — no note text is sent to a third party by OpenMed. Keep the access token and any PHI in memory only; do not log them.

Hand-off to / from OpenMed

  • From the EHR to OpenMed: fetched DocumentReference notes → openmed.deidentifyopenmed.analyze_text.
  • From OpenMed back to the EHR: built FHIR resources (exporting-to-fhir) → to_bundle (assembling-fhir-bundles) → write back with a write scope (e.g. patient/Condition.c) if your use case persists findings. Validate first (validating-us-core).
  • MCP option: if the app calls a local OpenMed MCP server, the tools are openmed_analyze_text and openmed_deidentify — same on-device guarantees.

Edge cases & gotchas

  • PKCE is mandatory in v2 and for public (browser) clients always. Generate a fresh code_verifier per launch; never reuse.
  • Validate state and aud. Reject the callback if state does not match; set aud to the FHIR base or the EHR will reject the authorize request.
  • Tokens are short-lived. Handle expires_in; use offline_access + refresh tokens only if you genuinely need background access, and store them securely (never client-side for confidential clients).
  • Scope down-grade is normal. The EHR may grant fewer scopes than requested; read the returned scope and degrade gracefully.
  • Don't persist PHI in the browser. Process in memory; if you must cache, cache the de-identified output only.
  • App registration is per-EHR. Epic (fhir.epic.com) and Cerner each have their own developer portals, client registration, and sandbox FHIR endpoints; test against the sandbox before go-live.
  • OpenMed stays local. The OAuth2 token authorizes FHIR calls to the EHR; it has nothing to do with OpenMed, which needs no network at inference time.

Standards & references

Version History

  • f213557 Current 2026-07-23 00:46

Same Skill Collection

skills/benchmark-pii-recall/SKILL.md
skills/building-with-openmed/SKILL.md
skills/deidentify-a-dataset/SKILL.md
skills/extract-clinical-entities-to-fhir/SKILL.md
skills/loading-openmed-models/SKILL.md
skills/pick-a-pii-model/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

Metadata

Files
0
Version
c8017bb
Hash
de04ebb4
Indexed
2026-07-23 00:46

trang chủ - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-07 02:15
浙ICP备14020137号-1 $bản đồ khách truy cập$