Skip to main content

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:

  1. Interprets lab results (fasting glucose, HbA1c)
  2. Estimates HbA1c from CGM mean glucose
  3. Analyzes CGM data for Time In Range, variability, and GMI
  4. Calculates a full insulin regimen from Total Daily Dose
  5. Screens for Diabetic Ketoacidosis
  6. Classifies hypoglycemia events
  7. Estimates cardiovascular risk
  8. Assigns ICD-10-CM diagnosis codes and DRG groupings
  9. Adjusts metformin dosing based on renal function
  10. 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;
tip

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);
FunctionWhat It CalculatesClinical Significance
time_in_range% of readings in 70-180 mg/dLInternational consensus target: 70%+
gmiGlucose Management IndicatorReplaces "estimated A1C" for CGM
glycemic_variabilityCV, MAGE, SDCV 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);
CalculationFormulaResult
Basal dose50% of TDD21 units/day
Hourly pump rateBasal / 240.88 u/hr
ISF (1800 rule)1800 / TDD42.9 mg/dL per unit
ICR (500 rule)500 / TDD11.9 g carb per unit
Correction(current - target) / ISF2.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.