Skip to content

Controller API

mas-lab serve starts the lab controller: the HTTP API that the web UI and the live dashboard talk to.

This is not mas-ctl serve, which exposes one agent over A2A.

mas-lab serve --host 127.0.0.1 --port 8090
Flag Meaning
--host Bind address. Loopback stays CORS-permissive; non-loopback binds send no CORS headers unless --cors-origin is set.
--port Listen port (default 8090).
--cors-origin URL Repeatable. Allowed browser origin for a remote UI.
--token-file PATH Bearer token. Clients send Authorization: Bearer. None = open (warning on non-loopback).
--state-dir PATH Persist jobs, runs, and uploads (SQLite + upload files). Default: the controller state directory.
--workspace PATH Project folder for config.yaml, labs, libraries, and the writable Workspace library. Sets MAS_WORKSPACE_ROOT. An explicit mas_lab.labs_search_paths in that folder makes the catalog exclusive.

Pin a lab or a workshop tree:

mas-lab serve --workspace ./labs/my-experiment.lab
mas-lab serve --workspace /workspace

Remote example:

mas-lab serve --host 0.0.0.0 --port 8090 \
  --token-file ./token \
  --cors-origin https://ui.example \
  --state-dir ./controller-state \
  --workspace ./labs/my-experiment.lab

Detached daemon: mas-lab control start (default port 9000). Workers: mas-lab worker.

Docker: docker compose up publishes the API on http://localhost:8090 and the studio on http://localhost:8080. See Web UI.


Who calls it

Client Role
Web UI Authoring studio (manifests, labs, jobs)
Live dashboard (task demo-ui) Topology, events, chat, metrics over one WebSocket
mas-lab demo-ui export Writes a static dashboard; does not keep the API running
Scripts GET /api/health, then the scope and run routes

The UI renders only what the controller returns. It never builds a server file path. Identity is a scope id (library:<name> / lab:<name>) plus an item id (name or name@version). The UI never derives an id from metadata.name and never displays a server path. A lab is not a library: lab-local libraries are separate library scopes with origin: lab. Writes go through KindLayout; runs persist under --state-dir; artifacts are read by opaque id.


HTTP surface

Auth is optional bearer (--token-file).

Group Examples
Health GET /api/health
Catalog GET /api/scopes, GET /api/kinds, GET /api/scopes/{scope_id}/items
Choices GET /api/choices/… (models, tools, overlays, skills, step types)
Schemas GET /api/schemas, GET /api/schemas/{id}
Runs GET/POST /api/runs, GET /api/runs/{id}, events and artifacts
Live WebSocket on the same origin as serve (live dashboard)

Older /api/libraries/**, /api/jobs/**, and /api/experiments/** routes remain as adapters for one release.

The process serves OpenAPI at /openapi.json (and /docs unless disabled). A committed snapshot is docs/schemas/controller-openapi.json in the source tree. Flags above win over the man page in lab/docs/cli/serve.md.