Repository navigation
Releases: soma-intelligence/open-health-sync
Release list
Open Health Sync v0.1.0
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.0The 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, andview=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 adminkey 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 withGET /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_ENDPOINTto 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 --demoloads 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,DELETErevokes them,
and every change is kept in a history. Records of a category not granted are never stored,
revoking deletes what was stored, andconsent.grantedandconsent.revokedwebhooks fire.OHS_CONSENT_REQUIRED=truestores nothing from a source until
consent is recorded. docs/consent.md - Complete user archive.
GET /v1/users/{id}/archivestreams 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.ziploads 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/Observationserves 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}/$everythingreturns it all in one Bundle and/fhir/metadataa
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.deletedand
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, andPOST /v1/webhooks/{id}/testsends 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}/freshnesssays how up to date each source of a user is, and why not. - Personal mode and recipes.
ohs admin personal setupreadies 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-intervalsserves the stored beat-to-beat
intervals, andGET /v1/users/{id}/hrvthe 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-cyclesand theget_menstrual_cyclesMCP
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}/tagsstores intervals that give context to a user's data
(illness, injury, travel and more), withtag.*webhook events and theget_tagsMCP tool.
Context only: nothing is computed from them.
docs/time-tags.md - Admin console. Set
OHS_CONSOLE=trueand open/consolewith 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=truedisconnects 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.erasedwebhook announces the end. A plain disconnect keeps the data, as before. - Sync history and connection health.
GET /v1/users/{id}/sync-runsshows what each pull
did and why it failed,POST /v1/users/{id}/connections/{provider}/syncpulls now, and every
connection says whether it is healthy and what to do (reconnect or wait). The
connection.brokenandconnection.restoredwebhooks tell your backend when that changes.
docs/sync-health.md - Hosted connection page.
POST /v1/users/{id}/connect-sessionsreturns 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.shwrites the database and raw store of a compose
install to one archive, andscripts/restore.shbrings it back; CI runs the full cycle.
[docs/backup-and-restore.md]...
Open Health Sync v0.0.2
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.2The 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>,-hand--helpon every command,
andohs --version. A command line error exits 2. - Clearer errors. A refused
ohs mcphandshake 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 anAllowheader instead of 404. Database, port and raw store failures name
the variable to check. - Raw store check at start.
ohs serveandohs doctorwrite 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.yamlserves 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 listand
key revoke. - Logs write durations as text (
24h0m0s), and the start line names the version. - MCP. Server instructions steer agents to
get_dailyfor trends. The image carries the
io.modelcontextprotocol.server.namelabel and the repository has aserver.jsonfor 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_URLmust be an absolutehttporhttpsURL with no query and no fragment.
localhost:8080(no scheme) andhttps://example.com/?x=1are refused. Before, a bad value
only broke OAuth callbacks later.OHS_LOG_LEVELmust 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
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.1The 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. /metricsis unauthenticated. It exposes instance wide counters only, but block it at
your reverse proxy or setOHS_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.