Mirobody
Turn scattered health data into answers you can trace.
A self-hosted AI health data engine for lab reports, wearables and genetic files.
Start with Docker and one model key, or run every model on your own machine.
English · 中文
Three reports, three names for the same test. One trend, with the file behind every number.
Start with Docker
Docker with Compose is all the stack needs: no Python, Node.js or GPU. On Windows, run these in a WSL 2 terminal.
git clone --depth 1 https://github.com/thetahealth/mirobody.git && cd mirobody
./deploy.sh
Open the setup link the script prints and paste one model key: OpenRouter, OpenAI, Gemini, Anthropic, DeepSeek, DashScope, or any OpenAI-compatible gateway. The key is kept only after one real request through it works. Postgres, the server, the worker and a synthetic demo record start together.
- Sign in as
you@mirobody.ai, code111111, on the Email code tab. The demo holds 2,019 readings across two records: yours, andmom@mirobody.ai's, which she shares with you view-only. - Ask "How has my cholesterol changed?" The answer charts the trend and names the file behind each number.
- Upload a sample from
demo/upload/on the Data page, or switch to mom's record and ask again.
Prefer every model on your own machine? No model key needed.
From the cloned folder, start the stack with llama.cpp's CPU image beside it:
COMPOSE_PROFILES=local-cpu ./deploy.sh
The script points Mirobody at llama.cpp, which serves a small answering model and a document reader; the setup page has nothing to ask. Allow 16 GB of memory, at least 8 GB of it for Docker, and a one-time download of about 3.7 GB. With no GPU a first answer takes minutes: 2–3 on an M1 Pro's cores, up to about 15 on a 4-vCPU x86 server. On a Mac, running llama-server natively uses the GPU: about 30 s per answer on a 16 GB M1 Pro.
→ Self-host guide · Walkthrough · Deploy on a server
What you can do
- Compare reports across labs. PDFs, phone photos and spreadsheets, 23 file types in all, land in one history. Every reading links to the page it was read from.
- Bring in everyday data. Import an Apple Health export, or connect Garmin, Oura and Whoop.
- Look after your family. Invite someone who shares their own record, or keep one for a parent who never signs in.
- Write a health journal.
headache since last night, BP 150/95, no feverbecomes a coded complaint and two coded readings; "no fever" is not logged as a fever. - Explore genetic data. Upload a 23andMe, AncestryDNA or WeGene export, or a VCF, and ask by rsID, gene or region. Drug questions get CPIC coverage, never a change of medication.
- Use your own agent. Connect Claude Code, Codex or Cursor over MCP, or embed the offline engine in Python.
Collect · Translate · Agent
| Stage | What it does | Where |
|---|---|---|
| ① Collect | Files, devices and journal entries come in; the source is kept, so every reading points back to it. | collect/ |
| ② Translate | A1c, HbA1c and Glycated Hemoglobin resolve to one code, units to one standard, offline. A name it cannot place stays unresolved. |
engine/ · translate/ |
| ③ Agent | Ask over the coded record: trends, comparisons across labs and devices, a chart, and the file behind every number. | agent/ |
The model reads documents and reasons; the codes and units come from vocabularies bundled with the package, never from the model. How a reading moves through the pipeline.
Care for your family
Joining a care circle shares nothing by itself. Each member decides whether others may view or edit their own record. A parent who never signs in can be managed by you until they claim the record and choose what you keep. See it in the walkthrough.
What stays on your machine
Your record lives in a Postgres you run, and nothing here reports usage anywhere. What leaves depends on who reads it:
| With a model key | 100% on this machine | |
|---|---|---|
| Your documents and questions | sent to that model vendor, under its terms | stay here |
| A name to a code, a unit to UCUM (② Translate) | here, from the bundled vocabulary, with no network | the same |
| Model weights | none | downloaded once from Hugging Face |
Device vendors see data only after you link one. Before this reaches a network you do not control, read SECURITY.md: it lists every address the server can call.
Build on Mirobody
| You want | Start here |
|---|---|
| Your record in Claude Code, Codex, Cursor or Gemini CLI | Settings → MCP link, then one line per client |
| Names and units resolved in your own code | pip install mirobody: offline, no key, numpy the only dependency (library guide) |
| Your coding agent taught the workflow | npx skills add thetahealth/mirobody --skill translate-health-data (skills) |
| A new device provider or tool | Drop a file into mirobody/collect/providers/ or mirobody/agent/tools/ (CONTRIBUTING) |
| A hosted API instead | Mirobody Cloud |
Over MCP the stack serves seven tools, each scoped to the signed-in person: four read your record (readings, medications, genotypes, pharmacogenomics) and three resolve names and units.
Try the vocabulary with no key, no network and, with uvx, no install:
uvx --python 3.12 mirobody resolve "LDL cholesterol" 血红蛋白 ヘモグロビン 血脂
from mirobody.engine import resolve, resolve_reading
resolve("血红蛋白").loinc # '718-7' any language, one code
resolve_reading("total cholesterol", "5.0", "mmol/L").loinc # '14647-2' the unit picks the code...
resolve_reading("total cholesterol", "193", "mg/dL").loinc # '2093-3' ...mass, not moles
resolve("中性粒细胞百分比").loinc # '26511-6' Neutrophils/Leukocytes
resolve("血脂").resolved # False a category, not one test
Numbers you can check
| Claim | Check it |
|---|---|
| 317/317 on the tests an ordinary checkup prints, in English, Chinese, Japanese, Russian and Estonian | test_engine_coverage.py prints the score |
| 330 UCUM units with dimensional analysis, and 316 standard device indicators | Standardization · Device crosswalk |
The package names its vocabulary: mirobody.BUNDLE_VERSION is loinc-2.83+2026.09.17-aacb2c715b56 |
python -c "import mirobody; print(mirobody.BUNDLE_VERSION)" |
| Public health-agent benchmarks: ESL-Bench, MedHall-Bench, MedHarm-Bench | mirobody-eval · benchmarks/ |
Mirobody is the engine under Theta Wellness, a live consumer health app.
Contributing
The most useful contribution is a term the resolver gets wrong. Run mirobody resolve "<term>"; if the answer is wrong or empty, report it or send a fix with a test case. CONTRIBUTING.md has the setup and the checks.
Built on HL7 FHIR, LOINC from the Regenstrief Institute, UCUM, ICPC-3 (WONCA), CPIC, llama.cpp and deepagents, with thanks. Terminology licences: LICENSE-3RD-PARTY.
If Mirobody helped you make sense of a report, a star helps the next person find it.
Documentation · Roadmap · Changelog · Security · AGENTS.md
Apache 2.0 · © 2026 Theta Health
Metadata
Release files for mirobody 1.5.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mirobody-1.5.4.tar.gz | 15.2 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mirobody-1.5.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.5 MB
Release files / mirobody-1.5.4.tar.gz
| Download URL | mirobody-1.5.4.tar.gz |
|---|---|
| Size | 15.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4fc22b7f6f55e4db5ba8010ff8c9f942fd595377b244cae23512a90107aa4925
|
|
BLAKE2b-256 checksum How to use checksums |
867c224ec96f98a9f2700798ba04c6915c4d2d521e41ef3b7c8bc24a11f8c690
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / mirobody-1.5.4-py3-none-any.whl
| Download URL | mirobody-1.5.4-py3-none-any.whl |
|---|---|
| Size | 15.3 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
aa4efdc41050d12d3a045a46a1009c43d74abc0817912815f968848b823843de
|
|
BLAKE2b-256 checksum How to use checksums |
a9ceb4e6eefc782deb9652d98b4b0f21fa49a33a5e61f29a7a6133c440df9583
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|