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

The Synheart Core Flutter SDK provides a unified API for collecting HSI-compatible data, processing human state on-device, and generating focus/emotion signals in Flutter applications. Key Features:
  • Cross-platform support (iOS + Android)
  • On-device HSI Runtime
  • Real-time state updates
  • Modular design (enable only what you need)
  • Privacy-first architecture

Installation

Add to your pubspec.yaml:
dependencies:
  synheart_core: ^0.0.4
Install dependencies:
flutter pub get

Platform Configuration

iOS Configuration

Add to ios/Runner/Info.plist:
<!-- Health data access (if using Wear module) -->
<key>NSHealthShareUsageDescription</key>
<string>This app needs access to your health data to provide insights.</string>

<!-- Motion & Fitness (if using Phone module) -->
<key>NSMotionUsageDescription</key>
<string>This app uses motion data to understand your activity patterns.</string>

Android Configuration

Add to android/app/src/main/AndroidManifest.xml:
<!-- Required permissions -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />

<!-- Health Connect Permissions (if using Wear module) -->
<uses-permission android:name="android.permission.health.READ_HEART_RATE"/>
<uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY"/>

Basic Usage

Initialize the SDK

import 'package:synheart_core/synheart_core.dart';

// Initialize with basic modules
await Synheart.initialize(
  userId: 'anon_user_123',
  config: SynheartConfig(
    allowUnsignedCapabilities: true,  // Use capabilityToken in production
  ),
);

Subscribe to HSI Updates

The HSI (Human State Intelligence) stream emits raw JSON from the on-device runtime:
// onHSIUpdate emits raw HSI JSON from the Synheart Runtime
Synheart.onHSIUpdate.listen((hsiJson) {
  print('HSI JSON: $hsiJson');
});

Activate optional modules

The SynheartFeature enum gates collection by feature. Activation is one of four conditions a feature needs (the others are consent, capability tier, and an active session — see Capability System).
// Available features:
//   SynheartFeature.wear         — biosignals from wearables
//   SynheartFeature.behavior     — interaction telemetry
//   SynheartFeature.phoneContext — motion / screen / app context
//   SynheartFeature.cloud        — HSI upload connector

Synheart.activate(SynheartFeature.wear);
Synheart.activate(SynheartFeature.cloud);

// Stop a feature without uninitializing the SDK.
Synheart.deactivate(SynheartFeature.cloud);
State signals (focus, emotion, recovery, etc.) are not separate features — they’re axes inside the HSI JSON emitted by Synheart.onHSIUpdate. Parse the JSON or use the typed Synheart.onStateUpdate stream to read them.

Enable the cloud connector

Upload HSI 1.3 snapshots when the host has been granted cloudUpload consent:
await Synheart.initialize(
  userId: 'anon_user_123',
  config: SynheartConfig(
    allowUnsignedCapabilities: true,  // use capabilityToken in production
    cloudConfig: CloudConfig(
      appId: 'your_app_id',
      subjectId: 'user_123',
      instanceId: 'device_abc',
      baseUrl: 'https://api.synheart.ai',
      maxQueueSize: 100,
    ),
  ),
);

// Uploads happen automatically when consent is granted, the queue has
// pending snapshots, and the network is reachable. Inspect upload state
// via the diagnostics getters:
final pending = Synheart.uploadQueueLength;
final lastBatch = Synheart.lastUploadBatchId;
final lastError = Synheart.lastUploadError;

Synheart.deactivate(SynheartFeature.cloud);   // pause uploads

Complete example

import 'package:flutter/material.dart';
import 'package:synheart_core/synheart_core.dart';

class HumanStateMonitor extends StatefulWidget {
  @override
  State<HumanStateMonitor> createState() => _HumanStateMonitorState();
}

class _HumanStateMonitorState extends State<HumanStateMonitor> {
  HSIState? _state;
  String? _rawHsi;
  bool _ready = false;

  @override
  void initState() {
    super.initState();
    _bootstrap();
  }

  Future<void> _bootstrap() async {
    await Synheart.initialize(
      userId: 'user_123',
      config: SynheartConfig(allowUnsignedCapabilities: true),
    );
    Synheart.activate(SynheartFeature.wear);
    Synheart.activate(SynheartFeature.behavior);

    Synheart.onHSIUpdate.listen((json) => setState(() => _rawHsi = json));
    Synheart.onStateUpdate.listen((s) => setState(() => _state = s));

    setState(() => _ready = true);
  }

  @override
  void dispose() {
    Synheart.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    if (!_ready) return const Center(child: CircularProgressIndicator());
    final axes = _state?.hsi;
    return Scaffold(
      appBar: AppBar(title: const Text('Human State')),
      body: ListView(padding: const EdgeInsets.all(16), children: [
        Text('Focus: ${axes?.focus?.value.toStringAsFixed(2) ?? '—'}'),
        Text('Arousal: ${axes?.arousal?.value.toStringAsFixed(2) ?? '—'}'),
        Text('Capacity: ${axes?.capacity?.value.toStringAsFixed(2) ?? '—'}'),
        const SizedBox(height: 16),
        if (_rawHsi != null)
          Text('Raw HSI: ${_rawHsi!.substring(0, 100)}…'),
      ]),
    );
  }
}

HSI state reference

Synheart.onHSIUpdate emits raw HSI 1.3 JSON strings. The typed projection of that JSON is HSIState, surfaced via Synheart.onStateUpdate. Most apps use the typed stream; reach for the raw JSON only when you need fields the typed projection doesn’t expose (for example, the 64D embedding vector).
class HSIState {
  final String subjectId;
  final int timestampMs;
  final HSIAxes hsi;
  final Modalities modalities;
  final Tiers tiers;
  final String rawJson;
}

class HSIAxes {
  final HSIAxisValue? focus;
  final HSIAxisValue? arousal;
  final HSIAxisValue? capacity;
  final HSIAxisValue? sleep;
}

class HSIAxisValue {
  final double value;       // 0.0–1.0
  final double confidence;  // 0.0–1.0
}
modalities and tiers carry per-axis source attribution and capability gating. The exact shape can drift between HSI versions; treat the typed fields as best-effort and the rawJson as authoritative. See the HSI specification and Synheart Core HSI mapping.

Cloud connector

The cloud connector uploads HSI 1.3 snapshots to the Synheart Platform when the host has been granted cloudUpload consent.
await Synheart.initialize(
  userId: 'anon_user_123',
  config: SynheartConfig(
    allowUnsignedCapabilities: true,  // use capabilityToken in production
    cloudConfig: CloudConfig(
      appId: 'your_app_id',
      subjectId: 'user_123',
      instanceId: 'device_abc',
      baseUrl: 'https://api.synheart.ai',
      maxQueueSize: 100,
    ),
  ),
);

// Once activated, the connector handles uploads automatically:
//   - flushes when HSI windows close and consent is granted
//   - queues during offline windows (FIFO, capped by maxQueueSize)
//   - retries failed uploads with exponential backoff
//
// Inspect state through diagnostic getters:
final pending = Synheart.uploadQueueLength;
final lastBatch = Synheart.lastUploadBatchId;
final lastError = Synheart.lastUploadError;

// Pause / resume:
Synheart.deactivate(SynheartFeature.cloud);
Synheart.activate(SynheartFeature.cloud);
Authentication is hardware-backed device ECDSA per RFC-AUTH-MOBILE-0001. The runtime owns request signing via the host’s synheart-auth integration — CloudConfig does not carry shared secrets or HMAC keys. See Synheart Auth overview for the device-identity flow. Upload Payload (HSI 1.3 format):
{
  "subject": {
    "subject_type": "pseudonymous_user",
    "subject_id": "user_123"
  },
  "snapshots": [
    {
      "hsi_version": "1.3",
      "observed_at_utc": "2025-12-28T10:30:00Z",
      "computed_at_utc": "2025-12-28T10:30:10Z",
      "producer": {
        "name": "Synheart Core SDK",
        "version": "1.0.0",
        "instance_id": "device_abc"
      },
      "windows": {
        "micro": {
          "start_utc": "2025-12-28T10:29:30Z",
          "end_utc": "2025-12-28T10:30:00Z",
          "duration_seconds": 30
        }
      },
      "axes": {
        "affect": {
          "arousal_index": 0.72,
          "valence_stability": 0.65
        },
        "engagement": {
          "engagement_stability": 0.81,
          "interaction_cadence": 0.55
        },
        "behavior": {
          "motion_index": 0.45,
          "posture_stability": 0.78,
          "screen_active_ratio": 0.90,
          "session_fragmentation": 0.22
        }
      },
      "embeddings": [
        {
          "dimension": 64,
          "model": "synheart-jl-64",
          "vector": [0.12, 0.34, ...]
        }
      ],
      "privacy": {
        "contains_pii": false
      }
    }
  ]
}

Configuration Options

final config = SynheartConfig(
  // Update interval for HSV processing
  updateInterval: Duration(seconds: 30),

  // Cloud configuration (optional).
  cloudConfig: CloudConfig(
    appId: 'your_app_id',
    subjectId: 'user_123',
    instanceId: 'device_abc',
    baseUrl: 'https://api.synheart.ai',
  ),

  // Capability JWT (optional, for extended/research access).
  capabilityToken: null,

  // Log level
  logLevel: LogLevel.info,
);

await Synheart.initialize(
  userId: 'user_123',
  config: config,
);

Error Handling

try {
  await Synheart.initialize(
    userId: userId,
    config: config,
  );
} on PermissionDeniedError catch (e) {
  print('Permission denied: ${e.message}');
} on InitializationError catch (e) {
  print('Initialization failed: ${e.message}');
} on SynheartError catch (e) {
  print('SDK error: ${e.message}');
}
The SDK enforces consent at multiple levels:
// Coarse status — granted | pending | expired | denied
final status = await Synheart.consentStatus();

// Per-type check (wire strings: biosignals, phoneContext, behavior,
// cloudUpload, vendorSync, research)
final canUpload = await Synheart.hasConsent('cloudUpload');
final canRead   = await Synheart.hasConsent('biosignals');

// Request consent — opens the cloud consent flow when configured.
final token = await Synheart.requestConsent();

if (await Synheart.hasConsent('cloudUpload')) {
  Synheart.activate(SynheartFeature.cloud);
}

// Revoke a single type or everything
await Synheart.revokeConsentType('cloudUpload');
await Synheart.revokeConsent();
For the full consent model (granular channels, tiers, JWT lifecycle), see Consent System.

Performance Considerations

These are design targets, not measured runtime numbers — profile your own app for ground truth on the current build. Use the diagnostic getters to inspect what the SDK is actually doing.

Diagnostics & upload inspection

// Live counters and last-error strings.
final diag = Synheart.runtimeDiagnostics();
print(diag);

// Synchronous getters — safe to read from UI code.
final depth = Synheart.uploadQueueLength;
final lastMs = Synheart.lastIngestSuccessAtMs;

// Manually flush queued snapshots when consent + network are eligible.
final result = await Synheart.ingestion.flushIfEligible();

API reference

Synheart

Main SDK class. Static methods:
MethodDescriptionReturns
initialize(...)Initialize the SDKFuture<void>
activate(feature)Activate a featurevoid
deactivate(feature)Deactivate a featurevoid
dispose()Tear down the SDK and release resourcesFuture<void>
runtimeDiagnostics()Live counters / last-error stringsMap<String, dynamic>
Streams:
StreamTypeDescription
onHSIUpdateStream<String>Raw HSI 1.3 JSON, emitted per window close
onStateUpdateStream<HSIState>Typed projection of onHSIUpdate

Resources