Skip to main content

Personal health data aggregation and analytics toolkit. Integrates Oura Ring, Hevy workouts, Renpho scale, and MyNetDiary.

Project description

vital-sync

Personal health data aggregation and analytics toolkit.

Integrates Oura Ring, Hevy workout app, Renpho scale, and MyNetDiary into a local cache with statistical analysis. Works standalone via CLI or as a context provider for LLM-based health assistants (Hermes, ChatGPT, Claude).

PyPI version Python 3.11+ License: MIT

Features

  • Oura Ring v2 API client — sleep periods, daily scores (sleep/readiness/activity), HRV, heart rate, SpO₂
  • Hevy workout API client — workout sync, exercise tracking, 1RM estimation, muscle group analysis
  • Statistics engine — rolling baselines, hybrid deviation detection (adaptive z-scores + absolute floors), Pearson correlations, circadian consistency
  • LLM context builders — pre-processed JSON output for morning check-ins and weekly trend reports
  • CSV import — Renpho body composition and MyNetDiary nutrition data (manual: export CSV from each app, then vital-sync-import)
  • Zero external dependencies — pure Python stdlib

Quick Start

pip install vital-sync

Set your API keys as environment variables:

export OURA_API_KEY="your-oura-personal-access-token"
export HEVY_API_KEY="your-hevy-api-key"  # requires Hevy Pro subscription

Or create a .env file in your working directory with the same variables.

Fetch your sleep data

from vital_sync.oura_client import pull_all

records = pull_all(days=7)
for date, data in sorted(records.items()):
    print(f"{date}: {data.get('sleep_duration_hours', '?'):.1f}h, score={data.get('sleep_score')}")

Analyse workout trends

from vital_sync.hevy_client import sync_workouts, workout_summary

workouts = sync_workouts()
summary = workout_summary(workouts, days=14)
print(f"Sessions: {summary['workouts']}, Volume: {summary['total_volume_kg']}kg")

Generate a morning check-in JSON

vital-sync-morning

Outputs a structured JSON object with today's sleep data, 7-day trends, recent workouts, and gap detection — ready for an LLM to interpret.

Generate a weekly health report JSON

vital-sync-weekly

Outputs comprehensive analysis: baselines vs previous week, correlations (e.g. training volume → sleep quality), circadian consistency, and detected deviations.

Architecture

vital_sync/
├── oura_client.py      # Oura Ring API v2
├── hevy_client.py      # Hevy workout API
├── analytics.py        # Statistics engine
├── morning_checkin.py  # Daily context builder
├── weekly_report.py    # Weekly trend report
├── pre_pull_check.py   # Backup + gap detection
├── import_csv.py       # Renpho/MyNetDiary CSV import
└── sleep_tags.py       # Nightly factor tracking

Data is stored as a local JSON cache at ~/.vital_sync/cache.json (configurable via VITAL_SYNC_CACHE env var).

Optional personal configuration is read from ~/.vital_sync/config.json (configurable via VITAL_SYNC_CONFIG). Copy config.example.json to that path and adjust it:

{
  "sleep_tags": {
    "early_wake": {
      "enabled": true,
      "before": "07:00"
    }
  }
}

Without this config, the automatic early wake sleep tag is disabled. Set enabled to false to turn it off again, or change before to whatever local wake-time cutoff you want.

Hermes Agent Integration

vital-sync is the health data backend for Hermes Agent but works with any LLM pipeline. The morning_checkin and weekly_report modules output structured JSON — Hermes cron jobs run them and inject the output as LLM context.

Setup

pip install vital-sync
export OURA_API_KEY="..." HEVY_API_KEY="..."
# Initialise the cache with a full pull
python -m vital_sync.pre_pull_check

Morning check-in (daily at 11:00)

Creates a Hermes cron job that runs vital-sync-morning, producing JSON with last night's sleep, 7-day trend, workout recaps, and gap detection. Hermes injects this into your morning health prompt:

# The script output (JSON) becomes LLM context for the morning check-in prompt
hermes cronjob create \
  --schedule "0 11 * * *" \
  --name "morning-health-checkin" \
  --script "$(which vital-sync-morning)" \
  --no-agent  # raw script output delivered as context

Weekly report (Sunday at 20:00)

hermes cronjob create \
  --schedule "0 20 * * 0" \
  --name "weekly-health-report" \
  --script "$(which vital-sync-weekly)" \
  --no-agent

Daily data pull (10:00)

Runs the backup + gap check, pulls fresh Oura data, syncs Hevy workouts, and merges into cache:

# Create a wrapper script that runs daily pull + merge
cat > ~/.vital_sync/pull.sh << 'EOF'
#!/bin/bash
source ~/.hermes/.env
set -e
python -m vital_sync.pre_pull_check
python -c "
from vital_sync.oura_client import pull_all
from vital_sync.hevy_client import sync_workouts
from vital_sync.analytics import load_cache, save_cache, merge_hevy_into_records
import os
cache = os.environ.get('VITAL_SYNC_CACHE', os.path.expanduser('~/.vital_sync/cache.json'))
records = load_cache(cache)
new_data = pull_all(days=2)
# Merge Oura into records
from datetime import date
from vital_sync.analytics import DailyRecord
for day_str, data in sorted(new_data.items()):
    r = DailyRecord(date=date.fromisoformat(day_str))
    for k, v in data.items():
        if k != 'date' and v is not None:
            setattr(r, k, v)
    replaced = False
    for i, existing in enumerate(records):
        if existing.date.isoformat() == day_str:
            r.sources = list(set(getattr(existing, 'sources', []) + ['oura']))
            for field in ['mood','notes','sleep_tags','calories_in','protein_g','body_fat_pct','weight_kg','hevy_workouts','hevy_total_volume_kg']:
                if getattr(existing, field, None) is not None:
                    setattr(r, field, getattr(existing, field))
            records[i] = r
            replaced = True
            break
    if not replaced:
        records.append(r)
workouts = sync_workouts()
records = merge_hevy_into_records(workouts, records)
records.sort(key=lambda r: r.date)
save_cache(records, cache)
print(f'Cache updated: {len(records)} records')
"
EOF
chmod +x ~/.vital_sync/pull.sh

hermes cronjob create \
  --schedule "0 10 * * *" \
  --name "health-data-pull" \
  --script ~/.vital_sync/pull.sh \
  --no-agent

Environment variables

Variable Default Description
OURA_API_KEY Oura Personal Access Token
HEVY_API_KEY Hevy API key
VITAL_SYNC_CACHE ~/.vital_sync/cache.json Cache file path
VITAL_SYNC_DATA_DIR ~/.vital_sync/ Data directory
VITAL_SYNC_SLEEP_TAGS ~/.vital_sync/sleep_tags.json Sleep tags file
VITAL_SYNC_CONFIG ~/.vital_sync/config.json Personal config file

Cache Schema

{
  "date": "2026-04-27",
  "sleep_score": 79.0,
  "readiness_score": 80.0,
  "sleep_duration_hours": 7.41,
  "sleep_efficiency": 88.0,
  "deep_sleep_min": 123.0,
  "rem_sleep_min": 82.5,
  "avg_hr": 60.12,
  "lowest_hr": 54.0,
  "hrv_ms": 32.0,
  "steps": 8500,
  "bedtime": "23:42:29",
  "wake_time": "08:06:17",
  "hevy_workouts": 1,
  "hevy_total_volume_kg": 4520.0,
  "hevy_muscle_groups": ["chest", "triceps", "shoulders"],
  "sources": ["oura", "hevy"]
}

Development

git clone https://github.com/mishmishb/vital-sync.git
cd vital-sync
pip install -e ".[dev]"
pytest

License

MIT — see LICENSE.

Author

Built by mishmishb as part of a personal health analytics pipeline. Contributions welcome.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vital_sync-0.1.4.tar.gz (124.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vital_sync-0.1.4-py3-none-any.whl (46.0 kB view details)

Uploaded Python 3

File details

Details for the file vital_sync-0.1.4.tar.gz.

File metadata

  • Download URL: vital_sync-0.1.4.tar.gz
  • Upload date:
  • Size: 124.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for vital_sync-0.1.4.tar.gz
Algorithm Hash digest
SHA256 2e3d0481b2ede2d91a83f026a2ba9585c2ab6cec68f736c62dd4ecced6e3000a
MD5 548a635fefd1bd88e61aae1651fba968
BLAKE2b-256 6b54745fa15dd42efa6f357373bccc696127abe3a6d847bc8962296c7a5abff4

See more details on using hashes here.

Provenance

The following attestation bundles were made for vital_sync-0.1.4.tar.gz:

Publisher: release.yml on mishmishb/vital-sync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file vital_sync-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: vital_sync-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 46.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for vital_sync-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 cb89c3c14269ae61843d7da3df4421143e5aefce29e36f8e4698128daa49c098
MD5 98d7c24039f5cbf9222a65b8cafba5f3
BLAKE2b-256 0fbe1005e384ed8cbe532c403c29af58f2544a043b0b4aec2a4030af78757227

See more details on using hashes here.

Provenance

The following attestation bundles were made for vital_sync-0.1.4-py3-none-any.whl:

Publisher: release.yml on mishmishb/vital-sync

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page