Work up before starting Semaglutide

Reading File
Finding Sources
Searching PubMed

semaglutide pre-treatment workup screening

Searching the Web

semaglutide pre-treatment workup labs baseline evaluation before starting 2025

Finding Sources
Finding Sources
Reading Web Page

https://pmc.ncbi.nlm.nih.gov/articles/PMC12346479

Finding Sources
Searching PubMed

semaglutide GLP-1 agonist safety monitoring

Reading File
Reading File
I now have sufficient information from the textbooks, the PMC peer-reviewed study, and the web sources to compile a thorough answer. Let me put it together.

Pre-Treatment Workup Before Starting Semaglutide (Ozempic / Wegovy / Rybelsus)

A thorough workup before initiating semaglutide serves three purposes: (1) confirm the indication is appropriate, (2) identify absolute and relative contraindications, and (3) establish a metabolic baseline for ongoing monitoring. A 2025 PMC study on pre-treatment semaglutide assessment found that only 1.8% of patients received a complete pre-treatment evaluation - highlighting how often this is underperformed in practice.

1. Confirm the Indication

IndicationCriteria
Type 2 Diabetes (Ozempic)Diagnosed T2DM, inadequate glycemic control
Obesity / Overweight (Wegovy)BMI ≥ 30, OR BMI ≥ 27 with at least one weight-related comorbidity (HTN, dyslipidemia, OSA, CVD)
Cardiovascular risk reductionEstablished CVD in T2DM patients

2. History and Physical Examination

Personal & Family History - Screen Specifically For:

  • Personal or family history of medullary thyroid carcinoma (MTC) - absolute contraindication
  • Multiple Endocrine Neoplasia type 2 (MEN 2) - absolute contraindication
  • History of pancreatitis (acute or chronic) - use with caution / relative contraindication
  • Gallbladder disease (cholelithiasis, cholecystitis) - increased risk on therapy
  • History of diabetic retinopathy - rapid glycemic improvement can transiently worsen DR in the first 1-2 years
  • Gastroparesis or severe GI motility disorders - semaglutide slows gastric emptying, can exacerbate
  • Eating disorders (anorexia, bulimia)
  • Depression / suicidal ideation - monitor mood on treatment
  • Prior bariatric surgery - dose adjustments may be needed

Vitals & Anthropometrics:

  • Weight, Height, BMI
  • Blood pressure
  • Waist circumference
  • Heart rate

3. Laboratory Workup

Essential (Required)

TestRationale
HbA1cGlycemic baseline; identifies undiagnosed diabetes in Wegovy patients; monitors hypoglycemia risk if on other anti-diabetics
Fasting plasma glucoseAcute glycemic status
Comprehensive Metabolic Panel (CMP)Includes electrolytes, BUN, creatinine, liver enzymes (ALT, AST, ALP, bilirubin), albumin
eGFR / Serum CreatinineSemaglutide is used with caution in severe renal impairment (eGFR < 15); GI side effects may cause dehydration worsening renal function
Lipid Panel (TC, LDL, HDL, TG)Cardiovascular risk stratification; baseline for monitoring improvement
TSHScreen for pre-existing thyroid disease; monitor for thyroid abnormalities; baseline before drug with theoretical thyroid C-cell risk

Highly Recommended

TestRationale
T3 / Free T4Deeper thyroid evaluation if TSH is abnormal
Fasting insulin + HOMA-IRAssesses insulin resistance; not captured by HbA1c alone
Amylase & LipaseBaseline pancreatic enzymes; semaglutide carries a risk of acute pancreatitis
CBC (Complete Blood Count)Rule out anemia, infection, or hematologic issues
Vitamin B12GLP-1 RAs reduce appetite significantly; nutritional monitoring baseline
Vitamin DCommon deficiency in obesity; baseline recommended
Serum CalcitoninSome protocols include this to screen for medullary thyroid pathology before GLP-1 RA initiation (STEP trials excluded patients with calcitonin ≥ 100 ng/L)
Urine albumin-to-creatinine ratio (uACR)Renal baseline, especially in diabetic patients
hs-CRPInflammation baseline

4. Cardiovascular Assessment

  • 12-lead ECG (if age > 40, or existing CVD risk)
  • Blood pressure both arms
  • Review current cardiovascular medications (especially other antihyperglycemics - high hypoglycemia risk when combined with insulin or sulfonylureas)

5. Eye Exam

  • Dilated fundoscopic / retinal exam - mandatory if any history of diabetic retinopathy, as intensive glucose lowering with semaglutide can transiently worsen existing DR within the first 1-2 years of therapy (per PMC 12346479 and SUSTAIN-6 trial data).

6. Absolute Contraindications

  • Personal or family history of Medullary Thyroid Carcinoma (MTC)
  • Personal or family history of MEN 2 syndrome
  • Pregnancy (or planned pregnancy - discontinue at least 2 months before conception)
  • Known hypersensitivity to semaglutide or any component of the formulation

7. Relative Contraindications / Use With Caution

  • History of pancreatitis
  • Severe renal impairment (eGFR < 15 mL/min) - not recommended
  • Severe hepatic impairment - limited data
  • Gastroparesis or delayed gastric emptying
  • High-risk diabetic retinopathy - requires close ophthalmologic follow-up
  • Concomitant use of insulin or insulin secretagogues (sulfonylureas) - increase hypoglycemia risk; consider dose reduction of the secretagogue

8. Medication Review

  • Check for insulin or sulfonylureas - reduce doses to prevent hypoglycemia
  • Check for oral medications with narrow therapeutic windows (warfarin, immunosuppressants) - slowed gastric emptying alters absorption
  • Review for concurrent QT-prolonging drugs if relevant

9. Patient Counseling Before Starting

  • Realistic expectations for weight loss timeline
  • GI side effects (nausea, vomiting, diarrhea) are common early - start low, titrate slow
  • Importance of adherence to injection technique (SC weekly)
  • Drug must be continued long-term - weight typically returns after cessation
  • Anesthesia considerations: hold semaglutide at least 1 week before elective surgery due to risk of aspiration from delayed gastric emptying (per Miller's Anesthesia, 10e)

Summary Checklist

CategoryDone?
BMI, BP, vitals
Personal/family history of MTC, MEN2, pancreatitis
HbA1c, fasting glucose
CMP (renal + hepatic panel)
Lipid panel
TSH (± T3/T4)
Amylase / lipase
CBC
B12, Vitamin D
Fasting insulin
Retinal exam (if diabetic or at-risk)
Medication reconciliation
Contraindications confirmed absent
Patient counseling completed

Key References:

Create a pre-treatment checklist PDF I can print for clinic

Reading File
Running Command

ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"

Running Command

mkdir -p /home/daytona/workspace/semaglutide-checklist && python3 -c "import rep…

Writing File

~/semaglutide-checklist/build_pdf.py

from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import KeepTogether

OUTPUT = "/home/daytona/workspace/semaglutide-checklist/Semaglutide_Pretreatment_Checklist.pdf"

# ── Colors ──────────────────────────────────────────────────────────────────
DARK_BLUE   = colors.HexColor("#1A3A5C")
MED_BLUE    = colors.HexColor("#2C6FAC")
LIGHT_BLUE  = colors.HexColor("#D6E8F7")
ACCENT      = colors.HexColor("#E8F4FD")
RED_WARN    = colors.HexColor("#C0392B")
LIGHT_RED   = colors.HexColor("#FADBD8")
GREEN_OK    = colors.HexColor("#1D6A3A")
LIGHT_GREEN = colors.HexColor("#D5F5E3")
GREY_LINE   = colors.HexColor("#BDC3C7")
WHITE       = colors.white
DARK_TEXT   = colors.HexColor("#1C2833")
MID_GREY    = colors.HexColor("#5D6D7E")

# ── Styles ───────────────────────────────────────────────────────────────────
styles = getSampleStyleSheet()

title_style = ParagraphStyle(
    "Title", parent=styles["Normal"],
    fontSize=20, leading=26, textColor=WHITE,
    fontName="Helvetica-Bold", alignment=TA_CENTER
)
subtitle_style = ParagraphStyle(
    "Subtitle", parent=styles["Normal"],
    fontSize=10, leading=14, textColor=colors.HexColor("#AED6F1"),
    fontName="Helvetica", alignment=TA_CENTER
)
section_style = ParagraphStyle(
    "Section", parent=styles["Normal"],
    fontSize=10, leading=13, textColor=WHITE,
    fontName="Helvetica-Bold", alignment=TA_LEFT
)
item_style = ParagraphStyle(
    "Item", parent=styles["Normal"],
    fontSize=9, leading=13, textColor=DARK_TEXT,
    fontName="Helvetica", leftIndent=4
)
item_bold_style = ParagraphStyle(
    "ItemBold", parent=styles["Normal"],
    fontSize=9, leading=13, textColor=DARK_TEXT,
    fontName="Helvetica-Bold", leftIndent=4
)
note_style = ParagraphStyle(
    "Note", parent=styles["Normal"],
    fontSize=8, leading=11, textColor=MID_GREY,
    fontName="Helvetica-Oblique", leftIndent=4
)
warn_style = ParagraphStyle(
    "Warn", parent=styles["Normal"],
    fontSize=8.5, leading=12, textColor=RED_WARN,
    fontName="Helvetica-Bold", leftIndent=4
)
footer_style = ParagraphStyle(
    "Footer", parent=styles["Normal"],
    fontSize=7.5, leading=10, textColor=MID_GREY,
    fontName="Helvetica", alignment=TA_CENTER
)

# ── Helpers ──────────────────────────────────────────────────────────────────
def section_header(text, color=MED_BLUE):
    """Returns a colored header row table."""
    data = [[Paragraph(text, section_style)]]
    t = Table(data, colWidths=[7.2 * inch])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0, 0), (-1, -1), color),
        ("ROWPADDING", (0, 0), (-1, -1), 5),
        ("LEFTPADDING", (0, 0), (-1, -1), 8),
        ("TOPPADDING", (0, 0), (-1, -1), 4),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 4),
        ("ROUNDEDCORNERS", [4, 4, 4, 4]),
    ]))
    return t

def checklist_table(rows, bg=WHITE):
    """
    rows: list of (label, note) tuples.
    Returns a table with a checkbox column and label/note columns.
    """
    data = []
    for label, note in rows:
        label_cell = Paragraph(label, item_bold_style if note else item_style)
        if note:
            combined = [label_cell, Spacer(1, 1), Paragraph(note, note_style)]
        else:
            combined = label_cell
        data.append(["", combined])

    col_widths = [0.35 * inch, 6.85 * inch]
    t = Table(data, colWidths=col_widths, repeatRows=0)

    ts = [
        ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
        ("LEFTPADDING", (0, 0), (0, -1), 6),
        ("RIGHTPADDING", (0, 0), (0, -1), 0),
        ("LEFTPADDING", (1, 0), (1, -1), 4),
        ("TOPPADDING", (0, 0), (-1, -1), 4),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 4),
        ("LINEBELOW", (0, 0), (-1, -2), 0.4, GREY_LINE),
    ]
    # Alternate row tints
    for i in range(len(rows)):
        if i % 2 == 1:
            ts.append(("BACKGROUND", (0, i), (-1, i), ACCENT))
    t.setStyle(TableStyle(ts))
    return t

def checkbox_symbol():
    """Returns a Unicode square (print-friendly checkbox)."""
    return "□"

def draw_checkbox_col(canvas, doc):
    """Draw actual checkbox squares after the table is placed — not used;
    instead we embed the checkbox character in the first column."""
    pass

# Override checklist_table to put checkbox char in col 0
def checklist_table(rows, section_bg=ACCENT):
    data = []
    for label, note in rows:
        if note:
            cell_content = [
                Paragraph(label, item_bold_style),
                Paragraph(note, note_style),
            ]
        else:
            cell_content = Paragraph(label, item_style)

        data.append([
            Paragraph("<font size=14>□</font>", ParagraphStyle(
                "cb", parent=styles["Normal"], fontSize=14,
                leading=16, textColor=MED_BLUE,
                fontName="Helvetica", alignment=TA_CENTER
            )),
            cell_content,
        ])

    col_widths = [0.3 * inch, 6.9 * inch]
    t = Table(data, colWidths=col_widths)
    ts = [
        ("VALIGN", (0, 0), (-1, -1), "TOP"),
        ("TOPPADDING", (0, 0), (-1, -1), 4),
        ("BOTTOMPADDING", (0, 0), (-1, -1), 4),
        ("LEFTPADDING", (0, 0), (0, -1), 4),
        ("LEFTPADDING", (1, 0), (1, -1), 6),
        ("LINEBELOW", (0, 0), (-1, -2), 0.3, GREY_LINE),
    ]
    for i in range(len(rows)):
        if i % 2 == 1:
            ts.append(("BACKGROUND", (0, i), (-1, i), section_bg))
    t.setStyle(TableStyle(ts))
    return t

# ── Build PDF ─────────────────────────────────────────────────────────────────
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=letter,
    rightMargin=0.65 * inch,
    leftMargin=0.65 * inch,
    topMargin=0.6 * inch,
    bottomMargin=0.7 * inch,
    title="Semaglutide Pre-Treatment Checklist",
    author="Orris Clinical Tools",
)

story = []

# ── HEADER BANNER ────────────────────────────────────────────────────────────
header_data = [[
    Paragraph("SEMAGLUTIDE PRE-TREATMENT CHECKLIST", title_style),
    Paragraph("Ozempic® / Wegovy® / Rybelsus®", subtitle_style),
    Paragraph("Patient Name: ______________________________    DOB: ______________    Date: ______________", ParagraphStyle(
        "hdr_sub2", parent=styles["Normal"], fontSize=9, leading=13,
        textColor=colors.HexColor("#AED6F1"), fontName="Helvetica", alignment=TA_CENTER
    )),
]]
# Flatten to one column
header_data2 = [
    [Paragraph("SEMAGLUTIDE  PRE-TREATMENT  CHECKLIST", title_style)],
    [Paragraph("Ozempic\u00ae (T2DM)  |  Wegovy\u00ae (Obesity)  |  Rybelsus\u00ae (Oral T2DM)", subtitle_style)],
    [Paragraph(
        "Patient: ________________________________  DOB: ________________  Date: _______________  Provider: ________________",
        ParagraphStyle("hf", parent=styles["Normal"], fontSize=8.5, leading=12,
                       textColor=colors.HexColor("#AED6F1"), fontName="Helvetica", alignment=TA_CENTER)
    )],
]
header_tbl = Table(header_data2, colWidths=[7.2 * inch])
header_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, -1), DARK_BLUE),
    ("LEFTPADDING", (0, 0), (-1, -1), 12),
    ("RIGHTPADDING", (0, 0), (-1, -1), 12),
    ("TOPPADDING", (0, 0), (0, 0), 12),
    ("TOPPADDING", (0, 1), (0, 1), 2),
    ("TOPPADDING", (0, 2), (0, 2), 6),
    ("BOTTOMPADDING", (0, 2), (0, 2), 12),
    ("ROUNDEDCORNERS", [6, 6, 6, 6]),
]))
story.append(header_tbl)
story.append(Spacer(1, 10))

# ── INDICATION BOX ───────────────────────────────────────────────────────────
ind_items = [
    ("BMI \u2265 30 kg/m\u00b2  (Obesity - Wegovy)", ""),
    ("BMI \u2265 27 kg/m\u00b2 with \u22651 weight-related comorbidity (HTN, dyslipidemia, OSA, CVD)", "e.g., for Wegovy"),
    ("Type 2 Diabetes Mellitus - inadequate glycemic control  (Ozempic / Rybelsus)", ""),
    ("Established CVD in T2DM for cardiovascular risk reduction  (Ozempic)", ""),
]
story.append(KeepTogether([
    section_header("1.  CONFIRM INDICATION", DARK_BLUE),
    Spacer(1, 3),
    checklist_table(ind_items, ACCENT),
    Spacer(1, 8),
]))

# ── CONTRAINDICATIONS ────────────────────────────────────────────────────────
abs_ci = [
    ("Personal or family history of Medullary Thyroid Carcinoma (MTC)", "ABSOLUTE contraindication - do NOT prescribe"),
    ("Personal or family history of Multiple Endocrine Neoplasia type 2 (MEN 2)", "ABSOLUTE contraindication - do NOT prescribe"),
    ("Known hypersensitivity / allergy to semaglutide", ""),
    ("Pregnancy (or planning pregnancy within 2 months)", "Discontinue \u22652 months before conception"),
]
abs_tbl = Table([[Paragraph(label, ParagraphStyle(
    "warn_item", parent=styles["Normal"], fontSize=9, leading=13,
    textColor=RED_WARN, fontName="Helvetica-Bold", leftIndent=4)),
    Paragraph(note, note_style)] for label, note in abs_ci],
    colWidths=[0.3*inch, 3.5*inch, 3.4*inch])

# Rebuild with checkboxes
abs_rows = []
for label, note in abs_ci:
    cb_style = ParagraphStyle("cb2", parent=styles["Normal"], fontSize=14,
                               leading=16, textColor=RED_WARN, fontName="Helvetica",
                               alignment=TA_CENTER)
    if note:
        cell = [Paragraph(label, ParagraphStyle("wi", parent=styles["Normal"], fontSize=9,
                           leading=13, textColor=RED_WARN, fontName="Helvetica-Bold", leftIndent=4)),
                Paragraph(note, note_style)]
    else:
        cell = Paragraph(label, ParagraphStyle("wi", parent=styles["Normal"], fontSize=9,
                          leading=13, textColor=RED_WARN, fontName="Helvetica-Bold", leftIndent=4))
    abs_rows.append([Paragraph("<font size=14>\u25a1</font>", cb_style), cell])

abs_tbl2 = Table(abs_rows, colWidths=[0.3*inch, 6.9*inch])
abs_tbl2.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, -1), LIGHT_RED),
    ("VALIGN", (0, 0), (-1, -1), "TOP"),
    ("TOPPADDING", (0, 0), (-1, -1), 4),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 4),
    ("LEFTPADDING", (0, 0), (0, -1), 4),
    ("LEFTPADDING", (1, 0), (1, -1), 6),
    ("LINEBELOW", (0, 0), (-1, -2), 0.3, colors.HexColor("#E74C3C")),
]))

story.append(KeepTogether([
    section_header("2.  ABSOLUTE CONTRAINDICATIONS  (if ANY checked, do NOT prescribe)", colors.HexColor("#922B21")),
    Spacer(1, 3),
    abs_tbl2,
    Spacer(1, 8),
]))

# ── HISTORY & PHYSICAL ───────────────────────────────────────────────────────
hx_items = [
    ("Weight _______ kg   Height _______ cm   BMI _______ kg/m\u00b2", ""),
    ("Blood pressure _______ / _______   HR _______   Waist circumference _______ cm", ""),
    ("Personal hx of pancreatitis (acute or chronic)", "Use with caution / may be relative CI"),
    ("Personal hx of gallbladder disease (stones, cholecystitis)", "Semaglutide increases gallbladder disease risk"),
    ("Personal hx of diabetic retinopathy", "Rapid glucose lowering can transiently worsen DR - mandatory eye exam"),
    ("Personal hx of gastroparesis or severe GI motility disorder", "Semaglutide slows gastric emptying - may worsen"),
    ("Personal hx of depression, suicidal ideation, or eating disorder", "Monitor mood; use with caution"),
    ("Prior bariatric surgery", "May alter dosing and response"),
    ("History of renal impairment (eGFR < 15)", "Not recommended in severe CKD"),
    ("History of severe hepatic impairment", "Limited safety data"),
    ("Family hx of thyroid cancer (non-MTC)", "Monitor thyroid closely"),
]
story.append(KeepTogether([
    section_header("3.  HISTORY & PHYSICAL EXAM", MED_BLUE),
    Spacer(1, 3),
    checklist_table(hx_items, ACCENT),
    Spacer(1, 8),
]))

# ── LABS - ESSENTIAL ─────────────────────────────────────────────────────────
labs_ess = [
    ("HbA1c  _______ %", "Glycemic baseline; identifies undiagnosed DM in obesity patients; monitors hypoglycemia risk"),
    ("Fasting Plasma Glucose  _______ mg/dL", "Acute glycemic status"),
    ("Comprehensive Metabolic Panel (CMP)", "Electrolytes, BUN, creatinine, glucose, LFTs (ALT, AST, ALP, bilirubin, albumin)"),
    ("eGFR / Serum Creatinine  _______ mL/min", "Not recommended if eGFR < 15; GI side effects risk dehydration"),
    ("Lipid Panel  (TC / LDL / HDL / TG)", "Cardiovascular risk baseline; expect improvement on therapy"),
    ("TSH  _______ mIU/L", "Screen for thyroid disease; baseline before drug with C-cell risk signal"),
]
story.append(KeepTogether([
    section_header("4a.  LABORATORY WORKUP - ESSENTIAL", MED_BLUE),
    Spacer(1, 3),
    checklist_table(labs_ess, ACCENT),
    Spacer(1, 8),
]))

# ── LABS - RECOMMENDED ───────────────────────────────────────────────────────
labs_rec = [
    ("Free T4 / T3  _______", "If TSH is abnormal - deeper thyroid evaluation"),
    ("Serum Amylase  _______   Lipase  _______", "Baseline pancreatic enzymes; semaglutide carries acute pancreatitis risk"),
    ("CBC (Complete Blood Count)", "Rule out anemia, infection, hematologic issues"),
    ("Fasting Insulin  _______   HOMA-IR  _______", "Insulin resistance assessment not captured by HbA1c alone"),
    ("Vitamin B12  _______", "Baseline nutrition marker - appetite suppression risks deficiency over time"),
    ("Vitamin D (25-OH)  _______", "Common deficiency in obesity"),
    ("hs-CRP  _______", "Inflammation baseline; semaglutide has anti-inflammatory effects"),
    ("Urine Albumin-to-Creatinine Ratio (uACR)  _______", "Renal baseline in diabetic patients"),
    ("Serum Calcitonin  _______ ng/L", "Optional; STEP trials excluded if calcitonin \u2265 100 ng/L"),
]
story.append(KeepTogether([
    section_header("4b.  LABORATORY WORKUP - HIGHLY RECOMMENDED", MED_BLUE),
    Spacer(1, 3),
    checklist_table(labs_rec, ACCENT),
    Spacer(1, 8),
]))

# ── CARDIOVASCULAR & EYE ─────────────────────────────────────────────────────
cv_items = [
    ("12-lead ECG", "If age > 40 or existing CVD risk factors"),
    ("Blood pressure documented bilaterally", ""),
    ("Dilated fundoscopic / retinal exam", "MANDATORY if any history of diabetic retinopathy - intensive glucose lowering can transiently worsen DR in yr 1-2 (SUSTAIN-6 data)"),
    ("Cardiovascular risk score calculated (e.g., ASCVD 10-yr risk)", ""),
]
story.append(KeepTogether([
    section_header("5.  CARDIOVASCULAR & OPHTHALMOLOGIC ASSESSMENT", MED_BLUE),
    Spacer(1, 3),
    checklist_table(cv_items, ACCENT),
    Spacer(1, 8),
]))

# ── MEDICATION REVIEW ────────────────────────────────────────────────────────
med_items = [
    ("Insulin  (current dose: _________________)", "Reduce dose to prevent hypoglycemia when adding semaglutide"),
    ("Sulfonylureas / Meglitinides  (current: ___________)", "Reduce dose; significantly increased hypoglycemia risk"),
    ("Oral medications with narrow therapeutic index", "Semaglutide slows gastric emptying - alters absorption of warfarin, immunosuppressants, etc."),
    ("Other antihyperglycemics documented", "Review for additive GI effects (e.g., metformin + semaglutide GI overlap)"),
    ("Current medications reviewed for interactions", ""),
]
story.append(KeepTogether([
    section_header("6.  MEDICATION RECONCILIATION", MED_BLUE),
    Spacer(1, 3),
    checklist_table(med_items, ACCENT),
    Spacer(1, 8),
]))

# ── PATIENT COUNSELING ───────────────────────────────────────────────────────
counsel_items = [
    ("Indication, expected benefits, and realistic timeline for weight loss / glycemic control discussed", ""),
    ("GI side effects (nausea, vomiting, diarrhea) explained - common early; start low, titrate slow", ""),
    ("Injection technique (SC, weekly) reviewed with patient / caregiver", "For injectable formulations (Ozempic, Wegovy)"),
    ("Oral administration (Rybelsus) instructions given if applicable", "30 min before first food/drink of day, with \u226490 mL water"),
    ("Weight regain expected if drug is discontinued - long-term therapy discussed", ""),
    ("Anesthesia hold: discontinue \u22651 week before any elective surgery", "Delayed gastric emptying raises aspiration risk (Miller\u2019s Anesthesia, 10e)"),
    ("Signs to report: severe abdominal pain, vomiting, visual changes, neck lump, rapid HR", ""),
    ("Pregnancy / contraception counseled; discontinue \u22652 months before conception", ""),
    ("Follow-up schedule established (3-month labs, annual ophthalmology, annual thyroid palpation)", ""),
]
story.append(KeepTogether([
    section_header("7.  PATIENT COUNSELING & CONSENT", colors.HexColor("#1A5276")),
    Spacer(1, 3),
    checklist_table(counsel_items, LIGHT_GREEN),
    Spacer(1, 8),
]))

# ── PRESCRIBER SIGN-OFF ──────────────────────────────────────────────────────
signoff_data = [
    [
        Paragraph("Prescriber Signature: ______________________________", item_style),
        Paragraph("Date: ___________________", item_style),
    ],
    [
        Paragraph("Indication confirmed:  \u25a1 T2DM (Ozempic / Rybelsus)   \u25a1 Obesity (Wegovy)   \u25a1 CV risk reduction", item_style),
        Paragraph("Starting dose: _______________", item_style),
    ],
    [
        Paragraph("All absolute CIs ruled out:  \u25a1 Yes   \u25a1 No (document reason if prescribing despite relative CI)", item_style),
        Paragraph("", item_style),
    ],
]
signoff_tbl = Table(signoff_data, colWidths=[4.5*inch, 2.7*inch])
signoff_tbl.setStyle(TableStyle([
    ("BACKGROUND", (0, 0), (-1, -1), LIGHT_BLUE),
    ("GRID", (0, 0), (-1, -1), 0.4, GREY_LINE),
    ("TOPPADDING", (0, 0), (-1, -1), 7),
    ("BOTTOMPADDING", (0, 0), (-1, -1), 7),
    ("LEFTPADDING", (0, 0), (-1, -1), 8),
    ("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
]))
story.append(KeepTogether([
    section_header("8.  PRESCRIBER SIGN-OFF", DARK_BLUE),
    Spacer(1, 3),
    signoff_tbl,
    Spacer(1, 10),
]))

# ── FOOTER ───────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=0.5, color=GREY_LINE))
story.append(Spacer(1, 4))
story.append(Paragraph(
    "References: Sabiston Textbook of Surgery 21e | Miller\u2019s Anesthesia 10e | Harrison\u2019s Principles of Internal Medicine 22e | "
    "PMC12346479 (2025) | STEP & SUSTAIN-6 Trial Data   \u2022   For clinical use only \u2014 verify against current prescribing information",
    footer_style
))

# ── RENDER ───────────────────────────────────────────────────────────────────
doc.build(story)
print("PDF created:", OUTPUT)
Running Command

cd /home/daytona/workspace/semaglutide-checklist && python3 build_pdf.py

Running Command

ls -lh /home/daytona/workspace/semaglutide-checklist/

Your print-ready checklist is ready:

Semaglutide Pretreatment Checklist

PDF Document · PDF


What's included in the PDF:
The checklist is formatted as a single letter-size page with color-coded sections and print-friendly checkbox squares (□) throughout:
SectionContents
HeaderPatient name, DOB, date, provider fill-in fields
1. Confirm IndicationBMI/comorbidity thresholds for Wegovy; T2DM criteria for Ozempic/Rybelsus
2. Absolute ContraindicationsRed-highlighted - MTC hx, MEN2, allergy, pregnancy
3. History & PhysicalVitals fill-ins, pancreatitis, retinopathy, gastroparesis, renal/hepatic hx
4a. Essential LabsHbA1c, FPG, CMP, eGFR, lipid panel, TSH (with fill-in values)
4b. Recommended LabsFree T4/T3, amylase/lipase, CBC, fasting insulin, B12, Vit D, calcitonin
5. CV & EyeECG, BP bilateral, fundoscopic exam, ASCVD risk
6. Medication ReconciliationInsulin/sulfonylurea dose reduction reminders
7. Patient CounselingGI SE, injection technique, anesthesia hold, signs to report
8. Prescriber Sign-offSignature, indication confirmation, starting dose, CI clearance

Create a follow-up monitoring schedule template (3-month, 6-month, 12-month labs)

Running Command

ls -la /home/daytona/workspace/semaglutide-checklist/

Writing File

~/semaglutide-checklist/build_followup_pdf.py

from reportlab.lib.pagesizes import letter
from reportlab.lib import colors
from reportlab.lib.units import inch
from reportlab.platypus import (
    SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
    HRFlowable, KeepTogether
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT

OUTPUT = "/home/daytona/workspace/semaglutide-checklist/Semaglutide_Followup_Monitoring.pdf"

# ── Colors ───────────────────────────────────────────────────────────────────
DARK_BLUE   = colors.HexColor("#1A3A5C")
MED_BLUE    = colors.HexColor("#2C6FAC")
LIGHT_BLUE  = colors.HexColor("#D6E8F7")
ACCENT      = colors.HexColor("#EBF5FB")
TEAL        = colors.HexColor("#148F77")
LIGHT_TEAL  = colors.HexColor("#D1F2EB")
PURPLE      = colors.HexColor("#6C3483")
LIGHT_PUR   = colors.HexColor("#E8DAEF")
ORANGE      = colors.HexColor("#BA4A00")
LIGHT_ORG   = colors.HexColor("#FDEBD0")
RED_WARN    = colors.HexColor("#C0392B")
LIGHT_RED   = colors.HexColor("#FADBD8")
GREY_LINE   = colors.HexColor("#BDC3C7")
GREY_BG     = colors.HexColor("#F2F3F4")
WHITE       = colors.white
DARK_TEXT   = colors.HexColor("#1C2833")
MID_GREY    = colors.HexColor("#5D6D7E")

# Column colors per visit
V_COLORS = {
    "base":  (DARK_BLUE,   LIGHT_BLUE),   # baseline (reference)
    "3mo":   (TEAL,        LIGHT_TEAL),   # 3-month
    "6mo":   (PURPLE,      LIGHT_PUR),    # 6-month
    "12mo":  (ORANGE,      LIGHT_ORG),    # 12-month
}

# ── Styles ───────────────────────────────────────────────────────────────────
base_styles = getSampleStyleSheet()

def ps(name, base="Normal", **kwargs):
    return ParagraphStyle(name, parent=base_styles[base], **kwargs)

title_s    = ps("T", fontSize=20, leading=26, textColor=WHITE,
                fontName="Helvetica-Bold", alignment=TA_CENTER)
sub_s      = ps("S", fontSize=9.5, leading=13, textColor=colors.HexColor("#AED6F1"),
                fontName="Helvetica", alignment=TA_CENTER)
hdr_fill_s = ps("HF", fontSize=8.5, leading=12, textColor=colors.HexColor("#AED6F1"),
                fontName="Helvetica", alignment=TA_CENTER)
sec_s      = ps("SEC", fontSize=9.5, leading=13, textColor=WHITE,
                fontName="Helvetica-Bold", alignment=TA_LEFT)
visit_s    = ps("VIS", fontSize=10, leading=14, textColor=WHITE,
                fontName="Helvetica-Bold", alignment=TA_CENTER)
visit_sub  = ps("VSUB", fontSize=8, leading=11, textColor=WHITE,
                fontName="Helvetica", alignment=TA_CENTER)
col_hdr_s  = ps("CH", fontSize=8.5, leading=12, textColor=WHITE,
                fontName="Helvetica-Bold", alignment=TA_CENTER)
item_s     = ps("IT", fontSize=8.5, leading=12, textColor=DARK_TEXT,
                fontName="Helvetica", leftIndent=4)
item_b_s   = ps("ITB", fontSize=8.5, leading=12, textColor=DARK_TEXT,
                fontName="Helvetica-Bold", leftIndent=4)
note_s     = ps("NT", fontSize=7.5, leading=10, textColor=MID_GREY,
                fontName="Helvetica-Oblique", leftIndent=4)
cb_s       = ps("CB", fontSize=13, leading=15, textColor=MED_BLUE,
                fontName="Helvetica", alignment=TA_CENTER)
val_s      = ps("VL", fontSize=8.5, leading=12, textColor=DARK_TEXT,
                fontName="Helvetica", alignment=TA_CENTER)
warn_s     = ps("WN", fontSize=8, leading=11, textColor=RED_WARN,
                fontName="Helvetica-Bold", leftIndent=4)
footer_s   = ps("FT", fontSize=7.5, leading=10, textColor=MID_GREY,
                fontName="Helvetica", alignment=TA_CENTER)
action_s   = ps("AC", fontSize=8, leading=11, textColor=DARK_TEXT,
                fontName="Helvetica-Oblique", alignment=TA_CENTER)

# ── Helper: Section Header ────────────────────────────────────────────────────
def section_hdr(text, bg=MED_BLUE, width=7.2*inch):
    t = Table([[Paragraph(text, sec_s)]], colWidths=[width])
    t.setStyle(TableStyle([
        ("BACKGROUND", (0,0),(-1,-1), bg),
        ("LEFTPADDING",(0,0),(-1,-1), 8),
        ("TOPPADDING",(0,0),(-1,-1), 4),
        ("BOTTOMPADDING",(0,0),(-1,-1), 4),
    ]))
    return t

# ── Helper: Visit column header ───────────────────────────────────────────────
def visit_col_hdr(label, sublabel, bg):
    data = [
        [Paragraph(label, visit_s)],
        [Paragraph(sublabel, visit_sub)],
    ]
    t = Table(data, colWidths=[1.55*inch])
    t.setStyle(TableStyle([
        ("BACKGROUND",(0,0),(-1,-1), bg),
        ("ALIGN",(0,0),(-1,-1),"CENTER"),
        ("TOPPADDING",(0,0),(-1,-1), 4),
        ("BOTTOMPADDING",(0,0),(-1,-1), 4),
    ]))
    return t

# ── Helper: Monitoring grid ───────────────────────────────────────────────────
# rows: list of dicts:
#   label, note, base, m3, m6, m12, action
#   base/m3/m6/m12 = "●" (required), "◑" (if indicated), "○" (optional), "" (not needed)
def monitor_grid(rows, show_action=True):
    """
    Columns: Lab/Assessment | Baseline | 3-Month | 6-Month | 12-Month | Action / Target
    """
    SYMBOL_COLOR = {
        "●": colors.HexColor("#1D6A3A"),   # required - dark green
        "◑": colors.HexColor("#B7770D"),   # if indicated - amber
        "○": MID_GREY,                     # optional - grey
        "":  MID_GREY,
    }

    # Header row
    header = [
        Paragraph("Lab / Assessment", col_hdr_s),
        visit_col_hdr("Baseline", "(Pre-Tx)", DARK_BLUE),
        visit_col_hdr("3 Months", "(±2 wks)", TEAL),
        visit_col_hdr("6 Months", "(±4 wks)", PURPLE),
        visit_col_hdr("12 Months", "(±4 wks)", ORANGE),
    ]
    if show_action:
        header.append(Paragraph("Action / Target", col_hdr_s))

    data = [header]

    for r in rows:
        sym_cells = []
        for sym_key in ["base", "m3", "m6", "m12"]:
            sym = r.get(sym_key, "")
            sym_color = SYMBOL_COLOR.get(sym, MID_GREY)
            sym_cells.append(
                Paragraph(
                    f'<font color="#{sym_color.hexval()[1:]}" size=14>{sym if sym else "-"}</font>',
                    ps(f"sc_{sym}", fontSize=14, leading=16, fontName="Helvetica",
                       alignment=TA_CENTER)
                )
            )

        label_cell = [Paragraph(r["label"], item_b_s)]
        if r.get("note"):
            label_cell.append(Paragraph(r["note"], note_s))

        row = [label_cell] + sym_cells
        if show_action:
            row.append(Paragraph(r.get("action",""), action_s))
        data.append(row)

    col_w = [2.35*inch, 0.75*inch, 0.75*inch, 0.75*inch, 0.75*inch]
    if show_action:
        col_w.append(1.85*inch)

    t = Table(data, colWidths=col_w, repeatRows=1)
    ts = [
        # header background
        ("BACKGROUND",(0,0),(0,0), MED_BLUE),
        ("BACKGROUND",(1,0),(1,0), DARK_BLUE),
        ("BACKGROUND",(2,0),(2,0), TEAL),
        ("BACKGROUND",(3,0),(3,0), PURPLE),
        ("BACKGROUND",(4,0),(4,0), ORANGE),
        ("ALIGN",(1,0),(-1,-1),"CENTER"),
        ("VALIGN",(0,0),(-1,-1),"MIDDLE"),
        ("TOPPADDING",(0,0),(-1,-1), 4),
        ("BOTTOMPADDING",(0,0),(-1,-1), 4),
        ("LEFTPADDING",(0,0),(0,-1), 6),
        ("LINEBELOW",(0,0),(-1,-2), 0.3, GREY_LINE),
        ("ROWBACKGROUNDS",(0,1),(-1,-1),[WHITE, ACCENT]),
    ]
    if show_action:
        ts.append(("BACKGROUND",(5,0),(5,0), MED_BLUE))
    t.setStyle(TableStyle(ts))
    return t

# ── Helper: Visit summary card ────────────────────────────────────────────────
def visit_card(title, date_label, bg_hdr, bg_body, items):
    """
    items: list of (category, text) or (category, [text1, text2, ...])
    """
    card_data = []
    # Title row
    card_data.append([
        Paragraph(f"{title}  |  {date_label}", ps(
            f"vt_{title}", fontSize=10, leading=14, textColor=WHITE,
            fontName="Helvetica-Bold", alignment=TA_LEFT)),
    ])
    for cat, content in items:
        if isinstance(content, list):
            lines = [Paragraph(f"<b>{cat}:</b>", item_b_s)]
            for c in content:
                lines.append(Paragraph(f"\u2003\u2022 {c}", item_s))
            card_data.append([lines])
        else:
            card_data.append([[
                Paragraph(f"<b>{cat}:</b>  {content}", item_s)
            ]])

    t = Table(card_data, colWidths=[7.2*inch])
    ts = [
        ("BACKGROUND",(0,0),(0,0), bg_hdr),
        ("BACKGROUND",(0,1),(-1,-1), bg_body),
        ("LEFTPADDING",(0,0),(-1,-1), 8),
        ("RIGHTPADDING",(0,0),(-1,-1), 8),
        ("TOPPADDING",(0,0),(0,0), 6),
        ("BOTTOMPADDING",(0,0),(0,0), 6),
        ("TOPPADDING",(0,1),(-1,-1), 4),
        ("BOTTOMPADDING",(0,1),(-1,-1), 4),
        ("LINEBELOW",(0,1),(-1,-2), 0.3, GREY_LINE),
        ("BOX",(0,0),(-1,-1), 0.5, GREY_LINE),
    ]
    t.setStyle(TableStyle(ts))
    return t

# ── Legend ────────────────────────────────────────────────────────────────────
def legend():
    leg_data = [[
        Paragraph('<font color="#1D6A3A" size=13>●</font>  <b>Required</b>', item_s),
        Paragraph('<font color="#B7770D" size=13>◑</font>  <b>If clinically indicated</b>', item_s),
        Paragraph('<font color="#5D6D7E" size=13>○</font>  <b>Optional / individualize</b>', item_s),
        Paragraph('<font color="#5D6D7E">—</font>  <b>Not routinely needed</b>', item_s),
    ]]
    t = Table(leg_data, colWidths=[1.8*inch, 2.2*inch, 2.2*inch, 1.0*inch])
    t.setStyle(TableStyle([
        ("BACKGROUND",(0,0),(-1,-1), GREY_BG),
        ("BOX",(0,0),(-1,-1), 0.5, GREY_LINE),
        ("TOPPADDING",(0,0),(-1,-1), 5),
        ("BOTTOMPADDING",(0,0),(-1,-1), 5),
        ("LEFTPADDING",(0,0),(-1,-1), 8),
        ("VALIGN",(0,0),(-1,-1),"MIDDLE"),
    ]))
    return t

# ═══════════════════════════════════════════════════════════════════════════════
# BUILD
# ═══════════════════════════════════════════════════════════════════════════════
doc = SimpleDocTemplate(
    OUTPUT,
    pagesize=letter,
    rightMargin=0.65*inch, leftMargin=0.65*inch,
    topMargin=0.6*inch, bottomMargin=0.7*inch,
    title="Semaglutide Follow-Up Monitoring Schedule",
    author="Orris Clinical Tools",
)
story = []

# ── PAGE HEADER ───────────────────────────────────────────────────────────────
hdr_data = [
    [Paragraph("SEMAGLUTIDE  FOLLOW-UP MONITORING SCHEDULE", title_s)],
    [Paragraph("Ozempic\u00ae  |  Wegovy\u00ae  |  Rybelsus\u00ae    \u2014    3-Month \u2022 6-Month \u2022 12-Month Labs & Assessment", sub_s)],
    [Paragraph(
        "Patient: ________________________________  DOB: _______________  "
        "Start Date: _______________  Indication: \u25a1 T2DM  \u25a1 Obesity  \u25a1 CV Risk",
        hdr_fill_s)],
]
hdr_tbl = Table(hdr_data, colWidths=[7.2*inch])
hdr_tbl.setStyle(TableStyle([
    ("BACKGROUND",(0,0),(-1,-1), DARK_BLUE),
    ("LEFTPADDING",(0,0),(-1,-1), 12),
    ("RIGHTPADDING",(0,0),(-1,-1), 12),
    ("TOPPADDING",(0,0),(0,0), 12),
    ("TOPPADDING",(0,1),(0,1), 2),
    ("TOPPADDING",(0,2),(0,2), 6),
    ("BOTTOMPADDING",(0,2),(0,2), 12),
]))
story.append(hdr_tbl)
story.append(Spacer(1, 8))

# ── LEGEND ────────────────────────────────────────────────────────────────────
story.append(legend())
story.append(Spacer(1, 10))

# ── SECTION A: GLYCEMIC MONITORING ───────────────────────────────────────────
glycemic_rows = [
    dict(label="HbA1c",
         note="Primary glycemic endpoint",
         base="●", m3="●", m6="●", m12="●",
         action="Target: <7% (T2DM) or monitor trend (obesity)"),
    dict(label="Fasting Plasma Glucose",
         note="",
         base="●", m3="●", m6="●", m12="●",
         action="Fasting 80-130 mg/dL (ADA target for T2DM)"),
    dict(label="Fasting Insulin / HOMA-IR",
         note="Insulin resistance marker",
         base="◑", m3="", m6="◑", m12="◑",
         action="Track trend; not a dose-adjustment driver alone"),
    dict(label="Hypoglycemia Episodes",
         note="Especially if on insulin or sulfonylurea",
         base="●", m3="●", m6="●", m12="●",
         action="If occurring: reduce insulin / SU dose"),
]
story.append(KeepTogether([
    section_hdr("A.  GLYCEMIC MONITORING", DARK_BLUE),
    Spacer(1,4),
    monitor_grid(glycemic_rows),
    Spacer(1,8),
]))

# ── SECTION B: RENAL FUNCTION ────────────────────────────────────────────────
renal_rows = [
    dict(label="Serum Creatinine + eGFR",
         note="GI side effects risk dehydration \u2192 AKI",
         base="●", m3="●", m6="●", m12="●",
         action="Hold if eGFR <15 or acute AKI; ensure hydration"),
    dict(label="BUN (Blood Urea Nitrogen)",
         note="Dehydration marker",
         base="●", m3="◑", m6="◑", m12="●",
         action="Elevated BUN:Cr ratio suggests prerenal state"),
    dict(label="Urine Albumin-to-Creatinine Ratio (uACR)",
         note="Diabetic nephropathy screening",
         base="◑", m3="", m6="◑", m12="●",
         action="Target: <30 mg/g (normoalbuminuria)"),
    dict(label="Electrolytes (Na, K, Cl, CO2)",
         note="Part of CMP",
         base="●", m3="●", m6="●", m12="●",
         action="Correct hyponatremia if vomiting prominent"),
]
story.append(KeepTogether([
    section_hdr("B.  RENAL FUNCTION", MED_BLUE),
    Spacer(1,4),
    monitor_grid(renal_rows),
    Spacer(1,8),
]))

# ── SECTION C: HEPATIC FUNCTION ──────────────────────────────────────────────
liver_rows = [
    dict(label="ALT / AST",
         note="Liver enzymes",
         base="●", m3="◑", m6="●", m12="●",
         action=">3x ULN: consider dose hold; evaluate for NAFLD improvement"),
    dict(label="ALP / GGT",
         note="Biliary marker; gallbladder disease risk with semaglutide",
         base="●", m3="◑", m6="◑", m12="●",
         action="Elevated: evaluate for cholelithiasis / cholecystitis"),
    dict(label="Total Bilirubin",
         note="",
         base="●", m3="", m6="◑", m12="●",
         action=""),
    dict(label="Albumin",
         note="Nutritional status",
         base="●", m3="", m6="◑", m12="●",
         action="Low albumin: assess for protein-calorie malnutrition"),
]
story.append(KeepTogether([
    section_hdr("C.  HEPATIC FUNCTION & GALLBLADDER", MED_BLUE),
    Spacer(1,4),
    monitor_grid(liver_rows),
    Spacer(1,8),
]))

# ── SECTION D: LIPIDS & CARDIOVASCULAR ───────────────────────────────────────
cv_rows = [
    dict(label="Lipid Panel (TC, LDL, HDL, TG)",
         note="Semaglutide typically improves lipid profile",
         base="●", m3="", m6="●", m12="●",
         action="LDL target depends on CV risk tier; expect TG \u2193"),
    dict(label="Blood Pressure",
         note="Each visit",
         base="●", m3="●", m6="●", m12="●",
         action="Target: <130/80 mmHg (AHA/ACC)"),
    dict(label="Heart Rate",
         note="GLP-1 RAs mildly raise HR (+2-4 bpm)",
         base="●", m3="●", m6="●", m12="●",
         action="Persistent tachycardia: evaluate; consider ECG"),
    dict(label="ECG",
         note="If symptomatic palpitations or new arrhythmia concern",
         base="◑", m3="◑", m6="◑", m12="◑",
         action="If resting HR >100 or symptoms: 12-lead ECG"),
]
story.append(KeepTogether([
    section_hdr("D.  LIPIDS & CARDIOVASCULAR", MED_BLUE),
    Spacer(1,4),
    monitor_grid(cv_rows),
    Spacer(1,8),
]))

# ── SECTION E: THYROID ────────────────────────────────────────────────────────
thyroid_rows = [
    dict(label="TSH",
         note="Theoretical C-cell risk signal from animal data",
         base="●", m3="", m6="◑", m12="●",
         action="If TSH abnormal: check Free T4; refer if thyroid mass felt"),
    dict(label="Free T4",
         note="If TSH out of range",
         base="◑", m3="◑", m6="◑", m12="◑",
         action="Hypothyroidism may worsen obesity outcomes if untreated"),
    dict(label="Serum Calcitonin",
         note="Optional; if neck mass or family hx non-MTC thyroid cancer",
         base="○", m3="", m6="○", m12="○",
         action="If \u2265100 ng/L: refer to endocrinology / discontinue"),
    dict(label="Thyroid palpation (clinical)",
         note="Check for new nodules at each visit",
         base="●", m3="●", m6="●", m12="●",
         action="New neck mass: urgent thyroid US + calcitonin"),
]
story.append(KeepTogether([
    section_hdr("E.  THYROID MONITORING", TEAL),
    Spacer(1,4),
    monitor_grid(thyroid_rows),
    Spacer(1,8),
]))

# ── SECTION F: PANCREATIC ────────────────────────────────────────────────────
panc_rows = [
    dict(label="Serum Amylase",
         note="Baseline and if abdominal pain develops",
         base="●", m3="◑", m6="◑", m12="◑",
         action="If \u22653x ULN with sx: hold drug, evaluate for pancreatitis"),
    dict(label="Serum Lipase",
         note="More sensitive than amylase for pancreatitis",
         base="●", m3="◑", m6="◑", m12="◑",
         action="Acute pancreatitis confirmed: DISCONTINUE permanently"),
    dict(label="Abdominal pain / N&V symptom screen",
         note="At every visit",
         base="●", m3="●", m6="●", m12="●",
         action="Severe persistent pain: hold drug, urgent imaging"),
]
story.append(KeepTogether([
    section_hdr("F.  PANCREATIC MONITORING", TEAL),
    Spacer(1,4),
    monitor_grid(panc_rows),
    Spacer(1,8),
]))

# ── SECTION G: WEIGHT & ANTHROPOMETRICS ──────────────────────────────────────
wt_rows = [
    dict(label="Body Weight (kg)",
         note="",
         base="●", m3="●", m6="●", m12="●",
         action="<5% loss at 16 wks: reassess indication / adherence"),
    dict(label="BMI (kg/m\u00b2)",
         note="",
         base="●", m3="●", m6="●", m12="●",
         action="Goal: \u22655% weight loss at 6 months to continue"),
    dict(label="Waist Circumference (cm)",
         note="Visceral adiposity proxy",
         base="●", m3="", m6="●", m12="●",
         action="Target: <88 cm (F), <102 cm (M)"),
    dict(label="Dose documentation & titration note",
         note="",
         base="●", m3="●", m6="●", m12="●",
         action="Titrate per tolerability; max 2.4 mg/wk (Wegovy)"),
]
story.append(KeepTogether([
    section_hdr("G.  WEIGHT, BMI & DOSE TITRATION", PURPLE),
    Spacer(1,4),
    monitor_grid(wt_rows),
    Spacer(1,8),
]))

# ── SECTION H: NUTRITIONAL & OPHTHALMOLOGIC ──────────────────────────────────
nutr_rows = [
    dict(label="Vitamin B12",
         note="Appetite suppression risks deficiency over time",
         base="●", m3="", m6="●", m12="●",
         action="If low: oral B12 supplementation"),
    dict(label="Vitamin D (25-OH)",
         note="Common deficiency in obesity",
         base="●", m3="", m6="○", m12="●",
         action="Target: >30 ng/mL; supplement if deficient"),
    dict(label="CBC",
         note="Nutritional anemia screen",
         base="●", m3="", m6="◑", m12="●",
         action="MCV changes may indicate B12/folate deficiency"),
    dict(label="Dilated retinal exam",
         note="Rapid glucose lowering can transiently worsen diabetic retinopathy",
         base="●", m3="", m6="", m12="●",
         action="Annually in DM pts; more frequent if pre-existing DR"),
    dict(label="Peripheral neuropathy screen",
         note="Monofilament + vibration",
         base="◑", m3="", m6="", m12="●",
         action="Annual foot exam in diabetic patients"),
]
story.append(KeepTogether([
    section_hdr("H.  NUTRITIONAL STATUS & OPHTHALMOLOGIC", PURPLE),
    Spacer(1,4),
    monitor_grid(nutr_rows),
    Spacer(1,8),
]))

# ── SECTION I: MENTAL HEALTH & SIDE EFFECTS ──────────────────────────────────
mh_rows = [
    dict(label="GI side effects (nausea, vomiting, diarrhea)",
         note="Most common early adverse effects",
         base="●", m3="●", m6="●", m12="●",
         action="Antiemetics PRN; consider dose hold / slower titration"),
    dict(label="Depression / Mood screening (PHQ-2/PHQ-9)",
         note="Especially if hx of mood disorder",
         base="◑", m3="◑", m6="◑", m12="●",
         action="Worsening mood: reassess; do not abruptly stop if T2DM"),
    dict(label="Injection site reactions",
         note="Rotate sites each week",
         base="", m3="●", m6="●", m12="●",
         action="Persistent nodules: review technique; consider rotation sites"),
    dict(label="Gallbladder symptom screen",
         note="Right upper quadrant pain, fatty food intolerance",
         base="●", m3="●", m6="●", m12="●",
         action="Symptomatic: RUQ US; refer surgery if cholelithiasis"),
    dict(label="Heart rate / palpitation screen",
         note="GLP-1 RAs cause small HR increase",
         base="●", m3="●", m6="●", m12="●",
         action="HR >100 at rest: ECG; consider cardiology referral"),
]
story.append(KeepTogether([
    section_hdr("I.  SIDE EFFECTS & MENTAL HEALTH SCREEN", ORANGE),
    Spacer(1,4),
    monitor_grid(mh_rows),
    Spacer(1,8),
]))

# ── SECTION J: VISIT SUMMARY CARDS ──────────────────────────────────────────
story.append(section_hdr("J.  VISIT SUMMARY CARDS  (detach or use separately)", DARK_BLUE))
story.append(Spacer(1, 6))

# 3-month card
card3 = visit_card(
    "3-MONTH VISIT", "Date: ___________________ / Provider: ___________________",
    TEAL, LIGHT_TEAL,
    [
        ("Weight", "_______ kg  |  BMI _______ kg/m\u00b2  |  BP _______ / _______  |  HR _______"),
        ("HbA1c", "_______ %  |  FPG _______ mg/dL"),
        ("CMP", "Cr _______ | eGFR _______ | ALT _______ | AST _______  | Na _______ | K _______"),
        ("Dose", "Current dose: _______________  \u25a1 Tolerated well  \u25a1 GI side effects present"),
        ("Hypoglycemia", "\u25a1 None   \u25a1 Episodes (document): _____________________________________"),
        ("GI Symptoms", "\u25a1 None  \u25a1 Nausea  \u25a1 Vomiting  \u25a1 Diarrhea  \u25a1 Constipation"),
        ("Thyroid Palpation", "\u25a1 Normal  \u25a1 Mass / nodule detected \u2192 order thyroid US + calcitonin"),
        ("Abdominal Pain", "\u25a1 None  \u25a1 Present \u2014 amylase / lipase ordered"),
        ("Plan", "_____________________________________________________________________________"),
        ("Next Visit", "6-month labs due: ___________________ "),
    ]
)
story.append(card3)
story.append(Spacer(1, 8))

# 6-month card
card6 = visit_card(
    "6-MONTH VISIT", "Date: ___________________ / Provider: ___________________",
    PURPLE, LIGHT_PUR,
    [
        ("Weight", "_______ kg  |  BMI _______ kg/m\u00b2  |  BP _______ / _______  |  HR _______  |  Waist _______ cm"),
        ("HbA1c", "_______ %  |  FPG _______ mg/dL  |  Fasting Insulin _______  |  HOMA-IR _______"),
        ("CMP (full)", "Cr _______ | eGFR _______ | ALT _______ | AST _______ | ALP _______ | Bili _______"),
        ("Lipids", "TC _______ | LDL _______ | HDL _______ | TG _______"),
        ("Thyroid", "TSH _______  |  Thyroid palpation: \u25a1 Normal  \u25a1 Abnormal"),
        ("Nutrition", "B12 _______  |  Vit D _______  |  CBC: Hgb _______"),
        ("Dose", "Current dose: _______________  \u25a1 At max dose  \u25a1 Titrating"),
        ("Response", "\u25a1 \u22655% weight loss achieved  \u25a1 <5% loss \u2014 reassess adherence, diet, consider adjunct therapy"),
        ("GI / Gallbladder", "\u25a1 No symptoms  \u25a1 RUQ pain \u2192 order RUQ US"),
        ("Plan", "_____________________________________________________________________________"),
        ("Next Visit", "12-month labs due: ___________________"),
    ]
)
story.append(card6)
story.append(Spacer(1, 8))

# 12-month card
card12 = visit_card(
    "12-MONTH VISIT", "Date: ___________________ / Provider: ___________________",
    ORANGE, LIGHT_ORG,
    [
        ("Weight", "_______ kg  |  BMI _______ kg/m\u00b2  |  BP _______ / _______  |  HR _______  |  Waist _______ cm"),
        ("HbA1c", "_______ %  |  FPG _______ mg/dL  |  Fasting Insulin _______  |  HOMA-IR _______"),
        ("Full CMP + CBC", "Cr _______ | eGFR _______ | LFTs _______ | Electrolytes _______ | Hgb _______"),
        ("Lipids", "TC _______ | LDL _______ | HDL _______ | TG _______"),
        ("Thyroid", "TSH _______  |  Free T4 _______  |  Thyroid palpation: \u25a1 Normal  \u25a1 Abnormal"),
        ("Nutrition", "B12 _______  |  Vit D _______  |  Albumin _______"),
        ("Renal", "uACR _______  mg/g  |  eGFR trend: improving / stable / declining"),
        ("Eyes", "\u25a1 Dilated retinal exam completed (date: ___________)  \u25a1 Referred to ophthalmology"),
        ("Neuropathy", "\u25a1 Monofilament normal  \u25a1 Abnormal \u2192 refer"),
        ("Mental Health", "PHQ-2 score: _______  \u25a1 No concerns  \u25a1 PHQ-9 ordered"),
        ("Dose", "Current dose: _______________  \u25a1 Maintenance achieved  \u25a1 Continue titrating"),
        ("Annual Assessment", "\u25a1 Benefit continues \u2192 continue  \u25a1 Inadequate response \u2192 reassess / switch"),
        ("Plan", "_____________________________________________________________________________"),
        ("Next Visit", "Annual follow-up due: ___________________"),
    ]
)
story.append(card12)
story.append(Spacer(1, 10))

# ── DISCONTINUATION TRIGGERS ──────────────────────────────────────────────────
disc_items = [
    ("Confirmed acute pancreatitis", "DISCONTINUE permanently - do not rechallenge"),
    ("Medullary thyroid carcinoma confirmed or newly diagnosed", "DISCONTINUE immediately - refer endocrinology / oncology"),
    ("Pregnancy confirmed", "DISCONTINUE immediately; switch to safe alternative"),
    ("Severe hypersensitivity reaction (anaphylaxis, angioedema)", "DISCONTINUE permanently"),
    ("eGFR < 15 mL/min or dialysis initiation", "DISCONTINUE; not recommended in severe CKD"),
    ("<5% weight loss at 16 weeks (obesity indication)", "Consider discontinuing - clinical guidelines suggest reassessment"),
    ("Severe or persistent GI symptoms affecting quality of life", "Consider dose reduction, hold, or switch agent"),
]
disc_rows = []
for label, note in disc_items:
    cb_p = Paragraph('<font color="#C0392B" size=13>\u25a1</font>',
                     ps("dc", fontSize=13, leading=15, textColor=RED_WARN,
                        fontName="Helvetica", alignment=TA_CENTER))
    if note:
        cell = [Paragraph(label, ps("dl", fontSize=9, leading=13, textColor=RED_WARN,
                                    fontName="Helvetica-Bold", leftIndent=4)),
                Paragraph(note, note_s)]
    else:
        cell = Paragraph(label, ps("dl2", fontSize=9, leading=13, textColor=RED_WARN,
                                   fontName="Helvetica-Bold", leftIndent=4))
    disc_rows.append([cb_p, cell])

disc_tbl = Table(disc_rows, colWidths=[0.3*inch, 6.9*inch])
disc_tbl.setStyle(TableStyle([
    ("BACKGROUND",(0,0),(-1,-1), LIGHT_RED),
    ("VALIGN",(0,0),(-1,-1),"TOP"),
    ("TOPPADDING",(0,0),(-1,-1), 4),
    ("BOTTOMPADDING",(0,0),(-1,-1), 4),
    ("LEFTPADDING",(0,0),(0,-1), 4),
    ("LEFTPADDING",(1,0),(1,-1), 6),
    ("LINEBELOW",(0,0),(-1,-2), 0.3, colors.HexColor("#E74C3C")),
]))

story.append(KeepTogether([
    section_hdr("K.  DISCONTINUATION TRIGGERS", colors.HexColor("#922B21")),
    Spacer(1,3),
    disc_tbl,
    Spacer(1,10),
]))

# ── ANNUAL RENEWAL CHECKLIST ───────────────────────────────────────────────────
renew_items = [
    ("\u25a1  Indication remains valid (BMI / DM / CV risk still meets criteria)", ""),
    ("\u25a1  Patient reports adherence and tolerability", ""),
    ("\u25a1  Documented clinical benefit (weight loss \u22655% OR HbA1c improvement)", ""),
    ("\u25a1  No new contraindications identified", ""),
    ("\u25a1  All annual labs reviewed and documented", ""),
    ("\u25a1  Prior authorization / refill submitted", ""),
]
renew_tbl_data = [[Paragraph(label, item_s)] for label, _ in renew_items]
renew_tbl = Table(renew_tbl_data, colWidths=[7.2*inch])
renew_tbl.setStyle(TableStyle([
    ("BACKGROUND",(0,0),(-1,-1), LIGHT_BLUE),
    ("LEFTPADDING",(0,0),(-1,-1), 10),
    ("TOPPADDING",(0,0),(-1,-1), 4),
    ("BOTTOMPADDING",(0,0),(-1,-1), 4),
    ("LINEBELOW",(0,0),(-1,-2), 0.3, GREY_LINE),
]))
story.append(KeepTogether([
    section_hdr("L.  ANNUAL RENEWAL CRITERIA", DARK_BLUE),
    Spacer(1,3),
    renew_tbl,
    Spacer(1,10),
]))

# ── FOOTER ────────────────────────────────────────────────────────────────────
story.append(HRFlowable(width="100%", thickness=0.5, color=GREY_LINE))
story.append(Spacer(1,4))
story.append(Paragraph(
    "References: Sabiston Textbook of Surgery 21e | Miller\u2019s Anesthesia 10e | Harrison\u2019s Principles of Internal Medicine 22e | "
    "PMC12346479 (2025) | ADA Standards of Care 2024 | STEP & SUSTAIN-6 Trial Data   \u2022   For clinical use only \u2014 verify against current prescribing information",
    footer_s
))

doc.build(story)
print("PDF created:", OUTPUT)
Running Command

cd /home/daytona/workspace/semaglutide-checklist && python3 build_followup_pdf.p…

Editing File

~/semaglutide-checklist/build_followup_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/semaglutide-checklist/build_followup_pdf.py'
Editing File

~/semaglutide-checklist/build_followup_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/semaglutide-checklist/build_followup_pdf.py'
Editing File

~/semaglutide-checklist/build_followup_pdf.py

Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/semaglutide-checklist/build_followup_pdf.py'
Running Command

cd /home/daytona/workspace/semaglutide-checklist && python3 build_followup_pdf.p…

Running Command

ls -lh /home/daytona/workspace/semaglutide-checklist/

Your monitoring schedule PDF is ready:

Semaglutide Followup Monitoring

PDF Document · PDF


What's inside (12 sections):
Monitoring Grid (Sections A-I) - Color-coded matrix showing each lab/assessment across all 4 timepoints with a symbol key:
  • 🟢 ● Required at that visit
  • 🟡 ◑ Order if clinically indicated
  • ⚪ ○ Optional / individualize
  • — Not routinely needed
SectionLabs & Assessments
A. GlycemicHbA1c, FPG, fasting insulin, hypoglycemia screen
B. RenalCreatinine, eGFR, BUN, electrolytes, uACR
C. Hepatic / GallbladderALT, AST, ALP, bilirubin, albumin
D. Lipids & CVFull lipid panel, BP, HR, ECG
E. ThyroidTSH, Free T4, calcitonin, palpation
F. PancreaticAmylase, lipase, abdominal symptom screen
G. Weight & DoseWeight, BMI, waist circumference, titration log
H. Nutrition & EyesB12, Vit D, CBC, retinal exam, neuropathy screen
I. Side Effects & Mental HealthGI symptoms, PHQ screen, gallbladder, injection sites
Visit Summary Cards (Section J) - Separate fill-in cards for 3-, 6-, and 12-month visits with all value fill-in fields, perfect for scanning or filing in the chart.
Section K - Discontinuation trigger checklist (red-flagged)
Section L - Annual renewal criteria checklist
This is a shared conversation. Sign in to Orris to start your own chat.