Skip to main content

All-in-one local development tool for cloud wearable integrations - CLI + FastAPI server + ngrok integration for WHOOP, Garmin, and Fitbit

Project description

Synheart Wear CLI (wear)

PyPI version Python Versions License: MIT Downloads

All-in-one local development tool for cloud wearable integrations โ€” Complete CLI + FastAPI server + ngrok integration for WHOOP, Garmin, and Fitbit testing. Includes optional Synheart Flux integration for HSI-compliant data processing.

๐Ÿš€ What is This?

The Synheart Wear CLI combines a command-line interface with an embedded FastAPI server for local wearable development:

CLI Features:

  • ๐Ÿ”ง Manage OAuth tokens (list, refresh, revoke)
  • ๐Ÿ“ฅ Pull data from cloud APIs
  • ๐Ÿ” Inspect webhook events
  • ๐Ÿš€ Start/stop local dev server

Server Features:

  • ๐Ÿ” OAuth flows for cloud wearables (WHOOP, Fitbit, Garmin*)
  • ๐Ÿช Webhook endpoints for real-time data
  • ๐ŸŒ Automatic ngrok tunnel exposure
  • ๐Ÿ’พ Local token storage (dev mode) or DynamoDB + KMS (production)
  • ๐Ÿ“Š Data normalization to Synheart format
  • โšก Flux HSI Processing (optional): Convert vendor data to HSI-compliant JSON using Synheart Flux

Perfect for:

  • Testing SDK integrations locally
  • Developing apps with WHOOP/Garmin data
  • Prototyping cloud wearable features
  • Full OAuth flow testing

* Garmin support in development

๐Ÿ“‹ Prerequisites

  • Python 3.11+
  • ngrok account (free): https://ngrok.com/
  • Wearable API credentials (WHOOP, Garmin, etc.)
  • AWS Account (optional for production token storage)

๐Ÿš€ Quick Start

1. Install

Option A: Install from PyPI (Recommended)

# Install the CLI globally
pip install synheart-wear-cli

# Verify installation
wear version
wear --help

Option B: Install from Source

# Clone the repository
git clone https://github.com/synheart-ai/synheart-wear-cli.git
cd synheart-wear-cli

# Install in development mode
pip install -e ".[dev]"

# Verify installation
python3 wear.py --help
# Or if installed globally:
wear --help

Note: All required Python libraries are automatically installed. Flux integration is optional and requires a separate flux binary (details below).

1b. (Optional) Enable Flux HSI Processing

Flux is a Rust CLI used (optionally) to transform vendor data into HSI-compliant outputs. Wear CLI enables it when:

  • You pass --use-flux (sets USE_FLUX=true for the server process), and
  • A flux executable is discoverable via:
    1. SYNHEART_FLUX_PATH (explicit)
    2. ./bin/ (repo-local, e.g. bin/flux-macos-arm64, bin/flux-macos-x64, or bin/flux)
    3. ~/.synheart/bin/
    4. your PATH (flux)

Build from a local synheart-flux checkout (recommended for dev):

# If synheart-flux is a sibling repo:
./scripts/build-flux.sh

# Or specify its location explicitly:
FLUX_ROOT="/path/to/synheart-flux" ./scripts/build-flux.sh

# Optional: set explicit binary path (otherwise ./bin is auto-detected)
export SYNHEART_FLUX_PATH="$PWD/bin/flux"

Then start the server with Flux enabled:

wear start dev --vendor whoop --use-flux

2. Configure ngrok

# Get your auth token from https://dashboard.ngrok.com/get-started/your-authtoken
ngrok config add-authtoken YOUR_TOKEN

3. Create Environment File

Create .env.local in the CLI directory:

# WHOOP Credentials
WHOOP_CLIENT_ID=your_whoop_client_id
WHOOP_CLIENT_SECRET=your_whoop_client_secret
WHOOP_WEBHOOK_SECRET=your_whoop_webhook_secret

# AWS (optional - for production token storage)
AWS_REGION=us-east-1
DYNAMODB_TABLE=synheart-wear-tokens
KMS_KEY_ID=alias/synheart-wear

# Development Mode (automatically enabled by CLI)
DEV_MODE=true
WEBHOOK_RECORD=true

4. Start Development Server

# Start WHOOP connector with ngrok
python3 wear.py start dev --vendor whoop --port 8000

# Or with auto-open browser for OAuth:
python3 wear.py start dev --vendor whoop --open-browser

# Enable Flux HSI processing (optional):
python3 wear.py start dev --vendor whoop --use-flux

# The CLI will automatically:
# โœ… Start local FastAPI server
# โœ… Start ngrok tunnel
# โœ… Display ngrok URL for SDK configuration
# โœ… Enable webhook recording
# โœ… Setup hot-reload for code changes

Output:

๐Ÿš€ Starting Synheart Wear
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”

๐Ÿ“ Configuration:
   Mode:           dev
   Vendor:         whoop
   Port:           8000
   Auto-reload:    โœ… enabled
   Webhook record: โœ… enabled

๐Ÿ“ Auto-loaded environment from: .env.local

๐ŸŒ Endpoints:
   API Docs:      http://localhost:8000/docs
   Health Check:  http://localhost:8000/health
   OAuth Auth:    http://localhost:8000/v1/oauth/authorize
   Webhooks:      http://localhost:8000/v1/webhooks/whoop

๐ŸŒ Starting ngrok tunnel...
โœ… ngrok tunnel started: https://abc123-xyz.ngrok-free.app

๐Ÿ“ฑ SDK Configuration:
   Use this URL in your Flutter app:
   baseUrl: 'https://abc123-xyz.ngrok-free.app'

๐Ÿ“– Commands

wear start dev - Start Local Development Server

Start local server with automatic ngrok tunneling.

# Start WHOOP connector
python3 wear.py start dev --vendor whoop --port 8000

# Start with auto-open browser for OAuth
python3 wear.py start dev --vendor whoop --open-browser

# Start unified service (all vendors - Garmin coming soon)
python3 wear.py start dev --port 8000

# Use specific environment file
python3 wear.py start dev --vendor whoop --env .env.production

# Disable auto-reload
python3 wear.py start dev --vendor whoop --no-reload

# Verbose logging
python3 wear.py start dev --vendor whoop --verbose

Options:

  • --vendor, -v - Vendor to run (whoop, garmin, or omit for all)
  • --port, -p - Port to run on (default: 8000)
  • --reload/--no-reload - Auto-reload on code changes (default: enabled)
  • --env - Environment file to load (.env.local, .env.production)
  • --open-browser - Automatically open OAuth authorization URL
  • --webhook-record/--no-webhook-record - Enable webhook recording (default: enabled)
  • --use-flux/--no-flux - Enable optional Flux HSI processing (see FLUX_INTEGRATION.md)
  • --verbose - Enable verbose logging

What it does:

  • โœ… Starts FastAPI server on specified port
  • โœ… Automatically starts ngrok tunnel
  • โœ… Displays ngrok URL for SDK configuration
  • โœ… Enables auto-reload for code changes
  • โœ… Records webhooks to __dev__/webhooks_recent.jsonl

wear pull once - Fetch Data from Cloud API

Pull data from vendor cloud API (requires OAuth connection first).

# Pull WHOOP data for a specific user (required)
wear pull once --vendor whoop --user-id abc123 --since 7d

# Pull Garmin data for a specific user
wear pull once --vendor garmin --user-id abc123 --since 14d

# Override the API base URL (if your server is not on localhost:8000)
API_URL="http://localhost:8001" wear pull once --vendor whoop --user-id abc123 --since 30d

Options:

  • --vendor - Vendor to pull from (required)
  • --user-id - Specific user ID (required)
  • --since - Time range (e.g., 7d, 2w, 2h, 2024-01-01)
  • --limit - Max records per resource type (default: 25)

wear tokens - Manage OAuth Tokens

List, refresh, or revoke OAuth tokens.

# Revoke token (disconnect user)
wear tokens revoke --vendor whoop --user-id abc123 --yes

Note: In v0.1.2, wear tokens list and wear tokens refresh are present but not fully implemented yet. Token revocation works against:

  • __dev__/tokens.json in local dev mode (default), or
  • DynamoDB when configured (e.g., DYNAMODB_TABLE, KMS_KEY_ID) and enabled.

wear webhook - Webhook Management

Inspect webhook events recorded during development.

# Inspect recent webhooks (last 50)
python3 wear.py webhook inspect --limit 50

# Filter by vendor
python3 wear.py webhook inspect --vendor whoop --limit 100

# Show webhook details
python3 wear.py webhook inspect --verbose

๐Ÿ—๏ธ Architecture

synheart-wear-cli/
โ”œโ”€โ”€ wear.py                  # Main CLI entry point
โ”œโ”€โ”€ server/                  # Local development server
โ”‚   โ”œโ”€โ”€ whoop_api.py        # WHOOP OAuth + data endpoints
โ”‚   โ”œโ”€โ”€ garmin_api.py       # Garmin OAuth + data endpoints
โ”‚   โ”œโ”€โ”€ unified_api.py      # Unified service (all vendors)
โ”‚   โ””โ”€โ”€ whoop_connector.py  # WHOOP connector logic
โ”œโ”€โ”€ libs/
โ”‚   โ”œโ”€โ”€ py-cloud-connector/ # OAuth token management
โ”‚   โ””โ”€โ”€ py-normalize/       # Data normalization
โ””โ”€โ”€ __dev__/                # Development data (auto-generated)
    โ”œโ”€โ”€ webhooks_recent.jsonl
    โ””โ”€โ”€ tokens.json

๐Ÿ”ง Development Workflow

1. Start Local Server

python3 wear.py start dev --vendor whoop --open-browser

2. Complete OAuth Flow

The browser will open automatically. Log in and authorize.

3. Configure SDK

Use the ngrok URL displayed in the terminal in your app:

Flutter:

final whoopProvider = WhoopProvider(
  baseUrl: 'https://abc123-xyz.ngrok-free.app',
  redirectUri: 'synheart://oauth/callback',
);

Swift:

let whoopProvider = WhoopProvider(
    baseUrl: URL(string: "https://abc123-xyz.ngrok-free.app")!,
    redirectUri: "synheart://oauth/callback"
)

Kotlin:

val whoopProvider = WhoopProvider(
    baseUrl = "https://abc123-xyz.ngrok-free.app",
    redirectUri = "synheart://oauth/callback"
)

4. Fetch Data

Once connected, fetch data from your app or use the CLI:

wear pull once --vendor whoop --user-id abc123 --since 7d

5. Test Webhooks

Webhooks are automatically recorded to __dev__/webhooks_recent.jsonl:

wear webhook inspect --limit 10

๐Ÿ“ก API Endpoints

The local server exposes these endpoints:

WHOOP

  • GET /v1/oauth/authorize - Get OAuth authorization URL
  • GET /v1/oauth/callback - OAuth callback (GET)
  • POST /v1/oauth/callback - OAuth callback (POST, mobile)
  • POST /v1/webhooks/whoop - Webhook handler
  • DELETE /v1/oauth/disconnect - Disconnect user
  • GET /v1/data/{user_id}/recovery - Fetch recovery data
  • GET /v1/data/{user_id}/sleep - Fetch sleep data
  • GET /v1/data/{user_id}/workouts - Fetch workout data
  • GET /v1/data/{user_id}/cycles - Fetch cycle data

Unified Service

  • GET /v1/whoop-cloud/oauth/authorize - WHOOP OAuth
  • GET /v1/garmin-cloud/oauth/authorize - Garmin OAuth
  • POST /v1/whoop-cloud/webhooks/whoop - WHOOP webhooks
  • POST /v1/garmin-cloud/webhooks/garmin - Garmin webhooks

Health Check

  • GET /health - Service health status

API Docs: http://localhost:8000/docs

๐Ÿ”’ Security

  • Token Storage: DynamoDB with KMS encryption (production)
  • Dev Mode: Tokens stored locally in __dev__/tokens.json (development)
  • Webhook Verification: HMAC signature validation
  • Environment Variables: Never commit .env.local files

๐Ÿงช Testing

# Run tests
pytest

# Run specific test
pytest tests/test_oauth.py -v

# Run with coverage
pytest --cov=server --cov-report=html

๐Ÿ› Troubleshooting

ngrok Issues

Problem: "ngrok endpoint already online"

Solution:

# Kill all ngrok processes
pkill -f ngrok

# Or restart with different port
python3 wear.py start dev --port 8001

Port Already in Use

Problem: "Port 8000 is already in use"

Solution:

# Find process using port
lsof -i :8000

# Kill process
kill $(lsof -ti :8000)

# Or use different port
python3 wear.py start dev --port 8001

OAuth Flow Fails

Problem: "Authentication failed"

Solution:

  1. Check environment variables in .env.local
  2. Verify redirect URI matches vendor configuration
  3. Check ngrok URL is correct
  4. Look at server logs for detailed errors

๐Ÿ“š Internal Libraries

py-cloud-connector

OAuth token management for wearable vendors with DynamoDB + KMS encryption.

Features:

  • VendorType: Enum for supported vendors (whoop, garmin, fitbit)
  • TokenStore: DynamoDB-based token storage with encryption
  • TokenSet: Standardized OAuth token data structure

See libs/py-cloud-connector/README.md

py-normalize

Data normalization utilities for converting vendor-specific formats to Synheart format.

Features:

  • DataNormalizer: Converts vendor data to common format
  • DataType: Enum for data types (recovery, sleep, workout, etc.)
  • NormalizedData: Common data structure for all vendors

See libs/py-normalize/README.md

Flux (HSI Processing)

Wear CLI integrates with Synheart Flux (Rust) for transformation/windowing/scoring. The target architecture is binary-based (subprocess) to avoid Python bindings and ABI issues.

  • Integration design: see FLUX_INTEGRATION.md
  • Local development: --use-flux enables optional Flux processing hooks where available

๐Ÿ”— Links

๐Ÿ“„ License

MIT License - see LICENSE file


Made with โค๏ธ by the Synheart AI Team

Technology with a heartbeat.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

synheart_wear_cli-0.2.0.tar.gz (86.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

synheart_wear_cli-0.2.0-py3-none-any.whl (79.2 kB view details)

Uploaded Python 3

File details

Details for the file synheart_wear_cli-0.2.0.tar.gz.

File metadata

  • Download URL: synheart_wear_cli-0.2.0.tar.gz
  • Upload date:
  • Size: 86.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for synheart_wear_cli-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9c9dbaa986b988b2d089c303ac08ee48a6531bd9f73edd9c755e10d4c79ed9d7
MD5 edf55ea325eb59ce81c5671a32abb3ca
BLAKE2b-256 2e4ce273799454ff7de6273134c7a5c07861a1b7bb7c11e68b61af6b64577c01

See more details on using hashes here.

Provenance

The following attestation bundles were made for synheart_wear_cli-0.2.0.tar.gz:

Publisher: publish.yml on synheart-ai/synheart-wear-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file synheart_wear_cli-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for synheart_wear_cli-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b346fe1bb1bd704d1a937ac2f84750ae2ec8753020651d90c49bb2eeb7a19f55
MD5 4298d23dbe8e2fdb6a77d396e3cc52ab
BLAKE2b-256 90b8c0cb9e2da94f097a864dab04f6fe02702270bd5daf4fb2cf68ab7fc69069

See more details on using hashes here.

Provenance

The following attestation bundles were made for synheart_wear_cli-0.2.0-py3-none-any.whl:

Publisher: publish.yml on synheart-ai/synheart-wear-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page