shanselman

nightscout-cgm

37
7
# Install this skill:
npx skills add shanselman/nightscout-cgm-skill

Or install specific skill: npx add-skill https://github.com/shanselman/nightscout-cgm-skill

# Description

Analyze CGM blood glucose data from Nightscout. Use this skill when asked about current glucose levels, blood sugar trends, A1C estimates, time-in-range statistics, glucose variability, or diabetes management insights.

# SKILL.md


name: nightscout-cgm
description: Analyze CGM blood glucose data from Nightscout. Use this skill when asked about current glucose levels, blood sugar trends, A1C estimates, time-in-range statistics, glucose variability, or diabetes management insights.


Nightscout CGM Analysis Skill

This skill provides tools for fetching and analyzing Continuous Glucose Monitor (CGM) data from Nightscout.

⚠️ Before Making Changes

Always run tests before and after modifying cgm.py:

cd <skill-path>
python -m pytest tests/ -q           # Quick check (255+ tests)
python -m pytest tests/ --cov=scripts  # With coverage

Available Commands

Run the cgm.py script from this skill's scripts/ directory:

python <skill-path>/scripts/cgm.py <command> [options]

Where <skill-path> is the location where this skill is installed (e.g., ~/.copilot/skills/nightscout-cgm, .github/skills/nightscout-cgm, or .claude/skills/nightscout-cgm).

Commands

Command Description
current Get the latest glucose reading
analyze [--days N] Analyze CGM data (default: 90 days)
report [--days N] [--open] Generate interactive HTML report with charts
compare --period1 P1 --period2 P2 Compare two time periods side-by-side
alerts [--days N] Get trend alerts for recurring patterns
refresh [--days N] Fetch latest data from Nightscout
patterns [--days N] Find interesting patterns (best/worst times, problem areas)
query [options] Query with filters (day of week, time range)
day <date> [options] View all readings for a specific date
worst [options] Find your worst days for glucose control
chart [options] Terminal visualizations (heatmap, sparkline, day chart)
pump Get current pump status (IOB, COB, predicted glucose) *
treatments [--hours N] Get recent treatments (boluses, temp basals, carbs) *
profile Get pump profile settings (basal rates, ISF, carb ratios) *

* Pump commands require Loop, OpenAPS, or similar closed-loop system. The skill auto-detects pump capabilities on first use. CGM-only users won't see errors—commands simply report that pump data isn't available.

Report Command

Generate a comprehensive, self-contained HTML report with interactive charts:
- --days N - Number of days to include (default: 90)
- --output PATH - Custom output path (default: nightscout_report.html)
- --open - Open report in browser after generating

Auto-Sync: Reports automatically sync from Nightscout if local data is more than 30 minutes old.

Report Features:
- Interactive date controls (7d/14d/30d/90d/6mo/1yr/All + custom date pickers)
- All charts recalculate dynamically in browser
- Time-in-Range pie chart
- Modal Day (24-hour profile with percentile bands)
- Daily trends, Day of week comparison
- Glucose histogram, Heatmap with hover tooltips
- Weekly summary
- Key stats: TIR%, GMI (estimated A1C), CV (variability)
- Insulin Delivery (if using Loop/OpenAPS): TDD breakdown (bolus/basal), stacked bar chart, carb tracking

Day Command

View detailed readings for a specific date:
- day <date> - Date can be 'today', 'yesterday', '2026-01-16', or 'Jan 16'
- --hour-start H - Start hour for time window (0-23)
- --hour-end H - End hour for time window (0-23)

Worst Command

Find your worst days ranked by peak glucose:
- --days N - Number of days to search (default: 21)
- --hour-start H - Start hour for time window (0-23)
- --hour-end H - End hour for time window (0-23)
- --limit N - Number of worst days to show (default: 5)

Query Options

The query command supports flexible filtering:
- --days N - Number of days to analyze (default: 90)
- --day NAME - Filter by day of week (e.g., Tuesday, or 0-6 where 0=Monday)
- --hour-start H - Start hour for time window (0-23)
- --hour-end H - End hour for time window (0-23)

Chart Options

The chart command creates terminal visualizations:
- --sparkline - Compact trend line using Unicode blocks (▁▂▃▄▅▆▇█)
- --hours N - Hours of data for sparkline (default: 24)
- --date DATE - Specific date for sparkline (e.g., today, yesterday, 2026-01-16)
- --hour-start H - Start hour for sparkline time window (0-23)
- --hour-end H - End hour for sparkline time window (0-23)
- --heatmap - Weekly grid showing time-in-range by day and hour
- --day NAME - Hourly breakdown for a specific day of week
- --color - Use ANSI colors (for direct terminal, not inside Copilot)

Pump Commands (Optional)

These commands require a closed-loop system (Loop, OpenAPS, AndroidAPS, etc.) uploading to Nightscout. The skill auto-detects pump capabilities—CGM-only users won't be bothered with errors.

pump - Get current pump/loop status:
- IOB (Insulin on Board) and COB (Carbs on Board)
- Predicted glucose trajectory
- Recommended bolus
- Last enacted action (temp basal or bolus)
- Pump status (manufacturer, model, suspended/bolusing)
- Phone battery level

treatments [--hours N] - Get recent treatments:
- Boluses (automatic and manual)
- Temp basals
- Carb entries
- Summary totals (total insulin, total carbs)

profile - Get pump profile settings:
- Basal rates by time of day
- Total daily basal
- ISF (Insulin Sensitivity Factor) by time
- Carb ratios by time
- Target glucose ranges
- Loop settings (max bolus, pre-meal targets, override presets)

Examples

# Get current glucose
python scripts/cgm.py current

# Generate interactive HTML report (opens in browser)
python scripts/cgm.py report --days 90 --open

# Analyze last 30 days
python scripts/cgm.py analyze --days 30

# Find patterns automatically (best/worst times, problem areas)
python scripts/cgm.py patterns

# What happened yesterday during lunch (11am-2pm)?
python scripts/cgm.py day yesterday --hour-start 11 --hour-end 14

# Find my worst lunch days in the last 3 weeks
python scripts/cgm.py worst --days 21 --hour-start 11 --hour-end 14

# What happens on Tuesdays after lunch?
python scripts/cgm.py query --day Tuesday --hour-start 12 --hour-end 15

# How are my overnight numbers on weekends?
python scripts/cgm.py query --day Saturday --hour-start 22 --hour-end 6
python scripts/cgm.py query --day Sunday --hour-start 22 --hour-end 6

# Morning analysis across all days
python scripts/cgm.py query --hour-start 6 --hour-end 10

# Show sparkline of last 24 hours (compact visual trend)
python scripts/cgm.py chart --sparkline --hours 24

# Show sparkline for a specific date and time range (with colors)
python scripts/cgm.py chart --date yesterday --hour-start 11 --hour-end 15 --color

# Show heatmap of time-in-range by day/hour
python scripts/cgm.py chart --heatmap

# Show hourly breakdown for a specific day
python scripts/cgm.py chart --day Saturday

# Generate interactive HTML report (opens in browser)
python scripts/cgm.py report --days 90 --open

# Compare two time periods
python scripts/cgm.py compare --period1 "last 7 days" --period2 "previous 7 days"
python scripts/cgm.py compare --period1 "this week" --period2 "last week"

# Get trend alerts (recurring patterns)
python scripts/cgm.py alerts --days 30

# Refresh data from Nightscout
python scripts/cgm.py refresh

Example Questions You Can Ask

With the pattern analysis capabilities, you can ask natural questions like:

  • "What's my current glucose?"
  • "Generate a report of my last 90 days"
  • "Compare this week to last week"
  • "How am I doing vs last month?"
  • "What trend alerts do you see?"
  • "Analyze my blood sugar for the last 30 days"
  • "What patterns do you see in my data?"
  • "What's happening on Tuesdays after lunch?"
  • "When are my worst times for blood sugar control?"
  • "How are my overnight numbers?"
  • "When do I tend to go low?"
  • "What day of the week is my best for time-in-range?"
  • "Show me my morning patterns"
  • "Show me a sparkline of my last 24 hours"
  • "Show me a heatmap of my glucose"
  • "What does Saturday look like?"
  • "What was my worst lunch this week?" (you'll be asked what hours you eat lunch)
  • "Show me what happened yesterday during dinner"
  • "What were my worst days for breakfast the last two weeks?"
  • "What's my current IOB?"
  • "How much insulin on board do I have?"
  • "Show me my pump status"
  • "What's my predicted glucose?"
  • "What treatments have I had in the last 6 hours?"
  • "How much insulin did I take today?"
  • "What are my basal rates?"
  • "What's my carb ratio?"
  • "What are my ISF settings?"
  • "Show me my Loop profile"

Output Interpretation

Time in Range (TIR)

  • Very Low (<54 mg/dL): Dangerous hypoglycemia
  • Low (54-69 mg/dL): Hypoglycemia
  • In Range (70-180 mg/dL): Target range
  • High (181-250 mg/dL): Hyperglycemia
  • Very High (>250 mg/dL): Significant hyperglycemia

Key Metrics

  • GMI: Glucose Management Indicator (estimated A1C from CGM data)
  • CV: Coefficient of Variation (<36% indicates stable glucose)
  • Hourly Averages: Shows patterns throughout the day

Configuration (Required)

Set the NIGHTSCOUT_URL environment variable to your Nightscout API endpoint:

# Linux/macOS
export NIGHTSCOUT_URL="https://your-nightscout-site.com/api/v1/entries.json"

# Windows PowerShell
$env:NIGHTSCOUT_URL = "https://your-nightscout-site.com/api/v1/entries.json"

# Windows (persistent)
[Environment]::SetEnvironmentVariable("NIGHTSCOUT_URL", "https://your-nightscout-site.com/api/v1/entries.json", "User")

The script will not run without this environment variable configured.

# README.md

Nightscout CGM Skill

Agent Skills
License: MIT

An Agent Skill for analyzing Continuous Glucose Monitor (CGM) data from Nightscout. Works with GitHub Copilot CLI, Claude Code, and VS Code agent mode.

Nightscout CGM Report with interactive charts

⚠️ Disclaimer: We are not doctors. This is DIY body hacking by and for the diabetes community. If you're using Nightscout, you already know the deal: don't trust anyone or anything to make decisions about your blood sugar except yourself. This tool is for informational purposes only and should never replace medical advice, your own judgment, or looking at your actual CGM.

Features

  • Interactive HTML Reports - Generate comprehensive local reports with charts (like tally for diabetes)
  • Pump/Insulin Integration - Reports automatically include insulin delivery data if you use Loop/OpenAPS (stacked bolus/basal charts, TDD breakdown)
  • AGP Reports - Generate clinical-standard Ambulatory Glucose Profile (AGP) reports for sharing with healthcare providers
  • Current Glucose - Real-time blood glucose with trend direction
  • Trend Alerts - Proactive pattern detection for recurring lows/highs (e.g., "Morning lows 8-10am")
  • Period Comparison - Compare different time periods side-by-side to track progress
  • Pattern Analysis - Find your best/worst times, problem days, overnight patterns
  • Specific Day Analysis - Drill into what happened on a particular date
  • Worst Days Finder - Find your problem days ranked by peak glucose
  • Time Queries - "What happens Tuesdays after lunch?"
  • Terminal Visualizations - Heatmaps, sparklines, and day charts
  • Statistics - Time-in-range, GMI (estimated A1C), glucose variability
  • Privacy-First - All data stored and analyzed locally on your machine

Ambulatory Glucose Profile (AGP) Reports

Generate clinical-standard AGP reports that match the format used by Dexcom, Libre, and diabetes clinics:

python scripts/cgm.py agp --days 14 --open

AGP Report Example

AGP Features

  • Standard Percentile Bands - Shows 5th, 25th, 50th (median), 75th, and 95th percentiles for each hour
  • Glucose Statistics - Average glucose, GMI (estimated A1C), CV (glucose variability), total readings
  • Time in Ranges - Visual bar chart showing distribution across all glucose ranges
  • Daily Glucose Profiles - Last 14 days displayed for pattern recognition
  • Print-Friendly - Optimized layout for printing and sharing with healthcare providers
  • Clinical Goals - Displays standard AGP targets (>70% TIR, <4% below range, CV <36%)

The AGP format is recognized by endocrinologists worldwide and makes it easy to discuss your data during appointments.

Interactive HTML Reports

Generate beautiful, self-contained HTML reports with interactive charts - similar to tally but for diabetes/CGM data:

python scripts/cgm.py report --days 90 --open

Glucose distribution, heatmap, and weekly summary

Report Features

  • Date Range Controls - Quick buttons for 7d/14d/30d/90d/6mo/1yr/All, plus custom date pickers
  • All charts update dynamically - No server needed, everything recalculates in your browser
  • Key Stats Dashboard - Time-in-Range %, GMI (estimated A1C), CV (variability), average glucose
  • 7 Interactive Charts:
  • Time-in-Range pie chart
  • Modal Day (typical 24-hour profile with percentile bands)
  • Daily trends (average glucose + TIR per day)
  • Day of week comparison
  • Glucose distribution histogram
  • Time-in-Range heatmap (day × hour) with hover tooltips
  • Weekly summary
  • Insulin Delivery Section (for Loop/OpenAPS users):
  • Avg Daily Total (bolus + basal TDD)
  • Bolus/Basal breakdown with ratio
  • Stacked bar chart showing daily insulin (bolus vs basal)
  • Total carbs tracked

Color Scheme

Uses CGM-style colors (like Dexcom/Libre):
- 🔵 Blue for lows (easier to see at a glance)
- 🟢 Green for in-range
- 🟡 Yellow for highs
- 🔴 Red for very high

Privacy

The report is a single self-contained HTML file. All your data stays local - no data is sent anywhere. Open it in any browser, share it with your doctor, or keep it for your records.

Quick Examples

Just ask naturally:

"What's my current glucose?"
"Generate a report of my last 90 days"
"Compare this week to last week"
"Generate an AGP report for my doctor"
"What patterns do you see in my data?"
"What's happening on Tuesdays after lunch?"
"When do I tend to go low?"
"Show me a sparkline of my last 24 hours"
"Show me a heatmap of my glucose"
"What does Saturday look like?"
"What was my worst lunch this week?"
"Show me what happened yesterday during dinner"
"How am I doing vs 90 days ago?"

Or use the CLI directly:

# Generate interactive HTML report
python scripts/cgm.py report --days 90 --open

# Current glucose
python scripts/cgm.py current

# Compare two time periods
python scripts/cgm.py compare --period1 "last 7 days" --period2 "previous 7 days"
python scripts/cgm.py compare --period1 "this week" --period2 "last week"
python scripts/cgm.py compare --period1 "January" --period2 "December"

# Get trend alerts (recurring patterns like morning lows)
python scripts/cgm.py alerts --days 30

# Find patterns (best/worst times, problem areas)
python scripts/cgm.py patterns

# What happened yesterday at lunch (11am-2pm)?
python scripts/cgm.py day yesterday --hour-start 11 --hour-end 14

# Find worst lunch days in last 3 weeks
python scripts/cgm.py worst --days 21 --hour-start 11 --hour-end 14

# Sparkline for a specific date and time window (with colors)
python scripts/cgm.py chart --date yesterday --hour-start 11 --hour-end 14 --color

# Tuesdays after lunch
python scripts/cgm.py query --day Tuesday --hour-start 12 --hour-end 15

# Sparkline of last 24 hours
python scripts/cgm.py chart --sparkline

# Weekly heatmap
python scripts/cgm.py chart --heatmap

Privacy & Data Architecture

Your glucose data stays on your machine. Here's how it works:

┌─────────────────────────────────────────────────────────────────────┐
│                         YOUR MACHINE                                │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────────────────┐  │
│  │ Copilot CLI │───>│  cgm.py     │───>│ SQLite DB (cgm_data.db) │  │
│  │ (local)     │    │  (local)    │    │ (local file)            │  │
│  └─────────────┘    └──────┬──────┘    └─────────────────────────┘  │
│                            │                                        │
└────────────────────────────┼────────────────────────────────────────┘
                             │ HTTPS (fetch only)
                             ▼
                    ┌─────────────────┐
                    │ YOUR Nightscout │
                    │ (your server)   │
                    └─────────────────┘

What stays local:
- ✅ SQLite database with your glucose readings (stored in the skill directory)
- ✅ All analysis (statistics, time-in-range, GMI, patterns) computed locally by Python
- ✅ The script runs entirely on your machine

What the AI sees:
- Only the JSON output you request (e.g., {"glucose": 152, "status": "in range"})
- This is just text in your conversation - same as if you typed it yourself
- The AI cannot access your Nightscout directly or read your SQLite database

What the AI does NOT have access to:
- ❌ Your Nightscout URL or API credentials
- ❌ Your SQLite database file
- ❌ Your historical readings (unless you explicitly ask for analysis)

The skill simply runs a local Python script and returns text output. Your health data never leaves your machine except to fetch from your own Nightscout server (which you already trust).

Prerequisites

  • Python 3.8+
  • requests library (pip install requests)
  • A Nightscout instance with API access

Installation

GitHub Copilot CLI / Claude Code (Personal Skill)

git clone https://github.com/shanselman/nightscout-cgm-skill ~/.copilot/skills/nightscout-cgm

Or for Claude Code:

git clone https://github.com/shanselman/nightscout-cgm-skill ~/.claude/skills/nightscout-cgm

Project Skill (Repository-specific)

cd your-repo
git clone https://github.com/shanselman/nightscout-cgm-skill .github/skills/nightscout-cgm

Install Dependencies

pip install requests

Configuration

Set the NIGHTSCOUT_URL environment variable to your Nightscout API endpoint.

⚠️ Important: Before configuring, test your Nightscout URL in a browser to ensure it returns JSON data. If your Nightscout instance requires authentication, you'll need to include your API token as a query parameter:
https://your-nightscout-site.com/api/v1/entries.json?token=YOUR_API_SECRET
You can find or create API tokens in your Nightscout settings under "Admin Tools" → "Subjects".

Linux/macOS:

export NIGHTSCOUT_URL="https://your-nightscout-site.com/api/v1/entries.json?token=YOUR_API_SECRET"

Windows PowerShell:

$env:NIGHTSCOUT_URL = "https://your-nightscout-site.com/api/v1/entries.json?token=YOUR_API_SECRET"

Windows (persistent):

[Environment]::SetEnvironmentVariable("NIGHTSCOUT_URL", "https://your-nightscout-site.com/api/v1/entries.json?token=YOUR_API_SECRET", "User")

Getting Started

After installation and configuration, just start asking questions! The skill automatically fetches your data on first use.

> What's my current glucose?

No local data found. Fetching from Nightscout (this may take a moment)...
Fetched 31123 readings. Total: 31123

{"glucose": 142, "unit": "mg/dL", "trend": "Flat", "status": "in range"}

Data is cached locally in a SQLite database for fast queries. Run refresh periodically to pull in new readings, or just ask the AI to "refresh my CGM data".

Usage

With AI Agents

Just ask naturally:

Basic queries:
- "What's my current glucose?"
- "Analyze my blood sugar for the last 30 days"
- "What's my estimated A1C?"
- "Show me my time in range"

Pattern analysis:
- "What patterns do you see in my data?"
- "What's happening on Tuesdays after lunch?"
- "When are my worst times for blood sugar control?"
- "How are my overnight numbers?"
- "When do I tend to go low?"
- "What day of the week is my best for time-in-range?"
- "Show me my morning patterns"

Specific day analysis:
- "What was my worst lunch this week?" (you'll be asked what hours you eat lunch)
- "Show me what happened yesterday during dinner"
- "What were my worst breakfast days the last two weeks?"
- "What did my blood sugar do on January 16th between 11am and 3pm?"

Visualizations:
- "Show me a sparkline of my last 24 hours"
- "Show me a heatmap of my glucose"
- "What does Saturday look like?"

Period comparison:
- "Compare this week to last week"
- "How does January compare to December?"
- "How am I doing vs 90 days ago?"

Direct CLI Usage

# Generate interactive HTML report (opens in browser)
python scripts/cgm.py report --days 90 --open

# Generate report for custom period
python scripts/cgm.py report --days 30 --output my_report.html

# Get current glucose reading
python scripts/cgm.py current

# Analyze last 90 days (default)
python scripts/cgm.py analyze

# Analyze last 30 days
python scripts/cgm.py analyze --days 30

# Compare two time periods
python scripts/cgm.py compare --period1 "last 7 days" --period2 "previous 7 days"
python scripts/cgm.py compare --period1 "this week" --period2 "last week"
python scripts/cgm.py compare --period1 "this month" --period2 "last month"
python scripts/cgm.py compare --period1 "January" --period2 "December"

# Get trend alerts (recurring patterns)
python scripts/cgm.py alerts --days 30

# Find patterns automatically (best/worst times, problem areas)
python scripts/cgm.py patterns

# View all readings for a specific date
python scripts/cgm.py day yesterday
python scripts/cgm.py day 2026-01-16 --hour-start 11 --hour-end 14

# Find your worst days (ranked by peak glucose)
python scripts/cgm.py worst --days 21 --hour-start 11 --hour-end 14

# What happens on Tuesdays after lunch?
python scripts/cgm.py query --day Tuesday --hour-start 12 --hour-end 15

# How are my overnight numbers on weekends?
python scripts/cgm.py query --day Saturday --hour-start 22 --hour-end 6

# Morning analysis across all days
python scripts/cgm.py query --hour-start 6 --hour-end 10

# Show sparkline of last 24 hours (compact visual trend)
python scripts/cgm.py chart --sparkline

# Show sparkline of last 6 hours
python scripts/cgm.py chart --sparkline --hours 6

# Show sparkline for a specific date and time range
python scripts/cgm.py chart --date yesterday --hour-start 11 --hour-end 14 --color

# Show week view (one sparkline per day - great for terminals!)
python scripts/cgm.py chart --week --days 14 --color

# Show ASCII heatmap (works inside Copilot)
python scripts/cgm.py chart --heatmap

# Show day chart with colors (direct terminal)
python scripts/cgm.py chart --day Saturday --color

# Generate interactive HTML report (like tally for diabetes)
python scripts/cgm.py report --days 90

# Generate report and open in browser
python scripts/cgm.py report --days 30 --open

# Save report to specific location
python scripts/cgm.py report --days 90 --output ~/my_glucose_report.html

# Generate AGP (Ambulatory Glucose Profile) report - clinical standard format
python scripts/cgm.py agp --days 14 --open

# Generate AGP report with custom period
python scripts/cgm.py agp --days 30 --output ~/agp_report.html

# Refresh data from Nightscout
python scripts/cgm.py refresh --days 90

Standalone Terminal Usage

You don't need an AI agent to use this tool! The Python script works great on its own with colorful ANSI output:

cd ~/.copilot/skills/nightscout-cgm
python scripts/cgm.py chart --week --days 7 --color

There's also a PowerShell script that generates a full report:

cd ~/.copilot/skills/nightscout-cgm
.\show-all-charts.ps1

This outputs:
- 📈 14-day sparklines (one line per day)
- 🗓️ Weekly heatmap
- 📊 Hourly breakdown for each day of the week
- 🔍 Pattern analysis (best/worst times)
- 📋 Full statistics

Interactive HTML Report

Generate a comprehensive, self-contained HTML report with interactive charts - similar to tally but for diabetes data:

python scripts/cgm.py report --days 90 --open

The report includes:
- 📊 Time-in-Range pie chart - Visual breakdown of glucose distribution
- 📈 Modal Day chart - Your typical 24-hour glucose profile with percentile bands
- 📅 Daily trends - Day-by-day average glucose and time-in-range
- 🗓️ Day of week comparison - Which days are your best/worst
- 📉 Glucose distribution histogram - See your glucose spread
- 🔥 Time-in-Range heatmap - Identify problem times at a glance
- 📆 Weekly summary - Track progress over weeks

The report is:
- Self-contained - Single HTML file with embedded Chart.js
- Privacy-first - All data stays local, no external servers
- Interactive - Hover for details, responsive design
- Shareable - Open in any browser, send to your doctor

Output Examples

Current Glucose

{
  "glucose_mg_dl": 142,
  "trend": "Flat",
  "timestamp": "2024-01-15T14:30:00.000Z",
  "status": "in range"
}

Analysis

{
  "date_range": {"from": "2024-10-17", "to": "2025-01-15", "days_analyzed": 90},
  "readings": 25920,
  "statistics": {"count": 25920, "mean": 138.5, "std": 42.1, "min": 45, "max": 320, "median": 132},
  "time_in_range": {
    "very_low_pct": 0.5,
    "low_pct": 2.1,
    "in_range_pct": 72.3,
    "high_pct": 18.6,
    "very_high_pct": 6.5
  },
  "gmi_estimated_a1c": 6.6,
  "cv_variability": 30.4,
  "cv_status": "stable"
}

Period Comparison

{
  "comparison": {
    "period1": {
      "date_range": {"from": "2026-01-14", "to": "2026-01-21", "description": "Last 7 days"},
      "readings": 2016,
      "statistics": {"count": 2016, "mean": 125.3, "std": 35.2, "median": 118},
      "time_in_range": {
        "very_low_pct": 0.3,
        "low_pct": 1.8,
        "in_range_pct": 78.5,
        "high_pct": 15.2,
        "very_high_pct": 4.2
      },
      "gmi_estimated_a1c": 6.3,
      "cv_variability": 28.1,
      "cv_status": "stable"
    },
    "period2": {
      "date_range": {"from": "2026-01-07", "to": "2026-01-14", "description": "Previous 7 days"},
      "readings": 2016,
      "statistics": {"count": 2016, "mean": 145.8, "std": 42.6, "median": 138},
      "time_in_range": {
        "very_low_pct": 0.8,
        "low_pct": 2.5,
        "in_range_pct": 68.2,
        "high_pct": 21.3,
        "very_high_pct": 7.2
      },
      "gmi_estimated_a1c": 6.8,
      "cv_variability": 29.2,
      "cv_status": "stable"
    }
  },
  "deltas": {
    "average_glucose": {"value": -20.5, "change": "improved", "percentage_change": -14.1},
    "time_in_range": {"value": 10.3, "change": "improved", "percentage_points": 10.3},
    "gmi_estimated_a1c": {"value": -0.5, "change": "improved", "percentage_change": -7.4},
    "cv_variability": {"value": -1.1, "change": "improved", "percentage_change": -3.8}
  },
  "summary": {
    "period1_description": "Last 7 days",
    "period2_description": "Previous 7 days",
    "key_improvements": [
      "Time in range increased by 10.3 percentage points",
      "GMI (estimated A1C) decreased by 0.5",
      "Glucose variability (CV) decreased by 1.1%"
    ],
    "key_regressions": ["No significant regressions"]
  }
}

Glucose Ranges

This skill uses your Nightscout configuration:
- Units: Automatically detected from your DISPLAY_UNITS setting (mg/dL or mmol/L)
- Thresholds: Uses your configured bgLow, bgTargetBottom, bgTargetTop, and bgHigh values

Default thresholds (if not configured in Nightscout):

Range mg/dL mmol/L Status
Very Low <55 <3.0 Dangerous hypoglycemia
Low 55-69 3.0-3.8 Hypoglycemia
In Range 70-180 3.9-10.0 Target range
High 181-250 10.1-13.9 Hyperglycemia
Very High >250 >13.9 Significant hyperglycemia

Key Metrics

  • GMI (Glucose Management Indicator): Estimated A1C calculated from average glucose
  • CV (Coefficient of Variation): Glucose variability measure. <36% is considered stable
  • Time in Range: Percentage of readings in each glucose range

License

MIT License - see LICENSE file.

Contributing

Contributions welcome! Please feel free to submit a Pull Request.

Appendix: How Nightscout Units Work

If you're wondering why we need to convert units when Nightscout already has a DISPLAY_UNITS setting - here's the quirk:

The Nightscout API always returns glucose values in mg/dL, regardless of your display settings. This is a deliberate design decision:

  • Database storage: Always mg/dL (integers are easier to store and compare)
  • API responses: Always mg/dL (the sgv field is always in mg/dL)
  • DISPLAY_UNITS setting: Only affects the Nightscout web UI, not the API

So a European user with DISPLAY_UNITS=mmol will see 8.4 mmol/L on their Nightscout dashboard, but the API still returns "sgv": 152 (mg/dL). Every Nightscout client app (including this skill) must convert values for display if the user prefers mmol/L.

This skill reads your DISPLAY_UNITS setting and converts automatically - you don't need to configure anything extra.

Development

Running Tests

The skill has 255+ tests covering all functionality:

cd ~/.copilot/skills/nightscout-cgm

# Run all tests
python -m pytest tests/ -v

# Quick run (just pass/fail)
python -m pytest tests/ -q

# With coverage report
python -m pytest tests/ --cov=scripts --cov-report=term-missing

# Run specific test file
python -m pytest tests/test_real_data.py -v

Always run tests before and after modifying cgm.py.

Test Structure

File Description
test_pure_functions.py Unit conversion, stats, sparklines
test_database.py SQLite storage operations
test_analysis.py Pattern analysis, worst days
test_charts.py Chart rendering output
test_cli.py Command-line argument parsing
test_edge_cases.py Error handling, boundaries
test_real_data.py Tests using real Nightscout API responses
test_pump.py Pump commands, treatments, profile
test_coverage_gaps.py Error handling edge cases

# Supported AI Coding Agents

This skill is compatible with the SKILL.md standard and works with all major AI coding agents:

Learn more about the SKILL.md standard and how to use these skills with your preferred AI coding agent.