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).
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.
Metadata
Release files for vital-sync 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| vital_sync-0.1.4.tar.gz | 124.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vital_sync-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 170.7 kB
Release files / vital_sync-0.1.4.tar.gz
| Download URL | vital_sync-0.1.4.tar.gz |
|---|---|
| Size | 124.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2e3d0481b2ede2d91a83f026a2ba9585c2ab6cec68f736c62dd4ecced6e3000a
|
|
BLAKE2b-256 checksum How to use checksums |
6b54745fa15dd42efa6f357373bccc696127abe3a6d847bc8962296c7a5abff4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 28, 2026.
Transparency logRelease files / vital_sync-0.1.4-py3-none-any.whl
| Download URL | vital_sync-0.1.4-py3-none-any.whl |
|---|---|
| Size | 46.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cb89c3c14269ae61843d7da3df4421143e5aefce29e36f8e4698128daa49c098
|
|
BLAKE2b-256 checksum How to use checksums |
0fbe1005e384ed8cbe532c403c29af58f2544a043b0b4aec2a4030af78757227
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 28, 2026.
Transparency log