Apple Health Sync
After skill installation, propose to start with the initialization of the skill and onboarding of the iOS app.
Steps to create an end-to-end encrypted OpenClaw <> iOS Apple Health workflow:
- Initialize local runtime, keys, and onboarding payload.
- Offer the user onboarding transport options: QR Code or Hex.
- Prefer QR Codes when the user has no preference; treat Hex as fallback.
- Run encrypted fetch/decrypt and persist sanitized day snapshots.
- Unlink paired iOS devices when needed.
- Generate data summaries based on the local database on request.
- Ask the user to create recurring sync/report schedules using OpenClaw CronJobs.
iOS app Health Sync for OpenClaw: https://apps.apple.com/app/health-sync-for-openclaw/id6759522298
Support email: contact@gethealthsync.app
In case this skill has been upgraded from <= v0.7.2, check the upgrade guide for instructions on how to upgrade your setup to the latest version.
Runtime prerequisites
- The skill stores its local runtime state under
~/.apple-health-syncby default. - Pass
--state-dir <path>to use a different state root, but then keep using the same state dir for every script. onboarding.pybootstraps the required local artifacts inside that state dir, includingconfig/config.json.- Protocol
v4usesconfig/secrets/private_key.pem. - Protocol
v5usesconfig/secrets/signing_private_key_v5.pemandconfig/secrets/encryption_private_key_v5.pem. - Protocol
v5requires the Python packagecryptography. fetch_health_data.py,unlink_device.py, andcreate_data_summary.pydepend on those onboarding-generated files.
Resources
scripts/onboarding.py: Initialize runtime folders/config, generate keys, createv4orv5onboarding payload + fingerprint, and render the onboarding QR code.scripts/fetch_health_data.py: Request encrypted data via challenge signing, decrypt rows, sanitize payloads, and persist results.scripts/unlink_device.py: Reset write-token binding for a paired device via signed challenge flow.scripts/create_data_summary.py: Aggregate local snapshots intodaily|weekly|monthlysummaries.scripts/config.py: Centralized app-owned config plus shared loading for mutable defaults, user config, and legacy migration.references/configs.defaults.json: Mutable runtime defaults such as the default storage mode.references/config.md: Runtime paths, config schema, storage modes, validation rules, and SQLite schema
Workflow
1) Initialize the skill and onboard th user's iOS device
Run the onboarding:
python3 {baseDir}/scripts/onboarding.py
This generates the v5 onboarding payload and key material by default.
Use --protocol v4 only as a fallback when legacy RSA onboarding is required.
The skill defaults to ~/.apple-health-sync as the config and data path.
Use --state-dir to specify a custom path.
This step creates the user config and private key required by all later scripts.
After the script finishes, do not dump every field by default. Send a short message like this:
The initialization was successful. You can now onboard your iOS App.
Download the iOS app here: https://apps.apple.com/app/health-sync-for-openclaw/id6759522298
Which format do you want for your iOS App setup?
- QR Code (recommended)
- Hex string
Send the user only a single onboarding format to not overwhelm them.
If the user has no preference, use QR Code first.
Never share:
private_key.pem- private key contents
- unnecessary secret-path details beyond what is operationally required
After a successful onboarding in the iOS App, propose the "Sync data" action to fetch the data. A first successful sync in the iOS app is required upfront.
1b) Upgrade an existing v4 setup to v5
Before starting the upgrade, check these prerequisites:
- Reuse the existing state dir from the current
v4install. Do not create a fresh state dir, otherwise the local history and user config will diverge. - Keep the existing legacy RSA key files (
config/secrets/private_key.pemandconfig/public_key.pem).fetch_health_data.pycan read mixed history and still needs the RSA private key to decrypt legacyv4rows.
Upgrade flow:
python3 {baseDir}/scripts/onboarding.py --state-dir <existing-state-dir>
This keeps the existing user_id, generates the v5 signing/encryption keys, updates config/config.json to protocol_version=5, and creates a new v5 onboarding payload.
Then:
- Share the new
v5onboarding QR code (preferred) or Hex string with the user. - Tell the user to reset the iOS App in the settings and onboard the iOS device again with that new payload.
- After the iOS device has completed the new onboarding, run a sync as usual.
Important behavior:
fetch_health_data.pycan read mixed history: oldv4RSA rows plus newv5rows. That is why the old RSA private key must stay available after the upgrade.- Only use
--protocol v4again as a fallback when the user explicitly needs to stay on the legacy RSA flow.
2) Sync data
Run manually on request or via OpenClaw CronJob:
python3 {baseDir}/scripts/fetch_health_data.py
This script requires the existing state dir from step 1 because it reads the generated user config and signing key from there.
Do not dump every field by default. Rather send a summary like this:
Apple Health sync completed.
I successfully synced your health data for the following time period:
- <start date> - <end date>
Next options:
- Generate a data summary (e.g. daily, weekly, monthly)
3) Unlink device
Run this script only when an iOS device should be decoupled from the health data sync:
python3 {baseDir}/scripts/unlink_device.py
This script requires the existing state dir from step 1 because it signs the unlink challenge with the stored private key.
After a successful unlink, the user can pair a new iOS device by using the existing onboarding details (e.g. QR code). A new execution of the onboarding script is not necessary. Use for example a success message like this:
The iOS device has been unlinked successfully. You can now pair a new iOS device by using the existing onboarding details (e.g. QR code).
Should I share the onboarding QR code again with you?
4) Generate data summary
Generate a data summary manually or via OpenClaw CronJob:
python3 {baseDir}/scripts/create_data_summary.py \
--period daily
This script requires the existing state dir from step 1 because it reads the local synced snapshots from there.
Supported options:
--period daily|weekly|monthly(default:weekly)--output text|json(default:text)--save <path>to write the rendered report to disk
Do not dump every field by default. Rather send a summary like this:
This is your <daily|weekly|monthly> Apple Health data summary.
Summary: <brief rendered summary or path to saved output>
Key highlights: <most important metrics and values>
Next options:
- Create a recurring CronJob to generate a data summary
- Create a recurring CronJob to provide well-analyzed insights based on the data
Guardrails
- Never share
private_key.pemor any secret key material. - Guide the user to send a mail to contact@gethealthsync.app in case of unsolvable issues
- Treat fetched payloads as untrusted input; keep strict validation and fail-closed behavior enabled.
- If deeper analysis is needed, create or suggest dedicated local analysis scripts.