Packages:
mas-runtime,mas-ctl,mas-lab(installed for you — Docker ortask install) Time: ~10 min (Docker fast path) · ~20 min (developer path) Goal: Install MAS Lab, configure LLM access, and run your firstmas-ctlcommands before Tutorial 1.
| Path | Best for | You need |
|---|---|---|
| Fast path — Docker only | Users, demos, benchmarks | Docker, git, OPENAI_API_KEY for live LLM runs |
| Path A — Docker (full) | Same as fast path + CLI patterns, mounts, task helpers |
Docker, optional go-task |
| Path B — Developers | Patching runtime, ctl, or lab | Python ≥ 3.11, uv, task, direnv recommended |
Both paths use the same manifests and tutorials. Developers can still use Docker
for the UI (task start) while editing Python sources on the host.
Infrastructure defaults (standard:openai, standard:ollama, bundles, trace cache)
are documented in § Infrastructure below —
not in the root README, because they only matter once you are setting up a run.
No uv, no task, no direnv. You will configure LLM access, build the Docker
images, and run a few mas-ctl commands to confirm the install.
- Docker Desktop or Docker Engine
git clone https://github.com/outshift-open/mas-lab.git && cd mas-lab
Three separate concerns — never mix secrets into YAML:
| Piece | What it is | Where it lives |
|---|---|---|
| Infra manifest | Non-secret endpoint config (API base URL, allowed models, api_key_env name) |
infra_refs in config.yaml or --infra-ref on CLI |
| Credential | API key or token | docker/.env (Docker) or gitignored .env (developers) |
| Flavour | Runtime environment bundle (local = default in library-standard) |
mas_ctl.flavour / mas_lab.flavour in workspace, or manifest |
Initialize your user config (creates ~/.config/mas/config.yaml and an optional infra manifest):
mas-lab init
# Prompts for LLM provider URL, API key env var, and model alias.
# Skip the infra step if you use a bundled provider (standard:openai, standard:ollama).Then set your API key:
cp docs/tutorials/00-environment-setup/.env.example docker/.env # Docker path
# Edit docker/.env — set OPENAI_API_KEY=sk-...The generated ~/.config/mas/config.yaml sets:
infra_refs— the manifest(s) to register (your custom file or a bundled ref likestandard:openai)default_infra— which registered manifest is used by default when no--infra-refflag is given
Keep secrets out of YAML: the infra manifest sources the key from an env var
(api_key_env: OPENAI_API_KEY) — the key is never written in the file.
Schema: docs/schemas/config.schema.yaml.
Full reference: user-config.md.
cd docker
docker compose build backend # CLI + controller API
# UI (optional): docker compose build uiTags: mas-lab-backend:local (required), mas-lab-ui:local (optional UI). First backend build takes several minutes.
Clean rebuild (remove old images first):
task docker-rebuild
# or: docker compose down --rmi local && docker rmi mas-lab-backend:local mas-lab-ui:local
# && docker compose build --no-cacheThese commands confirm that Docker can run mas-ctl and read tutorial manifests.
They do not call an LLM, so you can run them before adding an API key.
docker compose -f docker/compose.yaml run --rm --no-deps cli mas-lab config
docker compose -f docker/compose.yaml run --rm --no-deps cli mas-ctl validate \
docs/tutorials/01-building-an-agent/agent.yamlLive LLM (after OPENAI_API_KEY is in docker/.env):
docker compose -f docker/compose.yaml run --rm --no-deps cli mas-ctl chat \
docs/tutorials/01-building-an-agent/agent.yaml \
-q "What is the capital of France?"Corporate / OpenAI-compatible proxy — set infra_refs: [standard:llm-proxy] in
~/.config/mas/config.yaml (via mas-lab init) and
LLM_PROXY_API_BASE in .env / docker/.env. See
.env.example.
Offline mock (no network — uses mock infra overlay from Tutorial 1):
docker compose -f docker/compose.yaml run --rm --no-deps cli mas-ctl chat \
docs/tutorials/01-building-an-agent/agent.yaml \
-o docs/tutorials/01-building-an-agent/overlays/mock-llm.yaml \
-q "What is 2+2?"| CLI | What it does |
|---|---|
mas-ctl validate <agent.yaml> |
Schema + refs without running |
mas-ctl chat <agent.yaml> -q "…" |
Single agent, one turn |
mas-ctl run-mas <mas.yaml> -q "…" |
Full MAS workflow |
mas-ctl list-bundles |
Installed infra bundles (standard:openai, …) |
mas-lab config |
Effective data paths and overrides |
On mas-ctl, -o / --overlay applies a manifest overlay (not an output path).
To write the trace elsewhere, use --events-file /path/to/events.jsonl.
| Store | Default location | Purpose |
|---|---|---|
| Trace cache | $XDG_CACHE_HOME/mas/traces/ (default ~/.cache/mas/traces/) |
Content-addressed LLM traces — re-runs skip cached completions |
| Lab outputs | $XDG_DATA_HOME/mas/labs/<lab>/<experiment>/… |
Benchmark trees: …/itemN/rN/traces/events.jsonl, results/ |
| CLI chat traces | Next to manifest: traces/events.jsonl unless --events-file set |
Ad-hoc mas-ctl chat runs |
Confirm paths:
mas-lab configOverride output location
| Tool | Flag | Effect |
|---|---|---|
mas-lab benchmark run |
-o / --output-dir PATH |
Write this experiment under PATH instead of the global labs tree |
mas-lab benchmark run |
--trace-cache PATH |
Separate trace cache (bypass shared cache) |
mas-ctl chat |
--events-file PATH |
Write events.jsonl to PATH |
| Env | MAS_LABS_ROOT, MAS_TRACE_CACHE, MAS_RUNS_ROOT |
Override globals (see mas-lab config) |
Workspace paths: keys in config.yaml mirror $XDG_CONFIG_HOME/mas/config.yaml
when you want per-project defaults (schema: paths.labs_dir, paths.cache_dir,
paths.runs_dir).
The browser UI is the easiest way to browse manifests and benchmark results after install. It uses the same Docker stack as the CLI.
cd docker && docker compose up -d
# or from repo root: task start| Service | URL |
|---|---|
| Web UI | http://localhost:8080 |
| Controller API | http://localhost:8090/api/health |
What to try: open an experiment under labs/ or docs/tutorials/, validate it,
and inspect results/ from a completed run. Guide: Web UI.
→ Tutorial 1 — Building an Agent — prefix commands with
docker compose -f docker/compose.yaml run --rm --no-deps cli when staying on Docker.
Everything in the fast path, plus how mounts and config work.
| Container | Host (default) | Purpose |
|---|---|---|
/workspace |
Repository root (.. from docker/) |
labs/, infra/, tutorials |
/data |
docker/data/ |
Trace cache, benchmark outputs |
Override in docker/.env:
MAS_WORKSPACE_MOUNT=/path/to/your/project
MAS_DATA_MOUNT=/path/to/persistent-dataThe sample workspace file is at examples/config.yaml.
Copy it to your project root as config.yaml, or set
MAS_WORKSPACE_ROOT=examples when working from this checkout.
mas-lab init uses OSS templates from:
/workspace/config.yaml ← project copy (highest; optional on host mount)
/opt/mas-lab/config.yaml ← baked sample when mount has no project file
docker/.env ← OPENAI_API_KEY
/data/ ← trace cache & benchmark outputs
MAS_WORKSPACE_ROOT=/workspace is set in the container. The runtime does not
read a host $XDG_CONFIG_HOME/mas/config.yaml when that env var is set.
cd docker
# Benchmark (uses trace cache under /data)
docker compose run --rm cli mas-lab benchmark run \
labs/design-space.lab/01-design-patterns/experiment.yaml --dry-run
# Multi-agent
docker compose run --rm cli mas-ctl run-mas path/to/mas.yaml -q "Hello"The cli service uses the tools profile — it is the service for one-off CLI commands (docker compose --profile tools run --rm cli …). Don't use backend (the long-running API service) for CLI commands.
Install go-task, then from the repository root:
| Task | Purpose |
|---|---|
task start |
Build if needed, start UI + backend detached |
task restart |
Rebuild + recreate after docker/.env or code changes |
task verify-env |
Confirm OPENAI_API_KEY inside the running backend container |
task docker-rebuild |
Remove local images and docker compose build --no-cache |
Secrets belong in docker/.env only — shell export OPENAI_API_KEY is not
passed into containers (avoids stale keys). After editing .env, run task restart.
Full reference: docker/README.md in the repository.
Use this path when you change Python sources in runtime/, ctl/, or lab/.
| Tool | Purpose | Install |
|---|---|---|
| Python ≥ 3.11 | Runtime | python3 --version |
| uv | Fast installs | brew install uv or astral.sh/uv |
| task | Repo automation | brew install go-task |
| direnv (recommended) | Auto-activate .venv |
brew install direnv + hook in ~/.zshrc |
git clone https://github.com/outshift-open/mas-lab.git
cd mas-lab
direnv allow # optional; uses committed .envrc → ./.venv
task install # editable: runtime, ctl, library-standard, lab stackVerify CLIs:
command -v mas-lab mas-ctl mas-runtime
mas-lab --helpFor evaluation metrics, tutorials, and sample apps:
task install-dev # install + pytest, pyarrow, library-samples
# or full optional libraries:
task install-allManifest reference: references/index.md.
The committed .envrc sets UV_PROJECT_ENVIRONMENT=./.venv so this checkout
never shadows another project's venv.
Create a gitignored .env at the repo root for secrets:
cat > .env <<'EOF'
OPENAI_API_KEY=sk-...
EOFmas-lab benchmark run and mas-ctl chat walk up from the cwd and load .env
automatically. Never commit API keys.
Configure LLM access via mas-lab init (writes ~/.config/mas/config.yaml). The variables
below are for one-run overrides only — they take precedence over config.yaml for that
shell session and should not substitute for a proper config file.
| Variable | Purpose |
|---|---|
MAS_INFRA_REFS |
Replace infra_refs from config.yaml (e.g. standard:llm-proxy) |
MAS_CTL_MODEL |
Override the agent model for one run (e.g. gpt-4o-mini, or a provider-prefixed id via a proxy gateway) |
MAS_LLM_MODEL |
Alias for MAS_CTL_MODEL (legacy .env name) |
MAS_WORKSPACE_ROOT |
Point at a project root when cwd is elsewhere |
LLM_PROXY_API_BASE |
API base for standard:llm-proxy (read from .env) |
OPENAI_API_KEY |
Credential named by the LLMProxy manifest |
Machine-wide paths and default infra bundle:
mas-lab init
# Interactive: sets up ~/.config/mas/config.yaml and optionally ~/.config/mas/infra/<name>.yamlCheck effective paths:
mas-lab configRun task --list from the repo root. Common tasks:
| Task | Purpose |
|---|---|
task install / install-dev / install-all |
Editable package installs |
task verify |
Pre-commit gate (unit + tutorial manifests + smoke) |
task verify-tutorials |
Replay tutorial demo/scenario.yaml commands |
task reproduce |
Run all paper lab experiments |
task start / restart |
Docker UI stack |
task docs-serve |
Local MkDocs site (http://127.0.0.1:8000) |
task docs-build |
Build site to site/ (same as GitHub Pages CI) |
mas-ctl validate docs/tutorials/01-building-an-agent/agent.yaml
mas-ctl chat docs/tutorials/01-building-an-agent/agent.yaml \
-q "What is the capital of France?"Offline (no network):
mas-ctl chat docs/tutorials/01-building-an-agent/agent.yaml \
-o docs/tutorials/01-building-an-agent/overlays/mock-llm.yaml \
-q "What is 2+2?"git pull
task install # only if pyproject.toml dependencies changedEditable installs pick up code changes immediately; dependency changes need task install.
The runtime needs a non-secret infra reference (where to call the LLM) and a
secret API key in .env or docker/.env.
| Bundle | Use when |
|---|---|
standard:openai |
OpenAI API (OPENAI_API_KEY) |
standard:ollama |
Local Ollama at http://localhost:11434/v1 (no key) |
standard:production |
Default for tutorials — wraps standard:openai |
standard:development |
Local Ollama bundle |
List installed bundles:
mas-ctl list-bundles
# Docker:
docker compose -f docker/compose.yaml run --rm --no-deps cli mas-ctl list-bundlesSet the default in $XDG_CONFIG_HOME/mas/config.yaml (default_infra: standard:production) or
per-project in config.yaml (infra_refs:). CLI --infra-ref overrides
for one run.
mas-ctl chat docs/tutorials/01-building-an-agent/agent.yaml \
--infra-ref http://localhost:11434/v1 -q "Hello"| Setting | Contents |
|---|---|
labs_dir |
Experiment trees (<name>/<scenario>/itemN/rN/traces/events.jsonl) |
cache_dir/traces/ |
Content-addressed trace store |
cache_dir/artifacts/ |
Pipeline step cache |
Override: MAS_LABS_ROOT, MAS_TRACE_CACHE, or fields in $XDG_CONFIG_HOME/mas/config.yaml.
Always confirm with mas-lab config.
More detail: user-config.md.
Developer path (no Docker):
pytest tests/tutorials/test_scenario_commands.py -v -k "tuto-00 and Developer"Docker path (skipped automatically when the daemon is not running):
pytest tests/tutorials/test_scenario_commands.py -v -k tuto-00Full tutorial gate: task verify-tutorials.
Live LLM (requires OPENAI_API_KEY in .env or docker/.env):
TUTORIAL_ONLINE=1 pytest tests/tutorials/test_scenario_commands.py -v -k tuto-00Activate the venv: direnv allow or source .venv/bin/activate, then task install.
- Docker: set
OPENAI_API_KEYindocker/.env, thentask restart - Source: set
OPENAI_API_KEYin repo.envorsource .env - Check bundle:
mas-lab configanddefault_infrain$XDG_CONFIG_HOME/mas/config.yaml
Ensure you run docker compose from docker/ (or use docker compose -f docker/compose.yaml from repo root). Network is required for the first uv sync inside the image.
Run mas-lab config — outputs go to $XDG_DATA_HOME/mas/labs/ by default (or paths from user config).