Configuration¶
Every environment variable the platform reads at runtime, across all three components. Defaults are taken from live code.
Verified against code: 2026-08-26. Carried over from setup.md, which was
audited on 2026-08-02.
This is a reference — look things up here. For how to configure a real deployment in the right order, see Host your deployment.
Every variable the platform reads at runtime. Defaults are pulled from live code.
Frontend (app/)¶
| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_BACKEND_URL |
no | http://localhost:8000 |
Backend API base URL |
NEXT_PUBLIC_GOOGLE_CLIENT_ID |
if Google OAuth | (must set) | Google OAuth client ID |
NEXT_PUBLIC_NGROK_ENABLED |
no | unset / falsy | Set "true" behind ngrok tunnels to skip browser warnings |
NEXT_PUBLIC_DOCS_URL |
no | /docs/ |
Target of the in-app Documentation links. The default assumes this deployment serves its own copy — see Serve the documentation. Set it to an external copy if you do not build the site. |
NEXT_PUBLIC_* values are inlined at build time, not read at runtime. Changing one means rebuilding the frontend (npm run build), not just restarting it.
Old .env caveat: A stale variable NEXT_PUBLIC_API_URL used to exist. No code reads it — every call site uses NEXT_PUBLIC_BACKEND_URL. If your .env still has API_URL=..., the frontend silently falls back to port 8000. Remove the old entry or rename it.
Backend (backend/)¶
| Variable | Required | Default | Description |
|---|---|---|---|
SECRET_KEY |
yes (change in prod) | (see below) | JWT signing key. The code ships a default for dev only; at startup a WARNING is logged if you haven't changed it. Generate one with: openssl rand -hex 32. |
DATABASE_URL |
yes | (must set) | Postgres connection string. For local development, copy the example value from backend/.env.example; set it explicitly in every environment. |
GOOGLE_CLIENT_ID |
if Google OAuth | (must set) | Must match the client ID registered with Google, and must also be the same value as NEXT_PUBLIC_GOOGLE_CLIENT_ID. |
FRONTEND_URL |
no | http://localhost:3000 |
Base URL used in password-reset and invite email links. |
MAILGUN_API_KEY |
no | — | Mailgun API key. If unset, email sending is gracefully skipped. |
MAILGUN_DOMAIN |
no | — | Mailgun domain. Required alongside MAILGUN_API_KEY for emails to work. |
MAILGUN_FROM |
no | Sheshnag support <noreply@sheshnag.io> |
Default sender address for platform emails. |
CATALOG_AUTO_ADOPT |
no | registry-confirmed |
Auto-register worker-discovered models whose file hash the public registry confirms for their name (sweeper pass, every 60s). off keeps every unknown hash quarantined for manual POST /v1/models/adopt. |
CATALOG_AUTO_ADOPT_ENABLED |
no | true |
Whether auto-adopted entries are user-selectable immediately. false stages them (enabled: false) until an admin flips them in the Models tab. |
CORS_ORIGINS |
no | "*" (all origins) |
Comma-separated list of allowed origins for CORS. Keep the default for local dev; set to your frontend URL(s) in production. See also the credentials warning. |
Old .env caveat: CORS_ORIGINS used to be listed in backend/.env.example while doing nothing — origins were hardcoded to ["*"] in main.py. It is now read from the environment, so the variable behaves as its name suggests and no code change is needed at deploy time.
Daemon (daemon/)¶
Configured via a three-layer system: CLI > env (DAEMON_* prefix) > YAML file > defaults. Full precedence logic lives in daemon/config.py.
| Env var | Default | Description |
|---|---|---|
DAEMON_BACKEND_URL |
http://localhost:8000 |
Control plane API URL |
DAEMON_API_KEY |
(required) | Org worker API key (created in dashboard) |
DAEMON_WORKER_ID |
auto-generated | Unique worker ID with hostname prefix |
DAEMON_RUNTIME |
ollama |
Inference runtime(s) to drive: ollama, vllm or llamacpp, comma-separated (vllm,ollama) to run several on one worker |
DAEMON_OLLAMA_URL |
http://localhost:11434 |
Ollama server URL |
DAEMON_LLAMACPP_URL |
http://localhost:8080 |
llama-server URL. The provider starts and keeps it running; the daemon only attaches. |
DAEMON_VLLM_URL |
http://localhost:8100 |
vLLM server URL |
DAEMON_OLLAMA_MODELS_DIR |
auto-detected | Ollama's models tree. Set it where Ollama runs as its own service user, or the daemon resolves ~/.ollama/models and inventories the wrong store |
DAEMON_LLAMACPP_MODELS_DIR |
(unset) | The directory a router-mode llama-server serves. Its API names models but never locates them, and a model's identity is its weights file's sha256 — unset, the daemon reports models the catalogue cannot confirm, and each one needs an entry adopted by hand |
DAEMON_HF_HUB_CACHE |
auto-detect | HF hub cache vLLM serves from, for on-disk model identity (shard hashes, repo + commit). Auto-detect order: $HF_HUB_CACHE, $HF_HOME/hub, ~/.cache/huggingface/hub. Read-only. |
DAEMON_POLL_INTERVAL |
5 | Seconds between job polls |
DAEMON_HEARTBEAT_INTERVAL |
30 | Seconds between heartbeats |
DAEMON_PROGRESS_INTERVAL_SECONDS |
5.0 | Minimum seconds between progress reports. Completion is always reported regardless |
DAEMON_INFERENCE_TIMEOUT |
300.0 | Per-prompt inference timeout (seconds) |
DAEMON_MAX_CONCURRENT_PROMPTS |
8 | Prompts executed concurrently per job. Raise to use more of the GPU, lower to be gentler on a shared runtime |
DAEMON_LOG_LEVEL |
INFO |
Log level: DEBUG / INFO / WARNING / ERROR |
DAEMON_WORK_DIR |
~/.gpu-daemon/jobs |
Job artifacts directory |
DAEMON_MODELS |
(empty) | Comma-separated list of model names |
DAEMON_GPU_NAME |
unknown |
GPU model name for registration |
DAEMON_VRAM_GB |
0.0 | Advertised GPU memory in GB. Overrides detection — see below |
Copy daemon/.env.example to daemon/.env for a starting point; the systemd
unit reads it through EnvironmentFile.
Reaching the control plane through a proxy¶
A worker on a network with no outbound route reaches the control plane through
a proxy or an SSH SOCKS forward. These carry no DAEMON_ prefix — they are the
standard variables, read straight from the environment.
| Variable | Default | Purpose |
|---|---|---|
HTTPS_PROXY / https_proxy |
(unset) | Proxy for a TLS (https://) control plane. Checked first for that scheme. |
HTTP_PROXY / http_proxy |
(unset) | Proxy for a plain-http control plane. Checked first for that scheme. |
ALL_PROXY / all_proxy |
(unset) | Used when neither scheme-specific form is set, for either scheme. socks5h://host:port for an SSH -D forward. |
NO_PROXY / no_proxy |
(unset) | Hosts to reach directly even when a proxy is set, always — a control plane on this machine or the local network works alongside a proxied one. Include 127.0.0.1,localhost so the daemon's calls to its own runtime stay local. |
The scheme-specific pair works like curl and requests: a https:// control
plane reads HTTPS_PROXY, a plain http:// one reads HTTP_PROXY.
NO_PROXY takes curl's semantics — example.edu covers subdomains,
.example.edu covers only subdomains, * covers everything.
Prefer the socks5h scheme over socks5: the hostname is resolved at the
proxy, so certificate verification behaves as it would on a direct connection.
How a worker's VRAM is determined¶
The scheduler filters a worker out of any batch whose model needs more VRAM than the worker reports, so this number decides what the worker is offered.
DAEMON_VRAM_GB, when set above 0, wins over everything — in registration and in every heartbeat — so a provider can lend less than the hardware holds. If nothing was probed, registration advertises one synthetic GPU (vendor: other, name fromDAEMON_GPU_NAME) of that size; if several GPUs were probed, their sizes are scaled to sum to the declaration.- NVIDIA and AMD, otherwise:
nvidia-smiandrocm-smiare both probed and their GPUs summed, so a mixed-vendor host advertises its whole capacity. AMD hosts also report a ROCm version, read from/opt/rocm/.info/version— not the amdgpu kernel module versionrocm-smiprints, which is a different number. - Apple Silicon: Metal's
recommendedMaxWorkingSetSize, the cap macOS places on how much unified memory the GPU may wire. Requirespyobjc-framework-Metal(installed automatically on macOS). Without it,iogpu.wired_limit_mbis used when explicitly set, otherwise a deliberately conservative fraction ofhw.memsize. Detection stops here on an Apple Silicon Mac; the SMI tools are not probed. - Otherwise 0.0, and the worker is offered nothing.
That last case is the one to watch: a host with none of nvidia-smi,
rocm-smi or Metal — an Intel Mac, an Intel Arc box, CPU-only — registers
cleanly, heartbeats cleanly, and shows online in the dashboard while
never being handed a single batch. The daemon logs one warning
(Advertising 0 GB VRAM …) when this happens. Set DAEMON_VRAM_GB there.
Apple Silicon note. There is no dedicated VRAM; CPU and GPU share one memory pool. The reported figure is macOS's permission ceiling (about 17.8 GB on a 24 GB machine), not free memory — the two differ whenever anything else on the machine is using RAM.
vram_available_gbis therefore reported as unknown (null) on macOS: unified memory exposes no machine-wide "GPU memory in use" counter, and a confident "fully free" would be wrong whenever a model is resident. The provider portal renders that as "—" in the fleet list and "free unknown" on the worker card. The scheduler reads only the total today. Intel Macs are not detected (no unified-memory ceiling); setDAEMON_VRAM_GBthere.Free system RAM. Each heartbeat also carries
ram_available_gb—MemAvailableon Linux, free plus inactive pages on macOS, andnullanywhere neither is readable.nullmeans unknown, never none left. It is fitted against only by a runtime whose offload split is declared rather than inferred —llamacpp, which declares it with--n-gpu-layers. The other runtimes are fitted on VRAM alone: Ollama chooses its own split at load time and spills to RAM silently rather than failing, so the platform can neither predict the slowdown nor be sure the job fits, and vLLM has no hybrid mode at all.
See Daemon internals for the architecture and the backend contract.