您的健康,您的 AI — 以隐私为先。
No key, no config, no network — and with uvx, no install either:
uvx mirobody resolve "LDL cholesterol" 血红蛋白 ヘモグロビン "空腹血糖(GLU)" 血脂pip install mirobody instead if you want it on your PATH. Either way the
resolver answers from a bundle that ships with the package.
血红蛋白 and ヘモグロビン land on the same code as hemoglobin, LOINC 718-7;
空腹血糖(GLU) on fasting glucose. 血脂 (lipids) is a category, not an
observation, so the resolver returns nothing rather than a plausible wrong code.
…Pass the value and the unit when you have them. LOINC encodes the unit and
the result type into the identity, so the same name resolves to different codes.
resolve abstains rather than guessing: an empty code is a gap worth a second
look; method="refused" is a decision.
→ Engine reference · Indicators
./deploy.sh runs the whole
stack on your own machine; what comes out is LOINC-coded, FHIR-ready records
you can take anywhere, and the same tools are served over MCP to Claude
Desktop, Cursor or your own agent. No GPU: the app is self-hosted, the model
is not. You bring one API key to a hosted provider; nothing runs inference on
your machine. "Offline" here means the resolver — name to code, with no network
and no key — not a local LLM.The engine does three things, and the codebase, the docs and Contributing are organized around exactly these three stages:
| Stage | What it means | Where |
|---|---|---|
| ① Collect | Pull signals in: 3 device providers · 7 file formats · Apple Health (mirobody import apple export.zip, or a signed iOS client POSTs it in) |
collect/ |
| ② Translate (standardize) | One standard: resolve any reading to canonical codes (LOINC · SNOMED CT · RxNorm), normalize units to UCUM, land on FHIR-recognized code systems | indicator/ |
| ③ Agent | Reason: an agent reads the original documents through a virtual filesystem and answers with charts and citations | agent/ |
| Concept graph | 440,961 nodes · 22,044,110 cross-vocabulary edges · 595,746 source ids distilled into canonical concepts (LOINC · SNOMED CT · RxNorm bridges) |
| Aliases | 49,253 multilingual (中文 22,578 · 日本語 16,809 · de·es·fr·ko·ru); hemoglobin, 血红蛋白, 血紅素 and ヘモグロビン all land on 718-7 |
| Traditional Chinese | a shipped 3,336-character zh-Hant → zh-Hans fold table, plus curated Traditional rows — a curated row always beats a fold |
| Units | ~310 UCUM families with dimensional analysis and a molar-mass bridge keyed by LOINC code; 305 standard pulse indicators |
| Coverage | 213/213 on the panels an ordinary checkup prints, in English, Chinese (Simplified and Traditional) and Japanese (test_engine_coverage.py) |
| Bundle | LOINC 2.82: mirobody.BUNDLE_VERSION → loinc-2.82+2026.08.28-af2524b7a285 — release, cut date and a digest over the bundle's own members |
| Install | pip install mirobody is 2 packages, on numpy only — ~67 MB on macOS, ~100 MB on Linux, where numpy bundles its own BLAS |
Why 2.82 and not 2.83, what LOINC covers of the wearable world, and the opt-in semantic tier that cannot abstain: → Standardization in depth
The most-downloaded health-AI benchmarks in their category on Hugging Face, 4,000+ downloads a month each: ESL-Bench (event-driven longitudinal health agents — 100 synthetic users, 10,000 queries, arXiv:2604.02834) · MedHall-Bench (medical hallucination) · MedHarm-Bench (harmful medical advice). Reproduce any of them with one command via mirobody-eval, which also seeds a deployment with synthetic, PHI-free trajectories.
git clone --depth 1 https://github.com/thetahealth/mirobody.git && cd mirobody
git lfs install && git lfs pull # the resolver's LOINC bundle; a fresh clone holds a pointer stub until you do
./deploy.sh # Postgres + pgvector, Redis, server, worker → http://localhost:18060--depth 1 because the history is mostly superseded frontend builds and you
almost certainly do not want it: it takes the clone from ~125 MB to ~99 MB
(measured 2026-09-14 — most of what is left is the LFS bundle, which both
copies need).
Drop the flag if you plan to send a pull request. ./deploy.sh also fetches
the 22 MB concept graph behind semantic indicator search, which is a release
asset rather than a tracked file — see mirobody/res/EXTERNAL.tsv.
Sign in as [email protected], code 111111. No mail provider needed: the
sign-in page opens on password, and an account of your own is one request away:
curl -X POST localhost:18060/password/register -H 'Content-Type: application/json' \
-d '{"email":"[email protected]","password":"at-least-8-chars"}'Your care circle. The account is named for the role it plays: you sign in as the caregiver, and the record you read belongs to someone else. A circle is the unit of sharing — each member holds their own record and decides, on their own row, whether the others may view it.
SEED_DEMO_DATA is on by default, so the circle is already populated: you own a
thin record — a few weeks of self-tracked vitals and one unremarkable
checkup — and one synthetic person shares a thick one with you,
Demo (synthetic): 244 indicators, 14,273 readings across two years, five
documents the agent can read. Same question, two records: your HbA1c answers
with one boring-normal value from data you own; hers with a two-year story from
data you can only view. The recording walks both sides — your own indicators and
files, then the switch to her shared record and its two years of HbA1c:
The switch in that diagram is a column, not a promise:
care_circle_members.health_access, NOT NULL DEFAULT 0, on your own row.
Being invited into a circle shares nothing — the member decides, and no other
person's action can raise it. A route that forgets to check answers 403 instead of
handing over a record. examples/06_care_circle_rules.py
prints the whole decision table offline. Set SEED_DEMO_DATA=false for a
deployment that will hold real data.
One key runs everything, and none of it is your GPU. The key points at a
hosted model; your machine runs no inference. Browsing the seeded record needs no key; the upload
and the questions below ride one. Put ONE key in the .env next to compose.yaml
and docker compose restart — the app re-reads /app/.env; a shell export does
not reach the containers. The .env is the only place for the key:
config.llm.yaml names the variable (api_key: OPENROUTER_API_KEY), never the
secret. An OpenRouter key as
OPENROUTER_API_KEY is the recommended one; a DashScope key when openrouter.ai is
unreachable from your network; a Google, OpenAI
(OPENAI_API_KEY), Anthropic
(ANTHROPIC_API_KEY) or DeepSeek key works alone as well. Every model decision —
which model chats, which reads report photos, which extracts the indicators, which
embeds — is a line in config.llm.yaml, where you can read and
change it (a self-hosted gateway is one _BASE_URL in .env). The boot
log, and mirobody doctor, print what each surface selected and name the fix
where one has nothing.
① Collect + ② Translate. Drop demo/lab_report_2025-10-15.pdf
on the Data page and twelve analytes come out with values and units, each
linking back to the page it was read from:
③ Agent. Ask about her HbA1c and the agent finds the data, charts the three lab draws against 104 sensor-derived estimates, and says plainly that the improvement did not hold. Ask again about the report you just uploaded and it reads that instead — the fourth scene of the four-minute walkthrough.
→ Docker deployment · Configuration · Local Python setup
| You want | Do this | Docs |
|---|---|---|
| Offline resolution and units in your code | pip install mirobody — 2 packages, no key, no network |
Engine |
| A document turned into readings | pip install 'mirobody[parse]' — PDF, image, Excel, Word, PowerPoint, text; only a scanned page reaches a vision model |
Engine |
| The agent harness as a library | pip install 'mirobody[agent]' — middleware, virtual-filesystem backends, checkpointer |
Bringing your own agent |
| These tools in Claude Desktop, Cursor or your own loop | Settings → MCP: every agent tool is also served at /mcp, gated per user |
MCP servers · examples/07_claude_agent_sdk.py |
| Your app talking to a deployment | HTTP API, or backbone mode: your agent, our data layer | API overview · Backbone |
| A new tool, skill or device provider | Drop a file into mirobody/agent/tools/, mirobody/agent/skills/ or mirobody/collect/providers/ and restart — or pip install a package declaring a mirobody.providers / mirobody.tools / mirobody.agents entry point |
Adding tools · Skills · Providers |
| Your own agent harness | AGENT_DIRS → your directory replaces the shipped agent |
mirobody/agent/README.md |
| The LOINC axis table and alias sources at build time | mirobody.bundle — for generating a seed or a corpus |
mirobody/bundle.py |
The highest-leverage contribution is a term the resolver gets wrong. Run
mirobody resolve ""; if the answer is wrong or empty,
report it
or add a row to resolver_overrides.tsv plus a
case to test_engine_coverage.py — the
coverage score is the review.
pip install -e '.[test]' && pytest -q && lint-imports→ CONTRIBUTING.md · Contributing guide · Repository layout · Roadmap · CHANGELOG · SECURITY
docs.mirobody.ai, in English and Chinese — start at the [Quickst
暂无开放 Issues,或尚未同步最近议题。