# Manual installation **English** · **[中文](install.zh.md)** The one-line installer in the [README](../README.md#installation) is the usual way in. This page lists the equivalent steps one by one, for troubleshooting, for custom locations, or for environments where the script cannot run. A working setup has four separate parts: | Part | What it is | Where | | --- | --- | --- | | Mirobody server | The record: lab reports, wearables, medications. The plugin reads it through Mirobody's MCP endpoint, read-only | Docker, `http://127.0.0.1:18060` | | longevity-skills | The method library (skill scripts) and two reference tables | `~/longpi/longevity-skills` | | Python environment | Mirobody's terminology engine (LOINC, unit conversion) and the skills' dependencies | `~/longpi/.venv` | | DSH + this plugin | Conversation, tools and the health board; [dsh-plugin-mirobody](https://github.com/zwbao/dsh-plugin-mirobody) ships inside this plugin, nothing extra to install | `~/.dsh/profiles/web` | Run the blocks below in order. Everything goes under `~/longpi`; **in every new terminal, run the `export` at the top of step 0 first.** ## 0. Tools You need macOS or Linux, Node.js 22.19+, pnpm (`dsh plugin` installs through it), Python 3.12+, git with git-lfs, Docker (for Mirobody), and a [DeepSeek API key](https://platform.deepseek.com/api_keys), which you enter in the DSH web page. ```bash export LONGPI_HOME=~/longpi mkdir -p "$LONGPI_HOME" node -v # v22.19 or later npm install -g pnpm@10 @deepseek-ai/dsh # use sudo, or a Node from nvm/fnm, if npm lacks permission pnpm -v && dsh --version # checked with pnpm 10 and dsh 0.1.5-rc.3 python3.12 --version # else: brew install python@3.12, or uv python install 3.12 git lfs version # else: brew install git-lfs / apt install git-lfs docker info --format '{{.ServerVersion}}' # Docker must be running ``` ## 1. Start Mirobody (the record server) ```bash cd "$LONGPI_HOME" git clone --depth 1 https://github.com/thetahealth/mirobody.git cd mirobody git lfs install && git lfs pull # the LOINC bundle; without it the file is a pointer stub ./deploy.sh # Postgres + Redis + server + worker, about 800 MB of memory ``` Open and sign in as `you@mirobody.ai` with code `111111`. `SEED_DEMO_DATA=true` is the default, so two demo accounts already hold 2,019 readings, which is enough to check the plugin. - For your own data: set `SEED_DEMO_DATA=false` in `mirobody/.env` before the first start, then register your own account as in step 2. - Uploading a lab PDF or photo needs one model key (OpenRouter, Gemini, OpenAI, Anthropic or DeepSeek) in `mirobody/.env`, then `docker compose restart`. Reading existing data does not. - If it does not come up, `deploy.sh` prints the cause and the fix (a subnet clash, a Docker that refuses named volumes). ## 2. Get the record-server address (MCP) The plugin reads the record through a personal MCP address. In the web page it is **Settings → MCP**; from the command line: ```bash MIROBODY=http://127.0.0.1:18060 # Demo account: sign in with the fixed code JWT=$(curl -s -X POST "$MIROBODY/email/verify" -H 'Content-Type: application/json' \ -d '{"email":"you@mirobody.ai","code":"111111"}' \ | python3 -c 'import sys, json; print(json.load(sys.stdin)["data"]["access_token"])') # Your own account: replace the block above with a one-time register and a password sign-in # curl -s -X POST "$MIROBODY/password/register" -H 'Content-Type: application/json' \ # -d '{"email":"me@example.com","password":"at-least-8-chars"}' # JWT=$(curl -s -X POST "$MIROBODY/password/login" -H 'Content-Type: application/json' \ # -d '{"email":"me@example.com","password":"at-least-8-chars"}' \ # | python3 -c 'import sys, json; print(json.load(sys.stdin)["data"]["access_token"])') MCP_URL=$(curl -s -X POST "$MIROBODY/personal/mcp" -H "Authorization: Bearer $JWT" \ | python3 -c 'import sys, json; print(json.load(sys.stdin)["data"]["url"])') echo "$MCP_URL" # like http://127.0.0.1:18060/mcp/ ``` The address is the credential: anyone who has it can read this record, so keep it out of chats and screenshots. It is valid for 30 days by default (`MCP_URL_TTL_DAYS` in Mirobody's `.env`); when it expires, rerun this step and update the config from step 6. DSH reloads the config without a restart. ## 3. Python environment One virtual environment serves both Mirobody's terminology engine and the skill scripts. ```bash cd "$LONGPI_HOME" python3.12 -m venv .venv .venv/bin/pip install --upgrade pip .venv/bin/pip install mirobody numpy scipy openpyxl # with uv: uv venv --python 3.12 .venv && uv pip install --python .venv/bin/python mirobody numpy scipy openpyxl .venv/bin/python -c "import mirobody; print(mirobody.__version__, mirobody.BUNDLE_VERSION)" # prints something like: 1.5.0 loinc-2.83+2026.09.17-aacb2c715b56 ``` A few skills need heavier dependencies (pyaging, for example) and name a runtime in their `skill.json`. Without that interpreter configured, the plugin refuses to run them rather than try another environment; see `skillRuntimes` in the [configuration reference](reference.md#configuration). ## 4. The skill library ```bash cd "$LONGPI_HOME" git clone https://github.com/zwbao/longevity-skills.git ls longevity-skills/catalog.json longevity-skills/data # catalog.json, biological_variation.json, effects.jsonl ``` ## 5. Install the plugin ```bash dsh plugin --profile web add github:zwbao/dsh-plugin-longpi ``` The web profile is created if it does not exist. `missing peer @deepseek-ai/...` warnings are expected: DSH provides those packages. No `allowBuilds` is needed, because the repository carries the built `lib/`. ```bash ls ~/.dsh/profiles/web/node_modules/dsh-plugin-longpi/vendor/dsh-plugin-mirobody # the bundled Mirobody plugin grep -A 6 '"bundles"' ~/.dsh/profiles/web/package.json # lists dsh-plugin-longpi ``` Do not also `dsh plugin add` the Mirobody plugin: LongPi already mounts it in the same process, and a second copy registers the same tools twice. ## 6. Configure The config lives in the profile's patch file. A patch replaces the row's whole `config`, so every key is restated. The script backs up the existing file first; if the backup holds anything besides `[]`, merge it back by hand. ```bash P="${DSH_HOME:-$HOME/.dsh}/profiles/web/cordis.patch.yml" cp "$P" "$P.bak.$(date +%Y%m%d%H%M%S)" cat > "$P" <.tgz`. `npm run vendor:mirobody` refreshes the bundled Mirobody plugin from its release tag.