Building a Diabetes CGM Dashboard
This walkthrough guides you through building a comprehensive diabetes management protocol from scratch. You will use five MOISSCode modules together to analyze CGM data, calculate insulin regimens, screen for DKA, code diagnoses, and check drug safety.
What You Will Build
A protocol that:
- Interprets lab results (fasting glucose, HbA1c)
- Estimates HbA1c from CGM mean glucose
- Analyzes CGM data for Time In Range, variability, and GMI
- Calculates a full insulin regimen from Total Daily Dose
- Screens for Diabetic Ketoacidosis
- Classifies hypoglycemia events
- Estimates cardiovascular risk
- Assigns ICD-10-CM diagnosis codes and DRG groupings
- Adjusts metformin dosing based on renal function
- Persists results to the database
Modules used: med.glucose, med.lab, med.scores, med.icd, med.pk, med.db
Prerequisites
- MOISSCode v2.0.0 or later installed
- Basic familiarity with MOISSCode syntax (see Language Guide)
Step 1: Create the File
Create a new file called diabetes_cgm.moiss in your project directory:
touch diabetes_cgm.moiss
Start with the imports. This protocol uses six modules:
import med.glucose;
import med.lab;
import med.scores;
import med.icd;
import med.pk;
Imports are declarative in MOISSCode. All modules are always available, but listing them documents your dependencies.
Step 2: Define a Helper Function
Before the protocol, define a helper function to classify HbA1c levels. This demonstrates user-defined functions working alongside library calls:
function classify_a1c(value) {
if value >= 9.0 {
return "VERY HIGH - urgent intervention needed";
}
if value >= 7.0 {
return "ABOVE TARGET - therapy adjustment recommended";
}
return "AT TARGET - continue current regimen";
}
Why a helper function? MOISSCode protocols can call user-defined functions just like library methods. This lets you encode your institution's clinical decision logic alongside standardized calculations.
Step 3: Start the Protocol and Interpret Labs
Open the protocol block and interpret the patient's fasting glucose and HbA1c:
protocol DiabetesCGMDashboard {
input: Patient p;
let glucose_lab = med.lab.interpret("Glucose", 185);
let hba1c_lab = med.lab.interpret("HbA1c", 8.2);
let a1c_class = classify_a1c(8.2);
med.lab.interpret() checks the value against age/sex-adjusted reference ranges and returns a flag (NORMAL, HIGH, LOW, CRITICAL).
Expected output:
[Let] glucose_lab = {type: LAB, test: Glucose, value: 185, flag: HIGH, reference: (70, 100)}
[Let] hba1c_lab = {type: LAB, test: HbA1c, value: 8.2, flag: HIGH, reference: (4.0, 5.6)}
[Let] a1c_class = ABOVE TARGET - therapy adjustment recommended
Step 4: Estimate HbA1c from CGM Data
Use the ADAG equation (Nathan et al., Diabetes Care 2008) to estimate HbA1c from the patient's 14-day mean CGM glucose:
let a1c_est = med.glucose.hba1c_from_glucose(172);
The formula is: eA1C = (mean_glucose + 46.7) / 28.7
Expected output:
[Let] a1c_est = {type: GLUCOSE_A1C, mean_glucose_mgdl: 172.0, estimated_hba1c: 7.6, category: DIABETES}
Step 5: Analyze CGM Readings
This is the core of the dashboard. Pass an array of CGM readings to three analysis functions:
let cgm_data = [95, 120, 145, 190, 230, 185, 160, 110, 85, 72,
68, 90, 135, 175, 210, 195, 140, 105, 88, 130,
155, 180, 200, 170, 125];
let tir = med.glucose.time_in_range(cgm_data);
let gmi = med.glucose.gmi(172);
let variability = med.glucose.glycemic_variability(cgm_data);
| Function | What It Calculates | Clinical Significance |
|---|---|---|
time_in_range | % of readings in 70-180 mg/dL | International consensus target: 70%+ |
gmi | Glucose Management Indicator | Replaces "estimated A1C" for CGM |
glycemic_variability | CV, MAGE, SD | CV under 36% = stable glucose |
Expected output (TIR):
[Let] tir = {type: GLUCOSE_TIR, readings_count: 25, time_in_range_pct: 56.0,
time_below_range_pct: 12.0, time_above_range_pct: 32.0, assessment: NEEDS_IMPROVEMENT}
A TIR of 56% is below the 70% target - this patient needs therapy adjustment.
Step 6: Calculate Insulin Regimen
Compute a complete insulin regimen from the patient's Total Daily Dose (TDD):
let regimen = med.glucose.full_regimen(42);
let isf = med.glucose.insulin_sensitivity_factor(42);
let icr = med.glucose.carb_ratio(42);
let basal = med.glucose.basal_rate(42);
let sliding = med.glucose.sliding_scale(230);
let correction = med.glucose.correction_dose(230, 120, 43);
| Calculation | Formula | Result |
|---|---|---|
| Basal dose | 50% of TDD | 21 units/day |
| Hourly pump rate | Basal / 24 | 0.88 u/hr |
| ISF (1800 rule) | 1800 / TDD | 42.9 mg/dL per unit |
| ICR (500 rule) | 500 / TDD | 11.9 g carb per unit |
| Correction | (current - target) / ISF | 2.6 units |
Step 7: Screen for DKA
Check Diabetic Ketoacidosis criteria (glucose, pH, bicarbonate, ketones):
let dka = med.glucose.dka_check(350, 7.28, 16, 1.8);
Expected output:
[Let] dka = {type: GLUCOSE_DKA, glucose: 350, ph: 7.28, bicarb: 16, ketones: 1.8,
diagnosis: DKA, severity: MILD, criteria_met: 4,
management: IV insulin drip, fluid resuscitation, hourly BG monitoring}
In a real scenario, this would trigger the critical alert and escalation pathway.
Step 8: Check for Hypoglycemia
Classify the lowest CGM reading using ADA criteria:
let hypo = med.glucose.hypo_check(68);
A reading of 68 mg/dL falls into Level 1 (alert value, under 70 mg/dL). Level 2 (clinically significant) starts below 54 mg/dL.
Step 9: Assess Cardiovascular Risk
Diabetic patients have elevated cardiovascular risk. Use the Framingham Risk Score:
let cv_risk = med.scores.framingham(p);
This calculates the 10-year cardiovascular event probability based on age, sex, cholesterol, HDL, systolic BP, smoking status, and diabetes.
Step 10: Assign ICD-10 Codes
Look up the appropriate diagnosis code, search for related codes, and find the DRG grouping:
let dx_code = med.icd.lookup("E11.65");
let dx_search = med.icd.search("diabetes");
let drg = med.icd.drg_lookup(["E11.65"]);
let valid = med.icd.validate_codes(["E11.65", "E11.9", "FAKE.1"]);
E11.65 = Type 2 diabetes mellitus with hyperglycemia. The drg_lookup returns DRG 637 (Diabetes w MCC, weight 1.20).
validate_codes checks that the codes exist in the database - "FAKE.1" will be flagged as invalid.
Step 11: Check Metformin Safety
Calculate eGFR and determine if metformin needs a dose adjustment:
let gfr = med.lab.gfr(1.4, 62, "M");
let metformin_adj = med.pk.renal_adjust("Metformin", 55);
With an eGFR of 55 mL/min (Stage 3a CKD), metformin dose should be reduced by 25%.
Step 12: Save and Finalize
Persist the patient and lab data, then emit summary alerts:
med.db.save_patient("DM-001", "CGM Dashboard Patient", 62, 85.0, "M");
med.db.save_lab("DM-001", "HbA1c", 8.2, "%");
med.db.save_lab("DM-001", "Glucose", 185, "mg/dL");
alert "Diabetes CGM Dashboard complete" severity: info;
alert "A1c class: ABOVE TARGET" severity: warning;
alert "DKA screening: criteria met" severity: critical;
}
Running the Protocol
moiss run diabetes_cgm.moiss -v
Or via Python:
python -m moisscode.cli run diabetes_cgm.moiss -v
The -v flag enables verbose output showing every variable assignment and library call. The protocol generates 24 library calls across 6 modules.
Output Summary
After execution, the CLI displays:
▸ Library Calls (24)
────────────────────────────────────────────────────
◈ med.lab - 3 calls
◈ med.glucose - 12 calls
◈ med.scores - 1 calls
◈ med.icd - 4 calls
◈ med.pk - 1 calls
◈ med.db - 3 calls
And the clinical alerts:
▸ Clinical Alerts
────────────────────────────────────────────────────
ℹ️ [INFO] Diabetes CGM Dashboard complete
⚠️ [WARNING] A1c class: ABOVE TARGET
🚨 [CRITICAL] DKA screening: criteria met
Complete Source Code
The full source is at examples/diabetes_cgm.moiss in the repository.