[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-83927":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":16,"stars7d":17,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":18,"compositeScore":19,"rankGlobal":9,"rankLanguage":9,"license":9,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":9,"pushedAt":9,"updatedAt":24,"readmeContent":25,"aiSummary":9,"trendingCount":15,"starSnapshotCount":15,"syncStatus":26,"lastSyncTime":27,"discoverSource":28},83927,"noop","NoopApp\u002Fnoop","NoopApp","Offline WHOOP companion — pair your strap over Bluetooth, keep all data on your own device. No cloud, no account, no subscription.",null,"Swift",1445,657,9,11,0,99,974,1172,103.45,false,"main",true,[],"2026-06-12 04:01:42","\u003Cp align=\"center\">\n  \u003Cimg src=\"docs\u002Fassets\u002Fbanner.svg\" alt=\"NOOP — a local-first companion for WHOOP straps\" width=\"860\">\n\u003C\u002Fp>\n\n\u003Ch1 align=\"center\">NOOP\u003C\u002Fh1>\n\n\u003Cp align=\"center\">\u003Cb>Your strap. Your data. Your machine. Local-first, no cloud.\u003C\u002Fb>\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Cimg alt=\"Platforms\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fplatforms-macOS%20%C2%B7%20Android%20%C2%B7%20iOS-18C98B?style=flat-square\">\n  \u003Cimg alt=\"Local first\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flocal-first-18C98B?style=flat-square\">\n  \u003Cimg alt=\"Account free\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Faccount-free-2FE6A8?style=flat-square\">\n  \u003Cimg alt=\"WHOOP 4 and 5\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fworks%20with-WHOOP%204.0%20%26%205.0-8B9690?style=flat-square\">\n  \u003Ca href=\"LICENSE\">\u003Cimg alt=\"License: PolyForm Noncommercial 1.0.0\" src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-PolyForm%20Noncommercial%201.0.0-8B9690?style=flat-square\">\u003C\u002Fa>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"#keeping-noop-alive\">♥&nbsp;Support\u003C\u002Fa> ·\n  \u003Ca href=\"#download\">⬇&nbsp;Download\u003C\u002Fa> ·\n  \u003Ca href=\"#features\">Features\u003C\u002Fa> ·\n  \u003Ca href=\"docs\u002FPROTOCOL.md\">Protocol\u003C\u002Fa> ·\n  \u003Ca href=\"mailto:thenoopapp@gmail.com\">Contact\u003C\u002Fa>\n\u003C\u002Fp>\n\n---\n\n## Keeping NOOP alive\n\nNOOP is **free, forever** — no account, no cloud, no subscription, every feature unlocked, no nag. That doesn't change.\n\nBut here's the honest reality, up front: **NOOP is built and maintained by one person, out of pocket.** Reverse-engineering WHOOP's hardware — and keeping up as its firmware changes — takes real time and real test hardware. **The project continues if the people who use it help fund it. If that doesn't happen, it can't.** No drama, no guilt — just the maths of an unfunded project.\n\nIf NOOP saves you a subscription, or you just want WHOOP 5.0\u002FMG support finished and the work to keep going, **chipping in is what genuinely decides that.** It's optional, one-off, and tied to nothing about your data or access — there's no server and no record of who has or hasn't.\n\n### How to donate — 2 minutes, even if you've never touched crypto\n\nDonations are **crypto-only**, on purpose: staying anonymous (for the project *and* for you) rules out PayPal, Patreon, or anything with a name attached. If you don't already hold any:\n\n1. **Install a mainstream exchange app** — Coinbase, Binance, Kraken, or **Cash App** (Cash App handles Bitcoin directly).\n2. **Buy a small amount of Bitcoin (BTC) or Ethereum (ETH)** — even $5–10 is genuinely helpful.\n3. **Tap Send \u002F Withdraw, paste the matching address below, and send.** That's it. (Only ever send a coin to its own network.)\n\n| Coin | Network | Address |\n|---|---|---|\n| **BTC** | Bitcoin | `bc1qn2gkl7wslwpws06mvazjn2uu689zlkv7kg3kf5` |\n| **ETH** | Ethereum | `0xd64D508b531c4b1297Ca4023C774e0E97aA67B7F` |\n| **ADA** | Cardano | `addr1qxsju3y0mlke2h6h2g6qgnq4r3jstngtyjxs0nnp5zrv28zv8p5rgzruxyjz33j9k23pffta8z639e2snjdd4vcetfqsn4vwr3` |\n| **XRP** | XRP Ledger | `rpvijHi2nVY9WWAJhojsAX5tJmHdmLtFhq` |\n\nEach address also has a scan-to-donate **QR code** in the app under **Support** (and they're listed in [`docs\u002FDONATIONS.md`](docs\u002FDONATIONS.md)). *Always copy the full address and double-check the first and last characters; crypto transactions are irreversible, and only ever send a coin to its own network.*\n\n**Can't or would rather not?** Also genuinely valued: **⭐ star this repo**, file a good bug report, share a strap log, test on hardware you own, or just tell another WHOOP user. That moves NOOP forward too.\n\n---\n\n## Download\n\nPre-built apps you can run right now:\n\n| Platform | Build | Notes |\n|---|---|---|\n| **macOS** | `NOOP.app` (see [Releases](..\u002F..\u002Freleases)) | Apple Silicon + Intel. Drag to Applications. Not notarized — see **First launch on macOS** below. |\n| **Android** | `NOOP-full.apk` (see [Releases](..\u002F..\u002Freleases)) | The full app. `minSdk 26` (Android 8+). Sideload — enable \"install unknown apps\". |\n| **Android (demo)** | `NOOP-demo.apk` | Preloaded with sample data so you can explore every screen with no strap. Installs alongside the full app. |\n| **iOS** | Build from source — see [PR #42](..\u002F..\u002Fpull\u002F42) | An experimental community port (app + widgets + HealthKit). **Not distributed as a download:** iOS has no anonymous install path — the App Store and TestFlight both require a real Apple Developer identity — so it's build-it-yourself in Xcode, not officially maintained. |\n\n> **First launch on macOS.** NOOP is **not notarized** by Apple — notarization needs a paid Apple\n> Developer ID tied to a real identity, which doesn't fit an anonymous, free project. The app *is*\n> sandboxed and ad-hoc code-signed, and the full source is here to inspect. Because it isn't notarized,\n> macOS Gatekeeper blocks it on first open (you may see *\"damaged\"* or *\"unverified developer\"* — that's\n> the download quarantine flag, not real damage). To open it, do one of these **once**:\n>\n> - **Terminal (most reliable):** drag `NOOP.app` to Applications, then run\n>   `xattr -dr com.apple.quarantine \u002FApplications\u002FNOOP.app` and open NOOP normally.\n> - **No Terminal:** double-click NOOP (it'll be blocked), then open **System Settings → Privacy &\n>   Security**, scroll to the bottom, and click **\"Open Anyway\"** next to NOOP. (On macOS 14 and\n>   earlier you can also right-click the app → **Open**.)\n>\n> Prefer to avoid this entirely? Build from source — see [Quickstart](#quickstart-macos).\n\nPrefer to build it yourself? See [`docs\u002FBUILD.md`](docs\u002FBUILD.md).\n\nEverything runs **offline**. The only feature that ever uses the network is the optional **AI Coach**, and only with your own API key.\n\n---\n\nNOOP is a standalone, fully **offline** companion app for WHOOP straps (4.0 and\n5.0). It pairs directly with the strap over Bluetooth, stores everything on your\nown device in SQLite, imports your existing WHOOP and Apple Health history, and\ncomputes recovery, strain, HRV, and sleep **locally**, with no WHOOP account and\nno WHOOP cloud.\n\nIt is built on prior community reverse-engineering work and exists for one\nreason: to let someone who owns a WHOOP strap read **their own biometric data**\nfrom **their own device**, on a machine **they** control.\n\n> **Not affiliated with WHOOP.** NOOP is an independent, unofficial\n> interoperability project. It is not affiliated with, endorsed by, or connected\n> to WHOOP, Inc. \"WHOOP\" is used only to identify the hardware NOOP talks to. Use\n> it only with a device you own, and not in breach of any agreement that applies\n> to you. **NOOP is not a medical device**; every derived metric is an\n> approximation, not clinical data. See [`DISCLAIMER.md`](DISCLAIMER.md).\n\n---\n\n## Contents\n\n- [Why NOOP](#why-noop)\n- [Features](#features)\n- [Platform status](#platform-status)\n- [Architecture](#architecture)\n- [Quickstart (macOS)](#quickstart-macos)\n- [How your data flows](#how-your-data-flows)\n- [Privacy](#privacy)\n- [Attribution](#attribution)\n- [Support (optional)](#support-optional)\n- [Disclaimer](#disclaimer)\n- [License](#license)\n- [Docs](#docs)\n\n---\n\n## Why NOOP\n\nYou bought the strap. The biometric stream it produces is yours. NOOP is built on\nthat premise:\n\n- **Own your data.** NOOP reads heart rate, R-R intervals, SpO₂, skin temperature,\n  respiration, accelerometer\u002Fgravity, battery, and event data straight off the\n  strap over Bluetooth and writes it to a local SQLite database. Nothing is\n  uploaded anywhere.\n- **Account-free and local.** NOOP never logs into a WHOOP account and never hits\n  a WHOOP server. It does not bypass any login, paywall, or DRM; it simply talks to\n  a device you own and reads data you generated.\n- **Bring your history.** Already have years of data in the official app or in\n  Apple Health? Import the WHOOP CSV export and\u002For your Apple Health `export.xml`\n  once, and it's permanently on your machine.\n- **Transparent math.** Recovery, strain, HRV, and sleep are recomputed on-device\n  from documented, citable methods (Task Force 1996 HRV, Karvonen %HRR, Edwards \u002F\n  Banister TRIMP, Tanaka HRmax, and so on). The algorithms are approximations of —\n  not reproductions of — any proprietary model, and every analyzer file documents\n  exactly what it does.\n\n---\n\n## Features\n\nThe macOS reference app organizes everything behind a single sidebar\n(`Strand\u002FApp\u002FRootView.swift`). Each item below is a real screen in\n`Strand\u002FScreens\u002F`.\n\n| Screen | What it does |\n|---|---|\n| **Today** (Control Center) | Home dashboard: recovery ring, a \"today's synthesis\" insight, a grid of stat tiles (recovery, strain, sleep, HRV, RHR, SpO₂, respiratory, steps, weight, calories) each with a 14-day sparkline, recent workouts, and a data-sources footer. |\n| **Readiness** | An on-device \"should you push today?\" read that synthesizes established sports-science signals from your own history — HRV vs your baseline (Plews\u002FBuchheit), resting-HR drift (Lamberts), sleeping respiratory-rate drift, training-load balance (acute:chronic workload ratio, Gabbett) and training monotony (Foster) — into a single headline (Primed \u002F Balanced \u002F Strained \u002F Run down) with the drivers behind it. Pure local math, not medical advice. |\n| **Live** | Real-time view of the connected strap — heart rate and frame stream as they arrive (~1 Hz). |\n| **Breathe** | **HRV haptic breathing biofeedback.** The strap both *measures* HRV (R-R intervals) and *buzzes* its haptic motor, so NOOP paces your breath with felt cues (one buzz inhale, two exhale) and shows live HR + rolling RMSSD responding as the session deepens. Presets: Relax 4-6, Coherence 5.5, Box 4-4. |\n| **Intervals** | **Silent haptic HIIT timer.** The strap buzzes every transition (triple-buzz into WORK, single into REST, 3-2-1 tick at phase ends, long buzz on finish) so you train hands-free. Falls back to a glanceable visual timer with no strap. |\n| **Explore** (Metric Explorer) | Interrogate any single metric over time, built from the metric catalog (`Strand\u002FData\u002FMetricCatalog.swift`). |\n| **Compare** | Plot two metrics together \u002F against each other over a shared timeline. |\n| **Insights** | Behavioral and correlational insights derived from your own series. |\n| **Sleep** | Sleep sessions with a hypnogram, stage breakdown, efficiency, resting HR, and HRV — computed by the on-device sleep stager. |\n| **Trends** | Long-range trends across recovery, strain, sleep, and biometrics. |\n| **Workouts** | Detected exercise sessions with strain and heart-rate detail. |\n| **Health** | Biometric overview (HR, HRV, SpO₂, skin temperature, respiratory rate, etc.). |\n| **Stress** | Day-level stress \u002F autonomic load visualization. |\n| **Apple Health** | Browse and reconcile data imported from your Apple Health export. |\n| **Data Sources** | One-tap import of a WHOOP CSV export or an Apple Health export, plus live-strap status. \"Bring your history in once, then it's yours.\" |\n| **Notifications** | Configure local notifications and thresholds (`Strand\u002FData\u002FNotificationSettingsStore.swift`). |\n| **Automations** | Turn the strap's physical inputs and live biometrics into Mac actions — all on-device (see below). |\n| **Coach** | An optional **AI Coach** you can ask about your data in plain language. It's the one feature that ever uses the network: off until you add your own OpenAI\u002FAnthropic key, and it sends only a short text summary of recent metrics plus your question — never raw streams or identifiers. On the sandboxed macOS build it's blocked by the App Sandbox (no network entitlement); it works on Android. See [`docs\u002FPRIVACY_SECURITY.md`](docs\u002FPRIVACY_SECURITY.md). |\n| **Settings** | Profile, preferences, the in-app **What's new** changelog, and an opt-in **Experimental** section (WHOOP 5\u002FMG protocol probes). |\n| **Support** | Attribution + **optional** crypto donations. The whole app works without them. |\n\nThere is also a **menu-bar extra** (`Strand\u002FMenuBar\u002FMenuBarContent.swift`) with a\nglanceable live HR readout and a compact popover, a first-run **onboarding wizard**\nthat sets expectations (independent\u002Fexperimental, WHOOP 4.0 vs 5\u002FMG, on-device only),\nand an in-app **\"What's new\"** changelog shown after each update.\n\n### Automations (on-device)\n\n`Strand\u002FScreens\u002FAutomationsView.swift` + `Strand\u002FSystem\u002FMacActions.swift`:\n\n- **Double-tap → Mac action.** Double-tap the strap to lock the Mac, buzz back to\n  confirm, mark a moment, do nothing, or run any macOS **Shortcut** by name (via\n  the `shortcuts:\u002F\u002F` URL scheme, so it's sandbox-friendly).\n- **Wear & presence.** Lock the Mac (or run a Shortcut) the moment the strap\n  leaves your wrist; run a Shortcut when it goes back on. *(macOS reserves true\n  auto-**unlock** for Apple Watch — NOOP can lock, not unlock.)*\n- **Haptic coaching.** HR-zone coaching and an experimental resting-stress nudge —\n  the strap buzzes so you don't have to watch a screen.\n- **Smart alarm.** Arms the strap's own **firmware** alarm to buzz at your wake\n  time (still fires if the Mac is asleep or NOOP is closed), with an optional\n  light-sleep wake window when the Mac stays awake and connected.\n\n---\n\n## Platform status\n\nNOOP's logic lives in cross-platform Swift packages, and the same protocol,\nstorage, analytics, and scoring is ported to Kotlin on Android. Both apps pair\nwith the strap and **score recovery, strain and sleep on your own device** — no\nimport required.\n\n| Platform | Status |\n|---|---|\n| **macOS** | ✅ Full app (`Strand\u002F`, SwiftUI, macOS 13+). Pairs over BLE, offloads the strap's history, and scores recovery \u002F strain \u002F sleep on-device. The complete feature set above runs here. |\n| **Android** | ✅ Full app (`android\u002F`, Jetpack Compose, Android 8+). Pairs over BLE, persists and scores on-device, and imports WHOOP \u002F Apple Health \u002F Health Connect. Grab the APK from [Releases](..\u002F..\u002Freleases). |\n| **iOS** | 🧪 Experimental community port in [PR #42](..\u002F..\u002Fpull\u002F42) — app target + widgets + Live Activity + HealthKit, builds for the iOS simulator. **Build-from-source only, not officially maintained or distributed:** iOS has no anonymous distribution path (App Store and TestFlight both require a real Apple Developer identity), which is fundamentally at odds with this project staying anonymous. The shared packages already declare `.iOS(.v16)` and UI-framework code is guarded with `#if canImport(UIKit)` \u002F `AppKit`. |\n\n### Strap support\n\nNOOP is an independent, **experimental** project — capable, but a work in progress.\n\n| Strap | Status |\n|---|---|\n| **WHOOP 4.0** | ✅ The tested, supported path. Live HR, recovery, strain, sleep, history offload — the full experience. |\n| **WHOOP 5.0 \u002F MG** | 🧪 **Live heart rate works** (confirmed on real hardware). Pick \"WHOOP 5.0 \u002F MG\" before connecting — and see the pairing note below, because you can't just scan for it. Deeper 5\u002FMG metrics (recovery, strain, sleep) are still being reverse-engineered; there's an opt-in **Settings → Experimental** toggle for 5\u002FMG owners who want to help map the protocol. |\n\n> ### Pairing a WHOOP 5.0 \u002F MG — read this first\n>\n> A WHOOP strap holds an encrypted Bluetooth **bond with only one device at a time**, and yours is\n> normally bonded to the **official WHOOP app** on your phone. **You can't just scan for it in NOOP** —\n> if the strap is still bonded to the WHOOP app, NOOP's pairing is refused and the strap log shows\n> *\"Encryption is insufficient\"* \u002F *\"bond refused.\"* (Live **heart rate** is the exception — it rides the\n> standard Bluetooth heart-rate profile, so it streams without a bond. But pairing — needed for the\n> deeper features — does not.)\n>\n> **To pair properly:**\n> 1. **Close the official WHOOP app** on your phone (fully quit it, or turn that phone's Bluetooth off) so\n>    it isn't holding the bond.\n> 2. **Put the strap in pairing mode** — on a 5.0\u002FMG, **tap the band repeatedly** (firm taps on the\n>    sensor) until the **LEDs flash blue**.\n> 3. In NOOP: **Live → choose \"WHOOP 5.0 \u002F MG\" → Scan & Connect.** Success looks like\n>    *\"CLIENT_HELLO acked — link established\"* in the strap log (not *\"bond refused\"*). It can take a\n>    couple of attempts.\n>\n> **Only one device at a time.** Because the strap holds a single bond, don't leave it connected to your\n> phone *and* your Mac (or the WHOOP app) at once — live heart rate will still show on all of them\n> (that rides the bond-free standard profile), but **none** of them will have the real encrypted bond.\n> If HR streams fine yet **buzz, alarm, double-tap and history don't work**, that's the tell: the strap\n> isn't truly bonded to this device. Free it from everything else, then pair here.\n>\n> Bonding to NOOP may take the strap's bond away from the WHOOP app, so the official app might need to\n> re-pair afterwards. This is the **hardest part of 5\u002FMG support** — if it refuses, you're almost\n> certainly still bonded to the WHOOP app (or another device); free the strap and retry.\n\nThe app always tells you what's live now versus still building, both in onboarding and on each screen.\n\n### What to expect when you start\n\nNOOP computes your scores on your own device, so like any recovery wearable it\nneeds a little data before everything fills in:\n\n- **Live heart rate** shows the moment the strap connects.\n- **Strain and sleep** appear after you've worn it and synced — the strap's last\n  ~14 days offload automatically over the first few minutes.\n- **Recovery** needs a few nights for the app to learn your personal baseline,\n  then sharpens each night. WHOOP makes you wait for the same reason.\n- **In a hurry?** Import your WHOOP export in Data Sources and your full history\n  fills in about a minute.\n\n---\n\n## Architecture\n\nThe repository is split into platform-pure Swift packages plus a macOS app target.\nAll packages declare both `.iOS(.v16)` and `.macOS(.v13)`; framework-specific UI is\nguarded with `#if canImport(UIKit)` \u002F `#if canImport(AppKit)`.\n\n```\nStrand\u002F                  macOS SwiftUI reference app (this is what you build)\nPackages\u002F\n  WhoopProtocol\u002F         BLE frame parsing, CRC, command\u002Fevent\u002Fpacket decode\n  WhoopStore\u002F            GRDB\u002FSQLite persistence (migrations, streams, caches)\n  StrandAnalytics\u002F       HRV \u002F recovery \u002F strain \u002F sleep \u002F correlation math\n  StrandImport\u002F          WHOOP CSV + Apple Health importers\n  StrandDesign\u002F          SwiftUI design system (palette, components, charts)\nTools\u002FBackfill\u002F          CLI tool for backfilling decoded data\nFixtures\u002F                sample WHOOP export for tests\n```\n\n### `WhoopProtocol` — the reverse-engineering core\n\nPlatform-pure (no CoreBluetooth import) so it runs in tests and CLI tools\nunchanged. It decodes the on-wire frame format for both strap generations:\n\n```swift\npublic enum DeviceFamily: String, Sendable, CaseIterable {\n    case whoop4   \u002F\u002F CRC8 (poly 0x07) header check; service 61080001-…\n    case whoop5   \u002F\u002F CRC16-Modbus header check, \"puffin\" packet types; service fd4b0001-…\n}\n```\n\nDecoding is schema-driven (`Resources\u002Fwhoop_protocol.json`) and includes CRC8,\nCRC16-Modbus, and zlib CRC-32 implementations, frame framing, value\ninterpretation, and historical-stream reassembly. The app layer (`Strand\u002FBLE\u002F`,\n`Strand\u002FCollect\u002F`) wraps these UUID *strings* in `CBUUID` and handles bonding,\noffload, and live notifications.\n\n### `WhoopStore` — local SQLite via GRDB\n\nEverything is stored on-device in SQLite (using\n[GRDB.swift](https:\u002F\u002Fgithub.com\u002Fgroue\u002FGRDB.swift)). The schema is a versioned\nmigrator (`Database.swift`, currently through `v9`). Examples of decoded-stream\ntables created in `v1`–`v3`:\n\n```sql\nCREATE TABLE hrSample      (deviceId TEXT, ts INTEGER, bpm INTEGER, PRIMARY KEY(deviceId, ts));\nCREATE TABLE rrInterval    (deviceId TEXT, ts INTEGER, rrMs INTEGER, PRIMARY KEY(deviceId, ts, rrMs));\nCREATE TABLE spo2Sample    (deviceId TEXT, ts INTEGER, red INTEGER, ir INTEGER, PRIMARY KEY(deviceId, ts));\nCREATE TABLE skinTempSample(deviceId TEXT, ts INTEGER, raw INTEGER, PRIMARY KEY(deviceId, ts));\nCREATE TABLE respSample    (deviceId TEXT, ts INTEGER, raw INTEGER, PRIMARY KEY(deviceId, ts));\n```\n\nLater migrations add server-derived metric caches (`sleepSession`, `dailyMetric`),\ncursors, a raw frame outbox, and more.\n\n### `StrandAnalytics` — transparent, on-device math\n\nPure, database-free analyzers. Each is documented and grounded in published\nmethods (and is explicitly an approximation, not a reproduction of any proprietary\nmodel):\n\n| File | Computes |\n|---|---|\n| `HRVAnalyzer.swift` | RMSSD + SDNN from R-R intervals (Task Force 1996), with range + Malik ectopic filtering. |\n| `RecoveryScorer.swift` | A 0–100 recovery score: HRV-dominant z-score + logistic composite vs personal baselines. |\n| `StrainScorer.swift` | A 0–21 logarithmic strain scale from %HRR (Karvonen) and Edwards \u002F Banister TRIMP. |\n| `SleepStager.swift` | Sleep\u002Fwake detection + approximate 4-class staging from cardiorespiratory + gravity features. |\n| `CorrelationEngine.swift` | Pearson r, OLS regression, day-aligned and lagged correlations between two series. |\n| `WorkoutDetector.swift`, `Baselines.swift`, `BehaviorInsights.swift`, `AnalyticsEngine.swift` | Workout detection, rolling baselines, behavioral insights, and the per-day orchestrator. |\n\n### `StrandImport` — bring your own history\n\n- **WHOOP CSV export** (`WhoopExportImporter.swift`): header-name-driven, tolerant\n  parser for `physiological_cycles.csv`, `sleeps.csv`, `workouts.csv`, and\n  `journal_entries.csv`, from a folder or `.zip`. The same schema covers WHOOP 4 \u002F\n  5 \u002F MG.\n- **Apple Health export** (`AppleHealthImporter.swift`): a **streaming** SAX parser\n  (`XMLParser`) for `export.xml` (which can exceed 1 GB), with correlation-dedupe,\n  unit normalization (e.g. SpO₂ fraction → %), and sleep-stage mapping.\n\n### `StrandDesign` — the SwiftUI design system\n\nPalette, typography, motion, and reusable components\u002Fcharts (`RecoveryRing`,\n`StrainGauge`, `Hypnogram`, `Sparkline`, `TrendChart`, `YearHeatStrip`,\n`StrandCard`, `StatePill`, …) — no external UI dependencies.\n\n---\n\n## Quickstart (macOS)\n\n**Requirements:** macOS 13+, Xcode 15+ (Swift 5.9), and a Mac with Bluetooth. To\npair live, you need your own WHOOP strap; to just explore, you can import a CSV \u002F\nApple Health export instead.\n\nThe Xcode project is generated from [`project.yml`](project.yml) with\n[XcodeGen](https:\u002F\u002Fgithub.com\u002Fyonaskolb\u002FXcodeGen).\n\n```bash\n# 1. Clone\ngit clone \u003Cyour-fork-url> NOOP\ncd NOOP\n\n# 2. (Re)generate the Xcode project from project.yml\nbrew install xcodegen   # if you don't have it\nxcodegen generate\n\n# 3. Open and run\nopen Strand.xcodeproj\n# Select the \"Strand\" scheme → Run (⌘R). The built app is named NOOP.\n```\n\nNotes:\n\n- Bundle id `com.noopapp.noop`, product name **NOOP**, sandboxed with the\n  Bluetooth and user-selected-files entitlements.\n- Swift Package Manager resolves the only third-party dependencies automatically:\n  **GRDB.swift** (SQLite) and **ZIPFoundation** (export unzip).\n- Run the tests from Xcode (the `StrandTests` target + each package's test target),\n  or per-package with `swift test` inside `Packages\u002F\u003CName>\u002F`.\n\nTo explore without an Xcode project, the packages build on their own:\n\n```bash\ncd Packages\u002FWhoopProtocol && swift build && swift test\n```\n\n---\n\n## How your data flows\n\n```\nWHOOP strap ──BLE──▶ Strand\u002FBLE + Strand\u002FCollect ──▶ WhoopProtocol (decode)\n                                                          │\nWHOOP CSV  ─┐                                             ▼\nApple Health├─▶ StrandImport (parse) ───────────▶ WhoopStore (local SQLite)\n export.xml ─┘                                            │\n                                                          ▼\n                                            StrandAnalytics (recovery\u002Fstrain\u002F\n                                            HRV\u002Fsleep, on-device)\n                                                          │\n                                                          ▼\n                                          Strand (SwiftUI) + StrandDesign\n```\n\nEvery arrow stays on your machine.\n\n---\n\n## Privacy\n\n**Offline by design.** NOOP has no server, no telemetry, and no account. Your\nstrap data, imports, and computed metrics live in a local SQLite database on your\ndevice and never leave it.\n\n---\n\n## Attribution\n\nNOOP stands on community reverse-engineering and interoperability work. With\nthanks:\n\n- **`johnmiddleton12\u002Fmy-whoop`** — the WHOOP 4.0 BLE protocol; the `WhoopProtocol`\n  and `WhoopStore` packages and the collection logic are adapted from this work.\n- **`b-nnett\u002Fgoose`** — the WHOOP 5.0 \u002F MG BLE reverse-engineering (the `fd4b0001-…`\n  service family, CRC16-Modbus header, and \"puffin\" packet types) that NOOP's\n  WHOOP 5.0 path is ported from.\n- **`groue\u002FGRDB.swift`** — SQLite persistence.\n- **`weichsel\u002FZIPFoundation`** — export unzipping.\n\nNOOP contains no WHOOP proprietary code, firmware, logos, or assets, and performs\nno DRM circumvention. Full detail in [`ATTRIBUTION.md`](ATTRIBUTION.md).\n\n---\n\n## Support (optional)\n\nNOOP is free and always will be, and never gates a feature behind payment. If it's\nuseful to you and you want to help with the development and testing costs, optional\ncrypto donation addresses are shown on the in-app **Support** screen and listed in\n[`docs\u002FDONATIONS.md`](docs\u002FDONATIONS.md). Donations are 100% optional and the app\nnever asks twice.\n\n**Contact:** questions, feedback, and bug reports → [thenoopapp@gmail.com](mailto:thenoopapp@gmail.com)\n\n---\n\n## Disclaimer\n\nNOOP is an independent, unofficial, non-commercial interoperability project. It is\n**not affiliated with, endorsed by, or connected to WHOOP, Inc.** All references to\n\"WHOOP\" are nominative — used only to identify the third-party hardware NOOP\ninteroperates with.\n\n**NOOP is not a medical device.** Heart rate, HRV, recovery, strain, sleep stages,\nSpO₂, respiratory rate, and skin temperature are **approximations** computed from\npublished methods. They are not clinically validated and are not medical advice. Do\nnot use them to diagnose, treat, or make health decisions — consult a qualified\nprofessional.\n\nProvided **as-is**, with **no warranty**, for **personal and educational use**. You\nuse it at your own risk. Read the full notice in [`DISCLAIMER.md`](DISCLAIMER.md).\n\n---\n\n## License\n\nNOOP is **source-available** under the [PolyForm Noncommercial License 1.0.0](LICENSE):\n**free for personal and other non-commercial use** — read it, run it, fork it, and\ncontribute. Commercial use is not granted by this license. (PolyForm Noncommercial is\na proper software license with patent terms; it is deliberately *not* an OSI\n\"open-source\" licence, because that would permit the commercial use this project's\nnon-commercial nature rules out.)\n\nThe license covers NOOP's own original code and docs. Protocol facts (frame layouts,\ncommand numbers, byte offsets) are uncopyrightable and free to reuse; bundled\ndependencies keep their own licenses (GRDB.swift and ZIPFoundation are MIT — see\n[`NOTICE`](NOTICE)). By opening a pull request you agree your contribution is licensed\nunder the same terms — see [`docs\u002FCONTRIBUTING.md`](docs\u002FCONTRIBUTING.md).\n\n---\n\n## Docs\n\n- [`CHANGELOG.md`](CHANGELOG.md) — release history and what to expect (also shown in-app under **What's new**).\n- [`DISCLAIMER.md`](DISCLAIMER.md) — trademark, interoperability, and medical\u002Flegal notice.\n- [`ATTRIBUTION.md`](ATTRIBUTION.md) — full credits and licensing notes.\n- [`docs\u002FDONATIONS.md`](docs\u002FDONATIONS.md) — optional donation addresses (also in-app under **Support**).\n- [`project.yml`](project.yml) — XcodeGen project definition (source of `Strand.xcodeproj`).\n",2,"2026-06-11 04:11:50","CREATED_QUERY"]