Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.synheart.ai/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Most users open a Synheart-powered app with months or years of existing wearable history sitting in the platform health store. The longitudinal SRM is a great fit for that data — but it needs to be seeded from history, not just streamed live. The Health backfill sinks read historical sleep nights + overnight HR/HRV from the platform health store, aggregate per local wake-day, and push the SRM’s five primary dimensions per night via the runtime’s wearable_daily_values ingest path (secondary dimensions are populated when the underlying samples are present). After a one-time backfill, the user’s “your normal” baselines reflect their last N days of real sleep / recovery — instead of warming from zero over the first week of app use.
PlatformSourceSDKTime range
AndroidHealth Connect (live API)HealthConnectRuntimeSinkWhatever Health Connect retained — typically ~30 days HR, 1–2 years sleep
iOSHealthKit (live API)HealthKitRuntimeSinkWhatever HealthKit retained — effectively user-owned, often years
iOS (alternate)export.zip importAppleHealthRuntimeSink (Flutter / Swift)Years; full Apple Health archive
All three push the same five dimensions per wake-day at confidence: 0.85, fidelity: 1:
  • sleep_need (total asleep minutes × 60, in seconds)
  • deep_sleep_min
  • rem_sleep_min
  • hrv_rmssd
  • resting_hr

Android — Health Connect

import ai.synheart.core.backfill.HealthConnectRuntimeSink
import ai.synheart.wear.adapters.HealthConnectAdapter

// The HealthHistoryReader contract lives in synheart-wear-kotlin;
// HealthConnectAdapter implements it.
val reader = HealthConnectAdapter(context)
val sink = HealthConnectRuntimeSink(
    reader = reader,
    bridge = coreRuntime,
)

// Call after the user has granted Health Connect read permissions
// (and ConsentType.BIOSIGNALS on the Synheart side). Heavy — first
// run can take 10+ seconds for a year of HR samples on cold cache.
val result = sink.backfill(daysBack = 365)
println("seeded ${result.daysIngested} days, ${result.dimensionsPushed} dimensions in ${result.durationMs}ms")
HealthConnectBackfillResult carries daysIngested, dimensionsPushed, requestedDaysBack, skipped, skipReason, durationMs. The skipped: true path covers “Health Connect not available on this device”, “daysBack must be positive”, etc.

iOS — HealthKit

import SynheartCore
import SynheartWear

// HealthKitHistoryReader implements HealthHistoryReader; owns its own HKHealthStore.
let reader = HealthKitHistoryReader()
let sink = HealthKitRuntimeSink(
    reader: reader,
    pushDaily: { dimension, dayIndex, value, confidence, fidelity in
        coreRuntime.pushWearableDailyValue(
            dimension: dimension,
            dayIndex: dayIndex,
            value: value,
            confidence: confidence,
            fidelity: fidelity
        )
    },
    triggerRecompute: {
        coreRuntime.triggerWearableRecompute(triggerType: 0, asOfDay: 0)
    }
)

// Call after HealthKit authorization + ConsentType.biosignals granted.
let result = try await sink.backfill(daysBack: 365)
print("seeded \(result.daysIngested) days, \(result.dimensionsPushed) dims in \(result.durationMs)ms")

HealthHistoryReader contract

Both platforms consume the same wear-side reader contract — that’s what lets the core sink stay HealthKit / HealthConnect agnostic. Two methods, bucketed by local wake-day:
fetchSleepNights(start, end, zone) → Map<LocalDate, SleepNightSummary>
fetchOvernightPhysiology(start, end, zone) → Map<LocalDate, OvernightPhysiologySummary>
SleepNightSummary carries totalAsleepMinutes, optional deepMinutes / remMinutes. OvernightPhysiologySummary carries optional hrvRmssdMs / restingHrBpm averaged over the sleep window. Both are nullable because real sources can lack stage breakdowns or in-sleep HRV samples — the runtime accepts nulls and degrades the SRM gracefully.

When NOT to call it

  • Before the user has granted the platform health permission (sink returns skipped: true)
  • Before ConsentType.BIOSIGNALS is granted on the Synheart side — the runtime will accept the writes but the user hasn’t consented to longitudinal storage of derived dimensions
  • Periodically (don’t poll) — the runtime ingest is idempotent per (day_index, dimension), but pulling from the platform health store every app launch is wasteful. Run once on first launch + after a long backgrounded gap.

Cross-language

  • Flutter: lib/src/backfill/{health_connect_runtime_sink,apple_health_runtime_sink,apple_xml_backfill_sink}.dart
  • Kotlin: synheart-core/src/main/kotlin/ai/synheart/core/backfill/HealthConnectRuntimeSink.kt
  • Swift: SynheartCore/Modules/Backfill/HealthKitRuntimeSink.swift
Apple Health XML backfill (export.zip import) is iOS-only by design; Android users get Health Connect’s live API instead. Kotlin intentionally has no equivalent — the native backfill symbols are unbound on Android.
  • Baselines — reads the SRM these sinks seed
  • Scoring models — what the runtime computes once baselines are warm
  • synheart-wear — owns the HealthHistoryReader contract + platform-specific adapter