medgemma-vault 0.1.0
Local FHIR-based Personal Health Record
Requires Python: >=3.10

# medgemma-vault

A local-first personal health record backed by [FHIR R4](https://hl7.org/fhir/R4/) and SQLite. All data stays on your machine in a single database file at `~/.medgemma/vault.db`. Records are stored as validated FHIR R4 JSON, making them portable and interoperable with any FHIR-compatible system.

The optional [medgemma](https://github.com/chibokocl/medgemma) AI engine can be added for natural-language queries against your records, but the vault works standalone as a pure health record store.

## Features

- **FHIR R4 compliant** — every record is a validated FHIR resource (Patient, Observation, MedicationStatement, Condition, AllergyIntolerance, Procedure, DocumentReference)
- **SQLite storage** — single-file database with WAL mode, no server required
- **CLI interface** — manage records, import data, and export FHIR Bundles from the terminal
- **Apple Health import** — stream-parse large `export.xml` files with memory-efficient `iterparse`
- **CSV and JSON import** — bring in data from spreadsheets or existing FHIR Bundles
- **Document storage** — attach images, PDFs, and other files as FHIR DocumentReferences with content-hash deduplication
- **FHIR Bundle export** — export your entire record as a standard FHIR Bundle JSON
- **Optional AI queries** — ask natural-language questions about your health data (requires medgemma)

## Requirements

- Python 3.10+

## Installation

```bash
# Clone the repository
git clone git@github.com:chibokocl/medgemma-vault.git
cd medgemma-vault

# Install in editable mode
pip install -e .

# Or with AI features (requires medgemma)
pip install -e ".[ai]"

# Or with development dependencies
pip install -e ".[dev]"
```

## Quick start

### 1. Initialise the vault

Create the database and set up your patient profile:

```bash
medgemma-vault init --given-name Jane --family-name Doe
```

You can also provide optional flags:

```bash
medgemma-vault init \
  --given-name Jane \
  --family-name Doe \
  --birth-date 1990-05-15 \
  --gender female
```

If you omit `--given-name` or `--family-name`, the CLI will prompt you interactively.

### 2. Add records

```bash
# Vital signs
medgemma-vault add vitals --type weight --value 68.5
medgemma-vault add vitals --type heart_rate --value 72
medgemma-vault add vitals --type blood_pressure_systolic --value 120
medgemma-vault add vitals --type blood_glucose --value 95 --date 2024-06-01

# Medications
medgemma-vault add medication --name Metformin --dosage "500mg twice daily"
medgemma-vault add medication --name Aspirin --dosage "100mg daily" --status active

# Conditions
medgemma-vault add condition --name "Type 2 Diabetes"
medgemma-vault add condition --name "Seasonal allergies" --status active

# Clinical notes
medgemma-vault add note --text "Felt dizzy after lunch, resolved after 30 minutes"

# Documents (images, PDFs, etc.)
medgemma-vault add document chest-xray.png -d "Chest X-ray 2024"
medgemma-vault add document blood-work.pdf -d "Annual blood work results"
```

### 3. View records

```bash
# List all records
medgemma-vault list

# Filter by resource type
medgemma-vault list --type Observation
medgemma-vault list --type MedicationStatement

# Filter by date
medgemma-vault list --since 2024-01-01

# Limit results
medgemma-vault list --type Observation --limit 10

# Show full FHIR JSON for a specific record
medgemma-vault show <resource-id>

# Summary counts
medgemma-vault stats
```

### 4. Export

```bash
# Print FHIR Bundle to stdout
medgemma-vault export

# Save to file
medgemma-vault export -o my-records.json
```

The export produces a standard FHIR Bundle of type `collection` containing all resources in your vault.

## Importing data

### Apple Health

Export your data from the Apple Health app on iPhone (Health > profile picture > Export All Health Data), then:

```bash
medgemma-vault import apple-health export.xml
```

The adapter uses streaming XML parsing (`iterparse` with `elem.clear()`) so it can handle large export files without loading them entirely into memory. Units are automatically converted (e.g. lbs to kg, Fahrenheit to Celsius).

**Supported Apple Health types:**

| Apple Health Identifier | Mapped vital type |
|---|---|
| `HKQuantityTypeIdentifierBodyMass` | `weight` |
| `HKQuantityTypeIdentifierHeight` | `height` |
| `HKQuantityTypeIdentifierHeartRate` | `heart_rate` |
| `HKQuantityTypeIdentifierBloodPressureSystolic` | `blood_pressure_systolic` |
| `HKQuantityTypeIdentifierBloodPressureDiastolic` | `blood_pressure_diastolic` |
| `HKQuantityTypeIdentifierBodyTemperature` | `temperature` |
| `HKQuantityTypeIdentifierRespiratoryRate` | `respiratory_rate` |
| `HKQuantityTypeIdentifierOxygenSaturation` | `oxygen_saturation` |
| `HKQuantityTypeIdentifierBodyMassIndex` | `bmi` |
| `HKQuantityTypeIdentifierBloodGlucose` | `blood_glucose` |

### CSV

```bash
medgemma-vault import csv vitals.csv
```

Expected CSV format:

```csv
type,value,date
weight,72.5,2024-06-01
heart_rate,68,2024-06-02
blood_glucose,95,2024-06-03
```

The `type` column must be one of the supported vital types (see table below). Rows with unknown types or invalid values are skipped.

### JSON / FHIR Bundle

```bash
medgemma-vault import json records.json
```

Accepts either a single FHIR resource or a FHIR Bundle. Resources are validated against the FHIR R4B schema before being stored.

## Supported vital types

These can be used with `medgemma-vault add vitals --type <type>`:

| Type | LOINC Code | Display | Unit |
|---|---|---|---|
| `weight` | 29463-7 | Body weight | kg |
| `height` | 8302-2 | Body height | cm |
| `heart_rate` | 8867-4 | Heart rate | beats/minute |
| `blood_pressure_systolic` | 8480-6 | Systolic blood pressure | mmHg |
| `blood_pressure_diastolic` | 8462-4 | Diastolic blood pressure | mmHg |
| `temperature` | 8310-5 | Body temperature | C |
| `respiratory_rate` | 9279-1 | Respiratory rate | breaths/minute |
| `oxygen_saturation` | 2708-6 | Oxygen saturation | % |
| `bmi` | 39156-5 | Body mass index | kg/m2 |
| `blood_glucose` | 2339-0 | Glucose [Mass/volume] in Blood | mg/dL |

## CLI reference

| Command | Description |
|---|---|
| `medgemma-vault init` | Create DB and patient profile (prompts for name) |
| `medgemma-vault add vitals --type <type> --value <n>` | Add a vital sign observation |
| `medgemma-vault add medication --name <name> [--dosage <text>]` | Add a medication statement |
| `medgemma-vault add condition --name <name>` | Add a condition |
| `medgemma-vault add note --text <text>` | Add a clinical note |
| `medgemma-vault add document <file> [-d <description>]` | Upload an image or PDF |
| `medgemma-vault import apple-health <file>` | Import Apple Health export.xml |
| `medgemma-vault import csv <file>` | Import observations from CSV |
| `medgemma-vault import json <file>` | Import FHIR JSON or Bundle |
| `medgemma-vault list [--type <type>] [--since <date>]` | List records |
| `medgemma-vault show <id>` | Show full FHIR JSON for a record |
| `medgemma-vault export [-o <file>]` | Export all records as a FHIR Bundle |
| `medgemma-vault stats` | Show summary counts by resource type |
| `medgemma-vault ask "<question>"` | AI query (requires medgemma) |

## Architecture

```
medgemma-vault/
├── pyproject.toml
├── src/medgemma_vault/
│   ├── __init__.py
│   ├── __main__.py          # python -m medgemma_vault
│   ├── _version.py           # 0.1.0
│   ├── config.py              # paths, LOINC codes, Apple Health mapping
│   ├── db.py                  # SQLite connection, schema, low-level CRUD
│   ├── store.py               # VaultStore facade (high-level CRUD)
│   ├── models.py              # FHIR R4B resource builders + validation
│   ├── cli.py                 # Click CLI commands
│   ├── agent.py               # optional medgemma AI integration
│   └── adapters/
│       ├── base.py            # BaseAdapter ABC
│       ├── apple_health.py    # Apple Health XML adapter
│       ├── csv_import.py      # CSV adapter
│       ├── json_import.py     # JSON/FHIR Bundle adapter
│       └── document.py        # image/PDF adapter
└── tests/
    ├── conftest.py
    ├── test_config.py
    ├── test_db.py
    ├── test_models.py
    ├── test_store.py
    ├── test_cli.py
    └── test_adapters/
        ├── test_apple_health.py
        ├── test_csv_import.py
        └── test_document.py
```

### Data flow

```
CLI / Adapter
      │
      ▼
  VaultStore          (store.py — high-level facade)
      │
      ├──► models.py  (build + validate FHIR resources)
      │
      ▼
    db.py             (SQLite CRUD)
      │
      ▼
  ~/.medgemma/vault.db
```

### Database schema

The SQLite database has three tables:

**`resources`** — one row per FHIR resource, data stored as JSON:
- `id` (TEXT PK) — FHIR resource ID (UUID)
- `resource_type` (TEXT) — e.g. "Patient", "Observation"
- `patient_id` (TEXT) — reference to the owning Patient
- `recorded_date` (TEXT) — effective/recorded date for filtering
- `source` (TEXT) — origin of the record ("manual", "apple_health", "csv", etc.)
- `data` (TEXT) — full FHIR resource as JSON
- `created_at`, `updated_at` (TEXT) — ISO timestamps

**`documents`** — file metadata linked to DocumentReference resources:
- `id` (TEXT PK)
- `resource_id` (TEXT FK) — references `resources.id`
- `file_path`, `mime_type`, `sha256`, `file_size`

**`meta`** — key-value store for schema version tracking.

### Storage locations

| Path | Description |
|---|---|
| `~/.medgemma/vault.db` | SQLite database |
| `~/.medgemma/documents/` | Uploaded document files (content-hash prefixed) |

Override the base directory by setting the `MEDGEMMA_VAULT_DIR` environment variable:

```bash
export MEDGEMMA_VAULT_DIR=/path/to/custom/vault
```

## Development

```bash
# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest tests/ -v

# Run a specific test file
pytest tests/test_store.py -v

# Run with output
pytest tests/ -v -s
```

## Dependencies

| Package | Version | Purpose |
|---|---|---|
| [fhir.resources](https://pypi.org/project/fhir.resources/) | >=7.0.0 | FHIR R4B data models and validation |
| [click](https://pypi.org/project/click/) | >=8.0 | CLI framework |
| [medgemma](https://github.com/chibokocl/medgemma) | optional | AI-powered health queries (`[ai]` extra) |
| [pytest](https://pypi.org/project/pytest/) | >=7.0 | Testing (`[dev]` extra) |
| [pytest-mock](https://pypi.org/project/pytest-mock/) | any | Test mocking (`[dev]` extra) |

## License

MIT