> ## 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.

# Breathing module

> 4-pillar breathing-compliance detector — configure target rate, evaluate over the current RR window, render coaching.

## Overview

The Breathing module wraps the runtime's breathing-compliance detector. Every R-R interval pushed via `CoreRuntimeBridge.pushRr` (raw beat data from BLE chest straps and equivalent sources) automatically feeds the detector — this module only configures the target rate / population / window and reads back the verdict.

A "compliance" verdict has four pillars (peak frequency match, coherence, RSA amplitude, relative power) and a confidence score in \[0, 1]. The detector returns one of three verdicts:

* **Compliant** — user is meeting the target; metrics included
* **NotCompliant** — user is breathing but off-target; reason explains why (frequency, depth, regularity, no breathing signature) — feed into coaching copy
* **Insufficient** — not enough raw R-R data yet; reason explains what's missing

## Configuration

```kotlin theme={null}
// Kotlin
val breathing = BreathingModule(bridge = coreRuntime)
breathing.setTargetBpm(6.0)                            // resonance breathing
breathing.setWindowSecs(60)                            // 30–120s clamp
breathing.setPopulation(BreathingPopulation.BEGINNER)  // / EXPERIENCED / CLINICAL
breathing.reset()                                      // call before a new exercise
```

```swift theme={null}
// Swift
let breathing = BreathingModule(bridge: coreRuntime)
breathing.setTargetBpm(6.0)
breathing.setWindowSecs(60)
breathing.setPopulation(.beginner)  // / .experienced / .clinical
breathing.reset()
```

## Evaluate

Call once per UI frame (or at whatever cadence you render coaching):

```kotlin theme={null}
// Kotlin
when (val v = breathing.evaluate()) {
    is BreathingComplianceResult.Compliant -> showCompliant(v.metrics)
    is BreathingComplianceResult.NotCompliant ->
        showCoaching(BreathingGuidanceCopy.copyFor(v.reason))
    is BreathingComplianceResult.Insufficient -> showWarming(v.reason)
}
```

```swift theme={null}
// Swift
switch breathing.evaluate() {
case let .compliant(metrics):
    showCompliant(metrics)
case let .notCompliant(_, reason):
    showCoaching(BreathingGuidanceCopy.copyFor(reason))
case let .insufficient(reason):
    showWarming(reason)
}
```

## Metrics

`BreathingMetrics` (present on Compliant / NotCompliant, nil on Insufficient):

| Field                | Range    | Meaning                                                     |
| -------------------- | -------- | ----------------------------------------------------------- |
| `peakHz` / `peakBpm` | Hz / BPM | Detected breathing peak frequency (`peakBpm = peakHz * 60`) |
| `coherence`          | 0..1     | Peak power / total power in the 0.04–0.26 Hz band           |
| `rsaBpm`             | BPM      | Mean per-cycle `HR_max − HR_min` — depth of breath          |
| `relativePower`      | 0..1     | Peak power as a fraction of total breathing-band power      |
| `criteriaMet`        | 0..4     | Number of pillars passed                                    |
| `confidence`         | 0..1     | Mean of normalized pillar scores                            |

## NonComplianceReason

Structured reason types — render coaching copy from these instead of free-text from the engine:

| Reason                                   | When fired                                                |
| ---------------------------------------- | --------------------------------------------------------- |
| `WrongFrequency(detectedBpm, targetBpm)` | Cycle frequency missed the target band                    |
| `ShallowBreathing(rsaBpm)`               | Rhythm is right, RSA too low — breaths aren't deep enough |
| `IrregularPattern(coherence)`            | Coherence below threshold — uneven cadence                |
| `NoBreathingSignature`                   | Detector can't find a respiratory rhythm in the RR signal |

`BreathingGuidanceCopy.localize` is a swappable function for the default English coaching strings — override globally to ship in a different language or tone.

## InsufficientReason

| Reason                               | When fired                                                                                     |
| ------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `NotEnoughBeats(have, need)`         | Fewer than `need` (default 50) R-R samples buffered                                            |
| `WindowTooShort(haveSecs, needSecs)` | Window hasn't reached the configured length yet                                                |
| `VendorOnlyTier(device)`             | Source provides only summary metrics (no raw R-R intervals) — the detector needs raw beat data |
| `ExcessiveArtifacts(rejectedPct)`    | Too many RR samples failed artifact filtering (motion, missed beats)                           |

## Population profile

Adjusts the per-pillar thresholds:

| Profile              | Use                                                             |
| -------------------- | --------------------------------------------------------------- |
| `Beginner` (default) | First-time users; permissive thresholds, gives wins early       |
| `Experienced`        | Returning users with technique; tighter coherence + RSA cutoffs |
| `Clinical`           | Research / clinical settings; strictest thresholds              |

## Cross-language parity

Identical wire format across Flutter / Kotlin / Swift:

* Flutter: `lib/src/modules/breathing/{breathing_module,breathing_compliance_result,breathing_guidance_copy}.dart`
* Kotlin: `synheart-core/src/main/kotlin/ai/synheart/core/modules/breathing/{BreathingModule,BreathingComplianceResult,BreathingGuidanceCopy}.kt`
* Swift: `SynheartCore/Modules/Breathing/{BreathingModule,BreathingComplianceResult,BreathingGuidanceCopy}.swift`

## Related

* [Synheart Core overview](/synheart-core/overview)
* [Baselines](/synheart-core/baselines) — the same RR stream feeds longitudinal baselines
