health-os

Local-first personal health record, exposed over MCP.
Your labs, diagnoses, medications, wearable data and food log live in your own Postgres; any
MCP client β one running a local model or a cloud assistant β can read and update them through
guarded tools. Critical values, drug-safety rules and screening
schedules are deterministic code, not LLM judgement.

Medical disclaimer. This is not a medical device and does not give medical advice.
Critical-value alerts and screening reminders are only a signal to contact a doctor β
never a diagnosis and never a reason to delay care. Use at your own risk.
What it does
- Lab results β drop a PDF or photo into your MCP client; the model extracts the values,
health-os normalizes names (uk/ru/en/Latin synonyms) and units, and stages the panel as
pending. Nothing counts as fact until you approve it.
- Safety net in code β critical values alert immediately (log, macOS notification,
optional Telegram); critical findings in narrative reports are flagged; drug-interaction
questions are refused and redirected to a doctor/pharmacist (only deterministic checks run:
total daily paracetamol across products, biotin before lab tests); a crisis tool returns a
fixed response with hotlines, independent of the model.
- Trends and analytics β Mann-Kendall trends, personal baselines and anomalies,
age-gated risk calculators, a screening calendar, a weekly report, a doctor-visit brief.
- Food log β meals with a 41-nutrient profile, %RDA, deficiency/excess flags, meal templates.
- Devices β Apple Health export and Garmin import.
- 28 MCP tools + server instructions β the safety rules are sent to every client on connect;
see mcp_server/README.md.
Try it in one command
Only Docker needed. Starts a throwaway database with a fictional patient β two years of labs
(LDL creeping up), blood pressure, medications, a food log and a lab panel awaiting approval:
git clone https://github.com/andronaft/health-os && cd health-os/demo
docker compose up -d --build
Point your MCP client at it:
{
"mcpServers": {
"health-os-demo": {
"command": "docker",
"args": ["run", "-i", "--rm", "--network", "health-os-demo",
"-e", "DATABASE_URL=postgresql+psycopg://health:demo@db:5432/health_os",
"health-os:local"]
}
}
}
Ask "show my health summary", "is my LDL trending up?", "what's pending review?",
"what am I short on nutritionally?". Remove it all with docker compose down -v.
Install for your own data
Requires Docker and Python 3.12+.
git clone https://github.com/andronaft/health-os && cd health-os
cp .env.example .env
docker compose up -d db
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/alembic upgrade head
.venv/bin/python -m seed.load
.venv/bin/python -m seed.demo
Then connect an MCP client β config for LM Studio, Open WebUI, Ollama CLI and Claude is in
mcp_server/README.md. Try: "show my health summary",
"LDL trend", "what am I short on nutritionally this week?".
Local models: the server speaks standard MCP over stdio, so any MCP client that runs a
local model can use it. Verified so far: the server itself with the official MCP Python client
(CI + the Docker demo). Not yet verified end-to-end with a local model β see
#9; reports welcome.
How it works
MCP client (local or cloud model)
β stdio
mcp_server/ ββ read tools βββΆ approved views (read-only role, 5s timeout, row limits)
β ββ write tools ββΆ core/services: normalize β status β critical rules β pending
β
safety/ critical values, narrative flags, interactions, crisis, alerts
analytics/ trends, baselines, calculators, screening, nutrition, weekly report
β
PostgreSQL 16 + pgvector βββ ingestion/ (Apple Health, Garmin, embeddings)
| Directory | What's inside |
|---|
core/ | config, DB, normalization, services, dedup, health summary |
mcp_server/ | MCP server, read and write tools |
safety/ | deterministic safety rules and alert delivery |
analytics/ | trends, baselines, calculators, screening, nutrition, reports |
ingestion/ | extraction schema, confidence scoring, device importers, embeddings |
migrations/ | Alembic schema |
seed/ | reference catalog + the demo patient |
evals/ | red-team scenarios (injections, hidden critical values, unit tricks) |
scripts/ | backup/restore (restic; install_launchd.sh schedules them on macOS), read-only role setup, importers |
Privacy / local-first
- Your data stays in your own database. Postgres runs locally in Docker;
data/ and .env
are outside git. Nothing is sent anywhere by health-os itself.
- What leaves the machine depends on the MCP client you connect. With a local model
(LM Studio, Open WebUI + Ollama, β¦) nothing does. With a cloud assistant, whatever the tools
return is sent to that provider β use one whose terms fit medical data (no training on your
data, zero/short retention).
- The goal is fully local: local models for chat and extraction, local embeddings for search
(already supported via fastembed). Cloud clients remain optional.
- Optional alert channel (Telegram) sends only a generic "check your health system" text, never values.
- Encrypt the disk (FileVault / LUKS / BitLocker) β the database files are plaintext at rest.
- Never put real medical data in issues, PRs or tests β synthetic data only.
Tests
make test
make test-unit
make test-integration
Integration tests never touch the working database: tests/conftest.py drops and recreates
<POSTGRES_DB>_test on the same server (migrations + seed) on every run. Override with
TEST_DATABASE_URL (the name must end in _test). Without Postgres, integration tests are
skipped locally; CI sets REQUIRE_DB=1 so they fail instead.
Development history: PROGRESS.md.
License
AGPL-3.0-or-later. You may use, modify and fork health-os; if you distribute it or
run a modified version as a network service, you must publish your source under the same license.
Want to use it in a closed-source or commercial product without those obligations? A separate
commercial license is available from the author β reach out via GitHub
(@andronaft).
Contributions are welcome β see CONTRIBUTING.md (includes a short CLA).