← Back to project
● Shipped P2 Size M Vertical app

health-coach — Architecture

System diagrams, data flow, weighting tiers, smart-cap logic, Telegram delivery.

High-level data flow

┌─────────────────────────┐         ┌──────────────────────────┐
│ Garmin watch (anh)      │ daily   │ garmin-sync GH Actions   │
│                         │ ─sync──▶│ workflow                 │
└─────────────────────────┘         │ pulls API → JSON commit  │
                                    └────────────┬─────────────┘
                                                 │ git push

                                    ┌──────────────────────────┐
                                    │ GitHub repo data lake    │
                                    │ marcng-study/garmin-sync │
                                    └────────────┬─────────────┘
                                                 │ git pull (every 30 min)

              ┌─────────────────────────────────────────────────┐
              │ GCP VM 34.21.163.141                            │
              │  ┌────────────────────────────────────────────┐ │
              │  │ Python pipeline                            │ │
              │  │  ├─ loader.py     → DataFrame              │ │
              │  │  ├─ stats.py      → baseline + anomaly     │ │
              │  │  ├─ correlation.py→ Tier 1 lag-1 priors    │ │
              │  │  ├─ weighting.py  → Tier 2 literature      │ │
              │  │  ├─ planner.py    → daily plan + smart cap │ │
              │  │  ├─ chart.py      → matplotlib PNG         │ │
              │  │  ├─ digest.py     → Haiku LLM (weekly)     │ │
              │  │  ├─ retro.py      → descriptive stats      │ │
              │  │  ├─ manual_log.py → Option C log loop      │ │
              │  │  └─ delivery.py   → Telegram + fallback    │ │
              │  └────────┬───────────────┬───────────────────┘ │
              │           │               │                     │
              │  ┌────────▼─────┐  ┌──────▼──────────────┐      │
              │  │ Haiku 4.5    │  │ Telegram bot API    │      │
              │  │ (weekly LLM) │  │ @marc_healthbot     │      │
              │  └──────────────┘  └──────────┬──────────┘      │
              │                               │                 │
              │  systemd user timers (linger):│                 │
              │   morning-ping (04:00 UTC = 11:00 VN)            │
              │   anomaly-check (01:00 UTC = 08:00 VN)           │
              │   fire-due (15 min)                              │
              │   weekly-digest (Sat 14:00 UTC = T7 21:00 VN)    │
              │   weekly-chart (Sat 14:05 UTC = T7 21:05 VN)     │
              │   log-prompt (Sat 14:30 UTC = T7 21:30 VN)       │
              │   garmin-pull (30 min)                           │
              │                              │                  │
              │  ┌──────────────────────────▼─────────────────┐ │
              │  │ Google Calendar API (OAuth, fire-due reads)│ │
              │  └────────────────────────────────────────────┘ │
              └──────────────────────────────┼──────────────────┘


                              ┌────────────────────────────┐
                              │ User devices               │
                              │ • iPhone Telegram          │
                              │ • iPad Telegram            │
                              │ • Mac Telegram             │
                              │ • Web telegram.org         │
                              └────────────────────────────┘

Goal-weighted action ranking (3 tiers)

Each action carries an expected_sleep_score_delta (positive or negative). Planner picks top-N for today, ranked by |delta|.

TierSourceWhen used
Tier 1Personal lag-1 correlation from anh’s data (n≥10,effect
Tier 2Sleep-science literature priors (caffeine half-life, screen-blue light, late workout)Cold start (current default)
Tier 3Haiku LLM gut estimateLast resort for actions with no data + no literature

Each priors row carries a citation (e.g. Drake et al. 2013, J Clin Sleep Med). Citations surface in nudge body, e.g. Goal: sleep ≥80. Expected impact: -8 score. (Drake et al. 2013).

Smart cap (no fatigue)

  • Normal day (no anomaly): ≤2 nudges/day.
  • Anomaly day (sleep score <60 / sleep <5h / RHR z≥1.5 / HRV z≤-1.5): ≤4 nudges, escalated.
  • Hard cap 5/day — never exceeded.
  • Pre-meeting breath is in addition to the daily cap (it’s reactive, not scheduled).

Morning-ping format (ADHD-friendly)

Multi-line Telegram with sections:

  1. Title — traffic light + headline (🟢 Ổn, 🟡 Recovery, 🔴 Đêm qua tệ)
  2. Sub — natural Vietnamese sentence with the key metric (“Sáng nay anh ngủ được 78 điểm — ổn nhé.”)
  3. Quick metrics inline — ⚡ sleep 78 · HRV 34 · RHR 55
  4. Weekly goal progress — 🎯 Tuần này: 2/7 đêm ≥80 điểm
  5. Today’s actions (max 2) — bullet list with expected impact
  6. Calendar context — 📅 N meeting căng trong 14h tới (if any)

Weekly digest format (Saturday 21:00 VN)

Compressed by Haiku system prompt: ≤2 insights, ≤25 words each, Vietnamese weekday (Thứ 5, Chủ nhật) instead of YYYY-MM-DD because ADHD users find calendar dates hard to recall.

📊 Tuần qua
💤 sleep avg X (Δ vs baseline)
❤️ RHR X · 💗 HRV X · 🏃 load X

💡 Top:
• Thứ X [metric] (z=X) — 1-sentence hypothesis + action
• Thứ X ... (only if second insight)

🎯 Tuần này: 1-sentence physical action.

Manual log loop (Option C)

  • Default — 0 prompts.
  • Anomaly day — prompt morning after with: cafe sau 14h / rượu / late dinner / phone bed.
  • Saturday batch (21:30) — recall the week.
  • Streak-aware — 3 consecutive no-replies → pause 7 days.
  • Reply parsing — Haiku NLP for natural-language replies (“2 ly cafe sáng” → caffeine: 2).

After ≥10 manual log replies, correlation.compute_personal_priors() produces Tier 1 priors specific to anh, overriding Tier 2 literature defaults.

Calendar pre-meeting nudge

fire-due (every 15 min) calls calendar_reader.upcoming_stressful_events(window_min=10):

  • Reads next 10 minutes of Google Calendar primary calendar via OAuth.
  • “Stressful” heuristic: title matches keywords (review, interview, present, board, exec, 1on1, q[1-4] review, etc.) OR duration ≥60 min on a weekday.
  • If hit → fire 🫁 5min breath Telegram with event name + minutes-until.

Privacy boundaries

LayerWhat stays localWhat can leave
Garmin data lakeFull JSON (raw HR, GPS, sleep stages, activity GPS)Never sent to cloud LLM
LLM inputAggregate metrics: avg sleep score, HRV, RHR, anomaly flags + Vietnamese weekday
CalendarEvent title + duration (read-only OAuth)
TelegramFinal nudge text only
API keys~/.config/health-coach/* chmod 600Never logged