RanjithRagavan/Noctua

On-device AI wellness intelligence for Oura Ring — typed Oura API v2 Kotlin client + privacy-first ExecuTorch insight engine + Compose example app

2

stars

7

commits

Kotlin

primary language

Sep 9, 2026

updated

README

🦉 Noctua

On-device AI wellness intelligence for Oura Ring — privacy-first Android SDK.

Noctua (the owl genus — nocturnal wisdom) is an open-source Kotlin toolkit that combines a complete, typed client for the Oura API v2 with an on-device AI layer that turns raw biometrics into explainable insights and a next-day readiness forecast — without your health data ever leaving the phone.

Kotlin Compose ExecuTorch License


Screenshots

DashboardAI Coach (on-device)Connect
Dashboard — score rings, readiness forecast, 14-day trendAI Coach — explainable insights generated on-deviceConnect — PAT or OAuth2 sign-in

Captured from the example app running in demo mode on a Pixel 7 Pro emulator.

Why Noctua?

Most wearable companion apps ship your biometric history to a cloud LLM to generate "insights". Noctua takes the opposite stance:

Cloud AI companionsNoctua
Raw HRV / sleep / temperature datauploaded to a servernever leaves the device
Insight logicopaquetransparent, unit-tested rules + open model
Works offline
Latencynetwork round-trip< 5 ms on-device

Architecture

graph TD
    A[Oura Cloud API v2] -->|OAuth2 / PAT| B[noctua-core<br/>typed Kotlin client]
    B --> C[WellnessSnapshot<br/>readiness · sleep · activity · HRV]
    C --> D[noctua-ai<br/>FeatureExtractor]
    D --> E1[HeuristicInsightEngine<br/>explainable rules]
    D --> E2[ExecuTorchForecaster<br/>.pte neural model, on-device]
    E1 --> F[NoctuaReport]
    E2 --> F
    E2 -.missing runtime.-> E3[LinearHeuristicForecaster<br/>zero-dependency fallback]
    E3 --> F
    F --> G[example-app<br/>Jetpack Compose]
ModuleWhat it is
noctua-corePure-Kotlin Oura API v2 client — OAuth2 helpers, auto-refreshing tokens, all usercollection endpoints, pagination, sandbox support. Runs on Android and any JVM backend.
noctua-aiOn-device intelligence: feature extraction (sleep debt, HRV z-score vs personal baseline, readiness trend), explainable heuristic insights, and a neural readiness forecaster bridged to ExecuTorch.
example-appMaterial 3 Compose app — score rings, 14-day readiness trend, AI coach feed, OAuth/token connect flow, and a built-in demo mode that needs no Oura account.
model/PyTorch → ExecuTorch export script for the readiness forecaster.

Quickstart

1. Get Oura credentials

2. Add the libraries

The modules are plain Gradle project dependencies (publish to Maven or use via includeBuild / JitPack):

dependencies {
    implementation("com.noctua:noctua-core:0.1.0")
    implementation("com.noctua:noctua-ai:0.1.0")
    // Optional: enable the neural forecaster
    implementation("org.pytorch:executorch-android:1.0.0")
}

3. Fetch your data

val oura = OuraClient.Builder()
    .token("YOUR_TOKEN")
    .build()

// Coroutine-first; pagination is handled for you.
val readiness = oura.dailyReadiness(startDate = "2026-08-01", endDate = "2026-08-21")
val sleep     = oura.dailySleep(startDate = "2026-08-01", endDate = "2026-08-21")
val periods   = oura.sleep(startDate = "2026-08-01", endDate = "2026-08-21")

OAuth2 (client-side flow) in two lines:

val url = OuraOAuth.authorizationUrl(clientId, redirectUri = "myapp://callback")
// open `url` in a Custom Tab, then in your deep-link handler:
val token = OuraOAuth.parseClientSideRedirect(intent.dataString!!).accessToken

For long-lived apps, OAuthTokenProvider refreshes expiring tokens automatically via Oura's refresh_token grant.

4. Generate on-device insights

val ai = NoctuaAI()
val report = ai.analyze(WellnessSnapshot(
    readiness = readiness,
    sleep = sleep,
    activity = oura.dailyActivity("2026-08-01", "2026-08-21"),
    sleepPeriods = periods,
))

println(report.forecastedReadiness)   // e.g. 74 — tomorrow's predicted score
report.insights.forEach { println("• ${it.title} (${it.confidence}%)") }
// • Sleep debt accumulating (88%)
// • HRV below your baseline (80%)

5. Go neural with ExecuTorch

cd model
pip install torch executorch
python export_readiness_forecaster.py   # → readiness_forecaster.pte

Ship the .pte with your app and swap the forecaster:

val ai = NoctuaAI(forecaster = ExecuTorchForecaster(pteFile.absolutePath))

If the ExecuTorch runtime or model file is absent, Noctua silently falls back to the bundled linear model — the app never breaks.

API coverage

EndpointOuraClient methodScope
/v2/usercollection/personal_infopersonalInfo()personal
daily_sleep / daily_readiness / daily_activitydailySleep() · dailyReadiness() · dailyActivity()daily
daily_spo2 · daily_stress · daily_resiliencedailySpo2() · dailyStress() · dailyResilience()spo2 / daily
daily_cardiovascular_age · vO2_maxdailyCardiovascularAge() · vo2Max()heart_health
sleep (detailed periods) · sleep_timesleep() · sleepTime()daily
heartrate (time series)heartrate(start, end) ISO-8601 datetimesheartrate
workout · session · tag / enhanced_tagworkouts() · sessions() · tags() · enhancedTags()workout / session / tag
rest_mode_period · ring_configurationrestModePeriods() · ringConfigurations()daily / ring_configuration
Sandbox (/v2/sandbox/...)Builder().sandbox(true)none

Errors map to typed OuraException subtypes: Unauthorized, RateLimited (Oura allows ~5000 req / 5 min), Http, Network, Serialization.

Run the example app

git clone https://github.com/RanjithRagavan/Noctua.git
cd Noctua
./gradlew :example-app:installDebug

The app boots into demo mode with a deterministic 21-day dataset, so you can evaluate the full UX — score rings, trend chart, forecast card, AI coach — before connecting a real ring. The screenshots above show exactly what demo mode renders.

Roadmap

  • On-device LLM sleep coach (ExecuTorch Llama runner, fully local chat)
  • Personal fine-tuning loop: retrain the forecaster nightly on-device
  • Health Connect write-back (share derived insights with Android Health)
  • Webhook subscription helpers (/v2/webhook/subscription)
  • Compose Multiplatform + iOS (KMP) port of noctua-ai

Contributing

Issues and PRs welcome. The heuristics in HeuristicInsightEngine are deliberately readable — improving them with better evidence is a great first contribution. Run ./gradlew test before submitting.

License

Apache 2.0 — use it in personal or commercial apps.

Noctua is an independent open-source project and is not affiliated with, endorsed by, or sponsored by Ōura Health Oy.

Contributors

ranjith

7 commits

RanjithRagavan/Noctua

On-device AI wellness intelligence for Oura Ring — typed Oura API v2 Kotlin client + privacy-first ExecuTorch insight engine + Compose example app

2

stars

7

commits

Kotlin

primary language

Sep 9, 2026

updated

README

🦉 Noctua

On-device AI wellness intelligence for Oura Ring — privacy-first Android SDK.

Noctua (the owl genus — nocturnal wisdom) is an open-source Kotlin toolkit that combines a complete, typed client for the Oura API v2 with an on-device AI layer that turns raw biometrics into explainable insights and a next-day readiness forecast — without your health data ever leaving the phone.

Kotlin Compose ExecuTorch License


Screenshots

DashboardAI Coach (on-device)Connect
Dashboard — score rings, readiness forecast, 14-day trendAI Coach — explainable insights generated on-deviceConnect — PAT or OAuth2 sign-in

Captured from the example app running in demo mode on a Pixel 7 Pro emulator.

Why Noctua?

Most wearable companion apps ship your biometric history to a cloud LLM to generate "insights". Noctua takes the opposite stance:

Cloud AI companionsNoctua
Raw HRV / sleep / temperature datauploaded to a servernever leaves the device
Insight logicopaquetransparent, unit-tested rules + open model
Works offline
Latencynetwork round-trip< 5 ms on-device

Architecture

graph TD
    A[Oura Cloud API v2] -->|OAuth2 / PAT| B[noctua-core<br/>typed Kotlin client]
    B --> C[WellnessSnapshot<br/>readiness · sleep · activity · HRV]
    C --> D[noctua-ai<br/>FeatureExtractor]
    D --> E1[HeuristicInsightEngine<br/>explainable rules]
    D --> E2[ExecuTorchForecaster<br/>.pte neural model, on-device]
    E1 --> F[NoctuaReport]
    E2 --> F
    E2 -.missing runtime.-> E3[LinearHeuristicForecaster<br/>zero-dependency fallback]
    E3 --> F
    F --> G[example-app<br/>Jetpack Compose]
ModuleWhat it is
noctua-corePure-Kotlin Oura API v2 client — OAuth2 helpers, auto-refreshing tokens, all usercollection endpoints, pagination, sandbox support. Runs on Android and any JVM backend.
noctua-aiOn-device intelligence: feature extraction (sleep debt, HRV z-score vs personal baseline, readiness trend), explainable heuristic insights, and a neural readiness forecaster bridged to ExecuTorch.
example-appMaterial 3 Compose app — score rings, 14-day readiness trend, AI coach feed, OAuth/token connect flow, and a built-in demo mode that needs no Oura account.
model/PyTorch → ExecuTorch export script for the readiness forecaster.

Quickstart

1. Get Oura credentials

2. Add the libraries

The modules are plain Gradle project dependencies (publish to Maven or use via includeBuild / JitPack):

dependencies {
    implementation("com.noctua:noctua-core:0.1.0")
    implementation("com.noctua:noctua-ai:0.1.0")
    // Optional: enable the neural forecaster
    implementation("org.pytorch:executorch-android:1.0.0")
}

3. Fetch your data

val oura = OuraClient.Builder()
    .token("YOUR_TOKEN")
    .build()

// Coroutine-first; pagination is handled for you.
val readiness = oura.dailyReadiness(startDate = "2026-08-01", endDate = "2026-08-21")
val sleep     = oura.dailySleep(startDate = "2026-08-01", endDate = "2026-08-21")
val periods   = oura.sleep(startDate = "2026-08-01", endDate = "2026-08-21")

OAuth2 (client-side flow) in two lines:

val url = OuraOAuth.authorizationUrl(clientId, redirectUri = "myapp://callback")
// open `url` in a Custom Tab, then in your deep-link handler:
val token = OuraOAuth.parseClientSideRedirect(intent.dataString!!).accessToken

For long-lived apps, OAuthTokenProvider refreshes expiring tokens automatically via Oura's refresh_token grant.

4. Generate on-device insights

val ai = NoctuaAI()
val report = ai.analyze(WellnessSnapshot(
    readiness = readiness,
    sleep = sleep,
    activity = oura.dailyActivity("2026-08-01", "2026-08-21"),
    sleepPeriods = periods,
))

println(report.forecastedReadiness)   // e.g. 74 — tomorrow's predicted score
report.insights.forEach { println("• ${it.title} (${it.confidence}%)") }
// • Sleep debt accumulating (88%)
// • HRV below your baseline (80%)

5. Go neural with ExecuTorch

cd model
pip install torch executorch
python export_readiness_forecaster.py   # → readiness_forecaster.pte

Ship the .pte with your app and swap the forecaster:

val ai = NoctuaAI(forecaster = ExecuTorchForecaster(pteFile.absolutePath))

If the ExecuTorch runtime or model file is absent, Noctua silently falls back to the bundled linear model — the app never breaks.

API coverage

EndpointOuraClient methodScope
/v2/usercollection/personal_infopersonalInfo()personal
daily_sleep / daily_readiness / daily_activitydailySleep() · dailyReadiness() · dailyActivity()daily
daily_spo2 · daily_stress · daily_resiliencedailySpo2() · dailyStress() · dailyResilience()spo2 / daily
daily_cardiovascular_age · vO2_maxdailyCardiovascularAge() · vo2Max()heart_health
sleep (detailed periods) · sleep_timesleep() · sleepTime()daily
heartrate (time series)heartrate(start, end) ISO-8601 datetimesheartrate
workout · session · tag / enhanced_tagworkouts() · sessions() · tags() · enhancedTags()workout / session / tag
rest_mode_period · ring_configurationrestModePeriods() · ringConfigurations()daily / ring_configuration
Sandbox (/v2/sandbox/...)Builder().sandbox(true)none

Errors map to typed OuraException subtypes: Unauthorized, RateLimited (Oura allows ~5000 req / 5 min), Http, Network, Serialization.

Run the example app

git clone https://github.com/RanjithRagavan/Noctua.git
cd Noctua
./gradlew :example-app:installDebug

The app boots into demo mode with a deterministic 21-day dataset, so you can evaluate the full UX — score rings, trend chart, forecast card, AI coach — before connecting a real ring. The screenshots above show exactly what demo mode renders.

Roadmap

  • On-device LLM sleep coach (ExecuTorch Llama runner, fully local chat)
  • Personal fine-tuning loop: retrain the forecaster nightly on-device
  • Health Connect write-back (share derived insights with Android Health)
  • Webhook subscription helpers (/v2/webhook/subscription)
  • Compose Multiplatform + iOS (KMP) port of noctua-ai

Contributing

Issues and PRs welcome. The heuristics in HeuristicInsightEngine are deliberately readable — improving them with better evidence is a great first contribution. Run ./gradlew test before submitting.

License

Apache 2.0 — use it in personal or commercial apps.

Noctua is an independent open-source project and is not affiliated with, endorsed by, or sponsored by Ōura Health Oy.

Contributors

ranjith

7 commits

Languages

Kotlin

96.9%

Python

3.1%