Local control surface

Drive and observe MARS through the embedded dashboard API.

The shipped dashboard is part of the Go binary. It serves local HTML pages, authenticated JSON control endpoints, bounded read APIs, and a server-sent-events stream for live updates. Use this reference when using the local operator UI or building a bounded companion, or incident playbook around a running mars start or mars serve process.

Start The Dashboard

mars start runs a scoped single-repo lifecycle. mars serve runs the persistent orchestrator. Both can expose the embedded dashboard. The listener is always loopback-only. Page/login shells, embedded assets, and a minimal redacted status projection remain an observer surface. Repos, roles, telemetry, evolution, quality, throughput, orchestration, decisions, SSE, and browser mutations require MARS_DASHBOARD_CONTROL_SECRET with at least 32 bytes, login, the exact Host/Origin, and the current session CSRF token.

Single target lifecycle

MARS_DASHBOARD_CONTROL_SECRET='<owner-provided-32+-byte-secret>' \
mars start --repo /path/to/repo \
  --dashboard-addr 127.0.0.1:9090 \
  --addr 127.0.0.1:9091 \
  --execution-profile host --acknowledge-host-execution

Use this when one target repo is the active autonomous lifecycle.

Persistent orchestrator

mars serve \
  --addr 127.0.0.1:9091 \
  --concurrency 2 \
  --execution-profile host --acknowledge-host-execution

Use this when webhooks, cron, and multiple registered repos are managed by one process.

Open and verify

open http://127.0.0.1:9090
curl http://127.0.0.1:9091/healthz
curl http://127.0.0.1:9090/api/status
Port fallback: scoped start can fall back to an available local dashboard port when the requested dashboard address is occupied. Use the URL printed by the running command.

Addresses

MARS uses two loopback-only HTTP surfaces during runtime. Keep them distinct when scripting checks or debugging a port issue.

SurfaceDefault shapeContainsUse it for
Dashboard address--dashboard-addrData-free page/login shells, embedded assets, minimal status, authenticated bounded /api/events, controls, and privileged read APIs.Local observer shell and authenticated operator control.
Webhook/control address--addr/healthz, GitHub webhook receiver, Jira webhook receiver.Health checks and external event ingress.
curl http://127.0.0.1:9091/healthz
curl http://127.0.0.1:9090/api/status

Pages

The HTML pages are operator views. They do not replace repo-owned artifacts such as tickets, feature contracts, traces, release notes, or quality score documents.

PathPageUser question
/RedirectRedirects to /pipeline.
/pipelinePipeline FlowWhich lifecycle role is active and what path is next?
/orchestrationOrchestrationWhich dispatch mode, role topology, decisions, and stop reasons are visible?
/rolesRole HealthWhich roles have recent score, success, failure, or quality signals?
/throughputThroughputHow many jobs are pending, running, completed, or failed?
/debugDebugWhat does the operator need to inspect during a runtime incident?
/evolutionEvolution HistoryWhat telemetry, repeated patterns, or self-improvement events are visible?

Events Stream

GET /api/events is a server-sent-events stream. It requires an authenticated session even on loopback and accepts GET only. It sends an initial keepalive comment, replays buffered recent events, then streams new events as they are broadcast. Replay, event size, client count, and per-session connections are bounded. Event payloads are JSON strings with type and data fields.

Subscribe

curl -N http://127.0.0.1:9090/api/events

Typical event line

data: {"type":"status_change","data":"{\"state\":\"paused\"}"}
Event typeWhen users see itCommon reaction
status_changePause, resume, restart, stop, or worker state changes.Refresh status or update companion UI state.
scan_completeA dashboard-triggered scanner pass finishes.Inspect generated tickets and findings count.
Job and telemetry eventsRuntime components broadcast dashboard updates.Use as notification hints, then read durable repo evidence.

Control Endpoints

POST /api/login accepts only JSON containing the environment-configured secret and returns an opaque HttpOnly SameSite=Strict session cookie plus the session CSRF token. After the login-shell redirect, authenticated same-origin GET /api/session bootstraps the current CSRF without a second secret entry or URL/browser-storage persistence. Mutating endpoints require POST, that cookie, exact same-origin Origin, and X-MARS-CSRF-Token. Bodyless mutations reject any body; JSON controls reject unknown fields, trailing values, oversize values, and non-JSON content. They return JSON with {"ok":true} on success, or an error field when the request cannot be applied.

EndpointMethodRequestBehavior
/api/pausePOSTEmpty body.Pauses worker claims; running jobs are allowed to finish.
/api/resumePOSTEmpty body.Resumes worker claims after a pause.
/api/restartPOSTEmpty body.Warm restart: stop workers, reload manifests and triggers, start workers again. HTTP stays up.
/api/stopPOSTEmpty body.Requests graceful orchestrator shutdown.
/api/scanPOST{"repo_id":"..."}Runs scanner for a registered repo and can enqueue stale-ticket hygiene.
/api/run-rolePOST{"repo_id":"...","role":"engineer"}Validates the role in the repo manifest and enqueues a manual run.
/api/emergency-stopPOSTEmpty body.Runs configured emergency-stop callbacks; raw callback errors remain in owner-only local logs.
/api/logoutPOSTEmpty body.Invalidates the current session; requires the same mutation policy.
/api/sessionGETAuthenticated session cookie.Returns the current session CSRF for same-origin browser bootstrap.

Status And Selection Endpoints

EndpointMethodResponseUser purpose
/api/statusGEThealthy, paused, active_jobs, uptime_secs, repos.Read live orchestrator state.
/api/reposGETArray of registered repos with id and redacted basename.Resolve repo IDs before scan or run-role without exposing personal paths.
/api/repo-roles?repo_id=...GETArray of role names.Populate role selectors for a repo.

Read APIs

When the dashboard is created by the orchestrator, serve attaches authenticated read APIs that power the dashboard pages. Unauthenticated loopback requests receive 503 when no control secret exists or 401 when login is required. Treat these as local operational evidence views, not as durable storage.

EndpointResponse shapeUser purpose
/api/telemetry{"events":[...],"stats":{...}}Inspect recent telemetry events and failure category counts.
/api/evolution{"evolutions":[...],"telemetry":[...],"patterns":[...]}Inspect self-improvement history and repeated telemetry patterns.
/api/roles{"roles":[...]}Inspect role scores, sample sizes, success counts, and failure counts.
/api/quality-scoretext/markdownServe the first registered repo's docs/QUALITY_SCORE.md or the scoped repo quality score.
/api/throughput{"hourly":[...],"recent_jobs":[...],"summary":{...}}Inspect recent job throughput and status distribution.
/api/orchestration{"repos":[...],"dispositions":[...],"decisions":[...]}Inspect dispatch mode, role topology, dispositions, and decisions.
/api/orchestration/decisions{"decisions":[...]}Inspect recent decisions, optionally filtered with ?repo_id=....

Responses And Errors

Scripts should branch on HTTP status and then read the response body. The dashboard favors actionable text over opaque codes.

StatusWhen it appearsWhat to do
200Successful page, stream, read API, or control action.Parse the JSON, markdown, HTML, or SSE response for the endpoint.
400Host, body, value, or JSON shape is invalid.Use the exact printed dashboard authority and documented bounded request.
401/403Session, exact Origin, or CSRF is absent, expired, or mismatched.Log in again through the exact dashboard origin.
404Unknown page, unknown static asset, or unavailable quality score because no repo is registered.Verify the dashboard URL and repo registration state.
405Using GET for a post-only endpoint, or POST for a get-only endpoint.Use the method in this reference.
415A JSON endpoint received another content type.Send exactly application/json.
429Login, mutation, or SSE connection pressure exceeded a bound.Honor Retry-After and retry later.
500Callback failure, render failure, or control action error.Read the error body and inspect the command log.
501A dashboard was created without the corresponding callback.Use the endpoint only from a full start or serve runtime.

Successful control response

{"ok":true}

Control error response

{"ok":false,"error":"repo_id and role are required"}

Emergency-stop callback errors

{"ok":false,"error":"emergency stop did not complete; inspect the owner-only local command log"}

Recipes

Pause safely, inspect, then resume

Log in through the embedded browser, then use Pause and Resume. Programmatic clients must implement the same session, exact Origin, and CSRF exchange; anonymous curl mutations fail closed.

Resolve repo and role before manual run

curl http://127.0.0.1:9090/api/repos
curl "http://127.0.0.1:9090/api/repo-roles?repo_id=REPO_ID"

Use the authenticated dashboard controls to run the selected role.

Run a scanner pass

Authenticate in the embedded browser, choose a repository, and use Scan. Afterward inspect generated tickets and the bounded scan_complete event.

Watch orchestration decisions

curl http://127.0.0.1:9090/api/orchestration
curl "http://127.0.0.1:9090/api/orchestration/decisions?repo_id=REPO_ID"

Stop gracefully from a script

Use terminal q, Ctrl+C, or the authenticated dashboard Stop button. Anonymous POST requests are deliberately rejected.

Security

The dashboard API is an operator control surface. MARS binds it only to loopback. Optional remote browsing requires an exact HTTPS reverse-proxy origin selected by --dashboard-trusted-origin or MARS_DASHBOARD_TRUSTED_ORIGIN, and every remote route requires a valid session. Forwarded headers are ignored.

  • Use 127.0.0.1:PORT for local-only operation.
  • Set the control secret only through MARS_DASHBOARD_CONTROL_SECRET; never put it in flags, YAML, URLs, logs, or generated files.
  • The embedded browser sends the secret only to the bounded login body; every later mutation uses the opaque session and session CSRF.
  • Strict self-only CSP, safe DOM text construction, vendored pinned assets, and no runtime CDN make the dashboard usable with outbound networking disabled.
  • Prefer repo-owned evidence and logs for audit trails; dashboard responses are live operational views.

Troubleshooting

SymptomLikely causeRecovery
/healthz works but /api/status failsYou are calling the webhook/control address instead of the dashboard address.Use the dashboard URL printed by start or serve.
/api/repo-roles returns 400Missing repo_id query parameter.Call /api/repos, copy an ID, and retry with ?repo_id=....
/api/run-role returns an errorRole is not present in that repo's manifest or the repo ID is wrong.Call /api/repo-roles?repo_id=... and choose one of the returned roles.
SSE stream connects but no updates arriveNo new dashboard events have been broadcast yet.Trigger a benign status change, such as pause and resume, or inspect /api/status.
Quality score endpoint returns 404No repo is registered or no scoped repo is available.Register or start a repo, then run mars scores export --repo /path/to/repo if the artifact is missing.
Control endpoint returns 501The dashboard was created without that callback.Use a full MARS runtime rather than a test or standalone dashboard handler.