Skip to content

Admin Console

Zlatko Lakisic edited this page Aug 7, 2026 · 4 revisions

Admin Console

Always-on ops UI served by the bridge on :8781/admin. Production and dev. Shares the port with Google Desktop OAuth. Source of truth in-repo: docs/CONTRACTS.md § Admin console, docs/DEV_LOOP.md §2, terminal/admin/.

This is an operations console, not the marketing site. Same visual language (dark field, cyan = healthy, amber = degraded / LAN / DEV, red = fail / destructive). Live emblem reuses terminal/kiosk/emblem.js so the rail face matches the hallway panel.


Open it

# SSH tunnel (preferred from the Mac)
LocalForward 8781 127.0.0.1:8781   # in Host comstar
make admin                         # http://127.0.0.1:8781/admin/

# LAN (token required when bound to 0.0.0.0)
# http://<pi-ip>:8781/admin/?token=<COMSTAR_ADMIN_TOKEN>
# or header: X-Comstar-Lan-Token: <token>

On the Pi, prefer systemd EnvironmentFile:

# ~/.config/comstar/admin.env  (mode 0600; never commit)
COMSTAR_ADMIN_BIND_LAN=1
COMSTAR_ADMIN_TOKEN=<secret>

Wire with a drop-in EnvironmentFile=-%h/.config/comstar/admin.env on comstar-bridge.service. Tokens containing ! break raw systemd Environment= lines.


Path split on :8781

Prefix Role Admin token
/admin/* Ops UI + APIs Required when LAN-bound (except health + static assets)
/oauth/google/* Desktop Google OAuth Never
/health Alias → /admin/health None
/kiosk/* Shared emblem/presets for admin ES modules None

Routes

Route Method Auth Meaning
/admin/ GET token if LAN-bound Static UI (favicon.svg, CSS, JS)
/admin/health /health GET none Attention / session / WS snapshot (heal script)
/admin/api/status GET token if LAN-bound Extended status, host metrics, AO/CPAI probes (AO probe uses mTLS when enabled); includes ao_mtls + road at_home
/admin/api/logs GET token if LAN-bound SSE journalctl --user tail
/admin/api/restart POST token if LAN-bound {unit: bridge|audio|kiosk|stt|health|all}
/admin/api/reboot POST token if LAN-bound {confirm: "reboot"}
/admin/api/sleep POST token if LAN-bound {action: enter|exit}
/admin/api/road GET/POST token if LAN-bound Road VPN phone-home (ADR 0011)
/admin/api/network GET/POST token if LAN-bound Wi‑Fi + IPv4 via nmcli (ADR 0012)
/admin/api/ao_mtls GET/POST token if LAN-bound AO Reach mTLS pairing (ADR 0013)
/admin/inject POST token if LAN-bound Attention inject; 403 unless COMSTAR_ENV=dev
/oauth/google/* * none OAuth start / callback / resend

Restart units are whitelisted (comstar-*.service only).

Token accepted as X-Comstar-Lan-Token (preferred) or ?token=. Resolution order: COMSTAR_ADMIN_TOKENadmin.tokendev.lan_token.

The log panel uses fetch with the auth header (not EventSource), so proxy header injection (e.g. Warpgate) works without putting the token in the URL.


Bind rules

Default bind: 127.0.0.1. Bind 0.0.0.0 when any of:

  1. admin.bind_lan: true and a non-empty admin token, or
  2. COMSTAR_ADMIN_BIND_LAN=1 and COMSTAR_ADMIN_TOKEN (preferred on Pi), or
  3. the WS LAN triple-gate is active, or
  4. Google OAuth would have bound LAN (COMSTAR_OAUTH_BIND_LAN / redirect base)

Admin LAN bind is independent of the WebSocket triple-gate. Ports 8777/8778 still need COMSTAR_ENV=dev + comstar.dev.yaml + dev.lan_token. See Security.

When LAN-bound, the UI shows a permanent amber LAN badge and rule.


UI panels

Panel What you get
Top bar Brand, hostname, LOOPBACK/LAN badge, DEV badge, uptime, live poll dot, clock
Left rail Live emblem (actual attention state), userid, session/reach/sleep/uptime
Health AO, CPAI, STT, kiosk, audio cards + CPU/mem
Ops tabs Actions · AO pairing · Road VPN · Network · Logs (same panel)
Actions Restart units, sleep/wake; danger zone: restart all / reboot
AO pairing Enroll / clear / probe AO client certs; status dot on the tab (ADR 0013)
Road VPN Phone-home OpenVPN/L2TP; gray At home when VPN not needed (ADR 0011)
Network Wi‑Fi scan/connect + ethernet/wlan DHCP or static IPv4 (ADR 0012)
Inject Dev only (COMSTAR_ENV=dev): synthetic attention events
Logs Live JSONL tail (Ops → Logs tab): unit filter, text filter, pause, wrap, download

Status dots (Ops tabs)

Tab Cyan Amber / gray Red
AO pairing mTLS enabled and PEMs present (paired) Gray = mTLS disabled in config Enabled but not paired
Road VPN Tunnel up / healthy Gray At home (local CIDR; VPN idle by design) Off-home and down / unhealthy

GET /admin/api/status exposes ao_mtls: {enabled, paired} and road at_home for the rail.

AO pairing (Ops → AO pairing)

Ada AO ≥ 1.29 serves HTTPS with required client certs. Primary UX is this tab; headless alternative: make ao-mtls-enroll TOKEN=….

  1. Paste a one-time enrollment token from Ada.
  2. Enroll writes PEMs under ~/.local/share/comstar/ao-mtls/ (never commit).
  3. Probe / health use the same client cert + CA trust.
  4. Clear material to force re-pair (sessions fail closed until re-enrolled when mTLS is enabled).

Config: orchestration.mtls.* + base_url: https://…Configuration, ADR 0013.

Offline SoftAP (admin QR)

When the Pi has no ethernet and no Wi‑Fi client, the bridge brings up NM SoftAP comstar-hotspot (SSID COMSTAR-<hostname>, open, Pi at 10.87.65.1/24). The kiosk admin QR points at that IP, shows the SSID under the QR, and stays visible while the hotspot is up (even if kiosk debug UI is off). Join the SSID, then scan. Disable with COMSTAR_HOTSPOT=0. See ADR 0014.

Freshness: panels dim when the status poll fails. Unreachable emblem freezes grey with an amber ring.


Dev inject

Same handle(Event) entry point as hardware. Events are tagged src: "injected" in logs.

curl -sS -X POST 'http://127.0.0.1:8781/admin/inject?token=…' \
  -H 'content-type: application/json' \
  -H 'X-Comstar-Lan-Token: …' \
  -d '{"event":"TranscriptReady","text":"What time is it?"}'

Supported events: PersonDetected, PersonAbsent, FaceRecognized, FaceUnknown, WakeWord, SpeechStart, SpeechEnd, TranscriptReady, ResponseReady, PlaybackEnded, Tick, AttentionError, VisionDegraded, VisionRecovered.


Warpgate / reverse proxy notes

If you front :8781 with Warpgate (or similar):

  1. Terminate Warpgate auth for humans.
  2. Inject X-Comstar-Lan-Token: <secret> toward the Pi for /admin/* (except /admin/health, which needs no token).
  3. Pass /oauth/google/* through without requiring the COMSTAR admin token. Keep Google’s registered callback URL aligned with the public host.
  4. Do not buffer /admin/api/logs (SSE).
  5. Do not confuse this token with AO’s x-warpgate-token (orchestration).

Related pages

Clone this wiki locally