Skip to content

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 first mas-ctl commands 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 init writes the shared XDG config, which Docker mounts read-only as its user-config fallback.
  • mas-lab init --local writes config.yaml and infra/<name>.yaml in 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 like standard:openai)
  • default_infra — which registered manifest is used by default when no --infra-ref flag 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_KEY in docker/.env, then task restart
  • Source: set OPENAI_API_KEY in repo .env or source .env
  • Check bundle: mas-lab config and default_infra in $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).


Next

→ Tutorial 1 — Building an Agent