Skip to content

Releases: soma-intelligence/open-health-sync

Open Health Sync v0.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 06:24
ca37b22

Open Health Sync v0.1.0

From two sources to thirteen, and from one output format to five. Everything that landed on
main since v0.0.2 ships here: eleven new connectors, FHIR R4 and Open mHealth output, CSV and
Parquet exports, outgoing webhooks, background sync with per-source freshness, compression of
the largest table, a personal mode with ready-made recipes, a read-only admin console, a hosted
connection page, erasure of one provider's data when a user disconnects it, a Helm chart for Kubernetes, an
audit log, consent per source and category, a complete user archive, a merged view across sources, and client SDKs for Kotlin, Swift, React Native and Flutter. Still
an early preview: APIs, configuration and schema may change in any 0.x release, so pin the
version you run.

Install

Container image (linux/amd64, linux/arm64):

docker pull ghcr.io/soma-intelligence/open-health-sync:0.1.0

The image is tagged 0.1.0 and edge. There is no latest tag while the version is 0.x.
Binaries for Linux and macOS on amd64 and arm64 are attached below, with checksums.txt
(SHA-256). The quickstart
runs it with Docker Compose, Render, Fly.io or Railway host it for you, and the
Helm chart runs it on Kubernetes.

What's new

  • A merged view across sources. When a ring and a watch record the same night, or a phone
    and a watch the same steps, reads return the best ranked source's record only, so totals and
    daily summaries count nothing twice. The order is set per user and metric with
    GET/PUT /v1/users/{id}/source-priorities; every raw record stays stored, and view=all
    returns all of them. It applies to the API, daily summaries, FHIR (including $everything),
    Open mHealth, exports and the MCP tools.
    docs/api.md
  • Audit log. Every authenticated request, every ohs admin key command and every
    completed erasure is recorded (who, what, which user, status; never a value or a secret),
    append only and kept after a user's erasure. Read it with GET /v1/audit; it is pruned after
    OHS_AUDIT_RETENTION_DAYS (default 365). docs/audit-log.md
  • OpenTelemetry traces. Off by default; set OTEL_EXPORTER_OTLP_ENDPOINT to export spans
    over OTLP (HTTP or gRPC) for API requests, pull and processing jobs, webhook deliveries and
    their database queries. Spans never hold a health value or a secret.
    docs/observability.md
  • Try it without a wearable. ohs seed --demo loads 90 days of synthetic data from six
    overlapping sources and prints a demo API key, so the API, the merged view, FHIR and exports
    can be tried before any provider is connected.
    docs/demo.md
  • Consent per source and category. PUT /v1/users/{id}/consents/{provider} records which
    categories (activity, heart, sleep, location and more) a user granted, DELETE revokes them,
    and every change is kept in a history. Records of a category not granted are never stored,
    revoking deletes what was stored, and consent.granted and consent.revoked webhooks fire. OHS_CONSENT_REQUIRED=true stores nothing from a source until
    consent is recorded. docs/consent.md
  • Complete user archive. GET /v1/users/{id}/archive streams everything stored for one
    user as one zip (records as NDJSON, a FHIR Bundle, Open mHealth points, every raw payload),
    for data portability requests.
    docs/exports.md
  • Eleven new sources. Oura, WHOOP, Strava, Polar, Fitbit (Google Health API), Suunto,
    Ultrahuman, intervals.icu, Dexcom (CGM glucose) and OMRON (blood pressure) are pulled from
    their cloud APIs with OAuth, with webhooks where the provider has them. Health Connect gets an
    upload endpoint for your Android app, like Apple Health has for iOS. Provider deletions are
    honored: a record deleted upstream is removed and never written again.
  • Health app export import. ohs import apple-health export.zip loads years of Apple
    Health history without an iOS app, in constant memory, and a re-run uploads nothing twice.
  • FHIR R4. GET /v1/users/{id}/fhir/Observation serves samples, blood pressure panels,
    sleep, workouts and daily summaries as FHIR R4 Observations, coded with LOINC and UCUM, with
    the user as a Patient, the Devices the data came from and a Provenance for each Observation.
    /fhir/Patient/{id}/$everything returns it all in one Bundle and /fhir/metadata a
    CapabilityStatement. The official HL7 validator checks the mapping in CI. docs/fhir.md
  • Open mHealth. GET /v1/users/{id}/omh/data-points, every mapping checked against the
    official schemas in the unit tests. docs/open-mhealth.md
  • CSV and Parquet exports. GET /v1/users/{id}/exports/{dataset} streams a user's
    samples, sleep, workouts, nutrition or daily summaries as one file, for notebooks and BI
    tools. docs/exports.md
  • Outgoing webhooks. data.written, data.deleted, user.deleted and
    connection.needs_reauth, signed per Standard Webhooks and retried for about 28 hours.
    Payloads name the user, provider and days, never a health value. Each delivery keeps its
    attempts, can be replayed, and POST /v1/webhooks/{id}/test sends a sample of any event type.
    docs/webhooks.md
  • Background sync. Webhooks first, with backstop pulls that adapt to how often a provider
    notifies, silent subscriptions renewed, and notification pulls served before backfills.
    GET /v1/users/{id}/freshness says how up to date each source of a user is, and why not.
  • Personal mode and recipes. ohs admin personal setup readies a one person install and
    prints its env file. recipes/ holds eight single file Python tools with no dependency (sleep
    report, heart rate and HRV trend, source comparison, weekly digest, HTML dashboard, full
    export, read-only AI token, account connection).
    docs/recipes
  • RR intervals and HRV. GET /v1/users/{id}/rr-intervals serves the stored beat-to-beat
    intervals, and GET /v1/users/{id}/hrv the RMSSD, SDNN, pNN50 and mean heart rate of each
    heartbeat series, with MCP tools for both.
    docs/hrv.md
  • Menstrual cycles. GET /v1/users/{id}/menstrual-cycles and the get_menstrual_cycles MCP
    tool derive cycles from the recorded menstrual flow of Apple Health and Health Connect. They
    restate what was recorded and predict nothing.
    docs/menstrual-cycles.md
  • Time tags. /v1/users/{id}/tags stores intervals that give context to a user's data
    (illness, injury, travel and more), with tag.* webhook events and the get_tags MCP tool.
    Context only: nothing is computed from them.
    docs/time-tags.md
  • Admin console. Set OHS_CONSOLE=true and open /console with a tenant API key: users,
    connections, freshness and webhook deliveries on one read-only page, failing sources in red.
    docs/console.md
  • Erase a provider's data on disconnect.
    DELETE /v1/users/{id}/connections/{provider}?delete_data=true disconnects and erases every
    record, raw file and job of that user and provider in the background, and
    DELETE /v1/users/{id}/data/{provider} does the same for Apple Health or Health Connect. The
    data.erased webhook announces the end. A plain disconnect keeps the data, as before.
  • Sync history and connection health. GET /v1/users/{id}/sync-runs shows what each pull
    did and why it failed, POST /v1/users/{id}/connections/{provider}/sync pulls now, and every
    connection says whether it is healthy and what to do (reconnect or wait). The
    connection.broken and connection.restored webhooks tell your backend when that changes.
    docs/sync-health.md
  • Hosted connection page. POST /v1/users/{id}/connect-sessions returns a link to a page
    your instance serves: it lists the providers, shows which ones the user already connected and
    starts the consent, so your backend needs no OAuth screens of its own.
    docs/connect-page.md
  • Backup and restore. scripts/backup.sh writes the database and raw store of a compose
    install to one archive, and scripts/restore.sh brings it back; CI runs the full cycle.
    [docs/backup-and-restore.md]...
Read more

Open Health Sync v0.0.2

Choose a tag to compare

@github-actions github-actions released this 11 Oct 17:24
c8fdf12

Open Health Sync v0.0.2

A usability release for people who run and integrate Open Health Sync. No change to the data
model or the database schema. Everything in the v0.0.1 release notes
about the early preview still applies: APIs, configuration and schema may change in any 0.x
release, so pin the version you run.

Install

Container image (linux/amd64, linux/arm64):

docker pull ghcr.io/soma-intelligence/open-health-sync:0.0.2

The image is tagged 0.0.2 and edge. There is no latest tag while the version is 0.x.
Binaries for Linux and macOS on amd64 and arm64 are attached below, with checksums.txt
(SHA-256).

What changed

  • Help in the binary. ohs help, ohs help <command>, -h and --help on every command,
    and ohs --version. A command line error exits 2.
  • Clearer errors. A refused ohs mcp handshake says whether the key, the scope or the URL
    is wrong. A 403 names the credential the endpoint takes. A wrong method on a known path
    answers 405 with an Allow header instead of 404. Database, port and raw store failures name
    the variable to check.
  • Raw store check at start. ohs serve and ohs doctor write and delete a probe object, so
    an unwritable volume stops the start with a hint instead of failing every upload.
  • Request ids. Every API response carries X-Request-Id, repeated in problem bodies and on
    the log lines about the request.
  • GET /openapi.yaml serves the description of the running version, for Postman, Swagger
    UI or Redoc.
  • Key rotation without SQL. ohs admin tenant list, ohs admin key create, key list and
    key revoke.
  • Logs write durations as text (24h0m0s), and the start line names the version.
  • MCP. Server instructions steer agents to get_daily for trends. The image carries the
    io.modelcontextprotocol.server.name label and the repository has a server.json for the
    official MCP registry.
  • Docs. A providers page with supported and planned sources, upgrade, backup, restore and
    secret rotation in the self-hosting guide, Claude Desktop and Claude Code setup in the MCP
    guide, and a README with real screenshots.

Upgrade notes

Set OHS_VERSION=0.0.2 in your .env, then pull and recreate (the
self-hosting guide
has the full steps, including a backup first). Migrations apply on start as before.

Two settings are now validated when the process starts, so a configuration that 0.0.1
accepted can be refused. Check them before you upgrade:

  • OHS_PUBLIC_URL must be an absolute http or https URL with no query and no fragment.
    localhost:8080 (no scheme) and https://example.com/?x=1 are refused. Before, a bad value
    only broke OAuth callbacks later.
  • OHS_LOG_LEVEL must be a known level. An unknown value is refused instead of being
    ignored.

ohs migrate and ohs admin do not read these two settings, so they keep working while you fix
the file. ohs doctor reports both.

Also new at start: the raw store must accept writes. If the container user cannot write the
raw folder or bucket, ohs serve stops and prints the fix (typically a chown of the volume
to uid 65532).

Log lines now show durations as text rather than nanoseconds. If you parse them, update the
parser.

Known limitations

Unchanged from v0.0.1: crash recovery takes 10 minutes, one region per instance, no FHIR or
webhooks or SDKs yet, ECG and heartbeat series are stored but not served, /metrics is
unauthenticated, and the Withings steps are not verified with a real account.

Security

Report vulnerabilities privately through
GitHub Private Vulnerability Reporting.
See SECURITY.md.

Open Health Sync v0.0.1

Choose a tag to compare

@github-actions github-actions released this 11 Oct 16:34

Open Health Sync v0.0.1

The first public release of Open Health Sync, a self-hostable health data aggregator. It
collects data from Apple Health and Withings, keeps every raw payload, normalizes it into one
canonical model with one set of units, and serves it over a REST API and a read-only MCP
server. One Go binary plus Postgres with TimescaleDB.

This is an early preview. APIs, configuration and the database schema may change in any
0.x release. Pin the version you run and read the changelog before you upgrade.

Install

Container image (linux/amd64, linux/arm64):

docker pull ghcr.io/soma-intelligence/open-health-sync:0.0.1

The image is tagged 0.0.1 and edge (the newest final release, never a pre-release such as 0.1.0-rc.1). There is no latest tag while the
version is 0.x: pin a version. The compose file in deploy/ runs this image; see
self-hosting.

Binaries for Linux and macOS on amd64 and arm64 are attached below, with checksums.txt
(SHA-256). Check a download with sha256sum -c checksums.txt --ignore-missing.

What works

  • Apple Health. An iOS app (yours; no SDK ships yet) uploads HealthKit data as gzip NDJSON
    parts; quantities, categories, sleep, workouts with routes and nutrition land in the canonical
    model, and ECG and heartbeat series are stored.
  • Withings. Bring your own Withings developer app. Users connect over OAuth;
    measurements, activity, sleep, workouts and ECG are pulled on a schedule and on push
    notifications.
  • One model, one set of units. Deduplication, source and device attribution, validation,
    and daily summaries per local day.
  • Raw payloads as the source of truth, in a local folder or any S3 compatible store.
  • Multi-tenant API with tenant keys and scoped user tokens, described by
    api/openapi.yaml.
  • Read-only MCP server so an AI agent can read a user's data.
  • Hard deletion of a user's raw files and rows on request.
  • Crash-safe pipeline with retries, parking, an orphan scanner and a drainer.
  • Runs small. A Raspberry Pi 5 with 4 GB runs the full stack.

Known limitations

  • Crash recovery takes 10 minutes. After a hard kill (kill -9, power loss), a job that
    was in flight is claimed again only after its 10 minute visibility timeout.
  • Single region. One database and one raw store per instance; no multi-region replication.
  • Not yet available: FHIR import or export, outbound webhooks, mobile SDKs.
  • ECG and heartbeat series are stored but not served yet. No REST route or MCP tool reads
    them in this release.
  • Not verified on real devices yet: the Withings developer portal steps in the connector
    guide, and the units of physical effort and VO2 max.
  • /metrics is unauthenticated. It exposes instance wide counters only, but block it at
    your reverse proxy or set OHS_METRICS=false.

The operating notes list the rest of what an operator
should plan around.

Roadmap

  • More connectors for wearables and health platforms.
  • More outputs: standard formats such as FHIR, and webhooks when new data lands.
  • Client SDKs for mobile apps and servers.

Ideas and connector requests are welcome as GitHub issues.

Security

Report vulnerabilities privately through
GitHub Private Vulnerability Reporting.
See SECURITY.md.