Skip to content

Configuration

galois-edge reads its configuration from a single KEY=VALUE file. Defaults are baked into the binary; the file overrides defaults; environment variables override the file. A typical install never needs more than the four keys written by galois-edge setup.

The daemon resolves config in this order on startup:

  1. The path passed to --config on the CLI, if any.
  2. ${SystemConfigDir}/config.env.
  3. ${UserConfigDir}/config.env.
  4. Built-in defaults if no file is found.

Environment variables override the resulting struct as a final layer — they take effect after whichever source above was chosen.

PlatformSystem dirUser dir
Linux / macOS/etc/galois-edge/~/.config/galois-edge/
WindowsC:\ProgramData\galois-edge\%APPDATA%\galois-edge\

The system path is preferred for service installs; the user path is preferred for per-user development. Both setup and configure set follow the same precedence — they update an existing file in place if one is found, otherwise they write to the user dir (no root required).

# Comments start with '#'
EDGE_NAME=lab-pi-01
GRPC_PORT=50051
# Quoted values keep whitespace
PROFILE_DIR="/srv/galois/custom profiles"
# Optional `export` prefix is accepted (sourced shells also work)
export REGISTRATION_TOKEN=glc_XXXXXXXX

Values may be wrapped in single or double quotes. Inline comments are stripped from unquoted values (split on " #"). Booleans accept true / 1 / yes / false / 0 / no (case-insensitive). Comma-separated lists like LAN_INSTRUMENTS strip whitespace around each entry and drop empty values. Unknown keys are preserved on round-trip and forwarded to the Python engine as environment variables — useful for experimental flags like DEMO_MODE=1 or MODBUS_INSTRUMENTS=….

Terminal window
galois-edge configure list # show all keys + current values
galois-edge configure get GRPC_PORT # print one value
galois-edge configure set GRPC_PORT 50061 # validate + persist
galois-edge configure init # write a default config file

configure list masks REGISTRATION_TOKEN and TAILSCALE_AUTH_KEY to the last four characters so it’s safe in screenshots.

KeyDefaultDescription
EDGE_NAMEsystem hostnameHuman-readable name reported to the cloud and used as the tailnet hostname.
KeyDefaultDescription
PYTHON_BINauto-detectAbsolute path to galois-edge-daemon. If empty, the supervisor looks next to the Go binary, then on PATH (galois-edge-daemon, galois-engine).
KeyDefaultDescription
GRPC_PORT50051External gRPC port — what the cloud connects to over the tailnet. Also bound on 0.0.0.0 as a fallback.
GRPC_INTERNAL_PORT50052Localhost-only port the Python engine binds. The Go supervisor proxies GRPC_PORT → GRPC_INTERNAL_PORT. Must differ from GRPC_PORT.
GRPC_MAX_WORKERS10Python ThreadPoolExecutor size for blocking instrument I/O.
KeyDefaultDescription
WS_PORT8765External WebSocket port (telemetry / live data).
WS_INTERNAL_PORT8766Localhost port the Python engine binds; proxied from WS_PORT. Must differ from WS_PORT.
WS_ENABLEDtrueToggle the WebSocket server.
KeyDefaultDescription
BACKEND_URLemptyCloud control-plane URL. Empty → standalone mode (no registration, no heartbeat). Set to https://cloud.galoislabs.ai for the public service.
RELAY_URLderivedWebSocket relay URL. If empty and BACKEND_URL is set, derived as wss://<host>/api/v1/relay/ws.
REGISTRATION_TOKENemptyAPI key (glc_…). Required for cloud registration.
HEARTBEAT_INTERVAL_SEC30Seconds between heartbeats.
KeyDefaultDescription
INBOUND_AUTH_TOKENemptyOptional bearer token. When non-empty, the daemon’s gRPC server installs an interceptor that requires authorization: Bearer <token> metadata on every RPC except Ping. Empty disables auth (the network — tailnet or loopback — is the boundary). Auto-populated by setup if the backend returns one. Format convention: glc_internal_<32+ random chars>.
KeyDefaultDescription
TAILSCALE_AUTH_KEYemptyPre-auth key for joining the tailnet. Auto-populated by setup if the backend returns one.
HEADSCALE_URLemptyHeadscale control URL. Empty → use the public Tailscale control plane.
TSNET_STATE_DIRemptyPersistent state for the embedded Tailscale node. When empty, start resolves it to ${SystemConfigDir}/tsnet-state at runtime. The directory is created with mode 0700.
KeyDefaultDescription
PROFILES_ENABLEDtrueLoad YAML instrument profiles. When false, all instruments fall back to raw SCPI only.
PROFILE_DIRbundledOverride the profile search directory. The bundled set under the engine’s package dir is always loaded; this directory is loaded on top.
KeyDefaultDescription
GPIB_ENABLEDtrue on Linux, false elsewhereAccepts true / false / auto. The auto value is resolved to true/false at construction; what gets persisted is the resolved string.
GPIB_BOARD0linux-gpib board index.
GPIB_SCAN_ON_INITtrueScan the GPIB bus on startup. Disable for slower-booting setups that scan on demand.
KeyDefaultDescription
LAN_ENABLEDtrueDiscover LAN instruments.
LAN_MDNS_ENABLEDtrueUse mDNS / Zeroconf to browse _lxi._tcp.local. for LXI-compliant instruments.
LAN_INSTRUMENTSemptyComma-separated list of static VISA TCPIP addresses, e.g. TCPIP::192.168.1.10::INSTR,TCPIP::scope.lab::5025::SOCKET.
KeyDefaultDescription
USB_RAW_ENABLEDtrueEnable the raw-USB transport (pyusb) for vendor-specific non-USBTMC devices (e.g. Signal Recovery lock-in amplifiers). Standard USBTMC devices use PyVISA regardless of this setting.
KeyDefaultDescription
ZMQ_ENABLEDfalsePublish measurements on a ZMQ PUB socket (in addition to gRPC streaming).
ZMQ_PUB_PORT5556TCP port for the PUB socket.
KeyDefaultDescription
VISA_BACKENDemptyPass-through to PyVISA’s ResourceManager(...). Use @py for pure-Python pyvisa-py, or leave empty to let PyVISA pick (NI-VISA on Windows when present).
KeyDefaultDescription
RESCAN_INTERVAL_SEC60Seconds between background rediscovery sweeps. Lower = faster pickup of newly plugged instruments; higher = less bus traffic.
KeyDefaultDescription
CONNECTION_INITIAL_BACKOFF2.0First backoff in seconds when registration / heartbeat fails.
CONNECTION_MAX_BACKOFF300.0Maximum backoff (seconds). Must be ≥ CONNECTION_INITIAL_BACKOFF.
CONNECTION_FAILURE_THRESHOLD3Consecutive failures before the manager enters the Backoff state.
KeyDefaultDescription
LOG_LEVELinfoOne of debug, info, warn, error. Override at runtime with galois-edge start --log-level debug.

galois-edge start and configure set validate values before persisting. Failures surface as a single error listing every problem:

  • Ports must be 1–65535. ZMQ_PUB_PORT is only validated when ZMQ_ENABLED=true.
  • GRPC_PORT and GRPC_INTERNAL_PORT must differ; same for WS_PORT / WS_INTERNAL_PORT.
  • GPIB_ENABLED must be true / false / auto.
  • LOG_LEVEL must be one of the four levels above.
  • HEARTBEAT_INTERVAL_SEC, RESCAN_INTERVAL_SEC, GRPC_MAX_WORKERS, and CONNECTION_FAILURE_THRESHOLD must be ≥ 1.
  • CONNECTION_INITIAL_BACKOFF must be > 0.
  • CONNECTION_MAX_BACKOFF must be ≥ CONNECTION_INITIAL_BACKOFF.

Every key can be set as an environment variable of the same name. Env vars take precedence over the config file, which is convenient for systemd drop-ins and Kubernetes:

/etc/systemd/system/galois-edge.service.d/override.conf
[Service]
Environment=LOG_LEVEL=debug
Environment=BACKEND_URL=https://staging.galoislabs.ai
Terminal window
EDGE_NAME=lab-pi-01
BACKEND_URL=https://cloud.galoislabs.ai
REGISTRATION_TOKEN=glc_XXXXXXXX
TAILSCALE_AUTH_KEY=tskey-auth-XXXXXXXX
GPIB_ENABLED=true
LAN_INSTRUMENTS=TCPIP::scope.lab::INSTR,TCPIP::vna.lab::INSTR
LOG_LEVEL=info
Terminal window
EDGE_NAME=bench-1
GRPC_PORT=50051
WS_PORT=8765
LAN_ENABLED=true
GPIB_ENABLED=false
LOG_LEVEL=debug
Terminal window
EDGE_NAME=lab-pi-01
BACKEND_URL=https://galois.internal.example.com
REGISTRATION_TOKEN=glc_XXXXXXXX
HEADSCALE_URL=https://headscale.internal.example.com
TAILSCALE_AUTH_KEY=hskey-XXXXXXXX
TSNET_STATE_DIR=/var/lib/galois-edge/tsnet