Work up before starting Semaglutide
semaglutide pre-treatment workup screening
semaglutide pre-treatment workup labs baseline evaluation before starting 2025
https://pmc.ncbi.nlm.nih.gov/articles/PMC12346479
semaglutide GLP-1 agonist safety monitoring
| Indication | Criteria |
|---|---|
| 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 reduction | Established CVD in T2DM patients |
| Test | Rationale |
|---|---|
| HbA1c | Glycemic baseline; identifies undiagnosed diabetes in Wegovy patients; monitors hypoglycemia risk if on other anti-diabetics |
| Fasting plasma glucose | Acute glycemic status |
| Comprehensive Metabolic Panel (CMP) | Includes electrolytes, BUN, creatinine, liver enzymes (ALT, AST, ALP, bilirubin), albumin |
| eGFR / Serum Creatinine | Semaglutide 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 |
| TSH | Screen for pre-existing thyroid disease; monitor for thyroid abnormalities; baseline before drug with theoretical thyroid C-cell risk |
| Test | Rationale |
|---|---|
| T3 / Free T4 | Deeper thyroid evaluation if TSH is abnormal |
| Fasting insulin + HOMA-IR | Assesses insulin resistance; not captured by HbA1c alone |
| Amylase & Lipase | Baseline pancreatic enzymes; semaglutide carries a risk of acute pancreatitis |
| CBC (Complete Blood Count) | Rule out anemia, infection, or hematologic issues |
| Vitamin B12 | GLP-1 RAs reduce appetite significantly; nutritional monitoring baseline |
| Vitamin D | Common deficiency in obesity; baseline recommended |
| Serum Calcitonin | Some 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-CRP | Inflammation baseline |
| Category | Done? |
|---|---|
| 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 |
Create a pre-treatment checklist PDF I can print for clinic
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace not found"
mkdir -p /home/daytona/workspace/semaglutide-checklist && python3 -c "import rep…
~/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)
cd /home/daytona/workspace/semaglutide-checklist && python3 build_pdf.py
ls -lh /home/daytona/workspace/semaglutide-checklist/
Semaglutide Pretreatment Checklist
PDF Document · PDF
| Section | Contents |
|---|---|
| Header | Patient name, DOB, date, provider fill-in fields |
| 1. Confirm Indication | BMI/comorbidity thresholds for Wegovy; T2DM criteria for Ozempic/Rybelsus |
| 2. Absolute Contraindications | Red-highlighted - MTC hx, MEN2, allergy, pregnancy |
| 3. History & Physical | Vitals fill-ins, pancreatitis, retinopathy, gastroparesis, renal/hepatic hx |
| 4a. Essential Labs | HbA1c, FPG, CMP, eGFR, lipid panel, TSH (with fill-in values) |
| 4b. Recommended Labs | Free T4/T3, amylase/lipase, CBC, fasting insulin, B12, Vit D, calcitonin |
| 5. CV & Eye | ECG, BP bilateral, fundoscopic exam, ASCVD risk |
| 6. Medication Reconciliation | Insulin/sulfonylurea dose reduction reminders |
| 7. Patient Counseling | GI SE, injection technique, anesthesia hold, signs to report |
| 8. Prescriber Sign-off | Signature, indication confirmation, starting dose, CI clearance |
Create a follow-up monitoring schedule template (3-month, 6-month, 12-month labs)
ls -la /home/daytona/workspace/semaglutide-checklist/
~/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)
cd /home/daytona/workspace/semaglutide-checklist && python3 build_followup_pdf.p…
~/semaglutide-checklist/build_followup_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/semaglutide-checklist/build_followup_pdf.py'
~/semaglutide-checklist/build_followup_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/semaglutide-checklist/build_followup_pdf.py'
~/semaglutide-checklist/build_followup_pdf.py
Successfully replaced 1 instance(s) of the string in '/home/daytona/workspace/semaglutide-checklist/build_followup_pdf.py'
cd /home/daytona/workspace/semaglutide-checklist && python3 build_followup_pdf.p…
ls -lh /home/daytona/workspace/semaglutide-checklist/
Semaglutide Followup Monitoring
PDF Document · PDF
| Section | Labs & Assessments |
|---|---|
| A. Glycemic | HbA1c, FPG, fasting insulin, hypoglycemia screen |
| B. Renal | Creatinine, eGFR, BUN, electrolytes, uACR |
| C. Hepatic / Gallbladder | ALT, AST, ALP, bilirubin, albumin |
| D. Lipids & CV | Full lipid panel, BP, HR, ECG |
| E. Thyroid | TSH, Free T4, calcitonin, palpation |
| F. Pancreatic | Amylase, lipase, abdominal symptom screen |
| G. Weight & Dose | Weight, BMI, waist circumference, titration log |
| H. Nutrition & Eyes | B12, Vit D, CBC, retinal exam, neuropathy screen |
| I. Side Effects & Mental Health | GI symptoms, PHQ screen, gallbladder, injection sites |