loki-mode

Migrating from the classic dashboard to the Control Plane

Loki Mode 10.8 removes the classic dashboard UI (dashboard-ui/, dashboard/static/, and the UI served on port 57374). The Control Plane (packages/control-plane, UI in packages/control-plane/ui) is the only UI. Deploy files (Helm, compose, ECS) and the clients (SDKs, VS Code, run.sh) already point at it.

What changed

Before Now
UI and API on port 57374 (FastAPI, dashboard/server.py) Control Plane on port 47821 by default (loki control serve)
loki dashboard start serves the classic UI loki dashboard, loki dashboard start and loki dashboard open open the Control Plane
dashboard-ui build (npm run build:all) cd packages/control-plane && bun run build:all (UI plus bundled server)
REST under /api/* REST under /v1/*, plus /health and /ready
Token management through the dashboard One bearer token, LOKI_CONTROL_TOKEN, on /v1/*

Start the Control Plane

loki control serve                 # 127.0.0.1:47821, database ~/.loki/control/control.db
loki control serve --port 0        # any free port; the printed URL is the real one
loki control status                # reachable? how many runs held?
loki dashboard                     # reuse a running Control Plane, or start one, and open it

Notes:

Environment variables:

Variable Meaning
LOKI_CONTROL_PORT listen port for loki control serve, and the port clients assume (default 47821)
LOKI_CONTROL_URL where clients and the shipper send runs (overrides discovery)
LOKI_CONTROL_DB SQLite path (default ~/.loki/control/control.db)
LOKI_CONTROL_HOST bind address (default 127.0.0.1)
LOKI_CONTROL_TOKEN bearer token for /v1/*; required for any non-loopback bind, otherwise the server exits 2
LOKI_CONTROL_ALLOW_INSECURE_BIND 1 accepts a tokenless non-loopback bind (not recommended)
LOKI_CONTROL_ANSWER_DIR where BLOCKED-run answers are written

With a token set, send Authorization: Bearer <token> on every /v1/* call. Actions that touch the machine (start, stop, import, delete, config) exist only on a loopback-bound server and need a JSON content type.

Route mapping

Legacy routes come from dashboard/server.py. Rows marked “no direct legacy route” are Control Plane routes that did not exist in the classic server.

Legacy Control Plane
GET /api/status GET /v1/runs (list, filters verdict, repo, since, until, group_id, limit, cursor), GET /v1/runs/<source>/<run> (detail), GET /v1/stats
GET /api/cost GET /v1/stats/cost
POST /api/control/start POST /v1/start (alias POST /v1/runs)
POST /api/control/stop POST /v1/runs/<source>/<run>/stop
POST /api/control/resume POST /v1/runs/<source>/<run>/resume
(none) POST /v1/runs/<source>/<run>/retry, POST /v1/runs/<source>/<run>/verify, POST /v1/runs/<source>/<run>/answer
log streaming GET /v1/runs/<source>/<run>/events, GET /v1/runs/<source>/<run>/stream, GET /v1/stream, GET /v1/runs/<source>/<run>/artifact/<path>
GET /api/audit GET /v1/audit
GET /api/health family GET /health (liveness), GET /ready (database check)
(no direct legacy route) GET /v1/config, PUT /v1/config
(no direct legacy route) GET /v1/providers, GET /v1/integrations
(no direct legacy route) GET /v1/notifications
(no direct legacy route) GET /v1/merge/queue, POST /v1/merge/queue, POST /v1/merge/run, GET /v1/review/risk
(no direct legacy route) GET /v1/keys (public key only, loopback only)
(no direct legacy route) GET /v1/repos (names only, loopback only)
(no direct legacy route) POST /v1/ingest, POST /v1/import, DELETE /v1/runs/<source>/<run>

Not yet available in the Control Plane

These legacy features have no Control Plane route today:

Deploy

Clients

SDKs, the VS Code extension and run.sh talk to the Control Plane. Set LOKI_CONTROL_URL (and LOKI_CONTROL_TOKEN when the server has one) to point them at a remote instance.

Building from source

cd packages/control-plane && bun run build:all   # UI plus dist/server.js