Skip to content
PlantuchaPublic

About

Local-first physiological analyzers — oximetry, HRV, CGM, ECG . No network, no CDNs, no accounts.

Topics

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

4,671 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tepna — the Dex Suite

Read one raw biosignal → grade every number → fuse across signals.

Your data never leaves the browser — and CI proves it on every commit.

Live at tepna.net Suite v2.21.0 License: Apache-2.0 DOI

No network · CI-enforced Every metric graded Reproducible Nodes Releases

tepna.net · github.com/Plantucha/Tepna

README last synced to commit 779f348d (2026-10-04). Next refresh: git log --oneline 779f348d..origin/main lists what this page has not seen yet — fold that in, then move this stamp.

Tepna is a set of single-signal analyzers for the physiology sensors people actually own — a ring oximeter, a chest strap, an armband, a CGM, a CPAP machine — plus one capture box that records them all night on one clock. Each analyzer reads one raw signal, derives its metrics, and reports over a shared bus (Ganglior) so a fusion layer (the Integrator) can read across signals. Every number carries an evidence grade. The suite uploads nothing, ever: a headless gate boots every shipped surface and fails the build if anything reaches for the network.

What it finds that holds ships as a graded metric. The project publishes what fails too — Dead Ends is the citable map of the walls. The long-form why is docs/WHY-THIS-EXISTS.md.


Get it running

git clone https://github.com/Plantucha/Tepna.git

Open index.html in a browser and click your device. No build, no server, no install: every app is one self-contained HTML file that runs from disk. One sensor is a complete starting point — an O2Ring alone feeds OxyDex, an H10 alone feeds ECGDex and PulseDex — and an Android phone running the free Polar Sensor Logger or the Wellue app produces files the apps read directly. The capture box is the always-on, one-clock upgrade, not the entry fee.


The apps

App Signal Device What it reports Guide
OxyDex SpO₂ Wellue O2Ring ODI-4 · T90 · hypoxic burden reference
ECGDex raw ECG Polar H10 QTc · rMSSD · beat-level RR reference
PulseDex RR intervals Polar H10 · Coospo · Wahoo rMSSD · SDNN · nonlinear HRV reference
PpgDex raw PPG Polar Verity Sense · O2Ring PPI → HRV · pulse-wave morphology reference
HRVDex HRV summaries exports an additive multi-day HRV ledger reference
GlucoDex CGM exports Time in Range · GMI reference
CPAPDex CPAP therapy ResMed EDF pressure · leak · respiratory events · breath rate reference
MotionDex IMU Polar Verity Sense · H10 body position · actigraphy · motion quality (no guide yet)
EEGDex EEG Muse planned —

Each app writes a ganglior.node-export JSON. The Integrator fuses them; the Data Unifier routes single dropped files to the right app; OverDex does the same for a whole folder.


Every number is graded

Each metric carries one of five evidence tiers, shown as a disc badge whose shape encodes trust (so it reads the same in greyscale and to colour-blind users). A higher tier is not a better metric, only a louder one.

Tier Means Example
measured read off the device mean SpO₂, mean HR
validated anchored to a published standard ODI-4 · rMSSD · SDNN · QTc · Time in Range · GMI · hypoxic burden
emerging published, device-dependent nonlinear HRV, cardiopulmonary coupling
experimental internally consistent, not externally confirmed composite indices
heuristic directional only sleep-derived BP estimate

The eight registries define 520 graded metrics; just under half have the measured or validated grade and nearly two-fifths sit at experimental or heuristic. The distribution is the honest version of the count, which is why the ladder leads. If you read nothing else, read the validated row.


The privacy claim is a test

no-network.html statically scans every shipped surface, boots each one in a trapped iframe where any cross-origin request throws, and asserts zero egress; a planted canary inside the gate means a vacuous "all clear" cannot pass. Every bundle also ships a strict Content-Security- Policy with connect-src 'none' and hash-only script-src. verify-provenance.html content-addresses every bundle and every known-answer fixture, so a shipped app is provably the code it claims to be.

Every pull request must pass nine checks: tests (13,353 assertions across 801 groups, six partitioned shards) · no-network · types · biome · browser-gates (every bundle booted headless, computed values asserted in the DOM) · stale-file (an edit that never read the upstream version cannot overwrite a brief) · capture-host on py3.12 and py3.13 — 9,300+ Python tests at a 100 % statement and branch floor — and a diff-scoped mutation gate that breaks the lines a PR touched and refuses to merge what the suite would not notice. CodeQL runs beside them, and a static job re-derives every ledger the tree claims so a stale artefact reds the PR.


The Health Box

The apps read files; something has to write them. capture-host/ is a Python service for a small bedside PC that holds the live Bluetooth links — H10 ECG, Verity PPG and IMU, the O2Ring's SpO₂ and raw PPG, the CPAP's live flow — and writes the vendors' own file layouts into per-night folders. It is a producer outside the browser suite: no app ever talks to a device. It has its own gate, capture-host/check.sh, because this code runs unattended against hardware that misbehaves while nobody is awake.

Every morning the box judges the night it recorded. Night QC checks coverage and gaps, the loss audit attributes every minute worn but not recorded to its cause and holds it to the owner's bar (≤ 1 % of worn time), and SOLID-NIGHT composes one verdict per night across devices and bands. Every judgement is one tepna.verdict/1 object with a pre-stated criterion, written beside its prose — and an absent measurement is null with a reason, never a zero.

Per-device capture instructions without the box live in how-to-collect/.


Method, in four rules

  • Measurement before interpretation. A number is not a measurement until someone checks the acquisition path that produced it. ECGDex's estimatedAHI was withdrawn in v2.0.0, not relabelled: it correlated with device-scored AHI at r = −0.151.
  • Time is a measurement. Two devices reporting milliseconds need not share one. The Clock Contract puts every stream on a floating wall-clock axis, reconciles device crystals against the capture host with a running median that refuses rather than guesses, and names a drawn axis as drawn.
  • Agreement is not confirmation. Two sensors agreeing is evidence only if they are independent; the spread of residuals, not a rate, decides whether a recording holds a second clock at all.
  • The suite tests the gates too. tools/mutate.mjs and the Python mutation gate break the code on purpose and report what the suite fails to notice; the ledger records each surviving mutant with the probe that excused it, and never waves one through.

In 2.17.0 (2026-09-27 → 2026-10-05, 125 commits, 99 changesets). The capture lane learned to judge a night on its own: the loss audit got its bar, SOLID-NIGHT its tripwire for unrecorded clock shifts, the ring its honest completeness model and a declared clock stream, and the box judges a night twenty minutes after its data goes quiet instead of the next evening. The mutation gate stopped hiding survivors behind timeouts, declared the one module it cannot measure, and started reading Codex as a second opinion under mechanical verification. Full history in the changelog.


Suite at a glance

Suite version: 2.21.0  —  47 ledger-backed releases, each computed from a green tree, with 0 changesets pending since (the tree is exactly the release).

Every one of the 23 working preprints in papers/ regenerates from the live tool behind it. The methods overview is Science.html; the system design is Architecture.html.


The hardware

Every sensor is bone-stock and spoken to over the vendor's own protocol; the CPAP link is read-only by construction. Approximate US street prices, 2026:

Hardware Role Price
Lenovo ThinkCentre M900 Tiny (used) the Health Box ~$120
Wellue O2Ring-S overnight SpO₂ · pulse · raw PPG ~$170
Polar H10 raw ECG · RR · IMU ~$90
Polar Verity Sense raw PPG · IMU ~$105
nRF52840 dongles ×3 (open-source Zephyr HCI image) the box's Bluetooth radios ~$30
ez Share WiFi SD card pulls the CPAP's card ~$25
core capture kit ≈ $550

Optional: a GPS stratum-1 time server (the box holds microsecond offsets against it), a ResMed AirSense 11 (therapy equipment that was already there), an Abbott Lingo CGM, a Muse S for the planned EEG node. One attended lab night costs more than the whole kit and records one night; this records every night, raw, in your own bed. The two are not substitutes: if you suspect a sleep disorder, see a physician, and bring your exports.


Repo map

You want… Look at
a map of every document DOCS-INDEX.md — start here before opening any brief
the 60-second orientation for contributors ORIENTATION.md
the house rules CLAUDE.md · CONTRIBUTING.md · ARCHITECTURE-PRINCIPLES.md
how an app is built <node>-dsp.js · -render.js · -app.js · -registry.js + <App>.src.html; edit these, never the bundled *.html
the research tools and papers *-analysis.html and papers/
every script, indexed docs/TOOLS-INDEX.md
open verified defects briefs/RESIDUE.md

Acknowledgements

Tepna stands on others' documented work: nglessner/o2ring-s-protocol (the O2Ring-S protocol reference), m-kozlowski/airbreak-plus descending from osresearch/airbreak (the CPAP protocol), Polar Sensor Logger by j-ware, and the open-source foundations the capture lane leans on: bleak, mutmut, chrony. Development tools (not shipped) names every tool this repo builds, checks and searches with, gives each one's licence, and shows that none of them reaches a bundle. Built in the open with Built with Claude Code.

Licensing

Apache-2.0. Author: Michal Planicka (ORCID 0009-0008-3501-3596). Brand: Tepna. See LICENSE, NOTICE, CITATION.cff and THIRD-PARTY.md. Tepna is not a medical device and does not diagnose, treat or monitor any condition.

About

Local-first physiological analyzers — oximetry, HRV, CGM, ECG . No network, no CDNs, no accounts.

Topics

Resources

Contributing

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages