The session SDK decouples the engine from data sources via two abstractions. This page covers the contracts, the bundled implementations, and the integration semantics with the engine.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.
BiosignalProvider
The HR/HRV/RR source. Stream-based: the engine subscribes once per session and unsubscribes on stop.Contract (Dart)
interface BiosignalProvider) and Swift (protocol BiosignalProvider) mirror this. name is a debug identifier (not displayed to users). isAvailable is a self-report — the engine still subscribes when false if the host explicitly opts in.
BiosignalSample
timestampMs (epoch ms), bpm (instantaneous heart rate). Optional: rrIntervalMs (single inter-beat interval), accelerometer (tri-axis, present on watch builds), spo2 (when the wearable reports it).
Engine consumption
LiveSessionEngine subscribes on startSession and pushes each sample into a fixed-capacity ring buffer sized at windowSec. There is no provider-side rate limiting; the engine drops oldest samples on overflow.
The accelerometer and SpO₂ fields are not consumed by LiveSessionEngine today — they are forwarded only when the engine emits BiosignalFrame events (raw streaming opt-in). The watch companions populate them at source.
Bundled implementations
| Implementation | Package | Notes |
|---|---|---|
MockBiosignalProvider | all three | Deterministic with seed; safe for CI. |
WatchBiosignalProvider | Dart | Bridges through SessionChannel. isAvailable = true optimistically. |
WearBiosignalProvider | Kotlin | Reads from synheart-wear adapters. |
HealthConnectBiosignalProvider | Kotlin | Reads from Health Connect on the phone. |
| HealthKit provider | Swift | Under SynheartSessionHealthKit. |
| Wear (watchOS) provider | Swift | Under SynheartSessionWear. |
- BLE HRM: hosts can build a
BiosignalProvideroversynheart-wear’s BLE HRM client. - Custom mocks for replay tests.
BehaviorProvider
The behavioral signal source. Pull-based: the engine callscurrentSnapshot() at each frame tick.
Contract
null return means “no snapshot available right now”; the engine omits the behavior field on that frame.
BehaviorSnapshot
synheart_behavior’s BehaviorStats so the two SDKs share a contract without import dependencies. JSON serialisation uses snake_case.
When emitted on a SessionFrame.behavior field, only the non-null fields appear (the toJson strips nulls except appSwitchesPerMinute and timestamp).
Bundled implementations
| Implementation | Package | Notes |
|---|---|---|
MockBehaviorProvider | all three | Returns stable mid-range values for tests. |
synheart_behavior-backed provider | Dart, Kotlin, Swift | Apps wire BehaviorProvider to a synheart_behavior BehaviorEngine; the snapshots come from the active behavior session. |
synheart-core (which depends on both packages).
Integration with the engine
LiveSessionEnginestill emitsSessionStarted, frames withsample_count = 0,hr_mean_bpm = 0.0, no behavior, and a finalSessionSummary.- This is the deterministic-no-data path useful for testing the framing logic itself.
Provider state machine (informal)
stopStreaming() being called multiple times. They must stop emitting after stopStreaming() returns; samples emitted after the engine has unsubscribed are dropped silently.
Watch provider specifics
WatchBiosignalProvider:
BiosignalFrameevents → emit eachBiosignalSampledirectly to the controller.SessionFrameevents → synthesise one sample frommetrics.hr_mean_bpmwithrrIntervalMs = 60000.0 / bpm.SessionStarted,SessionSummary,SessionError→ ignored (lifecycle, not biosignal data).
Authoring a provider
A customBiosignalProvider should:
- Allocate any sensor resources (BLE GATT subscribe, HK authorization, etc.) on
startStreaming(). - Release them on
stopStreaming(). - Emit samples on the broadcast
Stream<BiosignalSample>returned fromstartStreaming(). - Not block the calling thread — the engine subscribes synchronously.
BehaviorProvider should:
- Maintain its own internal accumulators.
- Return a fresh
BehaviorSnapshoton eachcurrentSnapshot()call (ornullwhen no recent activity). - Use real
DateTime.now().millisecondsSinceEpochfor the snapshot timestamp.
Related
- Lifecycle — when the engine subscribes/unsubscribes.
- Watch Protocol —
BiosignalBatchandBiosignalSampleon the wire.