Server environment variables (full)
All variables are read at boot from the process environment. Most string booleans
accept 1 | true | yes (case-insensitive for true/yes) as truthy; other
values are falsy. A few flags use their own rule (e.g. SUPACLOUD_SMTP_USE_TLS
is on unless set to 0|false|no). The abbreviated admin page covers deployment
essentials — see
Environment variables (admin).
Server
Section titled “Server”| Variable | Default | Notes |
|---|---|---|
MODE |
dev |
dev relaxes prod-only guards (weaker JWT, no encryption-key requirement). Set to any other value — or omit — for production. |
SERVER_HOST |
0.0.0.0 |
Bind address. |
SERVER_PORT |
8080 |
Listen port. |
PUBLIC_URL |
http://localhost:<port> in dev, required in prod |
Canonical public origin. Seeds the CORS allowlist and callback URL derivation. |
CORS_ALLOWED_ORIGINS |
— | Comma-separated origins permitted to call the API. When empty, the allowlist defaults to PUBLIC_URL (plus the standard localhost dev origins in dev mode). |
Database
Section titled “Database”| Variable | Default | Notes |
|---|---|---|
DATABASE_URL |
postgresql://supacloud:supacloud@postgres:5432/supacloud |
libpq connection string. Can also come from the OpenBao supacloud/db path when SECRET_BACKEND=openbao. |
Authentication
Section titled “Authentication”| Variable | Default | Notes |
|---|---|---|
AUTH_PROVIDER |
builtin |
One of builtin, oidc, authelia_proxy, oidc_proxy. |
SUPACLOUD_JWT_SECRET |
dev default | Session-signing secret. ≥ 32 bytes required. The dev default is rejected for any non-loopback PUBLIC_URL. Also accepted as AUTH_JWT_SECRET (legacy). |
SUPACLOUD_INITIAL_ADMIN_EMAILS |
— | Comma-separated emails provisioned as workspace owner on first boot. Required in prod for builtin and oidc providers. Also accepted as SUPACLOUD_INITIAL_ADMIN_EMAIL. |
AUTH_SESSION_TTL_MINUTES |
480 |
Session lifetime (8 h). |
AUTH_COOKIE_SECURE |
true in prod, false in dev |
Set false for local HTTP. |
OIDC_ISSUER_URL |
— | OIDC provider discovery URL (AUTH_PROVIDER=oidc). |
OIDC_CLIENT_ID |
— | OIDC client ID. |
OIDC_CLIENT_SECRET |
— | OIDC client secret. Vault-hydrated from supacloud/app. |
OIDC_REDIRECT_URL |
— | OIDC callback URL (/api/auth/oidc/callback). |
OIDC_SCOPES |
openid email profile |
Space- or comma-separated. Must include openid. |
OIDC_PKCE_ENABLED |
true |
Set false only for legacy providers that reject code_verifier. |
OIDC_TOKEN_AUTH_METHOD |
basic |
basic or post (client_secret_post). |
AUTH_PROXY_USER_HEADER |
Remote-User |
Trusted-proxy user header (authelia_proxy / oidc_proxy). |
AUTH_PROXY_EMAIL_HEADER |
Remote-Email |
Trusted-proxy email header. |
AUTH_PROXY_NAME_HEADER |
Remote-Name |
Trusted-proxy display-name header. |
AUTH_PROXY_REQUIRED_HEADER |
— | Required for proxy modes. Header name that must be present. |
AUTH_PROXY_REQUIRED_VALUE |
— | Required for proxy modes. Expected value of the required header. |
AUTH_PROXY_LOGOUT_URL |
— | Upstream proxy sign-out URL surfaced in /config. Only meaningful in proxy-auth modes. |
SUPACLOUD_SSO_AUTOREDIRECT |
derived | on forces the single-IdP standalone redirect; off suppresses it. Derived from edition + SSO-realm-count when unset. |
DEFAULT_SSO_ORG |
— | Bare org slug pinned as the standalone SSO redirect target. |
Secret backend (ADR 0036)
Section titled “Secret backend (ADR 0036)”| Variable | Default | Notes |
|---|---|---|
SECRET_BACKEND |
auto | openbao or env. Auto-detects openbao when vault auth is present; otherwise env. A typo is a hard boot error. |
OPENBAO_ADDR |
https://vault.blockworx.tech |
OpenBao / Vault address. Also accepted as VAULT_ADDR. |
VAULT_TOKEN |
— | Direct token auth. |
OPENBAO_ROLE_ID |
— | AppRole role ID (used with OPENBAO_SECRET_ID). |
OPENBAO_SECRET_ID |
— | AppRole secret ID. |
With SECRET_BACKEND=openbao the following are read from the supacloud/app
KV2 map (env wins; vault fills gaps): SUPACLOUD_JWT_SECRET,
SUPACLOUD_CREDENTIAL_ENCRYPTION_KEY, OIDC_CLIENT_SECRET,
SUPACLOUD_MCP_CONFIRMATION_SECRET, DISCORD_BOT_TOKEN,
SUPACLOUD_{LINEAR,NOTION}_OAUTH_CLIENT_{ID,SECRET},
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, SUPACLOUD_SMTP_PASSWORD,
BW_FINTS_WORKER_API_KEY, SUPACLOUD_OPERATOR_TOKEN,
SUPACLOUD_EDITION_LICENSE, SUPACLOUD_EDITION_SECRET.
Credentials & encryption
Section titled “Credentials & encryption”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_CREDENTIAL_ENCRYPTION_KEY |
— | AES-256 key for DB-resident credential material. Accepts raw 32 bytes, hex, base64, or hex:/base64: prefix. Required in prod. When vault-sourced, the decoded key is held in-process and never re-exported to the environment. |
SUPACLOUD_MCP_CONFIRMATION_SECRET |
— | HMAC secret for deploy-tier MCP confirmation tokens (app.deploy, app.migration.apply). ≥ 32 bytes. Without it those tools fail closed. Vault-hydrated from supacloud/app. |
Edition & entitlements (ADR 0035 / #305)
Section titled “Edition & entitlements (ADR 0035 / #305)”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_EDITION_LICENSE |
— | HS256 JWT asserting edition=enterprise. Validated against SUPACLOUD_EDITION_SECRET. Vault-hydrated from supacloud/app. |
SUPACLOUD_EDITION_SECRET |
— | Signing secret for the edition license. ≥ 32 bytes. Vault-hydrated from supacloud/app. |
SUPACLOUD_EDITION |
— | Dev bypass only: set to enterprise together with MODE=dev to activate enterprise edition without a license token. Never use in production. |
Agent sandbox
Section titled “Agent sandbox”| Variable | Default | Notes |
|---|---|---|
AGENT_NETWORK |
supacloud-agents |
Docker network agent containers join. |
AGENT_IMAGE_PREFIX |
— | Registry prefix prepended to agent image names (e.g. git.blockworx.tech/blockworx/). |
AGENT_MEMORY_BYTES |
2147483648 |
Per-agent memory cap (bytes). |
AGENT_NANO_CPUS |
2000000000 |
Per-agent CPU cap (nano-CPUs; 2 000 000 000 = 2 vCPUs). |
AGENT_PIDS_LIMIT |
512 |
Per-agent PID limit. |
AGENT_READ_ONLY_ROOTFS |
true |
Mount the agent root filesystem read-only. |
AGENT_TMPFS_TMP_MB |
512 |
Size ceiling for the agent’s /tmp tmpfs, in MiB. |
AGENT_TMPFS_RUN_MB |
64 |
Size ceiling for the agent’s /run tmpfs, in MiB. |
AGENT_TMPFS_HOME_MB |
512 |
Size ceiling for /home/agent — the CLIs’ config/state and the npm cache. |
SUPACLOUD_AGENT_TEST_DB |
false |
Wand 6 option C — instance-level CAPABILITY gate for the per-task ephemeral Postgres sidecar. With it off no sidecar is ever created. With it on, a task gets a sidecar only when it opts in (task.config.test_db = true); a non-selected task gets none. An explicit caller TEST_DATABASE_URL wins: it is never overwritten and the sidecar is suppressed. The sidecar injects TEST_DATABASE_URL, its password (and full URL) is registered in the run’s redaction set, and it is removed with the agent container; a sidecar that cannot start prevents the agent container from starting (fail closed). The per-run decision, the resolved image AND the password ride the runner WorkPayload, so a dispatched run provisions the same sidecar and the hub’s relay redacts the same credential. |
AGENT_TEST_DB_IMAGE |
postgres:18 |
Image for the SUPACLOUD_AGENT_TEST_DB sidecar. |
AGENT_TASK_TIMEOUT_MINUTES |
90 |
Hard timeout per agent task. |
SUPACLOUD_HARNESS_FIRST_PROGRESS_SECS |
600 (opencode: 90) |
Clock 1 of the progress guard for CLI harnesses (#838): how long a harness may make no progress at all after it starts. A breach stops the run and the task ends as harness_stalled, carrying the harness’s last stderr line. The default is per-adapter. codex, qwen, copilot, gemini-agy and openclaude keep 10 minutes, because before their first output “made no progress” and “wrote no byte” are the same statement and a short window there would just be a shorter fuse on the old watchdog. opencode takes 90 s, and only because it is measured: with --print-logs it emitted its first structured line within ~1 s of spawn in every captured run. 0 disables it; a malformed value falls back to the 10-minute default — wrong in the direction that cannot kill a working run. |
SUPACLOUD_HARNESS_IDLE_CEILING_MINS |
20 |
Clock 2 of the progress guard (#838): how long a started harness may go without further progress. Unlike clock 1 this is rolling — every piece of progress re-arms it — so it never caps a run that is working; that is AGENT_TASK_TIMEOUT_MINUTES’ job. A breach ends the task as harness_no_progress, carrying the step the harness was last in, when it last got anywhere and its own last line. Progress means a run event, a completed stdout line or a stderr line that is a new step — never merely that a byte arrived, which is what the pre-#838 watchdog measured and why a harness that narrated and then wedged was supervised by nobody. 0 disables it. |
SUPACLOUD_HARNESS_LIVENESS_MINS |
(deprecated) | The pre-#838 name for the start deadline. Still honoured, and it feeds both clocks: it sets the idle ceiling, and it widens clock 1 (never narrows it), so an operator who raised it to stop a slow-starting harness being killed keeps that protection instead of having it silently swapped for a shorter default. An explicit 0 still means “no deadline”, on both. Prefer the two names above. |
SUPACLOUD_HARNESS_STARTUP_NOTICE_SECS |
30 |
The non-fatal stage between the two progress clocks (#838): while a harness is making no progress, a visible but non-fatal notice is posted to the task feed saying how long it has been quiet, the step it is in, its last line, and which MCP servers the runner configured. Bounded to three notices for the whole run with a doubling wait (30 s, 60 s, 120 s), on the progress axis rather than the byte axis — so a harness that narrates and then wedges is reported, while one that keeps working is not nagged. It never stops a run; only the two clocks above do. 0 disables it; a malformed value falls back to the default. |
OPENCODE_LOG_LEVEL |
INFO |
--log-level handed to the opencode CLI, which the runner always launches with --print-logs (#838). Without it opencode writes nothing to either stream until the model answers, so a slow provider is indistinguishable from a dead harness. INFO carries the bootstrap steps and the server unavailable warning for an MCP server that would not start; DEBUG, WARN and ERROR are the other accepted values. An unrecognised value falls back to INFO. The logs go to stderr only — the --format json event stream on stdout is unaffected. |
MAX_PARALLEL_TASKS_PER_WORKSPACE |
3 |
Concurrency cap per workspace. |
Connector executor (ADR 0034 Decision 6 / #361)
Section titled “Connector executor (ADR 0034 Decision 6 / #361)”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_CONNECTOR_EXECUTOR_MODE |
in_process |
in_process, pooled, or runner_fleet. |
SUPACLOUD_CONNECTOR_EXECUTOR_IMAGE |
— | Container image for pooled mode. |
SUPACLOUD_CONNECTOR_EXECUTOR_AUTH_TOKEN |
— | Shared token (≥ 16 chars) for pooled mode. Carried over the executor-only network. |
SUPACLOUD_CONNECTOR_EXECUTOR_NETWORK |
— | Dedicated Docker network for hub ↔ executor traffic in pooled mode. |
SUPACLOUD_CONNECTOR_EXECUTOR_POOL_SIZE |
2 |
Number of warm executor containers in pooled mode. |
SUPACLOUD_CONNECTOR_EXECUTOR_MAX_INFLIGHT |
4 |
Maximum concurrent in-flight runs in pooled mode. |
SUPACLOUD_CONNECTOR_EXECUTOR_MAX_RUNS |
0 |
Container recycling threshold in pooled mode. 0 = never recycle on run count. |
SUPACLOUD_CONNECTOR_EXECUTOR_REQUEST_TIMEOUT_SECS |
60 |
Maximum wait for a warm pool slot. |
SUPACLOUD_SCRIPT_RUNTIME_DIR |
crate dev/test assets | Absolute path to the pre-built Wasm script-runtime components (js-runner, ts-runner, py-runner). Unprovisioned languages degrade gracefully. |
SUPACLOUD_DOCS_DIR |
/app/docs, else the in-repo docs/ |
Absolute path to the documentation corpus the docs.search / docs.get / spec.get MCP read tools serve. A relative value is ignored on purpose. With no corpus present the tools answer corpus_available: false. |
Hub & runner fleet (ADR 0021)
Section titled “Hub & runner fleet (ADR 0021)”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_HUB_MODE |
false |
Opt-in to dispatching tasks to a registered remote runner fleet. When false, every task runs locally. |
SUPACLOUD_E2E_TASK_SESSION_MINT |
false |
E2E bench capability: lets a workspace owner/admin mint a task’s agent session (POST /api/workspaces/{id}/tasks/{task_id}/e2e-session) so a bench driver can reach the agent-MCP surface without a database write. Refused at boot when MODE=prod; off, the route answers 404. |
SUPACLOUD_HUB_EVENT_RELAY |
false |
Relay realtime hub events across server replicas over Postgres LISTEN/NOTIFY (the WS event fan-out, #623 P4). Inert on a single replica; enable for a multi-replica deployment. |
MODEL_CATALOG_REFRESH_HOURS |
24 |
How often the model catalog is refreshed (1–720). |
SUPACLOUD_CALIBRATION_BOARDS |
agent/latest/overall,webdev/latest/overall,text/latest/overall |
Which LMArena leaderboards the tier-chain calibration reads, comma-separated, as config[/split[/category[/shape[/max_rows]]]]. shape is rating (Elo boards) or score (the agent family) and defaults to rating; * in the category position reads every category; max_rows caps the read depth (default 600, measured to cover every default board’s overall block). Each board gets its own metric token, its own snapshot row and its own fold report. A malformed entry is a hard error naming it — it never falls back to the defaults. |
SUPACLOUD_CALIBRATION_TIER_WEIGHTS |
built-in per tier | Per-tier axis weights for the calibration frontier, comma-separated, as tier:quality/cost/speed (e.g. fast:0.2/0.5/0.3). A tier the value does not name keeps its built-in weights. The numbers are RATIOS, not shares — the frontier re-bases them over the axes a model is actually measured on. Instance-wide; a per-workspace override is not available. |
Management API
Section titled “Management API”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_MANAGEMENT_API_TOKEN |
— | Bearer token granting access to the M2M management API. Also accepted as MANAGEMENT_API_TOKEN (legacy). Vault-hydrated from supacloud/management. |
Chat bots
Section titled “Chat bots”| Variable | Default | Notes |
|---|---|---|
TELEGRAM_BOT_TOKEN |
— | Telegram control-bot token. Vault-hydrated from supacloud/messaging. Bot is disabled when unset. |
TELEGRAM_BOT_USERNAME |
— | Telegram bot username (without @). Vault-hydrated. |
TELEGRAM_WEBHOOK_SECRET |
— | Webhook secret for Telegram update validation. Vault-hydrated. |
DISCORD_BOT_TOKEN |
— | Discord control-bot token (ADR 0032). Vault-hydrated from supacloud/app. Bot is disabled when unset. Distinct from per-workspace Discord notify/trigger resources. |
SMTP (optional)
Section titled “SMTP (optional)”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_SMTP_HOST |
— | SMTP relay hostname. When unset the global SMTP transport is disabled; workspace SMTP resources still work. |
SUPACLOUD_SMTP_PORT |
587 |
SMTP port. |
SUPACLOUD_SMTP_USE_TLS |
true |
Enable TLS. |
SUPACLOUD_SMTP_STARTTLS |
true |
Use STARTTLS. |
SUPACLOUD_SMTP_USERNAME |
— | SMTP auth username. |
SUPACLOUD_SMTP_PASSWORD |
— | SMTP auth password. Vault-hydrated from supacloud/app. |
Hosted App frontends (ADR 0041 / #410)
Section titled “Hosted App frontends (ADR 0041 / #410)”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_APPS_HOSTED_FRONTEND |
false |
Enable serving of built React/Svelte App frontends. Requires SUPACLOUD_APPS_BASE_DOMAIN. |
SUPACLOUD_APPS_BASE_DOMAIN |
— | Bare domain (e.g. supacloud.net) on a different eTLD+1 than the control plane. Hosted Apps are served at <opaque-subdomain>.<apps_base_domain>. Boot fails if this shares a registrable domain with PUBLIC_URL. |
Issue-tracker OAuth (ADR 0029)
Section titled “Issue-tracker OAuth (ADR 0029)”| Variable | Default | Notes |
|---|---|---|
SUPACLOUD_LINEAR_OAUTH_CLIENT_ID |
— | Linear OAuth app client ID. Vault-hydrated. |
SUPACLOUD_LINEAR_OAUTH_CLIENT_SECRET |
— | Linear OAuth app client secret. Vault-hydrated. |
SUPACLOUD_NOTION_OAUTH_CLIENT_ID |
— | Notion OAuth app client ID. Vault-hydrated. |
SUPACLOUD_NOTION_OAUTH_CLIENT_SECRET |
— | Notion OAuth app client secret. Vault-hydrated. |
Billing & operator (Stripe / FinTS)
Section titled “Billing & operator (Stripe / FinTS)”| Variable | Default | Notes |
|---|---|---|
STRIPE_SECRET_KEY |
— | Stripe API secret key. Vault-hydrated from supacloud/app. |
STRIPE_WEBHOOK_SECRET |
— | Stripe webhook signing secret. Vault-hydrated from supacloud/app. |
BW_FINTS_WORKER_API_KEY |
— | Internal API key for the marketplace FinTS payout worker. Vault-hydrated from supacloud/app. |
SUPACLOUD_OPERATOR_TOKEN |
— | Operator bearer token for privileged internal calls. Vault-hydrated from supacloud/app. |
SUPACLOUD_METRICS_TOKEN |
— | Bearer token protecting the /metrics endpoint. Vault-hydrated from supacloud/app. |