agentleFS
OpenMinisOpenMinis/MinisSkills/health-sleep-analysis/SKILL.md

health-sleep-analysis

Skill584 starsChanged 59 days agoMITView on GitHub

Analyze sleep health data from Apple HealthKit, including sleep stages (Deep/REM/Core/Awake), blood oxygen saturation (SpO2) during sleep, sleep duration trends, bedtime patterns, resting heart rate, and HRV. Use this skill whenever the user asks about sleep quality, sleep analysis, blood oxygen during sleep, sleep stages breakdown, sleep trends over time, heart rate, HRV, or any health data analysis involving sleep or cardiac health. Triggers on: "sleep analysis", "blood oxygen", "sleep quality", "deep sleep", "REM sleep", "resting heart rate", "HRV", "heart health", "sleep analysis", "sleep quality", "blood oxygen", "deep sleep", "resting heart rate", "heart rate variability" and similar in any language.

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 0 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Important: Always write raw data to /tmp/ first, not /var/minis/workspace/.

    line 57
  2. Very specific:

    When rendering SVG charts, scripts accept --lang <code>.

    line 124
  3. Very specific:

    Write data and outputs to /tmp/

    line 222
  4. Very specific:

    Run scripts with /tmp/ paths

    line 223

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Sleep Health Analysis Skill

Fetch sleep, SpO2, heart rate, and HRV data from Apple HealthKit, analyze it, and produce visual reports.

Language Rules (IMPORTANT)

Detect the language of the user's message and apply it consistently throughout the entire response:

  • Written analysis, conclusions, health advice -> user's language
  • Chart/image text labels, titles, axes, legend, insight cards, footer -> user's language
  • Code, script internals, variable names -> English (always)
  • When rendering SVG charts: pass a --lang argument to the rendering scripts; the scripts will localize all on-chart text automatically

Supported --lang values: zh (Chinese, default), en (English), ja (Japanese) If the user writes in another language, fall back to en for chart text and reply in their language.


Pre-built Scripts (call directly, no rewriting needed)

ScriptPurpose
sleep_report_data.pyExtract 7-day report JSON from raw HealthKit data
sleep_report_librsvg.pyRender 7-day weekly report card -> SVG + PNG via rsvg-convert
sleep_month_trend_librsvg.pyRender 30-day monthly trend -> SVG + PNG via rsvg-convert
sleep_halfyear.pyLong-term trend (30+ days), matplotlib charts
cardiac_analysis.pyCardiac health: RHR, HRV, SpO2, max HR

Quick Start

Step 1 - Install dependencies

apk add rsvg-convert font-noto-cjk -q
python3 -c "import matplotlib, numpy" 2>/dev/null || apk add py3-matplotlib py3-numpy -q

Step 2 - Fetch data (write to /tmp to avoid workspace sync delay)

# 7-day weekly report
apple-healthkit sleep --days 8 --compact -q > /tmp/sleep_raw.json
apple-healthkit blood-oxygen --days 8 --limit 2000 --compact -q > /tmp/spo2_raw.json

# 30-day monthly trend
apple-healthkit sleep --days 31 --compact -q > /tmp/sleep_raw.json
apple-healthkit blood-oxygen --days 31 --limit 5000 --compact -q > /tmp/spo2_raw.json

Important: Always write raw data to /tmp/ first, not /var/minis/workspace/. The workspace directory has an iSH to iOS sync delay that causes stale reads. Copy to the workspace only after scripts finish.

Step 3 - Run the appropriate script

# ── 7-day weekly report card ──────────────────────────────────
python3 /var/minis/skills/health-sleep-analysis/sleep_report_data.py \
    --sleep /tmp/sleep_raw.json --spo2 /tmp/spo2_raw.json \
    --out /tmp/sleep_report_7d.json

python3 /var/minis/skills/health-sleep-analysis/sleep_report_librsvg.py \
    --data /tmp/sleep_report_7d.json \
    --out-prefix /tmp/sleep_report_7d \
    --lang zh                          # zh | en | ja

# ── 30-day monthly trend ──────────────────────────────────────
python3 /var/minis/skills/health-sleep-analysis/sleep_month_trend_librsvg.py \
    --days 30 \
    --sleep /tmp/sleep_raw.json --spo2 /tmp/spo2_raw.json \
    --out-prefix /tmp/sleep_month_trend \
    --lang zh                          # zh | en | ja

# ── Half-year trend (26 weeks, weekly aggregation) ────────────
apple-healthkit sleep --days 186 --compact -q > /tmp/sleep_raw.json
apple-healthkit blood-oxygen --days 186 --limit 10000 --compact -q > /tmp/spo2_raw.json
python3 /var/minis/skills/health-sleep-analysis/sleep_longterm_librsvg.py \
    --period halfyear \
    --sleep /tmp/sleep_raw.json --spo2 /tmp/spo2_raw.json \
    --out-prefix /tmp/sleep_halfyear \
    --lang zh                          # zh | en | ja

# ── Full-year trend (12 months, monthly aggregation) ──────────
apple-healthkit sleep --days 366 --compact -q > /tmp/sleep_raw.json
apple-healthkit blood-oxygen --days 366 --limit 10000 --compact -q > /tmp/spo2_raw.json
python3 /var/minis/skills/health-sleep-analysis/sleep_longterm_librsvg.py \
    --period year \
    --sleep /tmp/sleep_raw.json --spo2 /tmp/spo2_raw.json \
    --out-prefix /tmp/sleep_year \
    --lang zh

# ── Long-term trend (matplotlib, 30+ days) ───────────────────
DAYS=185
cd /var/minis/workspace
apple-healthkit sleep --days $((DAYS+1)) --compact -q > sleep_raw.json
apple-healthkit blood-oxygen --days $((DAYS+1)) --limit 10000 --compact -q > spo2_raw.json
python3 /var/minis/skills/health-sleep-analysis/sleep_halfyear.py
# Output: sleep_halfyear.png (current directory)

# ── Cardiac health ────────────────────────────────────────────
apple-healthkit heart-rate --days 30 --limit 5000 --compact -q > /tmp/hr_raw.json
apple-healthkit hrv --days 30 --limit 500 --compact -q > /tmp/hrv_raw.json
python3 /var/minis/skills/health-sleep-analysis/cardiac_analysis.py

Step 4 - Copy output and display

cp /tmp/sleep_report_7d.png /var/minis/workspace/sleep_report_7d.png
cp /tmp/sleep_month_trend.png /var/minis/workspace/sleep_month_trend.png

Display in chat with Markdown inline images. Follow up with a written analysis in the user's language.


Localization Reference

When rendering SVG charts, scripts accept --lang <code>. The following strings must be translated for each language:

Keyzhenja
report_title_7dWeekly Sleep ReportWeekly Sleep ReportWeekly Sleep Report
report_title_30dMonthly Sleep TrendMonthly Sleep TrendMonthly Sleep Trend
subtitle_suffixnights recordednights recordednights recorded
avg_sleepAvg SleepAvg SleepAvg Sleep
good_daysGoal DaysGoal DaysGoal Days
deep_avgAvg DeepAvg DeepAvg Deep
min_spo2Min SpO2Min SpO2Min SpO2
stage_trendSleep Stage TrendSleep Stage TrendSleep Stage Trend
key_insightsKey InsightsKey InsightsKey Insights
daily_detailDaily DetailDaily DetailDaily Detail
deepDeepDeepDeep
coreCoreCoreCore
awakeAwakeAwakeAwake
bedtimeBedtimeBedtimeBedtime
min_o2Min O2Min O2Min O2
spo2_trend_titleNightly Min SpO2Nightly Min SpO2Nightly Min SpO2
weekly_summaryWeekly SummaryWeekly SummaryWeekly Summary
monthly_conclusionMonthly SummaryMonthly SummaryMonthly Summary
insight_durationIssue: Sleep Too ShortIssue: Sleep Too ShortIssue: Sleep Too Short
insight_bedtimeLate BedtimeLate BedtimeLate Bedtime
insight_spo2SpO2 avg OK, low dips notedSpO2 avg OK, low dips notedSpO2 avg OK, low dips noted
recommend_7hGoal 7hGoal 7hGoal 7h
data_sourceSource: Apple HealthKit · For reference onlySource: Apple HealthKit · For reference onlySource: Apple HealthKit · For reference only
generatedGeneratedGeneratedGenerated
sleep_intelligenceSleep IntelligenceSleep IntelligenceSleep Intelligence

Script Argument Reference

sleep_report_data.py

--sleep   path to sleep_raw.json   (default: /var/minis/workspace/sleep_raw.json)
--spo2    path to spo2_raw.json    (default: /var/minis/workspace/spo2_raw.json)
--out     output JSON path         (default: /var/minis/workspace/sleep_report_7d.json)

sleep_report_librsvg.py

--data        input JSON from sleep_report_data.py
--out-prefix  SVG/PNG output prefix   (default: /var/minis/workspace/sleep_report_7d_librsvg)
--lang        zh | en | ja            (default: zh)
--width       canvas width px         (default: 1280)
--height      canvas height px        (default: 1760)

sleep_month_trend_librsvg.py

--days        number of nights to include  (default: 30)
--sleep       path to sleep_raw.json
--spo2        path to spo2_raw.json
--out-prefix  SVG/PNG output prefix        (default: /var/minis/workspace/sleep_month_trend)
--lang        zh | en | ja                 (default: zh)

Data Processing

Night attribution rule

Records between 00:00 and 13:59 belong to the previous calendar day (same sleep session):

def sleep_date(dt):
    return (dt - timedelta(days=1)).date() if dt.hour < 14 else dt.date()

Sleep stage mapping

HealthKit valueStage
asleepDeepDeep
asleepREMREM
asleepCoreCore (light)
awakeAwake
inBedIn-bed (excluded)

HealthKit JSON field names

Raw samples use start / end, not startDate / endDate. Always check both:

ss = s.get('startDate') or s.get('start')
ee = s.get('endDate')   or s.get('end')

Workspace sync delay

Writing large files directly to /var/minis/workspace/ can result in iSH reading a stale cached version. Always:

  1. Write data and outputs to /tmp/
  2. Run scripts with /tmp/ paths
  3. cp final PNGs to /var/minis/workspace/ for display

Health Standards

Sleep duration

RangeRating
≥ 7h✅ Sufficient
6-7h⚠️ Slightly short
< 6h❌ Insufficient (adults need 7-9h)

Sleep stages

StageHealthy %Function
Deep≥ 13%Physical recovery, immunity, memory
REM20-25%Emotion regulation, cognition
Core45-55%Transitional

SpO2

RangeRating
≥ 95%✅ Normal
90-94%⚠️ Low, monitor
< 90%❌ Dangerous, seek medical advice

Frequent drops below 95% (>20% of readings) or any reading below 90% warrants evaluation for obstructive sleep apnea (OSA), especially with snoring, daytime sleepiness, or morning headaches.

Resting Heart Rate (RHR)

RangeRating
< 40 bpm❌ Too low, consult doctor
40-60 bpm✅ Excellent (athlete level)
60-80 bpm✅ Normal
80-100 bpm⚠️ Elevated
> 100 bpm❌ Tachycardia, consult doctor

Estimate RHR from raw heart rate data (lowest 25% of daily readings):

vals = sorted(by_day[date])
rhr = mean(vals[:max(1, len(vals)//4)])

HRV (SDNN)

RangeRating
≥ 50 ms✅ Good
30-50 ms⚠️ Fair
< 30 ms❌ Low autonomic function

Common Issues

Q: Only a few SpO2 readings? A: Add --limit, use 2000 for short-term, 10000 for long-term.

Q: Chinese/Japanese characters show as boxes? A: Run apk add font-noto-cjk first.

Q: Missing data for some nights? A: Apple Watch likely not worn; nights with < 1h total are auto-filtered.

Q: Chart still shows stale data after re-running? A: Write outputs to /tmp/ and use --sleep /tmp/... --spo2 /tmp/... arguments. Copy PNG to the workspace only for display.

Q: 30-day chart shows only 6-7 bars? A: The workspace JSON is stale. Fetch fresh data to /tmp/ and pass /tmp/ paths explicitly to the script.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

Reviews can't be read right now.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.