Local-first personal health record: labs, meds, wearables, food log, deterministic safety checks
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.
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.
Requires Docker and Python 3.12+.
git clone https://github.com/andronaft/health-os && cd health-os
cp .env.example .env # set the passwords
docker compose up -d db # Postgres 16 + pgvector
python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/alembic upgrade head # schema
.venv/bin/python -m seed.load # marker catalog, synonyms, units, nutrients
.venv/bin/python -m seed.demo # optional: a fictional demo patient to play with
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.
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 |
data/ and .env
are outside git. Nothing is sent anywhere by health-os itself.make test # everything (needs Postgres for the integration part)
make test-unit # pure unit tests — no database needed
make test-integration # only tests marked `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.
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).
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
docker run -i --rm ghcr.io/andronaft/health-os:0.2.1Merge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-andronaft-health-os": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/andronaft/health-os:0.2.1"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceghcr.io/andronaft/health-os:0.2.1dockerhealth-os works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.