Markdown Converter
Agent skill for markdown-converter
> **Scope:** Ambient Scribe + Guardrailed Clinical Decision Support (CDS).
Sign in to like and favorite skills
Scope: Ambient Scribe + Guardrailed Clinical Decision Support (CDS).
System of Record (SoR): The EHR (OpenEMR/OpenMRS/Bahmni) for appointments, prescriptions, patient data, problems, allergies, vitals, labs, final notes.
Stack: JavaScript/TypeScript-first (Next.js + Node APIs).
Non-goals (v1): No full EHR. No autonomous clinical decisions. No claims/billing UI. Coding suggestions are read-only in v1.
Mission: Help clinicians produce high-quality notes quickly and surface defensible, cited suggestions—without altering core clinic ops that live in the EHR.
Primary Outcomes
Secondary Outcomes
ack: human_review=true) before any write to EHR.DocumentReference if APIs are missing.Do/Don’t Quick Table
| Do | Don’t |
|---|---|
Use for all EHR interactions | Call EHR REST/FHIR directly from random modules |
| Attach citations before showing advice | Render advice without sources or version info |
Save final note as PDF via | Persist final notes only in app DB |
Generate Rx via | Generate Rx PDFs instead of EHR orders when API exists |
| Queue writes with BullMQ | Fire-and-forget writes |
Keep prompts in | Scatter prompt strings across codebase |
Next.js (apps/web) ──▶ Node APIs (apps/api, Fastify/Nest) │ │ │ Live transcript, edit UI ├──▶ Scribe Service (LLM → SOAP JSON + flags) │ Evidence panel ├──▶ Receipts Service (RAG → citations+versioning) │ Schedule view (read-only) └──▶ EHR Adapter (FHIR/OpenEMR/OpenMRS; queued writes) │ Postgres (app state, audit) • Redis (BullMQ) • Object storage (audio blobs, optional)
export interface SoapNote { subjective: { cc?: string; hpi?: string; meds?: string[]; allergies?: string[] }; objective: { vitals?: Record<string, string | number>; exam?: string; labs?: string[] }; assessment: Array<{ problem: string; rationale?: string; citations?: Citation[] }>; plan: Array<{ problem: string; orders?: string[]; instructions?: string; followUp?: string }>; } export interface Citation { title: string; url: string; sectionPath?: string; quote: string; versionHash: string; effectiveFrom?: string; // ISO date if provided by source retrievedAt: string; // ISO timestamp confidence: number; // 0..1 }
export interface EhrAdapter { upsertPatient(p: Fhir.Patient): Promise<Fhir.Patient>; createEncounter(e: Fhir.Encounter): Promise<Fhir.Encounter>; createDocumentReference(d: Fhir.DocumentReference): Promise<Fhir.DocumentReference>; createMedicationRequest(m: Fhir.MedicationRequest): Promise<Fhir.MedicationRequest>; listAppointments(params: { start?: string; end?: string }): Promise<Fhir.Bundle>; }
Rule: All writes must go through this adapter. If a method is not supported by a site, throw a capability error and fall back to a PDF +
workflow where applicable.DocumentReference
POST /scribe/transcribe → { audioRef } → { transcript, speakers }POST /scribe/compose → { transcript, patientCtx } → { soap, flags[] }POST /receipts/attach → { section: 'assessment'|'plan', text } → { citations[] }POST /ehr/attach-document → { patientId, encounterId, pdfBase64, type } → { docRefId, auditId }POST /ehr/create-medication-request → { patientId, encounterId, medication, dosage } → { id, auditId }GET /ehr/appointments?start&end → FHIR Bundle (read-only)Job payload:
type EhrJob = | { type: 'DocumentReference.create'; payload: Fhir.DocumentReference } | { type: 'MedicationRequest.create'; payload: Fhir.MedicationRequest } | { type: 'Condition.create'; payload: Fhir.Condition } // phase 2 | { type: 'Procedure.create'; payload: Fhir.Procedure }; // phase 2
Job result:
{ ok: true, resourceId: string, statusCode: number }audit_event with stack and sanitized request body.
/scribe/transcribe./scribe/compose./receipts/attach → add citations.ack: human_review=true).DocumentReference.create with the PDF attachment.patientId, encounterId, docRefId (once written).MedicationRequest via adapter.DocumentReference.docRefId.listAppointments with timeframe./packages/prompts with unit tests./receipts/attach to fetch citations—quote the exact supporting span.versionHash, effectiveFrom (if available), retrievedAt.Example evidence payload:
{ "citations": [ { "title": "NICE NG128", "url": "https://example.org/ng128#4.1", "sectionPath": "4.1 Indications", "quote": "Offer CTA to adults with red-flag X within 6 hours...", "versionHash": "c0b1b8", "effectiveFrom": "2024-11-15", "retrievedAt": "2025-09-19T08:42:00Z", "confidence": 0.82 } ] }
.env, secret manager stub; never commit secrets.Create one JSON per site in
/configs/sites/<siteId>.json:
{ "ehr": "openemr", "baseUrl": "https://ehr.local/fhir/R4", "auth": "oauth2", "capabilities": { "MedicationRequest.create": "supported", "DocumentReference.create": "supported", "Appointment.search": "supported", "Condition.create": "supported", "Procedure.create": "partial" } }
Agents must check capabilities before attempting writes; fall back to PDF attach when writes are unsupported.
/tests/fixtures/asr), compute WER./tests/fixtures/receipts), compute precision@1/@3 via golden spans.DocumentReference and (if supported) MedicationRequest./docs/ADR when making architectural changes.pnpm idocker compose up -d (Postgres, Redis, optional MinIO)pnpm -C apps/api devpnpm -C apps/web dev/configs/sites/dev.json and set SITE_ID=dev in .envpnpm testCondition.create (ICD-10/11), Procedure.create; suggest codes with receipts; clinician approves; write to EHR.Reminder: CDS decides nothing on its own here—clinicians do. The agent’s job is to assist, cite, and safely write to the EHR.