Tutorial 0 — Environment Setup¶
Packages:
mas-runtime,mas-ctl,mas-lab(PyPI, Docker, or source checkout) 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.
Choose your path¶
| Path | Best for | You need |
|---|---|---|
| Path 0 — PyPI packages | Users running a published release | Python ≥ 3.11, uv |
| 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.
Path 0 — PyPI packages¶
PyPI publication pending: this path documents the intended release experience, but the packages are not uploaded yet. Use the Docker or developer paths below until the first public PyPI release is complete.
Use this path to run a published release without cloning or editing the MAS-Lab source tree. The packages are installed into a local venv; the console scripts are the same as in the source and Docker paths.
1 — Create a venv and install the release¶
uv venv .venv
uv pip install mas-lab mas-library-standard mas-library-samples
export PATH="$PWD/.venv/bin:$PATH"
For a specific release, add a version constraint to each package, for example
mas-lab==0.2.0. These are the public PyPI names and do not require a Cisco
checkout or internal package index.
2 — Configure and test the installed CLI¶
mas-lab init
export OPENAI_API_KEY=<your-key>
mas-ctl validate path/to/agent.yaml
mas-ctl chat path/to/agent.yaml -q "What is the capital of France?"
Use mas-ctl validate for an offline schema/ref check. Use mas-ctl chat or
mas-ctl run-mas only when the selected infra bundle has a reachable provider.
Fast path — Docker only¶
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.
1 — Prerequisites¶
- Docker Desktop or Docker Engine
git clone https://github.com/outshift-open/mas-lab.git && cd mas-lab
2 — Configure LLM access (read this first)¶
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 |
For the bundled standard:openai or standard:ollama providers, no host CLI
installation or mas-lab init step is required. Set the API key in the Docker
environment file:
cp docs/tutorials/00-environment-setup/.env.example docker/.env
# Edit docker/.env — set OPENAI_API_KEY=sk-...
For a custom provider, place the project config.yaml on the mounted workspace
or bind-mount a host config tree as described in the repository's Docker README.
The host-side initialization choices are:
mas-lab initwrites the shared XDG config, which Docker mounts read-only as its user-config fallback.mas-lab init --localwritesconfig.yamlandinfra/<name>.yamlin the project root; Docker sees these through/workspace, and they take priority.
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.
3 — Build images¶
cd docker
docker compose build backend # CLI + controller API
# UI (optional): docker compose build ui
Tags: 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-cache
4 — Verify the CLI (offline)¶
These 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 --profile tools run --rm --no-deps cli mas-lab config
docker compose --profile tools run --rm --no-deps cli mas-ctl validate \
docs/tutorials/01-building-an-agent/agent.yaml
Live LLM (after OPENAI_API_KEY is in docker/.env):
docker compose --profile tools 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 (no network — validate only; chat needs a live provider or llm_cache replay):
docker compose --profile tools run --rm --no-deps cli mas-ctl validate \
docs/tutorials/01-building-an-agent/agent.yaml
| 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.
5 — Trace cache and finding results¶
| 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 config
Override 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 |
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).
6 — Start the web UI¶
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.
7 — Next¶
→ Tutorial 1 — Building an Agent — prefix commands with
docker compose --profile tools run --rm --no-deps cli when staying on Docker.
Path A — Docker users¶
Everything in the fast path, plus how mounts and config work.
Volume mounts¶
| 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-data
The sample workspace is at library-samples/sample-workspace/.
Copy config.yaml to your project root, or run commands from
library-samples/sample-workspace/ when working from this checkout.
mas-lab init uses templates bundled in the mas-lab package (no library-samples install required):
- lab/src/mas/lab/templates/init/config.yaml
- lab/src/mas/lab/templates/infra/llmprovider.yaml
Configuration priority (inside Docker)¶
/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.
One-off CLI commands¶
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.
Taskfile helpers (optional)¶
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.
Path B — Developers (uv + task)¶
Use this path when you change Python sources in runtime/, ctl/, or lab/.
1 — Prerequisites (one-time)¶
| 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 |
2 — Clone and install¶
git clone https://github.com/outshift-open/mas-lab.git
cd mas-lab
direnv allow # recommended; uses committed .envrc → ./.venv
uv sync # workspace packages are installed editable by default
Without direnv, run uv venv .venv once and then uv sync from the repository
root. uv run executes commands in the synchronized workspace environment:
uv run mas-lab --help
uv run mas-ctl validate docs/tutorials/01-building-an-agent/agent.yaml
uv run pytest library-skills/tests -q
For the explicit editable-install workflow used by CI and the Taskfile:
task install-dev # editable packages plus test and sample dependencies
task verify-unit # unit and package boundary tests
Verify CLIs:
command -v mas-lab mas-ctl mas-runtime
mas-lab --help
For evaluation metrics, tutorials, and sample apps:
task install-dev # install + pytest, pyarrow, library-samples
# or full optional libraries:
task install-all
Manifest reference: references/index.md.
3 — direnv and .env¶
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:
cp docs/tutorials/00-environment-setup/.env.example .env
# Edit .env and set OPENAI_API_KEY=sk-...
mas-lab benchmark run and mas-ctl chat walk up from the cwd and load .env
automatically. Never commit API keys.
4 — Per-run overrides¶
Configure LLM access via mas-lab init (writes ~/.config/mas/config.yaml) or
workspace config.yaml. For a single run, use CLI flags — they are visible in
the command and do not leak into other runs:
| Flag | Purpose |
|---|---|
--infra-ref REF |
Use another infra bundle (e.g. standard:llm-proxy) |
--model ID (mas-ctl chat / tui) |
Override the agent model (e.g. gpt-4o-mini, or a provider-prefixed id via a proxy gateway) |
The environment is for secrets only:
| Variable | Purpose |
|---|---|
LLM_PROXY_API_BASE |
API base for standard:llm-proxy (read from .env) |
OPENAI_API_KEY |
Credential named by the LLMProxy manifest |
MAS_* override variables exist for test harnesses only; see
Environment overrides.
5 — User config ($XDG_CONFIG_HOME/mas/config.yaml)¶
Machine-wide paths and default infra bundle:
mas-lab init
# Interactive: sets up ~/.config/mas/config.yaml and optionally ~/.config/mas/infra/<name>.yaml
Check effective paths:
mas-lab config
6 — Self-contained projects (mas-lab init --local)¶
For a project you want to zip up, commit fixtures for, or hand to someone
else unchanged, keep every path inside the project folder instead of
$XDG_DATA_HOME / $XDG_CACHE_HOME:
mkdir my-project && cd my-project
mas-lab init --local --yes
--local writes config.yaml and infra/<name>.yaml under the current
directory instead of $XDG_CONFIG_HOME/mas/. Add a paths: block so traces,
the trace cache, and benchmark runs all resolve under a local data/ folder —
see config.local-example.yaml:
paths:
labs_dir: ./data/labs
cache_dir: ./data/cache
runs_dir: ./data/runs
Confirm every path now resolves inside the project:
mas-lab config
.gitignore the data/ directory and the project is fully portable: anyone
who checks it out gets the same layout, and nothing is written outside the
repo. Full precedence ladder (CLI flag → MAS_* env → paths: → user
config → XDG defaults): user-config.md § Data paths.
7 — Taskfile overview¶
Run task --list from the repo root. Common tasks:
| Task | Purpose |
|---|---|
task install / install-dev / install-all |
Editable package installs |
uv sync / uv run ... |
Synchronized editable workspace commands |
task verify |
Pre-commit gate (unit + tutorial manifests + smoke) |
task ci |
CI-parity suite, including functional and smoke gates |
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) |
8 — Smoke test¶
uv run mas-ctl validate docs/tutorials/01-building-an-agent/agent.yaml
uv run mas-ctl chat docs/tutorials/01-building-an-agent/agent.yaml \
-q "What is the capital of France?"
Offline (no network — validate only; chat needs a live provider or llm_cache replay):
uv run mas-ctl validate docs/tutorials/01-building-an-agent/agent.yaml
9 — Keeping up to date¶
git pull
task install # only if pyproject.toml dependencies changed
Editable installs pick up code changes immediately; dependency changes need task install.
Infrastructure: LLM endpoints and data paths¶
The runtime needs a non-secret infra reference (where to call the LLM) and a
secret API key in .env or docker/.env.
OSS infra bundles (library-standard)¶
| 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-bundles
Set 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.
Inline URL (quickest smoke test)¶
mas-ctl chat docs/tutorials/01-building-an-agent/agent.yaml \
--infra-ref http://localhost:11434/v1 -q "Hello"
Data directories¶
| 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: fields in $XDG_CONFIG_HOME/mas/config.yaml or workspace config.yaml.
Always confirm with mas-lab config.
More detail: user-config.md.
Verify this tutorial (CI)¶
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-00
Full 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-00
Common errors¶
command not found: mas-lab¶
Activate the venv: direnv allow or source .venv/bin/activate, then task install.
401 from the LLM¶
- 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
Docker build fails¶
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.
Wrong benchmark output path¶
Run mas-lab config — outputs go to $XDG_DATA_HOME/mas/labs/ by default (or paths from user config).