Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
bafa8c9
App-store-readiness prep (Phase 1, legal-review-driven)
abdulsaheel Jul 17, 2026
a6bf39e
Point kPrivacyPolicyUrl at the live hosted Privacy Policy
abdulsaheel Jul 18, 2026
9f8b88e
iOS submission prep: scrub hardcoded Team ID + sync Widget/Watch vers…
abdulsaheel Jul 18, 2026
7c6adc7
Offload derive second half to isolate; fix 3 fatal crashes; readiness…
abdulsaheel Jul 18, 2026
a074229
Merge pull request #91 from OpenStrap/fix/derive-offload-and-crashes
abdulsaheel Jul 18, 2026
e5691e3
Fix CodeRabbit findings on PR #93 (app-store-readiness prep)
abdulsaheel Jul 18, 2026
46da0fc
PRIVACY.md: finalize placeholders, document health data contribution
abdulsaheel Jul 18, 2026
1d9f415
Rewrite privacy/terms: no data collection, Firebase-only diagnostics
abdulsaheel Jul 18, 2026
54d51d9
No data collection: gate health-data upload off, Firebase-only diagno…
abdulsaheel Jul 18, 2026
2f156e9
Scope the "no data collection" claim to builds we actually distribute
abdulsaheel Jul 18, 2026
7c074fe
Address CodeRabbit: make the off-by-default health-data gate explicit
abdulsaheel Jul 18, 2026
6f77359
Carve out AI Coach / Health app integration from the absolute claims
abdulsaheel Jul 19, 2026
1c13e21
Carve out AI Coach / Health app integration from the absolute claims
abdulsaheel Jul 19, 2026
fae01fc
Merge docs/legal-site: fold the hosted legal-docs site into this PR
abdulsaheel Jul 19, 2026
1ec89b9
Bump kAlgoVersion 43 -> 44 for the partial-day + wake-steps fixes
abdulsaheel Jul 19, 2026
c0df061
iOS App Store prep: usage-description strings + real launch screen
abdulsaheel Jul 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ jobs:
run: |
echo "COMPANION_URL=${{ secrets.COMPANION_URL }}" > .env
echo "BACKEND_URL=${{ secrets.BACKEND_URL }}" >> .env
# Health-data contribution (full on-device DB upload) is OFF for
# every build we distribute, sideload included — matching
# PRIVACY.md's "we do not collect your data". Passed explicitly
# (not just relying on kHealthDataContributionEnabled's default)
# so this is true by construction of the CI config itself, not
# contingent on nobody ever changing that default later.
echo "ENABLE_HEALTH_DATA_CONTRIBUTION=false" >> .env

# Decode the release keystore from a secret. The gradle config picks these
# env vars up (ANDROID_KEYSTORE_PATH etc.) and signs the release build.
Expand Down Expand Up @@ -127,6 +134,13 @@ jobs:
run: |
echo "COMPANION_URL=${{ secrets.COMPANION_URL }}" > .env
echo "BACKEND_URL=${{ secrets.BACKEND_URL }}" >> .env
# Health-data contribution (full on-device DB upload) is OFF for
# every build we distribute, sideload included — matching
# PRIVACY.md's "we do not collect your data". Passed explicitly
# (not just relying on kHealthDataContributionEnabled's default)
# so this is true by construction of the CI config itself, not
# contingent on nobody ever changing that default later.
echo "ENABLE_HEALTH_DATA_CONTRIBUTION=false" >> .env

- name: Install flutterfire (required by Crashlytics Xcode build phase)
run: dart pub global activate flutterfire_cli 1.4.0
Expand Down
11 changes: 11 additions & 0 deletions NOTICE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Notice

Edge is an independent, open-source project (MIT License — see `LICENSE`). It
is not affiliated with, sponsored by, or endorsed by WHOOP, Inc. or any of its
trademarks.

No WHOOP source code, binaries, firmware, or copyrighted assets are included
in this repository. The Bluetooth protocol support in this project was
independently developed by observing the band's own Bluetooth communications;
see [the protocol repo's README](https://github.com/OpenStrap/protocol) for
methodology notes.
87 changes: 87 additions & 0 deletions PRIVACY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Privacy Policy — Edge / OpenStrap

_Last updated: July 18, 2026_

Edge ("the App") is an independent, open-source project. It is not affiliated
with, sponsored by, or endorsed by WHOOP, Inc.
Comment on lines +1 to +6

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Identify the data controller explicitly.

The policy names the project and an email address but does not identify the developer/controller legal name or jurisdiction. Align this with the store listing and add the required developer/privacy-contact details. Google Play requires developer information and a privacy point of contact. (support.google.com)

Also applies to: 70-71

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PRIVACY.md` around lines 1 - 6, Update the Privacy Policy header and
developer/contact sections to explicitly identify the legal data controller,
jurisdiction, developer information, and privacy point of contact, matching the
Google Play store listing. Apply the same details to the related content at the
referenced later lines, while preserving the existing project and affiliation
statements.

Source: MCP tools


**We do not collect your data**
This section describes every build we ourselves distribute — the signed
Android APK and iOS IPA published on GitHub Releases, and any future App
Store/Play Store submission. Your biometric/health data from your paired
WHOOP 4.0 band — heart rate, heart rate variability (RR intervals), motion
(accelerometer), raw skin-temperature/blood-oxygen sensor channels, and (if
you record workouts) GPS location during those workouts — is processed and
stored entirely on your device in every one of those builds. We do not
upload it, we do not operate a backend that receives it, and we never see it
— *unless you separately choose to enable AI Coach or Health app
integration, described below, which send specific data to services you
configure.*

Edge is open source. The underlying code contains an off-by-default,
compile-time flag (`kHealthDataContributionEnabled`, see
`lib/telemetry/health_uploader.dart`) that an independent developer could
enable in their *own*, separately-built and separately-distributed copy of
the app, pointed at a backend of their own choosing. No build we publish
enables it — our CI explicitly forces it off for every release (see
`.github/workflows/build.yml`) rather than relying on the flag's default. A
self-built copy compiled with that flag on is that builder's own software
and their own responsibility; it is not covered by this policy.

**Anonymous diagnostics (on by default)**
In every build we distribute, the only thing the App sends off your device
*automatically* — aside from the optional, user-initiated integrations
described next — is basic crash/error and performance monitoring, via
Firebase (Google) — Crashlytics, Performance Monitoring, and Analytics. This
is on by default; you can turn it off at any
time in Settings ("Send anonymous diagnostics"), which stops any further
collection immediately. It never includes your health data — only crash
reports, basic device info (OS/model/app version), and coarse performance
timing. This data is handled under Firebase's own privacy and security
practices, not a system we built or operate ourselves — see Google's Firebase
privacy & security documentation: https://firebase.google.com/support/privacy.

**Optional, user-initiated integrations**
If you choose to enable them, the App can also send data to services *you*
configure:
- **AI Coach** — if you enable this feature and supply your own API key,
summaries of your data are sent to the AI provider you configure (by
default, OpenAI) to generate coaching responses. Off by default and
requires your own API key.
- **Health app integration** — if you enable it, the App can write derived
daily metrics to Apple Health or Google Health Connect, which are controlled
by your device's own OS-level health app, not by us.

**What we don't do**
We do not sell your data. We do not send your health data to WHOOP, Inc. or
any advertising network. We do not require a WHOOP account or credentials to
use the App. We do not operate a backend that stores your health data.

**Your controls**
Turn off "Send anonymous diagnostics" at any time in Settings — this stops any
further collection immediately. You can also disable AI Coach or Health app
integration at any time in Settings if you'd previously turned them on.

Uninstalling the App deletes all of your locally stored data immediately.
That's the whole picture *unless* you had separately enabled one of the
optional integrations above — in that case, uninstalling stops the App from
sending anything further, but does not reach back and delete data already
sent:
- Anonymous diagnostics already sent to Firebase are retained and governed by
Firebase's own practices (linked above), not by us.
- Data already sent to your configured AI Coach provider (e.g. OpenAI) is
retained and governed by that provider's own policies, not by us.
- Metrics already written to Apple Health or Google Health Connect are
retained and governed by that platform's own data controls, not by us —
manage or delete them from that app directly.

**Children**
This App is not directed to children under 13 (or the relevant age of digital
consent in your jurisdiction) and we do not knowingly collect data from them.

**Changes**
We may update this policy; material changes will be reflected here with an
updated date.

**Contact**
Questions about this policy: abdulsaheel81@gmail.com.
87 changes: 61 additions & 26 deletions docs/privacy.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,26 +26,51 @@ <h1>Privacy Policy — Edge / OpenStrap</h1>
<p>Edge ("the App") is an independent, open-source project. It is not affiliated
with, sponsored by, or endorsed by WHOOP, Inc.</p>

<h2>Data we collect</h2>
<ul>
<li>Biometric/health data from your paired WHOOP 4.0 band over Bluetooth: heart
rate, heart rate variability (RR intervals), motion (accelerometer), raw
skin-temperature/blood-oxygen sensor channels, and (if you record workouts) GPS
location during those workouts.</li>
<li>Basic app usage/crash telemetry, only if you opt in.</li>
</ul>
<h2>We do not collect your data</h2>
<p>This section describes every build we ourselves distribute — the signed
Android APK and iOS IPA published on GitHub Releases, and any future App
Store/Play Store submission. Your biometric/health data from your paired
WHOOP 4.0 band — heart rate, heart rate variability (RR intervals), motion
(accelerometer), raw skin-temperature/blood-oxygen sensor channels, and (if
you record workouts) GPS location during those workouts — is processed and
stored entirely on your device in every one of those builds. We do not
upload it, we do not operate a backend that receives it, and we never see
it — <em>unless you separately choose to enable AI Coach or Health app
integration, described below, which send specific data to services you
configure.</em></p>

<p>Edge is open source. The underlying code contains an off-by-default,
compile-time flag (<code>kHealthDataContributionEnabled</code>) that an
independent developer could enable in their <em>own</em>, separately-built
and separately-distributed copy of the app, pointed at a backend of their
own choosing. No build we publish enables it — our CI explicitly forces it
off for every release rather than relying on the flag's default. A
self-built copy compiled with that flag on is that builder's own software
and their own responsibility; it is not covered by this policy.</p>

<h2>Anonymous diagnostics (on by default)</h2>
<p>In every build we distribute, the only thing the App sends off your device
<em>automatically</em> — aside from the optional, user-initiated
integrations described next — is basic crash/error and performance
monitoring, via Firebase (Google) — Crashlytics, Performance Monitoring, and
Analytics. This is on by default; you can turn it off at any time in
Settings ("Send anonymous diagnostics"),
which stops any further collection immediately. It never includes your
health data — only crash
reports, basic device info (OS/model/app version), and coarse performance
timing. This data is handled under Firebase's own privacy and security
practices, not a system we built or operate ourselves — see Google's Firebase
privacy &amp; security documentation:
<a href="https://firebase.google.com/support/privacy">firebase.google.com/support/privacy</a>.</p>

<h2>Where your data lives</h2>
<p>By default, all of the above is stored locally on your device only. We do not
upload it anywhere unless you explicitly opt in to one of the following:</p>
<h2>Optional, user-initiated integrations</h2>
<p>If you choose to enable them, the App can also send data to services
<em>you</em> configure:</p>
<ul>
<li><strong>Cloud backup</strong> — a one-time or periodic encrypted upload of
your local database to our own backend, only if you turn this on in
Settings.</li>
<li><strong>AI Coach</strong> — if you enable this feature and supply your own
API key, summaries of your data are sent to the AI provider you configure (by
default, OpenAI) to generate coaching responses. This is off by default and
requires your own API key.</li>
default, OpenAI) to generate coaching responses. Off by default and requires
your own API key.</li>
<li><strong>Health app integration</strong> — if you enable it, the App can
write derived daily metrics to Apple Health or Google Health Connect, which
are controlled by your device's own OS-level health app, not by us.</li>
Expand All @@ -54,18 +79,28 @@ <h2>Where your data lives</h2>
<h2>What we don't do</h2>
<p>We do not sell your data. We do not send your health data to WHOOP, Inc. or any
advertising network. We do not require a WHOOP account or credentials to use the
App.</p>
App. We do not operate a backend that stores your health data.</p>

<h2>Your controls</h2>
<p>You can disable cloud backup, telemetry, or AI Coach at any time in Settings.
Uninstalling the App deletes all of its local data from your device — there is
no separate local-data export left behind. In-app, Settings → "Reset profile"
clears your local profile (name, age, body metrics) and forgets your paired
band, but does not delete your previously stored band data on the device; full
local deletion currently requires uninstalling the App. If you opted in to
cloud backup, we do not yet have a self-serve deletion flow for that uploaded
copy — email us at <a href="mailto:abdulsaheel81@gmail.com">abdulsaheel81@gmail.com</a> to
request its deletion and we will process it manually.</p>
<p>Turn off "Send anonymous diagnostics" at any time in Settings — this stops any
further collection immediately. You can also disable AI Coach or Health app
integration at any time in Settings if you'd previously turned them on.</p>

<p>Uninstalling the App deletes all of your locally stored data immediately.
That's the whole picture <em>unless</em> you had separately enabled one of
the optional integrations above — in that case, uninstalling stops the App
from sending anything further, but does not reach back and delete data
already sent:</p>
<ul>
<li>Anonymous diagnostics already sent to Firebase are retained and
governed by Firebase's own practices (linked above), not by us.</li>
<li>Data already sent to your configured AI Coach provider (e.g. OpenAI)
is retained and governed by that provider's own policies, not by
us.</li>
<li>Metrics already written to Apple Health or Google Health Connect are
retained and governed by that platform's own data controls, not by us
— manage or delete them from that app directly.</li>
</ul>

<h2>Children</h2>
<p>This App is not directed to children under 13 (or the relevant age of digital
Expand Down
7 changes: 5 additions & 2 deletions docs/terms.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,13 @@ <h2>5. Your Responsibilities</h2>
</ul>

<h2>6. Third-Party Services</h2>
<p>Certain optional features rely on third-party services you separately
<p>The App uses Firebase (Google) for anonymous crash/error and performance
monitoring (Crashlytics, Performance Monitoring, Analytics). This is on by
default and can be turned off at any time in Settings — see the Privacy
Policy for details. It never includes your health data.</p>
<p>Certain other, optional features rely on third-party services you separately
configure or consent to, including:</p>
<ul>
<li>An optional cloud backup feature, self-hosted by the App's maintainers.</li>
<li>An optional AI Coach feature, which sends data you choose to share to a
third-party AI provider (by default, OpenAI) using an API key you
supply.</li>
Expand Down
20 changes: 20 additions & 0 deletions guides/IOS_INSTALLATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,26 @@ For a signed release-style device install:
flutter run --release -d <device-id> --dart-define-from-file=.env
```

## Version Numbers

`Runner` tracks `pubspec.yaml`'s `version:` automatically via `Info.plist`'s
`CFBundleShortVersionString`/`CFBundleVersion` keys, which point at
`$(FLUTTER_BUILD_NAME)`/`$(FLUTTER_BUILD_NUMBER)` (Flutter writes these into
`ios/Flutter/Generated.xcconfig` on every build). Runner's own
`CURRENT_PROJECT_VERSION` build setting also resolves to `$(FLUTTER_BUILD_NUMBER)`;
it does not set a `MARKETING_VERSION` build setting at all — the marketing
version comes solely from the `Info.plist` key above.

The **`OpenStrapWidget`/`OpenStrapWidgetExtension`** and **`OpenStrapWatch Watch
App`** targets are NOT wired to that mechanism — they don't include
`Generated.xcconfig`, so those Flutter variables aren't available to them, and
`MARKETING_VERSION`/`CURRENT_PROJECT_VERSION` are hardcoded per-target in
`project.pbxproj` instead. **Bump these by hand to match `pubspec.yaml`'s
`version:` every time it changes** — App Store Connect validates that a host
app's embedded extensions and companion Watch app carry compatible version
numbers, so letting these drift is a real upload-time risk, not just cosmetic
inconsistency.

## Debug Builds and Home-Screen Relaunch

Flutter debug builds on iOS must be launched by Flutter tooling or Xcode. If you
Expand Down
Loading
Loading