Files
helios/docs/superpowers/specs/2026-08-18-helios-design.md
marcuspaico cf5fd5a552 docs: Helios design spec
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-17 13:45:56 -07:00

6.3 KiB

Helios — design spec

2026-08-18 · status: approved pending Marcus's review

What

Helios is a self-hosted, MIT-licensed web app: a FOSS alternative to Illume Labs / Superpower. One Docker container per user (or household). The pitch: your health data lives on your server, and the AI runs on your key.

v1 features:

  • Connect wearables with the user's own credentials: Oura, Whoop, Fitbit (official APIs), Garmin (unofficial library, clearly labeled).
  • Upload lab PDFs → LLM extraction → user reviews/confirms → normalized biomarkers with units, reference ranges, and flags.
  • Log meals by photo or text → LLM macro estimate → editable card.
  • Grounded AI chat: tool-calls into the local DB, so only relevant data slices are sent to the LLM — never a full dump.
  • Daily brief generated at a user-chosen hour from the last 24 h + 30-day trends + flagged labs.
  • Dashboards: Today (brief + cards), Sleep, Training, Labs, Nutrition, Settings.

Non-goals for v1: multi-user SaaS, mobile app (planned fast-follow for HealthKit/Health Connect sync), Apple Health ingestion (needs the companion app), medical advice claims of any kind.

Architecture

API-first monolith. The web UI is a pure client of a typed REST API — that API is the contract a future mobile app reuses unchanged.

Web UI (Vite + React SPA)
  Today/brief · Chat · Sleep · Train · Labs · Nutrition · Settings
        │  typed REST (Zod-validated)
Server (Bun + Hono, one process)
  vendor pollers (in-process cron, per-token, with backfill)
  lab PDF → LLM extraction → review queue
  meal photo/text → LLM macro estimate
  chat orchestrator (typed tools over the DB)
  daily brief generator (cron)
        │
SQLite (single file, WAL, Drizzle ORM) + uploads dir on one /data volume
LLM: any OpenAI-compatible endpoint — OpenRouter documented default,
     Ollama/LM Studio for zero-third-party operation

Stack rationale: TypeScript end to end (shared types between API, UI, and LLM tool schemas); SQLite over Postgres because a per-user instance needs one-file backup and zero ops (Open WebUI ships the same way); SPA over Next.js because an API-first self-hosted app gains nothing from SSR and the SPA keeps the mobile-later contract honest.

health-api (marcus/health-api) is reference only: its lab normalization (normalize.ts, units.ts) and schema shapes inform clean re-implementations. No code copied with Marcus-specific assumptions, no personal data, MIT throughout.

Data model (Drizzle/SQLite)

  • settings — LLM base URL + key, vendor tokens, brief hour. Secret columns encrypted (see Security).
  • daily_metrics — per-day, per-source rollups: steps, resting HR, HRV, active calories, readiness/recovery scores.
  • sleep_sessions — start/end, stage durations, scores; raw vendor JSON retained in a raw column.
  • workouts — type, duration, load metrics; raw JSON retained.
  • lab_draws + biomarkers — draw metadata; marker slug, value, normalized unit, reference range, flag.
  • meals — timestamp, photo path, macro estimate, LLM confidence, user-edited flag.
  • chat_threads + chat_messages.
  • briefs — generated markdown + input snapshot.
  • sync_state — per-connector cursor/watermark for incremental polls.

Connectors

Vendor Path User setup
Oura official API paste personal access token
Whoop official API register own free dev app, paste client id/secret (documented 5-min flow)
Fitbit official API same own-app flow as Whoop
Garmin unofficial garmin-connect lib username/password; labeled "may break without notice"

Pollers run on an in-process cron; first connect triggers historical backfill; sync_state makes polls incremental. Every connector normalizes into the tables above and keeps raw vendor JSON.

Labs: PDF upload → LLM extraction prompt → review/confirm screen — nothing writes to biomarkers until the user approves the parsed values. Trust in medical numbers requires the human check.

Nutrition: photo or free-text → LLM estimates items + macros (Open Food Facts as grounding where possible) → editable card; edits stored, model estimate retained for calibration.

AI layer

  • Provider abstraction: base URL + key + model id; anything OpenAI-compatible works. OpenRouter is the documented default; Ollama is the fully-local option.
  • Chat tools (typed, Zod-schema'd): query_sleep, query_metrics, query_workouts, query_labs, query_meals, log_meal. Tools return bounded slices (date-ranged, capped row counts).
  • Daily brief: cron at the user's hour; prompt assembles yesterday's data, 30-day trends, and out-of-range biomarkers; output stored in briefs and rendered on Today.
  • Honest privacy wording everywhere (README + Settings): chat context is sent to the LLM endpoint the user chose. Only Ollama-class local endpoints mean zero third parties.

Security

  • Auth: single password (argon2id), rate-limited login, httpOnly session cookie. Passkeys are a later upgrade.
  • Secrets at rest: AES-256-GCM column encryption; key generated at first boot into the /data volume (secret.key).
  • The SQLite file itself is not app-encrypted in v1 (bun:sqlite lacks SQLCipher); docs prescribe disk encryption + encrypted backups. Column crypto covers the credential-theft blast radius.
  • No telemetry, no update phone-home. Outbound traffic only: chosen LLM endpoint + connected vendor APIs.
  • CSP on the SPA; uploads served with safe content-type handling.

Testing

  • Vitest: unit normalization (units/ranges/marker slugs), connector transforms against recorded vendor fixtures, tool-schema round-trips.
  • API integration tests over an in-memory SQLite.
  • CI: Gitea Actions — typecheck + tests on push.

Deploy

  • One Dockerfile (bun base), docker compose up, single /data volume.
  • Caddy reverse-proxy recipe in docs.
  • Repo: git.rehbock.xyz/marcus/helios (public). GitHub mirror optional later for discoverability.

Milestones

  1. Scaffold: repo, CI, Docker, auth, settings (LLM + encryption plumbing).
  2. First connector (Oura) end to end: poll → normalize → Sleep/Today UI.
  3. Chat + tools over whatever data exists.
  4. Labs pipeline (upload → extract → review → dashboard).
  5. Meals + daily brief.
  6. Whoop/Fitbit/Garmin connectors; docs site; v0.1 announcement.