Skip to content

Configuration and modules

The launcher reads one explicit environment file. That file takes precedence over environment variables inherited from a developer shell, reducing accidental connections to another database or bucket.

Terminal window
bun run deploy modules
bun run deploy config --env-file deploy/.env.staging

COMPOSE_PROFILES selects services. The default staging selection is core,world,automation,monitoring,voice.

Profile Services Additional configuration
core Mainframe, Postgres, SRS, indexer, Caddy Core secrets, storage, admin account, public IP
storage Local MinIO and bucket initialization Use for a local deployment, not the managed staging bucket
world world-sim Admin token, world configuration, advertised admin URL
automation auto-operator Mode, serial selection, provider selection, battery thresholds
monitoring Grafana, Prometheus, host/container/Postgres exporters, Loki, Alloy Grafana admin credentials
feeds Weather and radar-net Weather sites and upstream connectivity
detections Vision module OpenRouter key and model roster; incurs model usage
assistant On-page assistant (model proxy) OPENROUTER_API_KEY, ASSISTANT_MODELS (first is the default; verify the ids), ASSISTANT_MAX_CONCURRENT; incurs model usage per turn
interop TAK bridge CA, server certificate, key, and client certificates
autel Native Autel controller host and its authenticated MQTT broker Provisioned controller bindings (AUTEL_NATIVE_DIR/native.json)
vanagas Read-only observation of vanago-akis drones Its broker credentials and upstream SRS addresses
vanagas-phones Phone location, audio/video and recordings Shared Vanagas broker/SRS config plus dedicated snapshot URL/key
voice LiveKit, Redis and Egress for voice rooms and optional recording LIVEKIT_API_KEY, LIVEKIT_API_SECRET; 7881/tcp and 7882/udp open to PUBLIC_IP

autel and vanagas are separate modules with separate provider identities (MAINFRAME_AUTEL_API_KEY, MAINFRAME_VANAGAS_API_KEY) and can run together: real controllers on the native host while another system’s flights are observed. The launcher builds MAINFRAME_ENABLED_MODULES from the selected profiles. API keys remain stable across restarts; changing a configured value does not rotate an existing database key automatically.

For a sharded vanago-akis upstream, set VANAGAS_SRS_SOURCES to a JSON array of API/RTMP pairs, one per shard. For example:

Terminal window
VANAGAS_SRS_SOURCES='[{"api":"http://srs-1.example.com:1985","rtmp":"rtmp://srs-1.example.com:1935/live"},{"api":"http://srs-2.example.com:1985","rtmp":"rtmp://srs-2.example.com:1935/live"}]'

This takes precedence over the single VANAGAS_SRS_API/VANAGAS_SRS_RTMP pair. The Vanagas container must reach each API; the Mainframe source adapter must reach each RTMP address, including private DNS/VPN routes. /api/health reports per-shard discovery health and each relay’s source server. Discovery outages preserve existing pulls while healthy shards continue updating. Duplicate stream names without a previously selected owner are refused. This observer does not request new publishing assignments or send upstream controller commands.

Setting Meaning
MAINFRAME_BASE_URL Mainframe’s public authentication origin
MAINFRAME_PUBLIC_URL Frontend build-time default connection URL
MAINFRAME_TRUSTED_ORIGINS Browser origins allowed to carry credentials; also the passkey origins
MAINFRAME_SSO_ISSUER, MAINFRAME_SSO_CLIENT_ID, MAINFRAME_SSO_CLIENT_SECRET The OIDC identity provider for single sign-on; read only when Settings → Security → Single sign-on is on at boot
PUBLIC_IP SRS’s browser-reachable WebRTC address
MEDIA_RTC_PORT UDP and TCP media port (8189 by default; staging uses 8000)
MEDIA_SEGMENT_DURATION Minimum archive segment duration, default 60s
MEDIA_RTMP Publishing address reachable by providers and controllers
LIVEKIT_API_KEY, LIVEKIT_API_SECRET The voice server’s key pair; Mainframe mints join tokens with it and verifies its webhooks
LIVEKIT_PUBLIC_URL The signalling address browsers dial; defaults to wss://DOMAIN (Caddy proxies /rtc to LiveKit)
LIVEKIT_STUN_SERVERS JSON list of STUN servers clients receive; empty keeps stun.l.google.com:19302, [] for a LAN box without internet
BLOB_S3_* Private object-store endpoint, region, bucket, and credentials
WORLD_SIM_PUBLIC_URL Base URL for the simulator admin link
AUTO_OPERATOR_MODE Separate module behavior: suggestions or automatic mission dispatch
AUTO_OPERATOR_SERIALS Exact comma-separated serial allowlist
AUTO_OPERATOR_SERIAL_PREFIX Optional literal serial prefix; no wildcard syntax
AUTO_OPERATOR_PROVIDER_IDS Provider identities allowed by the serial selection

Exact serials and a prefix form an OR selection, then the provider restriction applies. Empty serial selection permits no aircraft. Automatic mode refuses to start without a selection.

Voice media takes two more host ports beside MEDIA_RTC_PORT: 7881/tcp (ICE over TCP, the fallback for networks that drop UDP) and 7882/udp (one multiplexed port for every participant). LiveKit advertises PUBLIC_IP as its only candidate, so a wrong value means one-way or no audio. The launcher sets LIVEKIT_URL for Mainframe only while the voice profile is selected; without it /api/voice/config answers enabled: false and the Voice panel says so. Microphones need a secure context: a LAN deployment reached over plain http:// by IP has no microphone, so serve Terminal over Caddy’s internal CA (install it on the laptops) or a real certificate.

Changes to deployment environment values require container recreation. Changing MAINFRAME_PUBLIC_URL also requires rebuilding the frontend image. Document edits made through Terminal take effect through Mainframe’s document watches.

These environment values seed Mainframe’s settings documents on the first boot of a database and are never read again. Change them afterwards in Terminal → Settings → Mainframe (administrators), where every change is audited; a variable edited in the environment after the first boot has no effect. The Settings page describes each section.

Variable Initial value of Settings section
MAINFRAME_AUTONOMY Autonomy (suggest or auto) Operations
MAINFRAME_STATE_RETENTION_DAYS State horizon (90 days) Retention
MAINFRAME_TELEMETRY_RETENTION_DAYS Telemetry horizon (14 days) Retention
MAINFRAME_BULK_RETENTION_HOURS Bulk horizon (48 hours) Retention
MAINFRAME_MEDIA_RETENTION_HOURS Recording retention (168 hours) Media
mainframe.config.tsmedia Default record policy and overrides Media

The launch battery minimum (30 %), the coverage grid (150 m cells, 10 minute horizon, 300 m border strip, the first geofence and border markings), the workspace defaults and the security values (7 day sessions, 10 sign-ins per 60 s, 12 character passwords, no two-factor requirement, passkeys and single sign-on off, 365 day personal keys) have no environment variable: they seed from code and are edited in Settings only. The session age, login limit, passkeys and single sign-on are read at boot (after restart in Settings); the password floor, the two-factor requirement and the key age apply at once.

Grants declared in mainframe.config.ts are desired state: every boot adds what is missing and removes a configured grant that left the file, and never touches a grant an administrator wrote in Settings → Access.

The shared environment helper supports _FILE variants for application secrets. To use Compose secrets, explicitly mount the file and pass its _FILE variable in the service configuration; the default deployment examples use a protected environment file.

The engine is selected when Vite builds the frontend. The checked-in apps/web/map-build.json selects Mapbox and supplies its public browser token, so Pages and clean checkouts use the same defaults. Override these in the Pages build environment or the ignored apps/web/.env.local file, then rebuild:

Variable Default Purpose
VITE_MAP_ENGINE mapbox maplibre or mapbox; other values fail the build
VITE_MAPBOX_ACCESS_TOKEN map-build.json Public pk.* token; required for Mapbox builds
VITE_MAP_STYLE unset Optional style URL overriding the chosen engine’s defaults

MapLibre keeps the registered PMTiles → Lithuania archive → CARTO resolution. Mapbox starts with dimmed Satellite Streets imagery (65% maximum brightness, slightly reduced saturation). Labels and operational overlays remain at full brightness. Layers → Satellite / Map switches the basemap in Mapbox builds. Map mode follows the application’s light/dark theme. An explicit VITE_MAP_STYLE fixes the basemap and hides that selector.

Both engines use the same markings, selection, route, drone, camera-footprint, coverage, and detection code. The build selects the matching Terra Draw adapter for vertex editing and the matching GL markers for draggable points and circles. Style changes restore operational layers and the current edit draft. Mapbox uses flat classic styles to keep the existing overlay ordering and canvas coverage projection; custom styles must support these same GL layers and label fonts.

The configured pk.* token is public and included in the browser bundle. Set VITE_MAP_ENGINE=maplibre to build the self-hosted MapLibre variant. Engine changes require a new frontend build; backend environment changes alone do not select an engine.

Set VOICE_RECORDING=1 on Mainframe to enable automatic room mixes and original speaker recording. Deploy the voice profile, provide private bucket access, and retain the Egress backup volume during upload outages. VOICE_S3_ENDPOINT can override the bucket address used inside Egress; it must identify the same bucket as BLOB_S3_*. Historical audio remains readable with recording disabled.

Recording status and indexed coverage differ: token issuance is not proof of audio capture. Monitor mainframe_voice_recordings, mainframe_voice_recording_reconcile_failures_total and mainframe_comms_purge_pending. Voice uses the Comms retention setting and honors archive preservation holds.

Transcription is deferred: its UI is hidden and no transcription backend runs, even if VOICE_TRANSCRIBE_COMMAND or Whisper settings are present. The local adapter code is retained for future use. Recording, playback and audible-activity analysis do not require a speech model.