Web UI (--ui flag)

The --ui flag mounts the mast-web operator UI at /ui/* on the attach listener. One binary, one port, one auth boundary — the SPA shares the same TLS cert, bearer token, and CORS origin as the attach API endpoints, eliminating cross-origin configuration entirely. The agent serves the UI; no separate web server required.

This is one of four ways to deploy mast-web. The others (hosted SPA, container image, self-host tarball) live in go-steer/mast-web and don’t involve core-agent at all. Pick --ui when you want a single binary, an air-gapped deployment, or local-dev iteration.

Quickstart

# Operator workstation or container
core-agent --attach-listen :7777 --session-db --ui

# Browser
open http://localhost:7777/ui/

Connect the SPA’s first-run modal to http://localhost:7777 with whatever bearer token the operator set via --attach-token (leave blank for an unauthenticated dev backend). Because the SPA loads same-origin against the attach listener, it can also use a relative path: /attach as the backend endpoint works.

Where the assets come from

The UI assets ship inside the core-agent binary via //go:embed. The build pipeline (dev/tools/fetch-mast-web) downloads a pinned mast-web release tarball and extracts it into internal/webui/dist/ before go build. The pin lives in the top-level .mast-web-version file:

# .mast-web-version
version=v0.1.0

Bumping mast-web is a one-line PR + rebuild.

If the embedded bundle is empty (no fetch-mast-web was run), core-agent --ui refuses to start with a clear error pointing at the fetch step. The fetch script tolerates a blank version pin (logs a skip; useful in CI when the agent build doesn’t need the UI).

--ui-dir for local development

When iterating on mast-web against a live agent, point --ui-dir at your checkout’s dist/ directory:

# In one terminal, build mast-web continuously
cd ~/projects/mast-web && make build   # populates dist/

# In another, run the agent serving from that dist/
core-agent --attach-listen :7777 --session-db --ui-dir ~/projects/mast-web/dist

The agent serves whatever’s in the directory at request time — no rebuild needed when you tweak web/app.js. --ui-dir implies --ui.

Auth + TLS

The UI route inherits the attach listener’s auth boundary:

  • --attach-token=ENV_VAR — bearer token required for both /ui/* and the attach API
  • --attach-tls-cert + --attach-tls-key — TLS for the listener (UI served over HTTPS)
  • --attach-client-ca — mTLS for client certs

The SPA reaches the attach API via same-origin relative paths, so the browser sends the bearer token (set in the first-run modal) on both UI asset loads and API calls. No CORS configuration required.

When NOT to use --ui

  • Multi-tenant deployments where the operator UI should be authenticated separately from the agent API. Use the container image deployment instead — it terminates auth in front of the agent and lets you front the UI with IAP / OIDC / SSO independently.
  • Hosted-SPA tryout (“just let me see what this looks like”). Visit the published mast-web site and point at your backend; no agent rebuild required. (Coming soon at go-steer.github.io/mast-web/app/.)
  • Custom-branded UI. Self-host the mast-web tarball with your modifications; the agent doesn’t need to know.

Why same-listener (not a second --ui-listen)

A separate port for the UI is occasionally useful — different auth, different LB routing — but the default trade-offs favor a shared listener:

  • One port to expose. K8s service / Cloud Run / firewall rule simplification.
  • Same-origin automatically. SPA fetches via relative paths; no CORS allowlist on the API.
  • Single auth boundary. Can’t accidentally leave the UI unauthenticated while gating the API.
  • One TLS cert. No second listener to manage.

If you need a separate listener, run the mast-web container image on its own port with BACKEND_URL pointed at the agent — same effect, cleaner separation.