Skip to content

Headless

github-actions[bot] edited this page Oct 19, 2026 · 1 revision

🌍 View in other languages

Headless Mode

Headless mode boots OmniRoute as a plain LLM proxy: the OpenAI-compatible API under /v1/* keeps working, but the dashboard is switched off and the optional subsystems that only feed the dashboard (or add opt-in features on top of the proxy) are not started at boot.

Use it for servers, containers and CI boxes where nobody opens the dashboard and you want a lighter, quieter process. Nothing is uninstalled or removed: unset the variable and restart to get the full server back.

Turning it on

Either set the environment variable:

OMNIROUTE_HEADLESS=1 omniroute serve

or pass the CLI flag, which sets OMNIROUTE_HEADLESS=1 on the server process for you:

omniroute serve --headless
omniroute serve --headless --port 20128 --daemon

Accepted truthy values are 1, true, yes and on (case-insensitive). Any other value, or an unset variable, keeps the full server. The flag is implemented in bin/cli/commands/serve.mjs; the single source of truth for the mode is src/lib/system/headless.ts.

With --headless the CLI does not open a browser and the startup banner prints Dashboard: disabled (headless). --headless cannot be combined with --tray (the tray menu exists to open the dashboard).

What stays on

Surface Headless
/v1/* (chat completions, responses, models, embeddings, …) on
/api/monitoring/health on
/api/auth/* and the API-key / REQUIRE_API_KEY checks on
Every other /api/* route (management API, used by the omniroute CLI) on
Proxy core at boot: DB, secrets, quota fetchers, settings hydration on
Background proxy work: quota refresh, token auto-refresh, cooldown recovery on
API bridge port, cleanup/VACUUM schedulers, backup schedule on
Memory: configured memory backends + typed-memory decay sweep on

Authentication is unchanged: if /v1/* needs an API key on the full server, it needs one in headless mode too.

What is switched off

Dashboard pages. /dashboard, /dashboard/*, /home and /home/* answer 404 with the JSON body {"error":"dashboard disabled (headless)"}. The gate runs in src/proxy.ts before the authorization pipeline, so no other route is affected.

Optional boot subsystems. registerNodejs() in src/instrumentation-node.ts skips:

Subsystem name What it does on the full server
free-proxy-sync Re-fetches free-proxy source lists on an interval
cloud-sync Cloud / model sync background bootstrap
embedded-services Auto-starts embedded services marked auto-start
embed-ws-proxy WebSocket proxy for embedded service UIs
conductor-bridge Mirrors OmniConductor hub tasks into A2A (opt-in, CONDUCTOR_HUB_URL)
arena-elo-sync Arena ELO leaderboard sync for the Free Provider Rankings page
radar-sync Radar daily feed sync (opt-in)
pricing-sync External pricing data sync (opt-in, PRICING_SYNC_ENABLED)
openrouter-provider-stats Provider directory / popularity enrichment for the dashboard
models-dev-sync models.dev capability sync (opt-in in settings)
live-dashboard-ws Real-time dashboard WebSocket daemon (port 20132)

Each skip is logged once at startup, for example:

[STARTUP] Headless mode: skipping free-proxy-sync
[STARTUP] Headless mode: skipping cloud-sync
[STARTUP] Headless mode: skipping optional subsystems: embedded-services, embed-ws-proxy, …

Checking it with curl

# Health — 200
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:20128/api/monitoring/health

# Models — 200 (add -H "Authorization: Bearer $OMNIROUTE_KEY" when REQUIRE_API_KEY is on)
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:20128/v1/models

# Dashboard — 404 with the headless error body
curl -s -w "\n%{http_code}\n" http://localhost:20128/dashboard
# {"error":"dashboard disabled (headless)"}
# 404

Limits

  • Set before start. The server process reads OMNIROUTE_HEADLESS from its own environment; switching modes means restarting the server with the variable set or unset.
  • Management API stays reachable. Headless mode only closes the dashboard pages. The /api/* management routes keep their normal authorization tiers, so the omniroute CLI (and remote mode) keep working. It is not a security boundary — keep using REQUIRE_API_KEY and a loopback bind (OMNIROUTE_SERVER_HOST) where appropriate.
  • Route-loaded features still load on demand. MCP, A2A, evals, gamification, webhooks and cloud agents have no boot-time init; they start lazily when their routes are called, in both modes.
  • Memory stays on. Memory is cross-cutting to the request pipeline (/v1 injects and queries it), so the configured memory backends and the typed-memory decay sweep start at boot in headless mode exactly as on the full server.
  • Code still ships. This mode changes what runs, not what is installed — the package size and the build are identical.

See also

  • ENVIRONMENT.md — OMNIROUTE_HEADLESS and OMNIROUTE_DISABLE_BACKGROUND_SERVICES (a separate switch that stops background schedulers but keeps the dashboard).
  • REMOTE-MODE.md — drive a remote (for example, headless) OmniRoute from your laptop with the omniroute CLI.

Clone this wiki locally