Skip to content

Repository files navigation

MyWellWallet

Flutter app for personal health data: MedGemma runs on the phone, FHIR comes in over MCP, and Apple Health adds day-to-day readings next to clinic data.

Flutter Dart License


What we are building

We started with small Gemma-style models for local inference. The app now targets MedGemma (a clinical Gemma variant) so inference can stay on the device.

Privacy. Prompts, FHIR JSON, and Apple Health-backed rows can stay on the phone when you use the full local path. You do not need a cloud LLM for that mode.

Why local on a phone. Phones sit idle a lot of the time. The app only does heavy work when you use it, so it can use spare CPU/GPU without paying for a server per user.

The phone stores EHR-style FHIR (from your MCP server) and Apple Health metrics in SQLite so queries and RAG can use both clinic records and home or wearable data.


Apple Health and the FHIR server

Apple Health (iOS). The app reads HealthKit metrics (glucose, heart rate, steps, blood pressure) into SQLite. It also pulls Clinical Health Records FHIR payloads for institutional lab results (e.g. Sonora Quest, Quest Diagnostics hospitals on Apple Health Accounts) via a native iOS helper that queries HKClinicalRecord labResultRecord samples—not only the Dart health package. Labs are stored in health_lab_results (LOINC, value, units, reference range, source, draw time).

Labs in the UI. Health → Lab results shows the latest value per analyte (grouped by LOINC when present). Tap a row for a clinician-style history table (up to twelve prior draws): date/time, result, reference range, in-range flag, Δ vs prior reading, source. Connect Apple Health under Profile, run Sync now, and approve Clinical Records lab access when iOS prompts.

iOS Info.plist. In addition to NSHealthShareUsageDescription / NSHealthUpdateUsageDescription, NSHealthClinicalHealthRecordsShareUsageDescription must be present. HealthKit terminates the process if you request HKClinicalType lab-authorization without that key—it is wired in ios/Runner/Info.plist. Entitlements include health-records; native parsing lives in ios/Runner/ClinicalHealthRecordsPlugin.swift, bridged via lib/services/clinical_lab_results_channel.dart.

See docs/SQLITE_SCHEMA.md and docs/INTEGRATED_HEALTH_EHR_DESIGN.md for tables and how EHR and Apple data fit together.

MCP and FHIR. The app includes an MCP (Model Context Protocol) client that talks to an MCP FHIR server built for this project. The server exposes FHIR resources (Patient, Observation, bundles, etc.) as MCP tools. The client pulls data, stores it in SQLite (fhir_patients, fhir_resources, fetch_summaries), and feeds it into query and RAG code.

Two paths into SQLite.

  • FHIR from the server: MCP sync → SQLite.
  • Apple Health: HealthKit → app service → SQLite (health_* tables, keyed by app user id).

docs/INTEGRATED_HEALTH_EHR_DESIGN.md explains how we merge or tag EHR JSON and Apple-derived facts so the model can tell chart data from device data.


How the on-device model works

  1. Weights. MedGemma 4B is shipped as a GGUF file. The download URL is in AppConfig.gemmaModelUrl inside lib/config/app_config.dart. The file is large and is not stored in git.

  2. Download. On iOS and Android the app starts background_downloader at launch so the GGUF can download in the background with sensible timeouts. See lib/main.dart and lib/services/gemma_model_service.dart.

  3. Load and run. llamadart loads the GGUF into a LlamaEngine. We cap context size, GPU layers, batch sizes, and output length so phones do not run out of memory. Details: docs/MEDGEMMA_AND_MEMORY_CAPS.md.

  4. Queries. GemmaModelService handles download and load. GemmaRAGService and LocalQueryService pull text from SQLite (FHIR plus optional merged Apple Health) for retrieval-augmented prompts.

  5. Home screen. You type or dictate questions; QueryProvider ties requests to the current user (appUserId) and FHIR patient id where applicable.

┌──────────────────┐     ┌─────────────────────┐
│ MCP FHIR server  │     │ Apple HealthKit     │
└────────┬─────────┘     └──────────┬──────────┘
         │ MCP client                │ Health sync
         ▼                           ▼
┌─────────────────────────────────────────────────┐
│ SQLite: users, fhir_*, health_* (incl. health_lab_results labs) │
└────────────────────────┬────────────────────────┘
                         │ LocalQueryService / RAG
                         ▼
┌─────────────────────────────────────────────────┐
│ MedGemma (llamadart) on the phone                 │
└─────────────────────────────────────────────────┘

Test database and Dify. To copy this SQLite onto a simulator or phone, or to export CSV/Markdown for Dify, read docs/DATABASE_FIXTURE_TESTING_AND_DIFY.md.


Where the code lives

Topic Paths
MCP client, routing, state lib/main.dart, lib/services/mcp_client.dart, lib/providers/
MedGemma, download, memory limits lib/services/gemma_model_service.dart, docs/MEDGEMMA_AND_MEMORY_CAPS.md
Apple Health → SQLite (vitals + clinical lab FHIR) lib/services/apple_health_service.dart, ios/Runner/ClinicalHealthRecordsPlugin.swift, lib/services/clinical_lab_results_channel.dart, lib/screens/health_lab_results_screen.dart, lib/screens/health_lab_detail_screen.dart, lib/services/database_service.dart
EHR + Apple design docs/INTEGRATED_HEALTH_EHR_DESIGN.md
Server URL and model URL lib/config/app_config.dart

Getting started

You need Flutter 3.8+, Dart 3.8+, Xcode for iOS, and the Android SDK for Android.

git clone https://github.com/maheshbalan/myWellWallet.git
cd myWellWallet
flutter pub get
dart run build_runner build --delete-conflicting-outputs
flutter pub run flutter_launcher_icons
flutter run

In-place installs (preserve data). Updating the same app on the phone replaces only the application bundle—not the app’s Documents / Library sandbox—so your SQLite database, registered users row, downloaded MedGemma weights, and other local files stay intact, as long as you do not delete the app icon first and the bundle identifier stays com.mywellwallet.mywellwallet.

  • Recommended: flutter run --release -d <device_id> after flutter devices (or Xcode → open ios/Runner.xcworkspace → select your iPhone → Run). This installs a signed build over the existing app. Append --no-resident if you only want install/launch without keeping the tooling attached (flutter run --release -d <device_id> --no-resident).
  • Avoid flutter install for upgrades if you see it log “Uninstalling old version…”—that step can remove local data. If you only have the CLI, use flutter run --release instead of flutter install.

Physical iPhone. Use flutter run --release when running with the native ML stack; see docs/IOS_DEBUG_CRASH.md if debug builds crash.

Apple Health. See docs/APPLE_HEALTH_SETUP.md (HealthKit, Profile → Apple Health, sync interval). Add participating providers under Apple Health → Browse → Add Account so Clinical lab records can sync before you open Lab results.

MCP base URL. Edit mcpBaseUrl in lib/config/app_config.dart.


Security and privacy

  • MCP traffic should use TLS.
  • If MedGemma runs fully on-device, that path does not require a cloud LLM.
  • FHIR and Apple Health rows live in SQLite on the device first.
  • The app is a client of your MCP FHIR server; access rules live on the server side.

Research next steps

1. FLAI and federated learning

We want the wallet to join a federated learning setup called FLAI, developed with Eli Yune at Balkeum Labs. Devices would send updates such as gradients or summaries instead of sending raw PHI, which matches the on-device privacy goal.

Presented at ICCE 2026 (44th IEEE International Conference on Consumer Electronics), Dubai, February 2026. Conference site.

Paper (PDF): FLAI, IEEE ICCE authored copy (Dropbox)


2. Federated LoRA for local models

We are also looking at federated LoRA (low-rank adapters) for models like MedGemma. The full weights stay fixed; small adapter matrices are trained or combined across participants. That cuts upload size versus full-model federated learning and still fits a local GGUF plus adapter layout on the phone.

A paper on this topic has been submitted to BCCA, Barcelona, November 2026.


3. Harness work (summer 2026)

Planned work includes a harness around the local model:

  • A knowledge graph for diseases, drugs, guideline snippets, and patient facts, used for lookup next to the neural model.
  • A rules layer that checks model output against stored protocols (paths, contraindications, numeric bands where we encode them). This is for research demos only; it is not medical advice.
  • Per-condition configs (for example diabetes, heart disease, cancer) that turn on different graph slices, rules, and RAG sources so one app build can focus the harness without splitting the whole codebase.

The idea is to pair neural output with explicit clinical structure on top of the current SQLite + FHIR + Apple Health stack.


Multi–local-LLM evaluation (CGU IST 345)

A separate class project (team: Mahesh Balan, Yashas Basavaraj Mahesh, Prajwal Vinod Naik, Brandon Medina) compares several on-device models (Gemma 3, Phi-3, MedGemma tiers) using Dify as the evaluation harness, focused on Type 2 diabetes scenarios and synthetic FHIR + RWE data. It does not replace the main app; it lives under:

projects/local-llm-evaluation/ — proposal summary, Dify checklists, eval test-set layout, model matrix, and results layout.


Contributing, license, author

Pull requests welcome. Please run flutter analyze before you submit.


Thanks

Thanks to the Flutter and Dart teams, the FHIR community, the llamadart project and open medical model publishers, and co-authors and partners on federated learning and mobile health work.


Issues

github.com/maheshbalan/myWellWallet/issues

Releases

Packages

Contributors

Languages