# ┌─────────────────────────────────────────────────────────────────────────────┐ # │ OmniRoute — .env Contract │ # │ This file documents EVERY environment variable read by the runtime. │ # │ Copy to .env and adjust values. Lines starting with # are commented out │ # │ (optional / off-by-default). Uncomment only what you need. │ # │ Reference: docs/ENVIRONMENT.md for full details and usage scenarios. │ # └─────────────────────────────────────────────────────────────────────────────┘ # ═══════════════════════════════════════════════════════════════════════════════ # 1. REQUIRED SECRETS — Must be set before first run! # ═══════════════════════════════════════════════════════════════════════════════ # These secrets are critical for security. Generate strong, unique values. # JWT signing key for dashboard session tokens. # Used by: src/lib/auth — signs/verifies all authenticated session cookies. # Generate: openssl rand -base64 48 JWT_SECRET= # Encryption key for API keys stored in the database. # Used by: src/lib/db/apiKeys.ts — encrypts API key values at rest in SQLite. # Generate: openssl rand -hex 32 API_KEY_SECRET= # Initial admin login password — CHANGE THIS before first use! # Used by: bootstrap only — sets the initial dashboard password on first boot. # After first login you can change it from Dashboard → Settings → Security. # Default: CHANGEME (insecure, for local dev only) INITIAL_PASSWORD=CHANGEME # ═══════════════════════════════════════════════════════════════════════════════ # 2. STORAGE & DATABASE # ═══════════════════════════════════════════════════════════════════════════════ # OmniRoute uses SQLite for all persistence. These variables control where # data lives, encryption, and cleanup policies. # Base directory for all persistent data (SQLite DB, logs, backups). # Used by: src/lib/db/core.ts — resolves the SQLite database file path. # Default: ~/.omniroute/ | Override for Docker or custom installations. # Hint: When running in Docker, consider mounting a host directory here for data persistence across container restarts # also if you want to share the same database as "npm run dev" use "./data" # DATA_DIR=/var/lib/omniroute # Encryption key for SQLite database encryption at rest. # Used by: src/lib/db/encryption.ts — encrypts the entire SQLite database. # Generate: openssl rand -hex 32 | Leave empty to disable DB encryption. STORAGE_ENCRYPTION_KEY= # Version tag for the encryption key — allows future key rotation. # Used by: scripts/bootstrap-env.mjs, electron/main.js — persists key version. # Default: v1 | Increment when rotating STORAGE_ENCRYPTION_KEY. STORAGE_ENCRYPTION_KEY_VERSION=v1 # Automatic SQLite backup on startup. # Used by: src/lib/db/backup.ts — creates a timestamped backup before migrations. # Default: false (backups enabled) | Set true to skip backup on every restart. DISABLE_SQLITE_AUTO_BACKUP=false # ── Redis (Rate Limiting) ── # Redis connection URL for the rate limiter backend. OPT-IN: leave this # commented out to use the built-in in-memory rate limiter. Setting it to a # non-running localhost (#4878) makes ioredis flood "[REDIS] Error:" logs. # Used by: src/shared/utils/rateLimiter.ts # Example: redis://localhost:6379 (or redis://redis:6379 in Docker) # REDIS_URL=redis://localhost:6379 # ═══════════════════════════════════════════════════════════════════════════════ # 3. NETWORK & PORTS # ═══════════════════════════════════════════════════════════════════════════════ # OmniRoute can run on a single port (default) or split Dashboard/API ports. # Canonical port for both Dashboard UI and API (single-port mode). # Used by: src/lib/runtime/ports.ts — base port for the Next.js server. # Default: 20128 PORT=20128 # Base path (URL subpath) when serving OmniRoute behind a reverse proxy under a subpath. # Used by: next.config.mjs — sets Next.js `basePath`; auth redirects are basePath-aware. # Default: "" (served at the domain root). Example: /omniroute to serve under https://host/omniroute # OMNIROUTE_BASE_PATH= # Split-port mode: serve Dashboard and API on separate ports for network isolation. # Used by: src/lib/runtime/ports.ts — overrides PORT for each service. # API_PORT=20129 # API_HOST=0.0.0.0 # DASHBOARD_PORT=20128 # Port for the real-time WebSocket live monitoring server. # Used by: src/server/ws/liveServer.ts, src/app/api/v1/ws/route.ts # Default: 20129 # LIVE_WS_PORT=20129 # Bind address for the live WebSocket server. # Default: 127.0.0.1 (loopback only). Set to 0.0.0.0 to expose on LAN — # remember to also configure LIVE_WS_ALLOWED_ORIGINS when doing so. # LIVE_WS_HOST=127.0.0.1 # Comma-separated extra origins allowed to open a live WebSocket. The # loopback dashboard origins are already permitted by default; use this # var when fronting the server with a domain (e.g. https://omni.local). # ⚠️ When using NEXT_PUBLIC_LIVE_WS_PUBLIC_URL or exposing the WS server # beyond loopback, this MUST include the public origin(s) — otherwise # the Origin allow-list check will reject all browser connections. # Example: LIVE_WS_ALLOWED_ORIGINS=https://omni.local,https://dashboard.example.com,https://ws.my-ai.com # LIVE_WS_ALLOWED_ORIGINS=https://omni.local,https://dashboard.example.com # Comma-separated extra hostnames allowed to open a live WebSocket (LAN/Tailscale). # Unlike LIVE_WS_ALLOWED_ORIGINS (which matches full origin URLs), this matches # only the host portion — useful for wildcard-ish LAN/Tailscale setups. # Used by: src/server/ws/liveServerAllowList.ts # Example: LIVE_WS_ALLOWED_HOSTS=omni.local,tailscale-host,192.168.1.50 # LIVE_WS_ALLOWED_HOSTS=omni.local,tailscale-host,192.168.1.50 # Public URL for the live dashboard WebSocket (client-side, browser only). # Set this when fronting the WS server with a reverse proxy or Cloudflare Tunnel. # The browser will connect to this URL instead of ws://hostname:20129. # The /live-ws path is already proxied from the main app (port 20128) to the # live WS server (port 20129) by scripts/dev/standalone-server-ws.mjs. # Used by: src/hooks/useLiveDashboard.ts # Example: NEXT_PUBLIC_LIVE_WS_PUBLIC_URL=wss://ws.my-ai.com/live-ws # NEXT_PUBLIC_LIVE_WS_PUBLIC_URL= # Disable the standalone live WebSocket helper used by scripts/start-ws-server.mjs. # Used by: scripts/start-ws-server.mjs (CI/embedded harness toggle). # OMNIROUTE_DISABLE_LIVE_WS=0 # Enable the real-time dashboard WebSocket server. # Used by: src/server/ws/liveServer.ts, scripts/start-ws-server.mjs # Default: ON. Set to 0 or false to disable startup of the live WS server. # Combine with LIVE_WS_HOST / LIVE_WS_ALLOWED_ORIGINS above when exposing # beyond loopback. # OMNIROUTE_ENABLE_LIVE_WS=1 # Per-(token,IP) relay rate limit, requests/minute. In-memory, per instance. # 0 or negative disables the IP-dimension gate (per-token DB limit still applies). # Default: 30 # Used by: src/app/api/v1/relay/chat/completions/route.ts # RELAY_IP_PER_MINUTE=30 # Bundler selection for `npm run dev`. Set to 0 to fall back to webpack. # Default is 1 (Turbopack). PR #4092 had forced webpack because earlier # Turbopack 16.2.x panicked on the OmniRoute module graph with "internal error: # entered unreachable code: there must be a path to a root" # (turbopack-core/module_graph/mod.rs:662). That panic no longer reproduces on # the pinned Next 16.2.9 — verified across a broad cold-compile sweep (36 # dashboard routes + open-sse-heavy API routes incl. /api/v1/chat/completions, # /api/v1/models, /api/mcp) and repeated HMR rebuilds: zero panics. Turbopack # also keeps dev memory far lower on the edit→rebuild loop (HMR rebuild RSS stays # ~flat vs webpack's monotonic growth), which mitigates the dev-server OOM on # this 60+ route app. The production build still uses webpack (build pipeline is # unaffected by this dev-only flag). OMNIROUTE_USE_TURBOPACK=1 # Skip the SQLite integrity health check on startup (faster boot on large DBs). # Used by: src/lib/db/core.ts, src/lib/db/healthCheck.ts. Set to 1 to skip. # OMNIROUTE_SKIP_DB_HEALTHCHECK=1 # Interval (ms) for the background credential health check scheduler. # Default: 300000 (5 minutes). Minimum: 10000 (10 seconds). # Used by: open-sse/config/constants.ts, src/lib/credentialHealth/scheduler.ts # CREDENTIAL_HEALTH_CHECK_INTERVAL=300000 # TTL (ms) for cached credential health status. # Default: 300000 (5 minutes). # Used by: open-sse/config/constants.ts, src/lib/credentialHealth/cache.ts # CREDENTIAL_HEALTH_CACHE_TTL=300000 # Set to 1 or true to disable background periodic testing of provider connections. # Default: false # Used by: src/lib/credentialHealth/scheduler.ts # OMNIROUTE_DISABLE_CREDENTIAL_HEALTH_CHECK=false # Set to "true" to emit `[ProxyFetch]` debug logs from the Vercel relay path # in open-sse/utils/proxyFetch.ts. Off by default to avoid leaking routing # hints in production logs. # OMNIROUTE_PROXY_FETCH_DEBUG=true # Docker production port mappings (docker-compose.prod.yml only). # These set the HOST-side published ports. Container ports use PORT/API_PORT. # PROD_DASHBOARD_PORT=20130 # PROD_API_PORT=20131 # Runtime override used by Electron and wrapped environments. # OMNIROUTE_PORT takes precedence over PORT when running inside wrappers. # Used by: src/lib/runtime/ports.ts — preserves canonical port in Electron. # OMNIROUTE_PORT=20128 # Hostname/bind address for the Next.js server. # Used by: scripts/dev/run-next.mjs (HOST), Playwright runner (HOSTNAME). # Default: 0.0.0.0 (HOST) / 127.0.0.1 (HOSTNAME inside tests). # NOTE: Do NOT use `HOSTNAME` — it is a POSIX shell variable automatically set to # the machine name by bash/zsh. The .env loader cannot override it (first-wins # semantics). Use OMNIROUTE_SERVER_HOST instead for `omniroute serve`. # See: https://github.com/diegosouzapw/OmniRoute/issues/6194 #HOST=0.0.0.0 #HOSTNAME=127.0.0.1 #OMNIROUTE_SERVER_HOST=0.0.0.0 # Environment mode — affects Next.js behavior, logging verbosity, and caching. # Values: production | development | Default: production NODE_ENV=production # Container runtime — controls startup script behavior (permissions, advice). # Values: docker | podman | Default: docker # Set to "podman" when running under rootless Podman so the entrypoint # gives the correct fix instructions (podman unshare chown vs sudo chown). CONTAINER_HOST=docker # ═══════════════════════════════════════════════════════════════════════════════ # 4. SECURITY & AUTHENTICATION # ═══════════════════════════════════════════════════════════════════════════════ # Salt for generating unique machine IDs (fingerprint diversification). # Used by: src/lib/auth — combined with hardware identifiers for machine-id hash. # Default: endpoint-proxy-salt | Change per-deployment for isolation. MACHINE_ID_SALT=endpoint-proxy-salt # Salt for deriving CLI machine-ID auth tokens (HMAC-SHA256). # Used by: src/lib/machineToken.ts — rotates the local CLI auth token without # touching code. Set to a new value to invalidate existing CLI tokens. # Default: omniroute-cli-auth-v1 # OMNIROUTE_CLI_SALT=omniroute-cli-auth-v1 # Set true when running behind HTTPS (reverse proxy with TLS termination). # Used by: src/lib/auth — sets the Secure flag on session cookies. # Default: false | MUST be true in any non-localhost deployment. AUTH_COOKIE_SECURE=false # Require an API key for all /v1/* proxy endpoints. # Used by: API middleware — rejects unauthenticated requests to the proxy API. # Default: false | Set true for multi-user/public deployments. REQUIRE_API_KEY=false # Allow revealing full API key values in the Dashboard UI. # Used by: src/shared/constants/featureFlagDefinitions.ts — controls show/hide of key values. # Also configurable from Dashboard > Settings > Feature Flags. # Default: false | Security risk if enabled on shared instances. ALLOW_API_KEY_REVEAL=false # Shared secret for the internal Codex Responses WebSocket bridge. # Used by: src/app/api/internal/codex-responses-ws/route.ts — authenticates # bridge requests between the Electron/browser WS relay and OmniRoute. # ⚠️ REQUIRED for production — if unset, all WS bridge requests are rejected. # Generate: openssl rand -base64 32 # OMNIROUTE_WS_BRIDGE_SECRET= # Per-process secret that proves the trusted peer-IP stamp came from OmniRoute's # own HTTP server (scripts/dev/peer-stamp.mjs). The custom server stamps the real # TCP peer IP as `|`; the authz middleware trusts the locality only # when the token matches. Used by: src/server/authz/policies/management.ts. # Auto-generated per boot — leave UNSET in normal use. Only set it to pin a fixed # value across processes (e.g. a multi-process setup that must share the stamp). # OMNIROUTE_PEER_STAMP_TOKEN= # Comma-separated API key IDs that skip request logging (GDPR/compliance). # Used by: src/lib/compliance/index.ts — suppresses logs for specific keys. # NO_LOG_API_KEY_IDS=key_abc123,key_def456 # Fallback per-day request budget applied to API keys whose `rate_limits` # column is null. Default (unset/empty/malformed) preserves the legacy # 1000/day, 5000/week, 20000/month windows so existing deployments do not # silently lose rate limiting on upgrade. # Set explicitly to "0" to opt out entirely (unlimited fallback). Any # positive integer N enables N/day, 5N/week, 20N/month. # Used by: src/shared/utils/apiKeyPolicy.ts — checkRateLimit() fallback. # DEFAULT_RATE_LIMIT_PER_DAY=1000 # Maximum request body size in bytes (rejects larger payloads). # Used by: src/shared/middleware/bodySizeGuard.ts — prevents oversized uploads. # Default: 10485760 (10 MB) # MAX_BODY_SIZE_BYTES=10485760 # Heap-pressure-aware admission for POST /v1/chat/completions (#5152). A large # coding-agent "compact" body amplifies into hundreds of MB of transient JS objects # on the combo path; concurrent compacts can stack past the V8 heap ceiling and OOM # the process. These shed a LARGE body with 503 (Retry-After) only while the heap is # already under pressure — healthy heap admits every body untouched. # Used by: src/shared/middleware/chatBodyAdmission.ts # Bodies below this size skip the guard entirely (heap not even sampled). Default 262144 (256 KB). # OMNIROUTE_CHAT_LARGE_BODY_BYTES=262144 # Hard cap — bodies above this are rejected with 413 before any clone/parse. Default 52428800 (50 MB). # OMNIROUTE_CHAT_HARD_MAX_BODY_BYTES=52428800 # Shed large bodies once heapUsed/heap_size_limit reaches this ratio (0). # Set this when OpenWebUI or another relay reaches OmniRoute by an internal URL # but the user's browser must fetch images from a LAN, tunnel, or public origin. # Do not include /v1; if included accidentally it will be normalized away. # OMNIROUTE_PUBLIC_BASE_URL=http://192.168.0.15:20128 # Absolute provider plugin manifest URL advertised to sidecar clients. # Used by: open-sse/config/providerPluginManifestUrl.ts. When unset, OmniRoute # derives the URL from request origin or HOST/PORT using OMNIROUTE_PUBLIC_PROTOCOL. # OMNIROUTE_PROVIDER_MANIFEST_URL=https://omniroute.example.com/api/v1/provider-plugin-manifest # Protocol used when deriving provider plugin manifest URLs without a request origin. # Used by: open-sse/config/providerPluginManifestUrl.ts. Defaults to http. # OMNIROUTE_PUBLIC_PROTOCOL=http # Max wait time for an async chatgpt-web image to land via the celsius # WebSocket, in milliseconds. Default 180000 (3 minutes). Increase during # upstream queue-deep windows ("Lots of people are creating images right now"). # OMNIROUTE_CGPT_WEB_IMAGE_TIMEOUT_MS=180000 # Total in-memory byte budget for the chatgpt-web image cache (used to serve # /v1/chatgpt-web/image/), in megabytes. Default 256. Lower this if you # run OmniRoute on a memory-constrained host; raise it if image generation # is heavy and clients are racing the 30-minute TTL. # OMNIROUTE_CGPT_WEB_IMAGE_CACHE_MAX_MB=256 # Overall wait budget for a chatgpt-web GPT-5.5 Pro background-poll handoff, # in milliseconds. Default 1200000 (20 minutes). Pro reasoning runs are slow # and complete out-of-band, so OmniRoute polls until the answer lands or this # budget elapses. Raise it if Pro requests time out before finishing. # OMNIROUTE_CGPT_WEB_PRO_TIMEOUT_MS=1200000 # Interval between chatgpt-web GPT-5.5 Pro background-poll attempts, in # milliseconds. Default 4000 (4 seconds). Lower for snappier completion at the # cost of more upstream polling; raise to reduce request volume. # OMNIROUTE_CGPT_WEB_PRO_POLL_INTERVAL_MS=4000 # Public cloud URL — client-side mirror of CLOUD_URL. NEXT_PUBLIC_CLOUD_URL= # Legacy alias — fallback for NEXT_PUBLIC_BASE_URL in sync schedulers. # NEXT_PUBLIC_APP_URL=http://localhost:20128 # Advanced reverse-proxy trust mode for deriving public origin from Forwarded / # X-Forwarded-* headers when no explicit public base URL is set. Prefer setting # NEXT_PUBLIC_BASE_URL. Only enable if direct client access to OmniRoute is blocked # and your proxy strips/rebuilds incoming forwarded headers. # Values: true/loopback (trust loopback proxy peers), private/lan (also trust LAN peers). # OMNIROUTE_TRUST_PROXY= # Public callback URL for asynchronous image/audio jobs (kie.ai, etc.). # Used by: open-sse/utils/kieTask.ts — overrides callbackUrlFromBaseUrl(). # Honor order: KIE_CALLBACK_URL → OMNIROUTE_KIE_CALLBACK_URL → OMNIROUTE_PUBLIC_URL. #KIE_CALLBACK_URL= #OMNIROUTE_KIE_CALLBACK_URL= #OMNIROUTE_PUBLIC_URL= # Headroom token-saver proxy URL. The dashboard lifecycle (api/headroom/*) spawns # a local headroom-ai CLI on loopback by default; override only to point at an # external Docker sidecar proxy. Defaults to http://localhost:8787 when unset. # Used by: src/lib/headroom/detect.ts. #HEADROOM_URL=http://localhost:8787 # Upstream quota endpoints used by the Usage page. Override only for # debugging or when routing through a corporate mirror. Used by: # open-sse/services/usage.ts. #OMNIROUTE_CROF_USAGE_URL=https://crof.ai/usage_api/ #OMNIROUTE_CODEWHISPERER_BASE_URL=https://codewhisperer.us-east-1.amazonaws.com #OMNIROUTE_OPENCODE_QUOTA_URL=https://opencode.ai/zen/go/v1/quota #OMNIROUTE_OPENCODE_GO_QUOTA_URL=https://api.z.ai/api/monitor/usage/quota/limit #OMNIROUTE_OPENCODE_GO_DASHBOARD_URL=https://opencode.ai/workspace #OMNIROUTE_OLLAMA_CLOUD_USAGE_URL=https://ollama.com/settings # OpenCode Go dashboard quota scraping. Prefer configuring these per connection # in Dashboard → Providers → OpenCode Go. Env vars are useful for headless # deployments or shared server defaults. The cookie is sensitive. #OPENCODE_GO_WORKSPACE_ID=wrk_... #OMNIROUTE_OPENCODE_GO_WORKSPACE_ID=wrk_... #OPENCODE_GO_AUTH_COOKIE=auth=... #OMNIROUTE_OPENCODE_GO_AUTH_COOKIE=auth=... # OpenCode Go/Zen VPS egress (#5997): on a datacenter VPS, Cloudflare in front of # opencode.ai/zen/go 403s chat requests that lack OpenCode CLI identity headers. # When your clients don't already send them, set this to synthesize the CLI headers # (User-Agent, x-opencode-client, x-opencode-project, fresh request/session UUIDs) on # absent keys. OFF by default — forward-only is safer when clients already send them. # Values are overridable via OPENCODE_GO_USER_AGENT / OPENCODE_USER_AGENT / OPENCODE_CLIENT / # OPENCODE_PROJECT (defaults: opencode-cli/1.0.0 / cli / default). #OPENCODE_SYNTHESIZE_CLI_HEADERS=true #OPENCODE_USER_AGENT=opencode-cli/1.0.0 #OPENCODE_CLIENT=cli #OPENCODE_PROJECT=default # Ollama Cloud quota scraping. Prefer configuring this per connection in # Dashboard → Providers → Ollama Cloud. The cookie is sensitive. #OLLAMA_USAGE_COOKIE=__Secure-session=... #OLLAMA_CLOUD_USAGE_COOKIE=__Secure-session=... #OMNIROUTE_OLLAMA_USAGE_COOKIE=__Secure-session=... # ═══════════════════════════════════════════════════════════════════════════════ # 8. OUTBOUND PROXY (Upstream Provider Calls) # ═══════════════════════════════════════════════════════════════════════════════ # Route upstream LLM API calls through an HTTP/SOCKS5 proxy. # Useful for corporate egress, geo-routing, or IP masking. # Enable SOCKS5 proxy support in both server and client components. # Used by: open-sse/executors — wraps fetch() calls through the proxy agent. ENABLE_SOCKS5_PROXY=true NEXT_PUBLIC_ENABLE_SOCKS5_PROXY=true # Standard proxy variables (lowercase variants also supported). # HTTP_PROXY=http://127.0.0.1:7890 # HTTPS_PROXY=http://127.0.0.1:7890 # ALL_PROXY=socks5://127.0.0.1:7890 # NO_PROXY=localhost,127.0.0.1 # Max concurrent sockets per cached HTTP/SOCKS proxy dispatcher. # Long-lived SSE streams such as Codex /v1/responses need more than one # connection when multiple requests share the same account-level proxy. # Set to 1 only for legacy diagnostics. Values above 256 are capped. # OMNIROUTE_PROXY_DISPATCHER_CONNECTIONS=32 # SOCKS5 handshake (connect) timeout in ms (default 10000, capped at 120000). # Raise it when a single residential gateway host is hit by high concurrency # (e.g. 100 simultaneous requests): the real SOCKS5 handshake can exceed 10s # under a saturated pool even though the proxy is reachable, which otherwise # surfaces as a false "[Proxy Fast-Fail] Proxy unreachable". # SOCKS_HANDSHAKE_TIMEOUT_MS=10000 # Proxy fail-open mode (default: false = fail-closed). # When false, a request whose assigned proxy fails to resolve is REFUSED rather than # falling back to a direct connection — prevents real-IP leaks in egress-controlled # deployments. Set true to restore the legacy DIRECT fallback (legacy behaviour). # Used by: src/sse/handlers/chatHelpers.ts # PROXY_FAIL_OPEN=false # TLS fingerprint spoofing (opt-in) — mimics Chrome 124 TLS handshake via wreq-js. # Reduces risk of JA3/JA4 fingerprint-based blocking by providers (e.g., Google). # Used by: open-sse/executors — replaces Node.js default TLS fingerprint. # ENABLE_TLS_FINGERPRINT=true # Allow the Claude Turnstile Playwright browser context to ignore HTTPS certificate errors. # Only enable for local debugging or trusted MITM/corporate proxy environments. # Used by: open-sse/services/claudeTurnstileSolver.ts # OMNIROUTE_TURNSTILE_IGNORE_TLS_ERRORS=false # ═══════════════════════════════════════════════════════════════════════════════ # 9. CLI TOOL INTEGRATION # ═══════════════════════════════════════════════════════════════════════════════ # Control how OmniRoute discovers and launches CLI sidecars (Claude, Codex, etc.). # Used by: src/shared/services/cliRuntime.ts # CLI discovery mode: auto = search PATH | manual = use explicit paths below. # CLI_MODE=auto # Additional PATH entries for finding CLI binaries (colon-separated). # CLI_EXTRA_PATHS=/host-cli/bin:/usr/local/bin # Home directory override for reading CLI config files (~/.claude, etc.). # CLI_CONFIG_HOME=/root # Allow OmniRoute to write CLI config files (token refresh, etc.). # CLI_ALLOW_CONFIG_WRITES=true # Auto-sync CLI profile files after provider model discovery changes. OPT-IN, default OFF for # both. When enabled, writes only the tool's profile files (~/.codex/*.config.toml or # ~/.claude/profiles//settings.json); never changes the active/default config. Both also # require CLI_ALLOW_CONFIG_WRITES (default on). Toggle from the CLI Code dashboard, or set here. # Leave unset to disable. (Feature flags — a DB/dashboard override takes precedence over env.) # OMNIROUTE_AUTO_SYNC_CODEX_PROFILES=true # OMNIROUTE_AUTO_SYNC_CLAUDE_PROFILES=true # Override binary paths for individual CLI tools. # CLI_CLAUDE_BIN=claude # CLI_CODEX_BIN=codex # CLI_DROID_BIN=droid # CLI_OPENCLAW_BIN=openclaw # CLI_CURSOR_BIN=agent # CLI_CLINE_BIN=cline # CLI_CONTINUE_BIN=cn # CLI_QODER_BIN=qoder # CLI_QWEN_BIN=qwen # CLI_AUGGIE_BIN=auggie # AUGGIE_BIN=auggie # Override the Hermes Agent home directory (where OmniRoute reads/writes the # Hermes CLI config). Matches the env var the Hermes PowerShell installer sets # on Windows (%LOCALAPPDATA%\hermes); defaults to ~/.hermes when unset. # Used by: src/lib/cli-helper/config-generator/hermesHome.ts # HERMES_HOME=~/.hermes # ═══════════════════════════════════════════════════════════════════════════════ # 10. INTERNAL AGENT & MCP INTEGRATIONS # ═══════════════════════════════════════════════════════════════════════════════ # Used by MCP server, A2A skills, and CLI sidecars to call the running instance. # Explicit base URL for MCP/A2A tools to reach OmniRoute (overrides localhost auto-detect). # For browser-visible generated image URLs, prefer OMNIROUTE_PUBLIC_BASE_URL above. # Used by: open-sse/mcp-server/server.ts, src/lib/a2a/ # OMNIROUTE_BASE_URL=http://localhost:20128 # API key for internal tool calls (MCP tools, A2A skills). # OMNIROUTE_API_KEY= # API key ID for MCP audit logging. # Used by: open-sse/mcp-server/audit.ts — tags audit events with a key identity. # OMNIROUTE_API_KEY_ID= # Legacy alias for OMNIROUTE_API_KEY. # ROUTER_API_KEY= # CLI remote-mode context/profile for `omniroute` commands (overrides the active # context in the local contexts store). Equivalent to the `--context ` flag. # Used by: bin/cli/program.mjs, bin/cli/api.mjs (remote mode). # OMNIROUTE_CONTEXT= # Enforce scope-based access control on MCP tool calls. # Used by: open-sse/mcp-server/server.ts — rejects calls outside allowed scopes. # OMNIROUTE_MCP_ENFORCE_SCOPES=false # Comma-separated scopes granted to this MCP connection. # Full list: admin, combos, health, models, routing, budget, metrics, pricing, memory, skills # OMNIROUTE_MCP_SCOPES=admin,combos,health # Compress MCP tool descriptions before serializing the manifest. # Used by: open-sse/mcp-server/descriptionCompressor.ts — reduces token spend # for clients that read the full tool catalog. # Accepted disabling values: 0, false, off. Default: enabled. # OMNIROUTE_MCP_COMPRESS_DESCRIPTIONS=1 # Algorithm/profile used when description compression is enabled. # Used by: open-sse/mcp-server/descriptionCompressor.ts # Set to 0/false/off to skip compression entirely. Default: rtk # OMNIROUTE_MCP_DESCRIPTION_COMPRESSION=rtk # Model catalog sync interval in hours. # Used by: src/shared/services/modelSyncScheduler.ts — periodic model refresh. # Default: 24 # MODEL_SYNC_INTERVAL_HOURS=24 # Provider limits sync interval in minutes (rate limit windows, quotas). # Used by: src/server-init.ts — polls provider health endpoints. # Default: 70 PROVIDER_LIMITS_SYNC_INTERVAL_MINUTES=70 # Gap (ms) between consecutive OAuth quota fetches in a bulk provider-limits sync. # OAuth providers are fetched one at a time with this spacing so a single host # never bursts simultaneous usage/refresh requests to the same upstream. Set to 0 # to opt out (restores fully concurrent fetches). Default: 1500 PROVIDER_LIMITS_SYNC_SPACING_MS=1500 # Min interval (ms) between consecutive UPSTREAM quota fetches on the per-request # preflight/monitor path (e.g. Codex /wham/usage), complementing the bulk-sync # spacing above. Many accounts on one IP fetching quota in the same second can look # like automation to the upstream and get an OAuth token revoked (#6009). This gate # serializes genuine network calls (cache hits are unaffected). Set to 0 to disable. # Default: 250 (clamped 0..5000). # OMNIROUTE_QUOTA_FETCH_MIN_INTERVAL_MS=250 # Delay (ms) before refreshing provider limits after a real usage event (e.g. a # completed request). Gives the upstream quota API time to register the consumption # before the dashboard polls. Default: 5000 #PROVIDER_LIMITS_POST_USAGE_REFRESH_DELAY_MS=5000 # Disable all background services (sync, pricing, model refresh). # Used by: src/instrumentation-node.ts, src/lib/initCloudSync.ts # Useful for: CI builds, test environments, or resource-constrained containers. # OMNIROUTE_DISABLE_BACKGROUND_SERVICES=false # Force runtime background tasks (healthchecks/sync) even under automated test # detection. Used by: src/lib/config/runtimeSettings.ts — overrides the test # heuristic in instrumentation-node.ts. Default: unset (tests skip background). #OMNIROUTE_ENABLE_RUNTIME_BACKGROUND_TASKS=1 # Proactive connection-cooldown recovery (#8): re-validates connections whose # transient `rate_limited_until` window has elapsed OUTSIDE the request hot path, # so the first request after a cooldown does not pay the probe latency. Lazy # recovery in getProviderCredentials still applies regardless. Used by: # src/lib/quota/connectionRecovery.ts. # Tick cadence (ms). Default 60000, floor 5000. # OMNIROUTE_CONNECTION_RECOVERY_INTERVAL_MS=60000 # Disable the proactive recovery scheduler entirely (default: false). # OMNIROUTE_DISABLE_CONNECTION_RECOVERY=false # Background job interval for budget reset checks (ms). Default: 600000 (10m). # Used by: src/lib/jobs/budgetResetJob.ts. Floor: 10000. #OMNIROUTE_BUDGET_RESET_JOB_INTERVAL_MS=600000 # Emergency budget-exhaustion fallback (set false or 0 to disable the reroute to # nvidia/openai/gpt-oss-120b when a request fails with a 402 budget error). # Used by: open-sse/services/emergencyFallback.ts. Default: enabled. #OMNIROUTE_EMERGENCY_FALLBACK=true # Reasoning cache cleanup cadence (ms). Default: 1800000 (30m). Floor: 60000. # Used by: src/lib/jobs/reasoningCacheCleanupJob.ts. #OMNIROUTE_REASONING_CACHE_CLEANUP_INTERVAL_MS=1800000 # Spend write batcher cadence (ms) and buffer size before forced flush. # Used by: src/lib/spend/batchWriter.ts. Defaults: 60000 ms / 1000 entries. #OMNIROUTE_SPEND_FLUSH_INTERVAL_MS=60000 #OMNIROUTE_SPEND_MAX_BUFFER_SIZE=1000 # Batch request processor retry, backoff, and concurrency settings. # Used by: open-sse/services/batchProcessor.ts. Defaults shown. #BATCH_RETRY_DURATION_MS=86400000 #BATCH_BACKOFF_BASE_MS=5000 #BATCH_BACKOFF_MAX_MS=3600000 #BATCH_MAX_CONCURRENT=1 # Config hot-reload polling interval (ms). Default: 5000. # Used by: src/lib/config/hotReload.ts. Lower than 1000ms is rejected. #OMNIROUTE_CONFIG_HOT_RELOAD_MS=5000 # Override the migrations directory used by src/lib/db/migrationRunner.ts. # Default: /src/lib/db/migrations. #OMNIROUTE_MIGRATIONS_DIR= # Mass-pending-migrations safety threshold (#3416). If more than this many # migrations are pending on an existing DB, startup aborts (a wiped tracking # table could cause data loss). Raise it to restore an older backup; set to 0 # to disable the check. Used by: src/lib/db/migrationRunner.ts. Default: 50. #OMNIROUTE_MAX_PENDING_MIGRATIONS=50 # Trust user-managed RTK project filter rules without strict signature checks. # Used by: open-sse/services/compression/engines/rtk/filterLoader.ts. Default: 0. #OMNIROUTE_RTK_TRUST_PROJECT_FILTERS=0 # T02 stacked-pipeline engine circuit-breaker (OPT-IN, default off). When enabled, a compression # engine that throws repeatedly across requests is skipped (fail-open) for a cooldown. # Used by: open-sse/services/compression/pipelineEngineBreaker.ts. #COMPRESSION_PIPELINE_BREAKER_ENABLED=false # master switch (default false) #COMPRESSION_PIPELINE_BREAKER_THRESHOLD=3 # consecutive failures before the engine opens #COMPRESSION_PIPELINE_BREAKER_COOLDOWN_MS=30000 # ms the engine stays skipped before a probe # T08/H8 — CCR retrieval-feedback ramp factor. Each prior retrieval of a stored block raises its # effective minChars linearly, so frequently-retrieved content is compressed progressively less # (>= 3 retrievals = never compressed). 1 disables the ramp (binary skip at the threshold only). # Used by: open-sse/services/compression/engines/ccr/index.ts. Default: 2. #COMPRESSION_CCR_RETRIEVAL_RAMP_FACTOR=2 # T08/H5 — usage-observed prefix freeze (OPT-IN, default off). When enabled, a system prompt seen # >= THRESHOLD times is treated as a stable cacheable prefix and preserved from compression even # for providers the static cache-aware heuristic does not recognize (freeze = preserve, never # mutates). Used by: open-sse/services/compression/prefixFreeze.ts. #COMPRESSION_PREFIX_FREEZE_ENABLED=false # master switch (default false) #COMPRESSION_PREFIX_FREEZE_THRESHOLD=3 # observations before a prefix is frozen # Skip the postinstall native-runtime warm-up (useful in CI / headless installs). Default: 0. # Used by: scripts/postinstall.mjs. #OMNIROUTE_SKIP_POSTINSTALL=0 # Operator-supplied JSON credentials for the offline compression-eval CLI # (parsed with JSON.parse; leave unset for a dry run). Developer tooling only. # Used by: scripts/compression-eval/index.ts. Default: {} (empty). #OMNIROUTE_EVAL_CREDENTIALS={} # Skip the DB healthcheck entirely on startup (useful for short-lived tasks / tests). # Used by: src/lib/db/core.ts, src/lib/db/healthCheck.ts. Set to 1 to disable. Default: 0. #OMNIROUTE_SKIP_DB_HEALTHCHECK=0 # Force a DB healthcheck regardless of cadence. Default: 0. # Used by: src/lib/db/core.ts::shouldRunDbHealthCheck(). #OMNIROUTE_FORCE_DB_HEALTHCHECK=0 # DB healthcheck cadence override (ms). Default: 21600000 (6h). # Used by: src/lib/db/core.ts::getDbHealthCheckIntervalMs(). #OMNIROUTE_DB_HEALTHCHECK_INTERVAL_MS=21600000 # Skip the Redis-backed auth cache used by API key lookups (forces DB reads). # Used by: src/lib/db/apiKeys.ts. Set to 1 to disable. Default: enabled. #OMNIROUTE_DISABLE_REDIS_AUTH_CACHE=0 # Flag set by bootstrap script after initial setup is complete. # Used by: src/app/(dashboard)/dashboard/page.tsx — shows setup wizard vs. dashboard. # OMNIROUTE_BOOTSTRAPPED=false # Allow request body to override the Antigravity project field. # Used by: open-sse/executors/antigravity.ts — escape hatch for multi-project setups. # OMNIROUTE_ALLOW_BODY_PROJECT_OVERRIDE=0 # Adjust how Antigravity advertises remaining credits. Used by: # open-sse/services/antigravityCredits.ts — accepts forced override strings. # Default: empty (use upstream-reported credits). #ANTIGRAVITY_CREDITS= # Override the path to the Antigravity CLI (agy) token file read by the # "auto-detect local login" import. Used by: # src/app/api/providers/agy-auth/apply-local/route.ts — for non-standard installs. # Default: ~/.gemini/antigravity-cli/antigravity-oauth-token #AGY_TOKEN_FILE= # ═══════════════════════════════════════════════════════════════════════════════ # 11. OAUTH PROVIDER CREDENTIALS # ═══════════════════════════════════════════════════════════════════════════════ # Built-in default credentials for localhost development. # For remote/VPS deployments, register your own at each provider's developer console. # The bootstrap-env script auto-populates these in .env if missing. # Can also be overridden via data/provider-credentials.json where supported. # ── Claude Code (Anthropic) ── CLAUDE_OAUTH_CLIENT_ID=9d1c250a-e61b-44d9-88ed-5944d1962f5e # Custom redirect URI override for Claude OAuth callback. # CLAUDE_CODE_REDIRECT_URI=https://platform.claude.com/oauth/code/callback # ── Codex / OpenAI ── CODEX_OAUTH_CLIENT_ID=app_EMoamEEZ73f0CkXaXp7hrann # Milliseconds to wait between consecutive Codex token refreshes. # Used by: open-sse/services/refreshSerializer.ts. Default: 0 (no spacing). # CODEX_REFRESH_SPACING_MS=0 # ── Trae (ByteDance) ── # Trae stream idle timeout (ms). Default: 300000 (5 min). # Used by: open-sse/executors/trae.ts. # TRAE_STREAM_TIMEOUT_MS=300000 # Trae OAuth token override. Used by: open-sse/executors/trae.ts. # TRAE_TOKEN= # ── The Old LLM (theoldllm) ── # Playwright navigation timeout (ms) for the browser-backed token capture. # Used by: open-sse/executors/theoldllm.ts. Default: 30000 (30s). # THEOLDLLM_NAV_TIMEOUT_MS=30000 # ── Gemini / Antigravity / Windsurf (all Google-based) ── # These providers ship public OAuth client_id/secret values (or Firebase Web # keys) embedded in their public CLIs/binaries. Defaults are baked into the # code via open-sse/utils/publicCreds.ts — leave the env vars unset to use # them. Only set these if you registered your own OAuth app and want to use # your own credentials instead. See docs/security/PUBLIC_CREDS.md for context. # # GEMINI_OAUTH_CLIENT_ID= # GEMINI_OAUTH_CLIENT_SECRET= # ANTIGRAVITY_OAUTH_CLIENT_ID= # ANTIGRAVITY_OAUTH_CLIENT_SECRET= # WINDSURF_FIREBASE_API_KEY= # ── Qwen (Alibaba) ── QWEN_OAUTH_CLIENT_ID=f0304373b74a44d2b584a3fb70ca9e56 # ── Kimi Coding (Moonshot) ── KIMI_CODING_OAUTH_CLIENT_ID=17e5f671-d194-4dfb-9706-5516cb48c098 # ── GitHub Copilot ── GITHUB_OAUTH_CLIENT_ID=Iv1.b507a08c87ecfe98 # ── GitLab Duo ── # Register an OAuth app at: https://gitlab.com/-/profile/applications # Set redirect URI to: http://localhost:20128/callback (or your NEXT_PUBLIC_BASE_URL + /callback) # Required scopes: ai_features, read_user (matches GITLAB_DUO_CONFIG.scope in src/lib/oauth/constants/oauth.ts) # GITLAB_DUO_OAUTH_CLIENT_ID=*** # GITLAB_DUO_OAUTH_CLIENT_SECRET=*** # optional — PKCE flow does not require a secret # # Self-managed GitLab Duo instance overrides. # Used by: src/lib/oauth/gitlab.ts and src/lib/oauth/constants/oauth.ts — # fall back to these when the _DUO_ variants above are unset. #GITLAB_DUO_BASE_URL=https://gitlab.com #GITLAB_BASE_URL=https://gitlab.com #GITLAB_OAUTH_CLIENT_ID= #GITLAB_OAUTH_CLIENT_SECRET= # ── Qoder ── # Public OAuth client secret embedded in the Qoder CLI binary. Required only # when QODER_OAUTH_AUTHORIZE_URL / TOKEN_URL / USERINFO_URL / CLIENT_ID are # also set (see QODER_CONFIG.enabled in src/lib/oauth/constants/oauth.ts). # Extract the value from the public Qoder CLI binary if you intend to use it. # QODER_OAUTH_CLIENT_SECRET= # ── Qoder Browser OAuth (experimental) ── # OmniRoute only enables the browser OAuth flow when ALL 5 variables below are set: # - QODER_OAUTH_AUTHORIZE_URL # - QODER_OAUTH_TOKEN_URL # - QODER_OAUTH_USERINFO_URL # - QODER_OAUTH_CLIENT_ID # - QODER_OAUTH_CLIENT_SECRET # # Redirect URI to register in the Qoder OAuth app: # - Localhost dev with PORT=20128: http://localhost:20128/callback # - LAN access (example): http://192.168.0.15:20128/callback # - Public domain (recommended): https://omniroute.example.com/callback # # Behind reverse proxy / public domain, also set NEXT_PUBLIC_BASE_URL to the same public origin. # If these values are not available, prefer QODER_PERSONAL_ACCESS_TOKEN below. # QODER_OAUTH_AUTHORIZE_URL= # QODER_OAUTH_TOKEN_URL= # QODER_OAUTH_USERINFO_URL= # QODER_OAUTH_CLIENT_ID= # QODER_OAUTH_CLIENT_SECRET= # ── Qoder Personal Access Token (direct API key fallback) ── # Used by: open-sse/executors/qoder.ts — bypasses OAuth when set. # QODER_PERSONAL_ACCESS_TOKEN= # QODER_CLI_WORKSPACE= # OMNIROUTE_QODER_WORKSPACE= # Override the Qoder CLI config dir (isolated PAT session, avoids clobbering a browser login). # QODER_CLI_CONFIG_DIR= # ── Blackbox Web validated-token override (issue #2252) ── # Used by: open-sse/executors/blackbox-web.ts. Blackbox `/api/chat` rejects # requests whose `validated` field doesn't match the frontend `tk` token, # returning HTTP 403 even with a valid session cookie + active subscription. # Set this to the `tk` value exported from app.blackbox.ai's Next.js bundle # to bypass the random-UUID fallback. Leave empty to keep the legacy behavior. # BLACKBOX_WEB_VALIDATED_TOKEN= # ── Vision Bridge OpenAI-compatible endpoint override (issue #2232) ── # Used by: src/lib/guardrails/visionBridgeHelpers.ts. By default the # vision-bridge guardrail sends non-Anthropic image-description calls to # `https://api.openai.com/v1`, which fails with 401 if your operator doesn't # have an OpenAI key or wants to use a different vision model # (e.g., `google/gemini-2.0-flash` via the Gemini OpenAI-compat endpoint, or # any model registered in OmniRoute via the self-loop endpoint). # # Set these two env vars to point the bridge at any OpenAI-compatible URL: # - VISION_BRIDGE_BASE_URL=http://localhost:20128/v1 (OmniRoute self-loop) # - VISION_BRIDGE_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai # - VISION_BRIDGE_BASE_URL=https://openrouter.ai/api/v1 # Anthropic models (anthropic/*) keep their dedicated path and are unaffected. # VISION_BRIDGE_BASE_URL= # VISION_BRIDGE_API_KEY= # ───────────────────────────────────────────────────────────────────────────── # ⚠️ GOOGLE OAUTH (Antigravity) & OTHER PROVIDERS — REMOTE SERVERS # ───────────────────────────────────────────────────────────────────────────── # The default Client IDs above ONLY work when OmniRoute runs on localhost. # For remote/VPS hosting (including Docker containers on remote servers): # 1. By default, the browser will attempt OAuth redirects back to localhost, which will fail. # 2. Set NEXT_PUBLIC_BASE_URL=https://your-domain.com to fix the redirect URI. # 3. You MUST create your own OAuth App in each provider's developer console (Google Cloud, etc.) # and set the Authorized redirect URI to your domain (e.g., https://your-domain.com/callback). # 4. Replace the _OAUTH_CLIENT_ID and _SECRET values above with your own credentials. # ───────────────────────────────────────────────────────────────────────────── # ── OAuth sidecar/CLI bridge (internal) ── # Used by: src/lib/oauth/config/index.ts — internal CLI↔OmniRoute auth bridge. # OMNIROUTE_SERVER=http://localhost:20128 # OMNIROUTE_TOKEN= # OMNIROUTE_USER_ID=cli # CLI_TOKEN= # legacy alias for OMNIROUTE_TOKEN # CLI_USER_ID= # legacy alias for OMNIROUTE_USER_ID # SERVER_URL= # legacy alias for OMNIROUTE_SERVER # ═══════════════════════════════════════════════════════════════════════════════ # 12. PROVIDER USER-AGENT OVERRIDES # ═══════════════════════════════════════════════════════════════════════════════ # Customize the User-Agent header sent to each upstream provider. # Format: {PROVIDER_ID}_USER_AGENT=custom-value # Used by: open-sse/executors/base.ts — buildHeaders() dynamic lookup. # Update these when providers release new CLI versions to avoid blocks. CLAUDE_USER_AGENT="claude-cli/2.1.195 (external, cli)" # Disable the deterministic tool-name cloak applied on both Anthropic-bound paths # (executors/base.ts native OAuth + executors/cliproxyapi.ts CLIProxyAPI) — # third-party-harness tool names are aliased to # Claude Code canonical or PascalCase forms so Anthropic does not refuse the # stream with a misleading 400 out-of-extra-usage placeholder. Set to true to # forward the original names verbatim (debugging only). # CLAUDE_DISABLE_TOOL_NAME_CLOAK=false CODEX_USER_AGENT="codex-cli/0.142.0 (Windows 10.0.26200; x64)" GITHUB_USER_AGENT="GitHubCopilotChat/0.54.0" ANTIGRAVITY_USER_AGENT="antigravity/2.0.1 linux/arm64 google-api-nodejs-client/10.3.0" KIRO_USER_AGENT="AWS-SDK-JS/3.0.0 kiro-ide/1.0.0" # KIRO_VERIFY_FULL_CRC=false # opt-in: full per-frame message CRC validation on the Kiro event stream (debug corrupted streams; prelude CRC + TLS already protect framing) # Optional override for the Kiro social device-code OAuth clientId. Kiro's # device endpoint accepts any non-empty string and behaves like a User-Agent # rather than a secret. Only override if AWS ever starts enforcing this field. # Used by: src/lib/oauth/constants/oauth.ts (KIRO_CONFIG.socialClientId). # KIRO_OAUTH_CLIENT_ID=kiro-cli # Enable full per-frame message CRC validation for Kiro streams. Off by default # because it is O(frame bytes) on the main thread; use only for debugging # suspected corrupted-stream issues. # Used by: open-sse/executors/kiro.ts # KIRO_VERIFY_FULL_CRC=false QODER_USER_AGENT="Qoder-Cli" QWEN_USER_AGENT="QwenCode/0.19.3 (linux; x64)" CURSOR_USER_AGENT="Cursor/3.4" # Override Codex client version sent in headers independently of the # CODEX_USER_AGENT string. Used by: open-sse/config/codexClient.ts. # CODEX_CLIENT_VERSION=0.142.0 # Kill-switch to strip non-standard `codex.*` SSE events (e.g. codex.rate_limits) # from the Codex Responses stream. These frames break the OpenAI SDK's # responses.stream() with a 502 "Controller is already closed". Off by default; # set to true/1/yes to enable. Used by: open-sse/executors/codex.ts. # OMNIROUTE_CODEX_DROP_NONSTANDARD_EVENTS=true # ═══════════════════════════════════════════════════════════════════════════════ # 13. CLI FINGERPRINT COMPATIBILITY (Anti-Detection) # ═══════════════════════════════════════════════════════════════════════════════ # When enabled, OmniRoute reorders HTTP headers and JSON body fields to match # the exact signature of official CLI tools, reducing account flagging risk. # Your proxy IP is preserved — you get both stealth AND IP masking. # Used by: open-sse/config/cliFingerprints.ts, open-sse/executors/base.ts # Enable per-provider: # CLI_COMPAT_CODEX=1 # CLI_COMPAT_CLAUDE=1 # CLI_COMPAT_GITHUB=1 # CLI_COMPAT_ANTIGRAVITY=1 # CLI_COMPAT_CURSOR=1 # CLI_COMPAT_KIMI_CODING=1 # CLI_COMPAT_KILOCODE=1 # CLI_COMPAT_CLINE=1 # CLI_COMPAT_QWEN=1 # Or enable for all providers at once: # CLI_COMPAT_ALL=1 # ── Kimi Coding CLI identity overrides ── # Used by: src/lib/oauth/providers/kimi-coding.ts — sent in OAuth + API headers. # Leave unset to use the captured defaults baked into the OmniRoute build. #KIMI_CLI_VERSION=1.36.0 #KIMI_CODING_DEVICE_ID= # ═══════════════════════════════════════════════════════════════════════════════ # 14. API KEY PROVIDERS # ═══════════════════════════════════════════════════════════════════════════════ # API keys for direct-authentication providers. # Preferred setup: Dashboard → Providers → Add API Key. # Setting here is an alternative for Docker/headless deployments. # Static API keys for direct-authentication providers wired through the runtime. # OmniRoute loads provider credentials from the encrypted database or # data/provider-credentials.json. The variables below are documented escape # hatches that are referenced in code today. # DEEPSEEK_API_KEY= # NVIDIA_API_KEY= # Windsurf / Devin CLI direct API key. # Used by: open-sse/executors/devin-cli.ts — bypasses OAuth when set. # WINDSURF_API_KEY= # Embedding Providers (optional — used by /v1/embeddings) # OpenAI/Mistral/Together/Fireworks/NVIDIA configured via Dashboard → Providers # also work for embeddings. # ═══════════════════════════════════════════════════════════════════════════════ # 15. TIMEOUT SETTINGS # ═══════════════════════════════════════════════════════════════════════════════ # All timeout values are in milliseconds. # Used by: src/shared/utils/runtimeTimeouts.ts — centralized timeout resolution. # # Hierarchy: REQUEST_TIMEOUT_MS acts as a global override. # If set, it becomes the default for FETCH_TIMEOUT_MS, STREAM_IDLE_TIMEOUT_MS, # and STREAM_READINESS_TIMEOUT_MS. # The fine-grained variables below override their respective defaults only when set. # ── Global shortcut ── # REQUEST_TIMEOUT_MS=600000 # Overrides both fetch and stream idle defaults # ── Upstream fetch (provider calls) ── # FETCH_TIMEOUT_MS=600000 # Total request timeout (default: 600000 = 10 min) # # Also drives anthropic-compatible-cc-* X-Stainless-Timeout. # FETCH_HEADERS_TIMEOUT_MS=600000 # Time to receive response headers # FETCH_BODY_TIMEOUT_MS=600000 # Time to receive full response body # FETCH_CONNECT_TIMEOUT_MS=30000 # TCP connection establishment (default: 30s) # FETCH_KEEPALIVE_TIMEOUT_MS=4000 # Keep-alive socket idle timeout (default: 4s) # Default timeout (ms) for src/shared/utils/fetchTimeout.ts. Acts as the # fallback when FETCH_TIMEOUT_MS is unset. Default: 120000 (2 min). # OMNIROUTE_DEFAULT_FETCH_TIMEOUT_MS=120000 # ── Firecrawl web-fetch executor ── # Point at a self-hosted Firecrawl instance (defaults to the public cloud API). # When set to a non-cloud base URL, the API key becomes optional. # FIRECRAWL_BASE_URL=https://api.firecrawl.dev # FIRECRAWL_TIMEOUT_MS=30000 # Per-request timeout (default: 30000 = 30s) # ── ChatGPT TLS sidecar (Firefox-fingerprinted client) ── # Used by: open-sse/services/chatgptTlsClient.ts — wire-level timeout for # the bogdanfinn/tls-client koffi binding and the JS-side grace window # layered on top of it when the native library is wedged. # OMNIROUTE_CHATGPT_TLS_TIMEOUT_MS=60000 # OMNIROUTE_CHATGPT_TLS_GRACE_MS=10000 # Max wait for the FIRST streamed byte from the ChatGPT TLS sidecar before the # request is aborted as a dead stream, in milliseconds. Default 30000 (30s). # Raise it if upstream cold-starts routinely exceed the window. # OMNIROUTE_CHATGPT_STREAM_FIRST_BYTE_TIMEOUT_MS=30000 # ── Claude TLS sidecar (Chromium-fingerprinted client) ── # Used by: open-sse/services/claudeTlsClient.ts — wire-level timeout for # the bogdanfinn/tls-client koffi binding and the JS-side grace window # layered on top of it when the native library is wedged. # OMNIROUTE_CLAUDE_TLS_TIMEOUT_MS=60000 # OMNIROUTE_CLAUDE_TLS_GRACE_MS=10000 # ── Perplexity TLS sidecar (Firefox-fingerprinted client) ── # Used by: open-sse/services/perplexityTlsClient.ts — wire-level timeout for # the bogdanfinn/tls-client koffi binding and the JS-side grace window # layered on top of it when the native library is wedged. # OMNIROUTE_PPLX_TLS_TIMEOUT_MS=30000 # OMNIROUTE_PPLX_TLS_GRACE_MS=10000 # ── Grok web TLS sidecar (Chrome-fingerprinted client) ── # Used by: open-sse/services/grokTlsClient.ts — wire-level timeout for the # bogdanfinn/tls-client koffi binding and the JS-side grace window layered on # top of it when the native library is wedged. # OMNIROUTE_GROK_TLS_TIMEOUT_MS=60000 # OMNIROUTE_GROK_TLS_GRACE_MS=10000 # ── Browser-backed web-cookie chat (Playwright shared pool) ── # Used by: open-sse/services/browserPool.ts + browserBackedChat.ts. The shared # browser pool warms a headless context for web-cookie providers (e.g. claude-web) # that need a real browser to satisfy anti-bot challenges. Set OMNIROUTE_BROWSER_POOL=off # to fully disable the pool; set WEB_COOKIE_USE_BROWSER=1 to opt a web-cookie chat # request into the browser-backed path. # OMNIROUTE_BROWSER_POOL=on # WEB_COOKIE_USE_BROWSER=0 # ── Circuit breaker thresholds and reset windows ── # Used by: open-sse/config/constants.ts → src/lib/resilience/settings.ts. # Defaults match historical PROVIDER_PROFILES values (post-scaling for # 500+ connections). Lower the threshold to react faster, raise it to # tolerate more transient failures before short-circuiting. # OMNIROUTE_CIRCUIT_BREAKER_OAUTH_THRESHOLD=8 # OMNIROUTE_CIRCUIT_BREAKER_OAUTH_RESET_MS=60000 # OMNIROUTE_CIRCUIT_BREAKER_API_KEY_THRESHOLD=12 # OMNIROUTE_CIRCUIT_BREAKER_API_KEY_RESET_MS=30000 # OMNIROUTE_CIRCUIT_BREAKER_LOCAL_THRESHOLD=2 # OMNIROUTE_CIRCUIT_BREAKER_LOCAL_RESET_MS=15000 # ── Context-cache pin health gate ── # Used by: open-sse/services/combo.ts. When a context-cache pin points at a # provider that is durably unhealthy, the pin is dropped to allow failover. # PIN_DROP_BACKOFF_LEVEL gates how deep a connection's backoff must be before the # pin is considered durably unhealthy; PIN_DROP_GRACE_MS is the anti-flap window # that tolerates brief transient cooldowns before dropping the pin. # PIN_DROP_BACKOFF_LEVEL=2 # PIN_DROP_GRACE_MS=20000 # ── Stream idle detection ── # STREAM_IDLE_TIMEOUT_MS=600000 # Max silence between SSE chunks (default: 600000) # # Extended-thinking models rarely pause >90s. # STREAM_READINESS_TIMEOUT_MS=80000 # Time to receive the first non-ping SSE event # STREAM_READINESS_MAX_TIMEOUT_MS=180000 # Cap for adaptive first-event extensions # # (large/tool-heavy/high-reasoning requests). # OMNIROUTE_AGENT_GOAL_POLICY_ENABLED=true # Kill-switch for the /goal heuristic below. # # Set to false to fully disable detection — # # readiness timeouts and stream recovery are # # never elevated by request body/headers when off. # OMNIROUTE_AGENT_GOAL_READINESS_MAX_TIMEOUT_MS=600000 # Auto cap for detected /goal agent runs # OMNIROUTE_AGENT_GOAL_STREAM_RECOVERY=true # Auto early stream recovery for /goal runs. # # NOTE: this can only ADD recovery on top of the # # operator default — it never overrides an explicit # # STREAM_RECOVERY_ENABLED / DB settings opt-out. # ── TLS client (wreq-js fingerprint proxy) ── # TLS_CLIENT_TIMEOUT_MS=600000 # Inherits from FETCH_TIMEOUT_MS by default # ── API Bridge (/v1 proxy server) ── # API_BRIDGE_PROXY_TIMEOUT_MS=600000 # Proxy hop timeout (default: 10min) # API_BRIDGE_SERVER_REQUEST_TIMEOUT_MS=600000 # Overall server request timeout (default: 10min) # API_BRIDGE_SERVER_HEADERS_TIMEOUT_MS=60000 # Time to send response headers # API_BRIDGE_SERVER_KEEPALIVE_TIMEOUT_MS=5000 # Keep-alive idle timeout # API_BRIDGE_SERVER_SOCKET_TIMEOUT_MS=0 # Raw socket timeout (0 = disabled) # ── Graceful shutdown ── # Time to wait for in-flight requests before force-exiting on SIGTERM/SIGINT. # Used by: src/lib/gracefulShutdown.ts # Default: 30000 (30 seconds) # SHUTDOWN_TIMEOUT_MS=30000 # ═══════════════════════════════════════════════════════════════════════════════ # 16. LOGGING # ═══════════════════════════════════════════════════════════════════════════════ # Used by: src/lib/logEnv.ts, src/lib/logRotation.ts, src/shared/utils/logger.ts # Application log level — controls console and file log verbosity. # Values: debug | info | warn | error | Default: info # APP_LOG_LEVEL=info # Log output format. # Values: text | json | Default: text # APP_LOG_FORMAT=text # Write logs to file in addition to stdout. # Default: true | Set false to disable file logging. APP_LOG_TO_FILE=true # Path to the application log file. # Default: /logs/application/app.log (DATA_DIR defaults to ~/.omniroute) # APP_LOG_FILE_PATH=logs/application/app.log # Maximum single log file size before rotation. # Accepts: plain bytes or suffixed (50M, 1G, 512K). Default: 50M # APP_LOG_MAX_FILE_SIZE=50M # Days to keep rotated application log files before auto-deletion. # Default: 7 # APP_LOG_RETENTION_DAYS=7 # Maximum number of rotated log file backups to keep. # Default: 20 # APP_LOG_MAX_FILES=20 # How often OmniRoute checks whether the active log file has exceeded # APP_LOG_MAX_FILE_SIZE and triggers a rotation. Set lower for very verbose # services to prevent log files from growing large between checks. # Accepts milliseconds. Default: 60000 (1 minute) # APP_LOG_ROTATION_CHECK_INTERVAL_MS=60000 # Days to keep request/call log entries in the database before auto-cleanup. # Default: 7 # CALL_LOG_RETENTION_DAYS=7 # Maximum call log entries stored in-memory buffer. # Default: 10000 # CALL_LOG_MAX_ENTRIES=10000 # Maximum rows in the call_logs SQLite table before oldest entries are pruned. # Default: 100000 # CALL_LOGS_TABLE_MAX_ROWS=100000 # Maximum age for orphaned active request log entries before the in-memory # pending-request reaper removes them. Accepts milliseconds. # Default: 3600000 (1 hour) # MAX_PENDING_REQUEST_AGE_MS=3600000 # Whether call log pipeline capture stores stream chunks when enabled in settings. # Only applies when call_log_pipeline_enabled=true. # Default: true # CALL_LOG_PIPELINE_CAPTURE_STREAM_CHUNKS=true # Maximum call log artifact size for pipeline captures, in KB. # Only applies when call_log_pipeline_enabled=true. # Default: 512 # CALL_LOG_PIPELINE_MAX_SIZE_KB=512 # Call log payload truncation limits — controls how much of request/response # bodies is retained in the database. # Used by: open-sse/handlers/chatCore.ts — cloneBoundedChatLogPayload() # CHAT_LOG_TEXT_LIMIT=65536 # Max string length before truncation (default: 64 KB) # CHAT_LOG_ARRAY_TAIL_ITEMS=24 # Number of array items retained from tail (default: 24) # CHAT_LOG_MAX_DEPTH=6 # Max nesting depth before truncation (default: 6) # CHAT_LOG_MAX_OBJECT_KEYS=80 # Max object keys retained (default: 80, 0 = no limit) # Maximum rows in the proxy_logs SQLite table. # Default: 100000 # PROXY_LOGS_TABLE_MAX_ROWS=100000 # ═══════════════════════════════════════════════════════════════════════════════ # 17. MEMORY OPTIMIZATION (Low-RAM / Docker) # ═══════════════════════════════════════════════════════════════════════════════ # Node.js V8 heap limit in MB, passed to the server via --max-old-space-size. # Used by the standalone launcher (Docker CMD) and `omniroute serve`. # Clamped to [64, 16384]. Default: 512 (safe for a 1 GB / 1 core VPS). Size it to # roughly half the box's RAM, leaving the rest for native memory (better-sqlite3, # buffers — ~300 MB) and the OS: # 1 GB RAM → 512 (default) # 2 GB RAM → 1024 # 4 GB RAM → 2048 # In a memory-capped container, set this EXPLICITLY: Node reads the HOST's RAM, # not the cgroup limit, so leaving it to a RAM heuristic can oversize the heap and # get the container OOM-killed. (#2939) # OMNIROUTE_MEMORY_MB=512 # Heap-pressure shed threshold (MB) — chatCore returns 503 when V8 heapUsed exceeds # it, to avoid hard OOM under concurrent large-context load. # LEAVE UNSET: it now AUTO-CALIBRATES to 85% of the actual V8 heap ceiling, so it # tracks OMNIROUTE_MEMORY_MB above and never sits below the ~260 MB runtime baseline # (a fixed 200 here used to reject every request). Used by: open-sse/utils/heapPressure.ts. # Override only to hand-tune for a known workload. # HEAP_PRESSURE_THRESHOLD_MB= # ── CLI helpers (bin/cli/) ── # Override UI language for CLI output. Accepts BCP-47 locale (e.g. en, pt-BR). # Falls back to LC_ALL / LC_MESSAGES / LANG / en if unset. # OMNIROUTE_LANG=en # Show server logs inline when running in supervised mode (omniroute serve). # Set to "1" to forward server stdout/stderr to the terminal. # Equivalent to the --log flag on `omniroute serve`. # OMNIROUTE_SHOW_LOG=1 # Bearer token injected as x-omniroute-cli-token header for machine-auth (task 8.12). # Auto-generated on first run if machine-id is available; set manually to override. # OMNIROUTE_CLI_TOKEN= # Per-attempt HTTP timeout for CLI → server calls (milliseconds). Default: 30000. # OMNIROUTE_HTTP_TIMEOUT_MS=30000 # Set to 1 to print retry/backoff details to stderr during CLI commands. # OMNIROUTE_VERBOSE=0 # Custom directory for CLI plugin discovery (omniroute-cmd-* packages). # Default: ~/.omniroute/plugins/ Override in dev/CI to point at a local plugin tree. # OMNIROUTE_PLUGIN_PATH= # Allow plugins to request the 'exec' permission (spawn child processes from the # plugin worker sandbox). Disabled by default; set to 1 to enable (local operator only). # OMNIROUTE_PLUGINS_ALLOW_EXEC=0 # ── Prompt cache (system prompt deduplication) ── # Used by: open-sse/services — caches identical system prompts across requests. # PROMPT_CACHE_MAX_SIZE=50 # Max cached entries (default: 50) # PROMPT_CACHE_MAX_BYTES=2097152 # Max total cache size in bytes (default: 2 MB) # PROMPT_CACHE_TTL_MS=300000 # Cache entry TTL (default: 5 minutes) # ── Semantic cache (deterministic response dedup, temperature=0) ── # Used by: open-sse/services — caches identical temperature=0 responses. # SEMANTIC_CACHE_MAX_SIZE=100 # Max cached entries (default: 100) # SEMANTIC_CACHE_MAX_BYTES=4194304 # Max total cache size in bytes (default: 4 MB) # SEMANTIC_CACHE_TTL_MS=1800000 # Cache entry TTL (default: 30 minutes) # ── In-memory log buffers ── # Maximum recent stream events kept in memory for the Dashboard live view. # STREAM_HISTORY_MAX=50 # ── Context length default ── # Global fallback max context length for models without explicit config. # Used by: open-sse/services/contextManager.ts # CONTEXT_LENGTH_DEFAULT=128000 # ── Usage token buffer ── # Extra token headroom reserved when tracking usage quotas (prevents over-limit). # Used by: open-sse/utils/usageTracking.ts # USAGE_TOKEN_BUFFER=100 # ═══════════════════════════════════════════════════════════════════════════════ # 18. PRICING SYNC # ═══════════════════════════════════════════════════════════════════════════════ # Automatic model pricing synchronization from external sources. # Used by: src/lib/pricingSync.ts # Enable periodic pricing data sync. Default: false (opt-in only). # PRICING_SYNC_ENABLED=false # Sync interval in seconds. Default: 86400 (24 hours). # PRICING_SYNC_INTERVAL=86400 # Comma-separated data sources. Default: litellm # PRICING_SYNC_SOURCES=litellm # ═══════════════════════════════════════════════════════════════════════════════ # 18b. ARENA ELO SYNC # ═══════════════════════════════════════════════════════════════════════════════ # Auto-update model intelligence from Arena AI leaderboard ELO scores (powers the # Free Provider Rankings page). ON by default — fetches from api.wulong.dev on startup # (non-blocking, never fatal). Set to false to opt out of the outbound sync. # Also configurable from Dashboard > Settings > Feature Flags. # Used by: src/shared/constants/featureFlagDefinitions.ts, src/lib/arenaEloSync.ts # ARENA_ELO_SYNC_ENABLED=true # Sync interval in seconds. Default: 86400 (24 hours). # ARENA_ELO_SYNC_INTERVAL=86400 # ═══════════════════════════════════════════════════════════════════════════════ # 19. MODEL SYNC (Dev) # ═══════════════════════════════════════════════════════════════════════════════ # Development-time model catalog sync interval in seconds. # Used by: src/lib/modelsDevSync.ts # Default: 86400 (24 hours) # MODELS_DEV_SYNC_INTERVAL=86400 # Self-correcting context-window reconciler interval in seconds (feature 5004). # Pins provider-declared windows from /models discovery as auto:discovery overrides # when they diverge from the catalog. Set to 0 to disable. Never overwrites manual overrides. # Used by: src/lib/contextWindowResolver.ts # Default: 86400 (24 hours) # CONTEXT_WINDOW_RECONCILE_INTERVAL=86400 # ═══════════════════════════════════════════════════════════════════════════════ # 20. PROVIDER-SPECIFIC SETTINGS # ═══════════════════════════════════════════════════════════════════════════════ # ── OpenRouter ── # OpenRouter model catalog cache TTL in ms. # Used by: src/lib/catalog/openrouterCatalog.ts # Default: 86400000 (24 hours) # OPENROUTER_CATALOG_TTL_MS=86400000 # ── Model catalog response shape ── # Include display-friendly name fields in /v1/models responses. # Disable for clients that expect model IDs only. # Defined in: src/shared/constants/featureFlagDefinitions.ts # Used by: src/app/api/v1/models/catalog.ts # Default: true # MODEL_CATALOG_INCLUDE_NAMES=true # ── NanoBanana (Image Generation) ── # Polling config for async image generation jobs. # Used by: open-sse/handlers/imageGeneration.ts # NANOBANANA_POLL_TIMEOUT_MS=120000 # Max wait for job completion (default: 120s) # NANOBANANA_POLL_INTERVAL_MS=2500 # Poll frequency (default: 2.5s) # ── AWS Bedrock (Kiro / Audio) ── # Region used to construct AWS Bedrock endpoints. Used by: # src/lib/providers/validation.ts and open-sse/handlers/audioSpeech.ts. # AWS_REGION takes precedence over AWS_DEFAULT_REGION when both are set. # AWS_REGION=us-east-1 # AWS_DEFAULT_REGION=us-east-1 # ── Cloudflare Workers AI ── # Account ID override for Cloudflare Workers AI executor. # Used by: open-sse/executors/cloudflare-ai.ts # CLOUDFLARE_ACCOUNT_ID= # ── Deno Deploy proxy relay (#4643 / 9router#1437) ── # Override the Deno Deploy REST API base used by the proxy-pool relay deployer. # Default: https://api.deno.com/v2 (omit unless mocking). # Used by: src/app/api/settings/proxy/deno-deploy/route.ts # DENO_DEPLOY_API_BASE=https://api.deno.com/v2 # Default Deno Deploy app name suggested in the "Deploy Relay" modal. # Used by: src/app/(dashboard)/dashboard/settings/components/proxy/DenoRelayModal.tsx # NEXT_PUBLIC_DENO_RELAY_DEFAULT_PROJECT=omniroute-deno-relay # Set to "false" to hide the Deno Deploy relay option from the Proxy Pool tab. # Used by: src/app/(dashboard)/dashboard/settings/components/proxy/ProxyPoolTab.tsx # NEXT_PUBLIC_DENO_RELAY_ENABLED=true # ── Cloudflare Workers proxy relay (#4640 / 9router#1360) ── # Override the Cloudflare REST API base used by the proxy-pool relay deployer. # Default: https://api.cloudflare.com/client/v4 (omit unless mocking). # Used by: src/app/api/settings/proxy/cloudflare-deploy/route.ts # CLOUDFLARE_API_BASE=https://api.cloudflare.com/client/v4 # Default worker project name suggested in the "Deploy Relay" modal. # Used by: src/app/(dashboard)/dashboard/settings/components/proxy/CloudflareRelayModal.tsx # NEXT_PUBLIC_CLOUDFLARE_RELAY_DEFAULT_PROJECT=omniroute-relay # Set to "false" to hide the Cloudflare Workers relay option from the Proxy Pool tab. # Used by: src/app/(dashboard)/dashboard/settings/components/proxy/ProxyPoolTab.tsx # NEXT_PUBLIC_CLOUDFLARE_RELAY_ENABLED=true # ── Cloudflare Tunnel (cloudflared) ── # Custom path to cloudflared binary for tunnel management. # Used by: src/lib/cloudflaredTunnel.ts # CLOUDFLARED_BIN=/usr/local/bin/cloudflared # ── Search cache ── # TTL for search API response caching (Perplexity, Brave, etc.). # Used by: open-sse/services/searchCache.ts # Default: 300000 (5 minutes) # SEARCH_CACHE_TTL_MS=300000 # ── OpenAI-compatible multi-connection ── # Allow multiple simultaneous connections per OpenAI-compatible provider node. # Used by: src/app/api/providers/route.ts # ALLOW_MULTI_CONNECTIONS_PER_COMPAT_NODE=false # ── CC-compatible provider (experimental) ── # Enable the Claude Code compatible provider endpoint. # This is only for third-party relays that accept Claude Code clients exclusively. # OmniRoute rewrites requests to pass those relays' Claude Code client validation. # If you only want to use Claude Code CLI, or you are not sure what these relays are, # keep this disabled and add a regular Anthropic-compatible provider instead. # Used by: src/shared/utils/featureFlags.ts # ENABLE_CC_COMPATIBLE_PROVIDER=false # ── 9router embedded service ── # Override the host/port where the embedded 9router instance listens. # Rarely needed — defaults match the bootstrap config (127.0.0.1:20130). # Used by: open-sse/executors/ninerouter.ts # NINEROUTER_HOST=127.0.0.1 # NINEROUTER_PORT=20130 # ── Embedded service WebSocket proxy ── # Standalone WebSocket proxy that tunnels WS connections to embedded services. # Binds to loopback by default. Only change EMBED_WS_PROXY_HOST if you know # what you are doing — exposing this to non-loopback bypasses local-only policy. # Used by: src/lib/services/embedWsProxy.ts # EMBED_WS_PROXY_HOST=127.0.0.1 # EMBED_WS_PROXY_PORT=20131 # ── CLIProxyAPI bridge (legacy) ── # Connection settings for external CLIProxyAPI instances. # Used by: open-sse/executors/cliproxyapi.ts # CLIPROXYAPI_HOST=127.0.0.1 # CLIPROXYAPI_PORT=5544 # CLIPROXYAPI_CONFIG_DIR=~/.cli-proxy-api # ── Mux embedded service ── # Override the port where the embedded Mux (coder/mux) agent-orchestration # daemon listens. Always bound to 127.0.0.1 — never configurable to 0.0.0.0. # Rarely needed — defaults to 8322. # Used by: src/lib/services/bootstrap.ts, src/app/api/services/mux/_lib.ts # MUX_SERVICE_PORT=8322 # ── Local hostnames (Docker networking) ── # Comma-separated additional hostnames treated as "local" for provider routing. # Used by: open-sse/config/providerRegistry.ts — allows Docker service names. # LOCAL_HOSTNAMES=omlx,mlx-audio # ═══════════════════════════════════════════════════════════════════════════════ # 21. PROXY HEALTH # ═══════════════════════════════════════════════════════════════════════════════ # Fine-tune proxy health checking behavior. # Used by: src/lib/proxyHealth.ts # Timeout for fast-fail health checks (ms). Default: 2000 # PROXY_FAST_FAIL_TIMEOUT_MS=2000 # Health check result cache TTL (ms). Default: 30000 (30s) # PROXY_HEALTH_CACHE_TTL_MS=30000 # Unhealthy health check result cache TTL (ms). Default: 2000 (2s) # Keeps transient fast-fail timeouts from poisoning a proxy for the full # healthy-result cache window under high concurrency. # PROXY_HEALTH_UNHEALTHY_CACHE_TTL_MS=2000 # Background proxy health scheduler (src/lib/proxyHealth/scheduler.ts). # Periodically probes every registered proxy and (optionally) removes dead ones. # Set "false" to disable the scheduler entirely. Default: enabled. # PROXY_HEALTH_ENABLED=true # Sweep interval in ms (minimum 60000). Default: 600000 (10min). # PROXY_HEALTH_INTERVAL_MS=600000 # Reachability probe target for the scheduler and the auto-test endpoint. # Point it at an internal/self-hosted URL to avoid the public default. # PROXY_HEALTH_TEST_URL=https://httpbin.org/ip # Set "true" to let the scheduler auto-remove proxies after repeated failures. # PROXY_AUTO_REMOVE=false # Consecutive failures before an auto-remove fires. Default: 3. # PROXY_AUTO_REMOVE_AFTER=3 # Let automated reachability probes (the scheduler + the "Test All" button) WRITE # a proxy's status. Default "false": probes are read-only and never deactivate a # proxy — only the operator sets active/inactive (a flaky probe must not strand an # assigned proxy; #6246). Set "true" to restore the legacy test-and-set behaviour. # PROXY_HEALTH_AUTO_DEACTIVATE=false # Allow OAuth and provider validation flows to bypass a pinned proxy and connect # directly when proxy reachability pre-checks fail. Default: false. # Also configurable from Dashboard > Settings > Feature Flags. # OMNIROUTE_CONTROL_PLANE_PROXY_DIRECT_FALLBACK=false # Rate limit maximum wait time before failing a request (ms). Default: 120000 (2 min) # Used by: open-sse/services/rateLimitManager.ts # RATE_LIMIT_MAX_WAIT_MS=120000 # Force the auto-enable rate limit safety net on/off regardless of the persisted # Dashboard setting. Used by: open-sse/services/rateLimitManager.ts. # Accepted values: true|1|on (force on), false|0|off (force off), unset (use Dashboard). # RATE_LIMIT_AUTO_ENABLE= # Provider cooldown tracking: minimum time (ms) before a failed provider/connection # can be retried. Prevents subsequent requests from re-walking failing providers. # Scaled exponentially: minCooldown * 2^(failures-1), capped at maxRetryCooldownMs. # Used by: open-sse/services/providerCooldownTracker.ts # PROVIDER_COOLDOWN_MIN_MS=5000 # Provider cooldown tracking: maximum time (ms) before a failed provider/connection # is retried regardless. Hard cap to prevent providers from being skipped indefinitely. # Used by: open-sse/services/providerCooldownTracker.ts # PROVIDER_COOLDOWN_MAX_MS=300000 # Enable/disable global provider cooldown tracking. Opt-in: this global # cross-request cooldown overlaps the existing Connection Cooldown / Provider # Circuit Breaker layers, so it is OFF by default. When disabled, only the # existing per-request/per-connection cooldown state is used (previous behavior). # Used by: open-sse/services/providerCooldownTracker.ts # Accepted values: true|1|on (enable). Unset or anything else = disabled (default). # PROVIDER_COOLDOWN_ENABLED=true # Transparent stream recovery (free-claude-code port). When enabled, the opening SSE # window is briefly held (up to STREAM_RECOVERY.HOLDBACK_MS) so an upstream truncation # before any byte reaches the client can be retried invisibly. Opt-in: holding the # window adds up to that much time-to-first-token latency on every stream, so it is # OFF by default. Seeds ResilienceSettings.streamRecovery.enabled. # Used by: open-sse/services/streamRecovery.ts, open-sse/handlers/chatCore.ts # Accepted values: true|1|on (enable). Unset or anything else = disabled (default). # STREAM_RECOVERY_ENABLED=true # Mid-stream continuation (Fase 4.4): when an upstream stream truncates AFTER bytes # already reached the client, re-request with the partial text as an assistant prefill # and stitch the missing suffix (plain-text OpenAI-compatible streams only; never with a # tool call in flight). OFF by default — the recovered tail arrives as one burst, not # token-by-token. Independent of STREAM_RECOVERY_ENABLED (different risk profile). # Seeds ResilienceSettings.streamRecovery.continueMidStream. # Used by: open-sse/services/streamRecovery.ts, open-sse/handlers/chatCore.ts # Accepted values: true|1|on (enable). Unset or anything else = disabled (default). # STREAM_RECOVERY_MIDSTREAM_ENABLED=true # Stagger interval (ms) between provider token healthchecks at startup. # Used by: src/lib/tokenHealthCheck.ts. Default: 3000. # HEALTHCHECK_STAGGER_MS=3000 # ═══════════════════════════════════════════════════════════════════════════════ # 22. DEBUGGING # ═══════════════════════════════════════════════════════════════════════════════ # These variables enable verbose debugging output. NEVER enable in production. # Cursor executor verbose debug (decoded SSE chunks, etc.). # CURSOR_STREAM_DEBUG is kept as a backward-compatible alias. # Used by: open-sse/executors/cursor.ts # CURSOR_DEBUG=1 # Enable verbose trace logging for OmniRoute internals. # Used by: open-sse/handlers/chatCore.ts. # OMNIROUTE_TRACE=true # Standard DEBUG flag (same effect as OMNIROUTE_TRACE). # DEBUG=true # CURSOR_STREAM_DEBUG=1 # When CURSOR_DEBUG=1, also append raw decoded chunks to this file path. # CURSOR_DUMP_FILE=/tmp/cursor-stream.log # Cursor stream idle timeout (ms). Default: 300000 (5 min). # Used by: open-sse/executors/cursor.ts. # CURSOR_STREAM_TIMEOUT_MS=300000 # Cursor tool-commit directive toggle. Default-on: when a request declares # tools, a directive is prepended so composer-2.5 reliably issues tool calls # instead of narrating intent. Set to 0 to disable. # Used by: open-sse/executors/cursor.ts. # CURSOR_TOOL_DIRECTIVE=1 # Per-image fetch timeout (ms) for remote image_url vision input. Default: 15000. # Used by: open-sse/utils/cursorImages.ts. # CURSOR_IMAGE_FETCH_TIMEOUT_MS=15000 # Cursor state DB path override (for cursor version detection). # Used by: open-sse/utils/cursorVersionDetector.ts. Default: probed automatically. # CURSOR_STATE_DB_PATH= # Direct Cursor bearer token used by scripts/ad-hoc/cursor-tap.cjs (developer tooling). # CURSOR_TOKEN= # Log Responses API SSE-to-JSON translation details. # DEBUG_RESPONSES_SSE_TO_JSON=true # Log request shape (content-type + content-length) for large chat payloads. # Used by: src/app/api/v1/chat/completions/route.ts. Set to "0" to silence. # Default: enabled. # OMNIROUTE_LOG_REQUEST_SHAPE=1 # Write raw (untruncated) request/response JSON in call log artifacts. # When enabled, serializeArtifactForStorage skips size-based truncation. # Also enabled automatically when APP_LOG_LEVEL=debug. # WARNING: produces large files — use only for temporary debugging. # CHAT_DEBUG_FILE=true # Enable E2E test mode — relaxes auth and enables test harness hooks. # NEXT_PUBLIC_OMNIROUTE_E2E_MODE=true # ═══════════════════════════════════════════════════════════════════════════════ # 23. GITHUB INTEGRATION (Issue Reporting) # ═══════════════════════════════════════════════════════════════════════════════ # Allow users to report issues directly from the Dashboard to GitHub. # Used by: src/app/api/v1/issues/report/route.ts # GitHub repository in owner/repo format. # GITHUB_ISSUES_REPO=owner/repo # GitHub Personal Access Token with issues:write scope. # GITHUB_ISSUES_TOKEN=ghp_xxxx # Generic GitHub access token consumed by issue triage / agent helpers. # Used by: src/app/api/v1/issues/* and src/lib/cloudAgent/* — falls back to # GITHUB_ISSUES_TOKEN when unset. # GITHUB_TOKEN= # ═══════════════════════════════════════════════════════════════════════════════ # 24. PROVIDER QUOTAS, TUNNELS & SANDBOXED SKILLS # ═══════════════════════════════════════════════════════════════════════════════ # Provider quota endpoints, network tunnels (Tailscale, Ngrok, MITM debug # proxy), 1Proxy egress pool, skills sandbox runtime, and miscellaneous CLI # binaries referenced by the executor layer or the dashboard runtime. # ── Alibaba (Bailian) coding plan quota ── # Host/full URL override used by: open-sse/services/bailianQuotaFetcher.ts. # When unset the fetcher uses the production Alibaba endpoints. # ALIBABA_CODING_PLAN_HOST= # ALIBABA_CODING_PLAN_QUOTA_URL= # ── Context window tuning ── # Tokens reserved for completion output when computing prompt budgets. # Used by: open-sse/services/contextManager.ts. Default: 1024. # CONTEXT_RESERVE_TOKENS=1024 # ── Model alias rewriting (legacy compatibility) ── # Toggle the legacy model-alias compatibility layer used by older clients. # Used by: open-sse/services/model.ts. Default: enabled. # MODEL_ALIAS_COMPAT_ENABLED=true # ── Devin CLI binary path ── # Used by: open-sse/executors/devin-cli.ts. Default: looked up via PATH. # CLI_DEVIN_BIN=devin # ── Command Code (custom CLI) callback ── # Local port used for OAuth-style callbacks from the Command Code CLI helper. # Used by: src/app/api/providers/command-code/auth/shared.ts. # COMMAND_CODE_CALLBACK_PORT= # ── Command Code CLI version header ── # Value sent as the x-command-code-version header to the Command Code upstream. # Overrides the built-in default; bump if the upstream requires a newer CLI version. # Used by: open-sse/executors/commandCode.ts # Default: 0.33.2 # COMMAND_CODE_VERSION=0.33.2 # ── MITM debug proxy (development only) ── # Used by: src/mitm/server.cjs — captures upstream traffic for inspection. # MITM_LOCAL_PORT=443 # MITM_DISABLE_TLS_VERIFY=0 # Idle socket timeout (ms) for proxied connections; sockets idle past this are torn # down to avoid leaking half-open tunnels (src/mitm/socketTimeouts.ts, server.cjs). # MITM_IDLE_TIMEOUT_MS=60000 # Routing-decision log verbosity: 0 silences, higher values log more bypass/route # decisions (src/mitm/server.cjs, _internal/bypass.cjs). # MITM_VERBOSE=1 # Strip the leading `sudo` from MITM cert-trust commands (src/mitm/systemCommands.ts) — # for root-less / user-namespaced deployments (e.g. rootless Docker/Podman) # where the operator trusts the CA manually (e.g. via Node's extra-CA-certs mechanism). # OMNIROUTE_NO_SUDO=0 # ── Test/CI-only guards (never needed in production) ── # Set automatically by tests/_setup/isolateDataDir.ts and the CI workflows: the # test suite must NEVER mutate the OS trust store (a fake test PEM installed via # update-ca-certificates broke all system TLS on a persistent runner, 2026-07-05). # OMNIROUTE_SKIP_SYSTEM_TRUST=1 # check-changelog-integrity.mjs (anti CHANGELOG-eat gate): explicit base ref # override, and the justified-removal escape hatch for intentional bullet removals. # CHANGELOG_BASE_REF=origin/release/v0.0.0 # ALLOW_CHANGELOG_REMOVALS=1 # ── 1Proxy egress pool ── # Used by: src/lib/oneproxySync.ts — fetches proxy nodes from the OmniRoute # CrofAI 1Proxy service. Disable, override URL, or tune the import quality. # ONEPROXY_ENABLED=true # ONEPROXY_API_URL=https://1proxy-api.aitradepulse.com # ONEPROXY_MAX_PROXIES=500 # ONEPROXY_MIN_QUALITY_THRESHOLD=50 # ── Free Proxy Pool (1proxy source) ── # Used by: src/lib/freeProxyProviders/oneproxy.ts # Set FREE_PROXY_1PROXY_ENABLED=false to disable this source. # FREE_PROXY_1PROXY_ENABLED=true # FREE_PROXY_1PROXY_API_URL=https://1proxy-api.aitradepulse.com/api/v1/proxies/advanced # FREE_PROXY_1PROXY_MAX=500 # FREE_PROXY_1PROXY_MIN_QUALITY=50 # ── Free Proxy Pool (Proxifly source) ── # Used by: src/lib/freeProxyProviders/proxifly.ts # Enabled by default; set to false to disable. # FREE_PROXY_PROXIFLY_ENABLED=true # FREE_PROXY_PROXIFLY_QUANTITY=100 # FREE_PROXY_PROXIFLY_ANONYMITY=elite # ── Free Proxy Pool (IPLocate source) ── # Used by: src/lib/freeProxyProviders/iplocate.ts # Opt-in only; must set FREE_PROXY_IPLOCATE_ENABLED=true to activate. # FREE_PROXY_IPLOCATE_ENABLED=false # FREE_PROXY_IPLOCATE_BASE_URL=https://raw.githubusercontent.com/iplocate/free-proxy-list/main/protocols # ── Free Proxy Pool (Webshare source) ── # Used by: src/lib/freeProxyProviders/webshare.ts # Paid, per-account proxy list — requires FREE_PROXY_WEBSHARE_API_KEY to activate, # regardless of FREE_PROXY_WEBSHARE_ENABLED. # FREE_PROXY_WEBSHARE_ENABLED=true # FREE_PROXY_WEBSHARE_API_KEY= # FREE_PROXY_WEBSHARE_API_URL=https://proxy.webshare.io/api/v2/proxy/list/ # FREE_PROXY_WEBSHARE_MAX=500 # ── Vercel Relay ── # Used by: src/app/api/settings/proxy/vercel-deploy/route.ts # Hides the "Deploy Relay" button when set to false. # NEXT_PUBLIC_VERCEL_RELAY_ENABLED=true # VERCEL_API_BASE=https://api.vercel.com # Default project name pre-filled in the Vercel Relay deploy modal. # NEXT_PUBLIC_VERCEL_RELAY_DEFAULT_PROJECT=omniroute-relay # ── Tailscale tunnel binaries ── # Optional explicit paths to tailscale/tailscaled binaries used by the # dashboard's tunnel manager. Used by: src/lib/tailscaleTunnel.ts. # TAILSCALE_BIN=/usr/local/bin/tailscale # TAILSCALED_BIN=/usr/local/bin/tailscaled # Pre-shared Tailscale auth key for non-interactive / headless `tailscale up` # (passed via --auth-key=). When unset, login falls back to the interactive # browser auth URL. Used by: src/lib/tailscaleTunnel.ts. # TAILSCALE_AUTHKEY= # ── Ngrok tunnel ── # Used by: src/lib/ngrokTunnel.ts — authenticates outbound tunnels. # NGROK_AUTHTOKEN= # ── Database backups ── # Used by: src/lib/db/backup.ts. # DB_BACKUP_MAX_FILES=20 # DB_BACKUP_RETENTION_DAYS=0 # ── TLS sidecar override ── # Used by: open-sse/services/chatgptTlsClient.ts tests. Production deployments # should leave this unset; the sidecar is auto-managed. # OMNIROUTE_TLS_PROXY_URL= # ── Skills sandbox (experimental) ── # Used by: src/lib/skills/builtins.ts. All values support comma lists where # noted in the source. # SKILLS_MAX_FILE_BYTES=1048576 # SKILLS_MAX_HTTP_RESPONSE_BYTES=256000 # SKILLS_MAX_SANDBOX_OUTPUT_CHARS=100000 # SKILLS_SANDBOX_TIMEOUT_MS=10000 # SKILLS_SANDBOX_NETWORK_ENABLED=0 # SKILLS_ALLOWED_SANDBOX_IMAGES= # ═══════════════════════════════════════════════════════════════════════════════ # 25. TEST & E2E # ═══════════════════════════════════════════════════════════════════════════════ # Used by scripts/dev/run-next-playwright.mjs, scripts/dev/smoke-electron-packaged.mjs, # scripts/dev/run-ecosystem-tests.mjs and scripts/build/uninstall.mjs. # Production deployments should leave every value below unset. # E2E bootstrap mode for the Playwright runner. Accepted: auth | fresh | reuse. # Default (when unset): auth. # OMNIROUTE_E2E_BOOTSTRAP_MODE=auth # Admin password injected into the Playwright test environment. # Falls back to INITIAL_PASSWORD when unset. # OMNIROUTE_E2E_PASSWORD= # Disable the local healthcheck poll during Playwright runs (default: true). # OMNIROUTE_DISABLE_LOCAL_HEALTHCHECK=true # Disable the OAuth token healthcheck loop during tests (default: true). # OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK=true # Exclude specific providers from the PROACTIVE token-refresh sweep (comma-separated, # case-insensitive). Targeted alternative to OMNIROUTE_DISABLE_TOKEN_HEALTHCHECK: keeps # rotating-cascade providers (Codex/OpenAI share one Auth0 family) on the reactive 401 # path only, while short-TTL providers like Kimi-coding keep being refreshed proactively. # OMNIROUTE_HEALTHCHECK_SKIP_PROVIDERS=codex,openai # Silence healthcheck noise in Playwright stdout (default: true). # OMNIROUTE_HIDE_HEALTHCHECK_LOGS=true # Skip the Next.js production build before Playwright starts (CI optimization). # OMNIROUTE_PLAYWRIGHT_SKIP_BUILD=0 # Skip the OmniRoute uninstall hook (used by CI to keep node_modules intact). # OMNIROUTE_SKIP_UNINSTALL_HOOK=0 # Ecosystem/protocol test orchestrators wait this long (ms) for the server to # become healthy. Default: 180000. # ECOSYSTEM_SERVER_WAIT_MS=180000 # Docs translation pipeline (used by scripts/i18n/run-translation.mjs). # OpenAI-compatible base URL, e.g. https://cloud.omniroute.online/v1 # OMNIROUTE_TRANSLATION_API_URL= # Bearer token for the translation backend (NEVER commit a real key here). # OMNIROUTE_TRANSLATION_API_KEY= # Model id, e.g. gpt-4o-mini or cx/gpt-5.4-mini. # OMNIROUTE_TRANSLATION_MODEL=gpt-4o-mini # Per-request timeout in milliseconds (default 60000). # OMNIROUTE_TRANSLATION_TIMEOUT_MS=60000 # Number of parallel translation requests (default 4). # OMNIROUTE_TRANSLATION_CONCURRENCY=4 # ─── Cloud Sync hardening (v3.8.6) ────────────────────────────────────────── # Shared secret used to verify the HMAC-SHA256 of the Cloud sync response body # (the Cloud endpoint must sign each response with the same secret and place # the hex digest in the X-Cloud-Sig header). When unset, v3.8.6 logs a warning # but accepts unsigned responses for back-compat. v3.9 will make this required. # OMNIROUTE_CLOUD_SYNC_SECRET= # # Set to "true" to allow the Cloud Sync endpoint to overwrite local OAuth # tokens (accessToken / refreshToken / providerSpecificData). Default OFF — # only non-credential metadata is synced. See docs/security/SOCKET_DEV_FINDINGS.md §5. # OMNIROUTE_CLOUD_SYNC_SECRETS=false # ─── Zed import legacy compat (v3.8.6) ────────────────────────────────────── # Set to "true" to fall back to the v3.8.5 one-step "import everything from # the keychain" behaviour. Default OFF — the new 2-step confirmation flow # requires `confirmedAccounts` in the request body. See SOCKET_DEV_FINDINGS.md §2. # OMNIROUTE_ZED_IMPORT_LEGACY_ONE_STEP=false # ─── Build profile (build-time only) ──────────────────────────────────────── # Set to "minimal" before `npm run build` to physically remove four optional # privileged modules (MITM cert install, Zed keychain import, Cloud Sync, # 9router installer) from the standalone bundle. The resulting artifact is # intended to be published as `omniroute-secure`. See SECURITY.md. # OMNIROUTE_BUILD_PROFILE=full # Electron smoke harness (used by scripts/dev/smoke-electron-packaged.mjs). # ELECTRON_SMOKE_URL=http://127.0.0.1:20128/login # ELECTRON_SMOKE_TIMEOUT_MS=45000 # ELECTRON_SMOKE_SETTLE_MS=2000 # ELECTRON_SMOKE_APP_EXECUTABLE= # ELECTRON_SMOKE_DATA_DIR= # ELECTRON_SMOKE_KEEP_DATA=0 # ELECTRON_SMOKE_STREAM_LOGS=0 # Playground Studio # Default model used by the improve-prompt route (optional; falls back to model in request body). PLAYGROUND_IMPROVE_PROMPT_DEFAULT_MODEL= # Maximum number of parallel compare columns in the Compare tab. PLAYGROUND_COMPARE_MAX_COLUMNS=4 # Memory engine (plan 21) # MEMORY_EMBEDDING_CACHE_TTL_MS=300000 # default 5 min # MEMORY_EMBEDDING_CACHE_MAX=1000 # default 1000 entries # MEMORY_TRANSFORMERS_MODEL=Xenova/all-MiniLM-L6-v2 # MEMORY_STATIC_MODEL=minishlab/potion-base-8M # HF repo id (download once) # MEMORY_STATIC_CACHE_DIR= # default /embeddings # MEMORY_VEC_TOP_K=20 # default top-K for vector search # MEMORY_RRF_K=60 # RRF k constant (sqlite-vec hybrid recipe) # HF_HUB_ENDPOINT=https://huggingface.co # override Hugging Face Hub base URL for static potion downloads # TV6 typed memory decay (OPT-IN, default off — the sweep DELETES decayed memories) # MEMORY_TYPED_DECAY_ENABLED=false # master switch for the destructive sweep (default off) # MEMORY_TYPED_DECAY_EPISODIC_DAYS=30 # episodic TTL in days; 0 = episodic immune too # MEMORY_TYPED_DECAY_ACCESS_IMMUNITY=3 # access_count >= N → immune; 0 disables access immunity # MEMORY_TYPED_DECAY_SWEEP_INTERVAL=0 # periodic sweep interval (seconds); 0 = no periodic sweep # AgentBridge + Traffic Inspector (Group A) # AgentBridge AGENTBRIDGE_UPSTREAM_CA_CERT= # Inspector INSPECTOR_BUFFER_SIZE=1000 INSPECTOR_HTTP_PROXY_PORT=8080 INSPECTOR_HTTP_PROXY_AUTOSTART=false INSPECTOR_TLS_INTERCEPT=false INSPECTOR_SYSTEM_PROXY_GUARD_MINUTES=30 INSPECTOR_MAX_BODY_KB=1024 INSPECTOR_MASK_SECRETS=true INSPECTOR_LLM_HOSTS_EXTRA= INSPECTOR_INTERNAL_INGEST_TOKEN= # Quota Sharing (Group B — planos 16+22) QUOTA_STORE_DRIVER=sqlite # sqlite | redis # QUOTA_STORE_REDIS_URL= # ex.: redis://localhost:6379 (apenas quando driver=redis) # QUOTA_SATURATION_THRESHOLD=0.5 # 0..1; >= threshold ativa modo strict (sem empréstimo) # QUOTA_SOFT_DEPRIORITIZE_FACTOR=0.7 # 0..1; multiplicador do score quando soft policy ativa # STATUS_SOFT_DEPRIORITIZE_FACTOR=0.5 # 0..1; multiplicador do score p/ provider esgotado (credits_exhausted/rate_limited) quando preflight cutoff OFF (#4540) # QUOTA_CONSUMPTION_RETENTION_DAYS=14 # GC de buckets quota_consumption.updated_at antigos # QUOTA_PREFLIGHT_CUTOFF_ENABLED=false # opt-in (default OFF): hard quota cutoff drops low-quota candidates before auto-routing scoring # ─── Auto-Combo tier filter (#4517) ─────────────────────────────────────── # When an `auto/:free` (or any `:`) request matches NO connected # candidates, OmniRoute returns an EMPTY pool by default — so `:free` really means # "free tier only" and a paid model is never picked just because no free provider is # connected. Set this to `true`/`1` to restore the legacy behavior of falling back to # the full (unfiltered) pool with a warning. Source: open-sse/services/autoCombo/virtualFactory.ts # OMNIROUTE_AUTO_FREE_FALLBACK_TO_FULL_POOL=false # ─── OpenCode config regeneration (scripts/ad-hoc/regen-opencode-config.ts) ─── # Base URL of the OmniRoute instance to query for /v1/models when regenerating # an opencode.json with accurate limit.context values. Used by: # scripts/ad-hoc/regen-opencode-config.ts. Default: http://localhost:20128 # OMNIROUTE_URL= # API key to authenticate against the OmniRoute /v1/models endpoint. Falls back # to OPENCODE_API_KEY when unset. Used by: scripts/ad-hoc/regen-opencode-config.ts. # OMNIROUTE_KEY= # OpenCode-style API key (sk-...) for the regenerated opencode.json. Used by: # scripts/ad-hoc/regen-opencode-config.ts. Falls back to OMNIROUTE_KEY. # OPENCODE_API_KEY= # ─── Bifrost Go sidecar (PR-4 in #3932) ────────────────────────────────────── # Master kill switch for the bifrost sidecar proxy. When set to 0, the # /api/v1/relay/chat/completions/bifrost route returns 503 with the # X-Bifrost-Killswitch header and the operator is bounced to the TS path. # Use this to disable the sidecar without redeploying (e.g. during a # tier-1 router incident or a key rotation). Default: 1 (sidecar active). # BIFROST_ENABLED=1 # When BIFROST_BASE_URL is set, /api/v1/relay/chat/completions/bifrost routes # traffic to the Go gateway instead of the TS relay handler, removing TS from # the hot path. Auth/rate-limit/injection-guard stay in the route (security not # duplicated). Falls back to TS path via X-Bifrost-Fallback header on # timeout/failure. See bin/omniroute for the local-redis companion. # BIFROST_BASE_URL= # Port the supervised Bifrost embedded service binds to (127.0.0.1:), read by # src/lib/services/bootstrap.ts when OmniRoute manages the Bifrost sidecar lifecycle. # Default: 8080. # BIFROST_PORT=8080 # API key for the Bifrost gateway (sent as Authorization: Bearer ...). If # unset, the route expects the request to carry a valid OmniRoute API key; # this key is for gateway-side auth only. # BIFROST_API_KEY= # When true, the Bifrost sidecar route streams responses back via SSE through # the gateway rather than the TS streaming executor. Default: true (when # BIFROST_BASE_URL is set). # BIFROST_STREAMING_ENABLED= # Per-request timeout when proxying to the Bifrost gateway. Default: 30000 (30s). # BIFROST_TIMEOUT_MS= # Alias for BIFROST_API_KEY (used by scripts that read the env via # OMNIROUTE_*). BIFROST_API_KEY takes precedence when both are set. # OMNIROUTE_BIFROST_KEY= # Relay backend selection for the OpenAI-compatible relay endpoint: # ts | bifrost | auto. "ts" (default when Bifrost is not configured) uses the # TypeScript relay; "auto" selects Bifrost when BIFROST_BASE_URL is set (and # BIFROST_ENABLED != 0) and falls back to TS if the sidecar is unreachable; # "bifrost" forces Bifrost (strict — no TS fallback). Auth, rate limits, # injection guard and model allowlists always run in the Next route first. # RELAY_ROUTING_BACKEND is an accepted alias. Responses carry X-Routing-Backend # and X-Routing-Fallback. # OMNIROUTE_RELAY_BACKEND= # RELAY_ROUTING_BACKEND= # Cooldown (ms) after a Bifrost sidecar hop fails in "auto" mode before the relay # re-attempts the sidecar; it goes straight to the TS path while the cooldown lasts. # 0 disables. Default 5000. Only applies when OMNIROUTE_RELAY_BACKEND=auto. # OMNIROUTE_BIFROST_FAILURE_COOLDOWN_MS= # Opt-in native HTTPS/TLS for `omniroute serve` (equivalent to --tls-cert / # --tls-key). Provide BOTH a PEM certificate and its private key and the # standalone server terminates TLS on the same listener (wss:// works # unchanged). With neither set the server stays plain HTTP; providing only one # (or an unreadable path) logs a warning and stays HTTP (never half-enables). # OMNIROUTE_TLS_CERT= # OMNIROUTE_TLS_KEY= # ─── 1-click local service launchers (PR-3 in #3932) ──────────────────────── # Master switch for /api/local/* routes. When unset or "0", all /api/local/* # routes return 503 in production. Default: 0. Must be "1" in non-loopback # deploys to enable the Redis launcher and similar 1-click local service # starters. Belt-and-suspenders with the isLocalOnlyPath() route-guard # classification (LOCAL_ONLY_API_PREFIXES in src/server/authz/routeGuard.ts). # OMNIROUTE_LOCAL_ENDPOINTS_ENABLED= # Bearer token for /api/local/* callers that aren't on loopback (e.g. the # desktop app). When set, requests from non-loopback IPs must carry # Authorization: Bearer . Required when # OMNIROUTE_LOCAL_ENDPOINTS_ENABLED=1 in non-loopback deployments. Default: # unset (loopback-only). # OMNIROUTE_LOCAL_ENDPOINTS_TOKEN= # Container name for the 1-click Redis launcher (`omniroute redis up`). # Default: omniroute-redis. Used by bin/cli/commands/redis.mjs and the # RedisLauncherPanel. # OMNIROUTE_REDIS_CONTAINER_NAME= # Host port for the 1-click Redis launcher. Default: 6379. Bump if the host # already binds 6379. The container's internal port stays 6379. # OMNIROUTE_REDIS_HOST_PORT= # Redis image used by the 1-click Redis launcher. Default: redis:7-alpine. # Override to redis:8-alpine or a private registry mirror as needed. # OMNIROUTE_REDIS_IMAGE= # ── Cluster Profile: Qdrant Vector Memory (opt-in via `docker compose --profile memory up`) ── # Qdrant is an OPTIONAL sidecar for deployments that need cosine-distance vector # search at >1M embeddings. The default vector store is sqlite-vec # (src/lib/memory/vectorStore.ts:108); flip this profile on only if you hit the # sqlite-vec ceiling or want persistent cross-replica vector state. See # docs/architecture/cluster-decisions.md § "Qdrant (memory profile)". # QDRANT_HOST=qdrant # QDRANT_PORT=6333 # QDRANT_GRPC_PORT=6334 # QDRANT_API_KEY= # QDRANT_COLLECTION=omniroute-memory # QDRANT_EMBEDDING_MODEL=text-embedding-3-small # QDRANT_VECTOR_SIZE=1536 # QDRANT_HNSW_EF_CONSTRUCT=128 # ── Cluster Profile: Bifrost Tier-1 Router (opt-in via `docker compose --profile bifrost up`) ── # Bifrost is an OPTIONAL Go-based Tier-1 router that handles the upstream-provider # multiplexing layer. Default: OmniRoute's open-sse/executors/bifrost.ts in-process # executor handles routing directly. Flip this profile on only if you want the # gateway as a separate sidecar (helps in 3+ replica deployments where you want # provider rotation centralised). See docs/architecture/cluster-decisions.md § # "Bifrost (bifrost profile)". # Set OMNIROUTE_RELAY_BACKEND=auto to use this sidecar when healthy, or # OMNIROUTE_RELAY_BACKEND=bifrost to require it without TS fallback. # BIFROST_BASE_URL=http://bifrost:8080 # BIFROST_API_KEY= # BIFROST_STREAMING_ENABLED=true # BIFROST_TIMEOUT_MS=30000