{"id":49768671,"url":"https://github.com/mandarnilange/health_forge","last_synced_at":"2026-05-11T11:31:33.927Z","repository":{"id":354849403,"uuid":"1225449281","full_name":"mandarnilange/health_forge","owner":"mandarnilange","description":"Federated, zero-backend Flutter toolkit aggregating health data   (HealthKit, Health Connect, Oura, Strava) into a unified model with conflict resolution — without losing provider-specific   metrics.","archived":false,"fork":false,"pushed_at":"2026-04-30T12:36:58.000Z","size":321,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-30T14:17:31.067Z","etag":null,"topics":["dart","federated","fitness","flutter","health","health-connect","health-data","healthkit","melos","monorepo","oauth2","oura","pub-dev","sleep-tracking","strava","wearables"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/health_forge","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mandarnilange.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-30T09:36:12.000Z","updated_at":"2026-04-30T12:24:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/mandarnilange/health_forge","commit_stats":null,"previous_names":["mandarnilange/health_forge"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/mandarnilange/health_forge","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandarnilange%2Fhealth_forge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandarnilange%2Fhealth_forge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandarnilange%2Fhealth_forge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandarnilange%2Fhealth_forge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mandarnilange","download_url":"https://codeload.github.com/mandarnilange/health_forge/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mandarnilange%2Fhealth_forge/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32893110,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-10T13:40:02.631Z","status":"online","status_checked_at":"2026-05-11T02:00:05.975Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","federated","fitness","flutter","health","health-connect","health-data","healthkit","melos","monorepo","oauth2","oura","pub-dev","sleep-tracking","strava","wearables"],"created_at":"2026-05-11T11:31:33.219Z","updated_at":"2026-05-11T11:31:33.918Z","avatar_url":"https://github.com/mandarnilange.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Health Forge\n\n[![CI](https://img.shields.io/github/actions/workflow/status/mandarnilange/health_forge/ci.yaml?branch=main\u0026label=CI)](https://github.com/mandarnilange/health_forge/actions/workflows/ci.yaml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Dart](https://img.shields.io/badge/dart-%3E%3D3.6.0-0175C2.svg)](https://dart.dev)\n[![Flutter](https://img.shields.io/badge/flutter-%3E%3D3.27.0-02569B.svg)](https://flutter.dev)\n[![style: very_good_analysis](https://img.shields.io/badge/style-very__good__analysis-B22C89.svg)](https://pub.dev/packages/very_good_analysis)\n[![melos](https://img.shields.io/badge/maintained%20with-melos-f700ff.svg)](https://github.com/invertase/melos)\n\nA federated, zero-backend Flutter toolkit for aggregating health data from multiple providers into a unified data model — without losing provider-specific metrics.\n\n## Why Health Forge?\n\nThe Flutter health ecosystem is fragmented:\n\n| Approach | Problem |\n|----------|---------|\n| `health` package | Strips provider-specific metrics (Oura readiness, Strava suffer score) |\n| Individual provider wrappers | Inconsistent APIs, incomplete coverage, some GPL-licensed |\n| Commercial SDKs | Vendor lock-in, backend required, closed source |\n\n**Health Forge** solves this with a unified model that preserves every metric, a built-in conflict resolution engine for multi-source data, and a federated architecture where you only depend on the providers you use.\n\n## Features\n\n- **Unified data model** — 21 record types across 6 families (activity, cardiovascular, sleep, recovery, respiratory, body)\n- **Provider-specific extensions** — type-safe access to Oura readiness scores, Strava suffer scores, Garmin body battery, etc.\n- **Conflict resolution engine** — 5 strategies for deduplicating and merging overlapping records from multiple providers\n- **Pure Dart core** — isolate-safe, zero Flutter dependencies in the core package\n- **Federated architecture** — only pull the provider packages you need\n- **MIT licensed** — no GPL contamination\n\n## Packages\n\n| Package | Version | Description | Status |\n|---------|---------|-------------|--------|\n| [`health_forge_core`](https://pub.dev/packages/health_forge_core) | [![pub](https://img.shields.io/pub/v/health_forge_core.svg)](https://pub.dev/packages/health_forge_core) | Models, enums, interfaces, merge engine (pure Dart) | Available |\n| [`health_forge`](https://pub.dev/packages/health_forge) | [![pub](https://img.shields.io/pub/v/health_forge.svg)](https://pub.dev/packages/health_forge) | Flutter client: registry, auth, queries, cache | Available |\n| [`health_forge_apple`](https://pub.dev/packages/health_forge_apple) | [![pub](https://img.shields.io/pub/v/health_forge_apple.svg)](https://pub.dev/packages/health_forge_apple) | Apple HealthKit adapter (14 metric types) | Available |\n| [`health_forge_ghc`](https://pub.dev/packages/health_forge_ghc) | [![pub](https://img.shields.io/pub/v/health_forge_ghc.svg)](https://pub.dev/packages/health_forge_ghc) | Google Health Connect adapter (14 metric types) | Available |\n| [`health_forge_oura`](https://pub.dev/packages/health_forge_oura) | [![pub](https://img.shields.io/pub/v/health_forge_oura.svg)](https://pub.dev/packages/health_forge_oura) | Oura Ring REST API adapter (8 metric types) | Available (not yet tested end-to-end) |\n| [`health_forge_strava`](https://pub.dev/packages/health_forge_strava) | [![pub](https://img.shields.io/pub/v/health_forge_strava.svg)](https://pub.dev/packages/health_forge_strava) | Strava REST API adapter (5 metric types) | Available (not yet tested end-to-end) |\n| `health_forge_garmin` | — | Garmin adapter | Planned (next) |\n\n## Quick Start\n\n\u003e For a comprehensive guide covering platform setup, OAuth configuration, provider-specific extensions, and conflict resolution — see **[docs/getting_started.md](docs/getting_started.md)**.\n\u003e\n\u003e **Note:** Health Forge is in active development. The core data model, Flutter client, and Apple/GHC adapters are functional and device-tested. The Oura and Strava adapters are code-complete with full unit test coverage but have **not yet been tested end-to-end against live APIs**. Garmin adapter is planned.\n\n### Installation\n\nAdd only the packages you need:\n\n```yaml\ndependencies:\n  health_forge: ^0.1.1\n  health_forge_apple: ^0.1.1   # iOS — HealthKit\n  health_forge_ghc: ^0.1.1     # Android — Health Connect\n  health_forge_oura: ^0.1.1    # Oura Ring — REST API\n  health_forge_strava: ^0.1.1  # Strava — REST API\n```\n\n### Usage\n\n```dart\nimport 'package:health_forge/health_forge.dart';\nimport 'package:health_forge_apple/health_forge_apple.dart';\nimport 'package:health_forge_ghc/health_forge_ghc.dart';\n\nfinal forge = HealthForgeClient();\n\n// Register providers\nforge.use(AppleHealthProvider());\nforge.use(GhcHealthProvider());\n\n// Authorize all registered providers\nfinal authResults = await forge.auth.authorizeAll();\n\n// Build and execute a query\nfinal builder = forge.query()\n  ..forMetrics([MetricType.heartRate, MetricType.sleepSession])\n  ..inRange(TimeRange(\n    start: DateTime.now().subtract(const Duration(days: 7)),\n    end: DateTime.now(),\n  ));\n\nfinal executor = QueryExecutor(\n  registry: forge.registry,\n  mergeEngine: MergeEngine(config: const MergeConfig()),\n);\nfinal result = await executor.execute(builder.build());\n\n// Access unified records\nfor (final record in result.records) {\n  print('${record.provider}: ${record.providerRecordType}');\n}\n\n// Sync data to local cache\nawait forge.sync(\n  provider: DataProvider.apple,\n  metric: MetricType.heartRate,\n  range: TimeRange(\n    start: DateTime.now().subtract(const Duration(days: 1)),\n    end: DateTime.now(),\n  ),\n);\n```\n\n## Agent Skills\n\nHealth Forge ships a set of [Agent Skills](https://skills.sh) so AI coding agents (Claude Code, Cursor, Codex, OpenCode, and 50+ others) can integrate the packages into a Flutter app on your behalf.\n\n```bash\n# Install all skills into the current project\nnpx skills add mandarnilange/health_forge\n\n# Or install just the skill for the package you're using\nnpx skills add mandarnilange/health_forge --skill integrate-health-forge-oura\n\n# List available skills\nnpx skills add mandarnilange/health_forge --list\n```\n\n| Skill | When the agent triggers it |\n|---|---|\n| `integrate-health-forge` | Building a Flutter app aggregating multi-provider health data |\n| `integrate-health-forge-core` | Pure-Dart use (server, isolate, custom provider) |\n| `integrate-health-forge-apple` | Apple HealthKit on iOS |\n| `integrate-health-forge-ghc` | Google Health Connect on Android |\n| `integrate-health-forge-oura` | Oura Ring REST API |\n| `integrate-health-forge-strava` | Strava REST API |\n\nSee [`skills/`](skills/) for the source recipes.\n\n## Data Model\n\n### Record Families\n\n| Family | Records |\n|--------|---------|\n| **Activity** | ActivitySession, WorkoutRoute, StepCount, DistanceSample, CaloriesBurned, ElevationGain |\n| **Cardiovascular** | HeartRateSample, RestingHeartRate, HeartRateVariability |\n| **Sleep** | SleepSession, SleepStageSegment, SleepScore |\n| **Recovery** | ReadinessScore, StressScore, RecoveryMetric |\n| **Respiratory** | RespiratoryRate, BloodOxygenSample |\n| **Body** | Weight, BodyFat, BloodPressure, BloodGlucose |\n\nEvery record implements `HealthRecordMixin`, providing a consistent envelope with provider, timestamps, provenance, and type-safe extension slots.\n\n### Conflict Resolution\n\nWhen multiple providers report overlapping data (e.g., Apple Watch and Oura both tracking sleep), Health Forge's merge engine groups likely duplicates by **metric type** and **time overlap** (configurable threshold), then resolves each group using configurable strategies:\n\n| Strategy | Behavior |\n|----------|----------|\n| **Priority-based** | Pick from the highest-priority provider per metric |\n| **Keep all** | Preserve all records with attribution and conflict report |\n| **Average** | Average numeric values across providers |\n| **Most granular** | Keep the record with highest temporal resolution |\n| **Custom** | Your own resolution callback |\n\n## Architecture\n\n```\nhealth_forge_core (pure Dart)\n    ├── enums/          7 enum types\n    ├── models/         21 record types + envelope\n    ├── interfaces/     HealthProvider, ProviderCapabilities\n    └── merge/          MergeEngine + 5 strategies\n\nhealth_forge (Flutter)\n    ├── HealthForgeClient      main entry point\n    ├── ProviderRegistry       register/discover providers\n    ├── AuthOrchestrator       authorize/deauthorize flows\n    ├── QueryBuilder/Executor  fluent query API\n    ├── CacheManager           InMemory or DriftCacheManager (SQLite)\n    ├── SyncManager            sync coordination + dedup\n    └── TokenStore             secure OAuth token persistence\n\nhealth_forge_apple / health_forge_ghc\n    ├── {Provider}HealthProvider   implements HealthProvider\n    ├── {Provider}Capabilities     14 supported metrics\n    ├── HealthDataRecord           platform-agnostic DTO\n    └── mappers/                   5 mapper classes per provider\n\nhealth_forge_oura (REST API adapter)\n    ├── OuraHealthProvider         implements HealthProvider (8 metrics)\n    ├── auth/                      OAuth 2.0 PKCE + token management\n    ├── api/                       Dio client + rate limiter + pagination\n    ├── models/                    7 response DTOs\n    └── mappers/                   7 mapper classes\n\nhealth_forge_strava (REST API adapter)\n    ├── StravaHealthProvider       implements HealthProvider (5 metrics)\n    ├── auth/                      OAuth 2.0 PKCE + client_secret\n    ├── api/                       Dio client + dual rate limiter + page pagination\n    ├── models/                    3 response DTOs (bare array support)\n    └── mappers/                   5 mapper classes (kJ→kcal, streams→HR)\n\nexample/ (Flutter demo app)\n    ├── Real OAuth                 Oura PKCE + Strava OAuth via deep links\n    ├── Mock providers             Apple + Oura + Strava with fake data (desktop)\n    ├── Dashboard                  10 metric cards with source-aware aggregation\n    ├── Provider Status            Auth management with local state tracking\n    └── Data Browser               Query by MetricType + date range + detail sheet\n```\n\nSee `design/adr/` for architectural decision records.\n\n## Development\n\n### Prerequisites\n\n- Dart SDK \u003e= 3.6.0\n- Flutter \u003e= 3.27.0 (for Flutter packages)\n- Melos (`dart pub global activate melos`)\n\n### Setup\n\n```bash\ngit clone https://github.com/mandarnilange/health_forge.git\ncd health_forge\ndart pub get\ndart run melos bootstrap\n```\n\n### Common Commands\n\n```bash\ndart run melos run analyze    # Lint all packages (zero warnings required)\ndart run melos run test       # Run all tests\ndart run melos run test:coverage   # Packages only; writes coverage/lcov.info per package (example excluded)\ndart run melos run coverage:verify # ≥90% line coverage per packages/* (same excludes as CI; example not gated)\nbash tool/merge_lcov.sh      # Requires `lcov` on PATH; merges package lcov into coverage/lcov.info\ndart run melos run format     # Check formatting\ndart run melos run generate   # Run code generation (freezed, json_serializable)\n```\n\n### Contributing\n\n- Follow TDD: write a failing test before implementing\n- Run `dart run melos run analyze` — zero warnings required\n- CI requires **≥90% line coverage per package** under `packages/` (after excluding `*.g.dart` / `*.freezed.dart` / `*.part.dart`, and the declarative Drift schema file `health_cache_database.dart` in `health_forge`). The **example** app is not included in that gate; run `cd example \u0026\u0026 flutter test` separately. Use `dart run melos run coverage:verify` locally (optional: `COVERAGE_MIN_PERCENT=85`).\n- Architecture changes need an ADR in `design/adr/`\n- No Flutter imports in `health_forge_core`\n- No GPL dependencies\n\n## License\n\nMIT — see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandarnilange%2Fhealth_forge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmandarnilange%2Fhealth_forge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmandarnilange%2Fhealth_forge/lists"}