Skip to content
Get Started

Getting Started

Quickstart

Clone Mirobody, run ./deploy.sh, sign in at localhost:18080, and add an LLM key.

One path from an empty directory to a signed-in Mirobody: clone, run ./deploy.sh, open the browser, sign in with a demo account, then add an LLM key. Everything runs in Docker, so you do not need Python or Node on the host for this page.

RequirementWhy
Docker + Docker Composedeploy.sh builds one image and starts four containers.
GitTo clone the repository.
Git LFSTerminology and indicator resources under mirobody/res/ are LFS objects. Without LFS you get pointer files and startup fails.

Install Git LFS before cloning: apt install git-lfs, brew install git-lfs, or bundled with Git for Windows.

Terminal window
git lfs install # once per machine
git clone https://github.com/thetahealth/mirobody.git
cd mirobody
Terminal window
./deploy.sh

The script does four things:

Writes .env

Sets ENV=localdb and generates a 32-character CONFIG_ENCRYPTION_KEY. Existing files are left alone.

Writes config.localdb.yaml

Your override file, seeded with a random JWT_KEY, the demo login codes, and commented-out placeholders for the LLM keys.

Builds the image

An Ubuntu 24.04 image with a Python virtualenv and Node.js. If hub.docker.com is unreachable the script falls back to the docker.1ms.run mirror, and npm is pointed at registry.npmmirror.com.

Starts the stack

docker compose up -d, then tails the logs in the foreground. Four containers come up: pg (18082), redis (18089), mirobody (18080), and mirobody_worker.

Open http://localhost:18080. The engine serves a prebuilt web client from the frontend/ directory next to the process; it lives outside the Python package on purpose, so a wheel ships the engine rather than 8 MB of JavaScript.

deploy.sh writes three predefined accounts into config.localdb.yaml. Use any of them, with the code as the verification code:

demo1@mirobody.ai
777777

Deleting the block from config.localdb.yaml is not enough: the config.yaml template carries its own predefined accounts (exp1@exp3@), and it loads first. Override the key with an empty value instead:

config.localdb.yaml
EMAIL_PREDEFINE_CODES:

You are signed in, but the agent has no model to call yet. Edit config.localdb.yaml and set at least one key:

config.localdb.yaml
# Pick whichever provider you have a key for. One is enough to start.
OPENROUTER_API_KEY: 'sk-or-...'
# GOOGLE_API_KEY: 'AIza...'
# OPENAI_API_KEY: 'sk-...'

Then restart the two application containers:

Terminal window
docker compose restart mirobody mirobody_worker

Which models each agent may use is set per agent under PROVIDERS_DEEP and PROVIDERS_BASE; the defaults in config.yaml already reference the key names above.

An LLM key is not enough. The worker’s indicator sync embeds indicator names to standardize them, and that is a different key:

config.localdb.yaml
EMBEDDING_PROVIDER: gemini # the default
GOOGLE_API_KEY: 'AIza...' # what `gemini` needs
# EMBEDDING_PROVIDER: qwen # the other supported provider
# DASHSCOPE_API_KEY: 'sk-...'

With only an OpenRouter key, chat works but Health indicators stays 0: the embedding call fails in the worker, and it fails quietly. docker compose logs mirobody_worker is where it says so.

Terminal window
# All four containers up?
docker compose ps
# Liveness — returns JSON with the service name, version, and counts of
# tools, resources and agents that were discovered at startup.
curl http://localhost:18080/api/health
# MCP discovery — JSON-RPC 2.0 over POST, lists the registered tools.
curl -X POST http://localhost:18080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

If /api/health reports "tools": 0, the tool directories were not scanned; check MCP_TOOL_DIRS and the startup log (docker compose logs mirobody).