> ## Documentation Index
> Fetch the complete documentation index at: https://docs.antasphere.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Environment reference

> Generated from the zod env schema (apps/server/src/env.ts) — do not edit by hand; run pnpm --filter @slideless/server docs:env after changing the schema. The app refuses to boot on an invalid environment and prints a readable table of problems.

## Required

| Variable       | Type   | Default | Description                                             |
| -------------- | ------ | ------- | ------------------------------------------------------- |
| `DATABASE_URL` | string | —       | Postgres connection string. The only required variable. |

## Optional

| Variable                            | Type                                                         | Default                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| ----------------------------------- | ------------------------------------------------------------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PORT`                              | number                                                       | `3000`                  | Port the single HTTP listener binds.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `HOST`                              | string                                                       | `0.0.0.0`               | Bind address.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `PUBLIC_BASE_URL`                   | string                                                       | `http://localhost:3000` | Public origin of this instance (scheme matters: https => Secure cookies).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `VIEWER_BASE_URL`                   | string                                                       | —                       | Base URL share links point at (the `/v/{secret}` viewer). Unset (default) = same origin as PUBLIC\_BASE\_URL — the proven-safe default: user HTML only ever renders under `Content-Security-Policy: sandbox` (opaque origin, never `allow-same-origin`). Setting this to a dedicated user-content origin (a domain that carries no app cookies and no API, fronting the same instance) is the documented hardening path (docs/security/viewer-security-model.md): share URLs are then built on that origin, that hostname serves ONLY decks and the token-authed viewer API (the dashboard, login, /mcp and the rest of /api/v1 answer 404 there; deck links on the app hostname redirect across), the app API refuses requests carrying the viewer origin, and a header regression can no longer expose the dashboard session across a real origin boundary. Must differ from PUBLIC\_BASE\_URL's origin. |
| `VIEW_DEDUPE_WINDOW_MINUTES`        | number                                                       | `10`                    | De-dupe window (minutes) for share-link view counting: repeat opens of the same link from one browser inside this window count once, so browser prefetch/prerender, reloads, and mail-scanner hits no longer inflate a token's accessCount. Enforced with a signed, token-scoped HttpOnly cookie; cookie-less clients (SDKs, curl) count every fetch. Large values shift the metric toward "unique browsers" rather than "opens". 0 disables de-dupe: every entry GET counts and no cookie is set.                                                                                                                                                                                                                                                                                                                                                                                                         |
| `DATA_DIR`                          | string                                                       | `/data`                 | Writable data directory (auto-generated secret, local file storage).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `AUTO_MIGRATE`                      | string                                                       | `true`                  | Apply pending migrations at boot. When false the app only checks and refuses readiness while behind.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `SERVICE_ROLE`                      | `all` \| `api` \| `worker`                                   | `all`                   | all = API + workers in one process; api = HTTP only; worker = jobs only.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `AUTH_SECRET`                       | string                                                       | —                       | Session/JWKS encryption secret. Auto-generated into DATA\_DIR/secret when unset or empty.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `API_KEY_PEPPERS`                   | string                                                       | —                       | Versioned API-key peppers for secret rotation: `<version>:<secret>` entries joined by `;` (e.g. `1:<historical AUTH_SECRET>;2:<new pepper>`, secrets >=32 chars). Version 1 defaults to AUTH\_SECRET and, when pinned here, MUST keep the historical AUTH\_SECRET-derived value or every existing key stops resolving; new keys mint under the highest version. Rotation runbook: internal/security-runbooks.md.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `SETUP_TOKEN`                       | string                                                       | —                       | The credential POST /api/v1/setup requires (constant-time compared). setup.sh generates one into .env. Unset, the server generates a token into `$DATA_DIR/setup-token` at first boot and prints it to the container log — the first-boot claim is never free (PRDCT-1347).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `ALLOW_INSECURE_SETUP`              | string                                                       | `false`                 | Allow POST /api/v1/setup over plaintext HTTP on a non-loopback PUBLIC\_BASE\_URL. Default false: the wizard 403s, because the owner password and the setup token would cross the network in the clear on the one request that decides who owns the instance. Reach a TLS-less server through an SSH tunnel (`ssh -L`) instead; set this true only on a trusted private network.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `SUPERADMIN_EMAILS`                 | string                                                       | —                       | Break-glass operator allowlist: comma-separated emails. A caller is superadmin ONLY on a SESSION whose VERIFIED email is listed here — machine credentials (API keys, OAuth tokens) never qualify, they 403 fail-closed. Unset (default) = the break-glass endpoints are dormant and 403 for everyone. Runbook: internal/security-runbooks.md.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `GOOGLE_CLIENT_ID`                  | string                                                       | —                       | Optional Google social login.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `GOOGLE_CLIENT_SECRET`              | string                                                       | —                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `EDITION`                           | `oss` \| `cloud`                                             | `oss`                   | Edition selector (internal/federation.md): `oss` (default, self-host — zero hub surface at runtime) or `cloud` (federates human login + entitlements to the Antasphere hub; requires the HUB\_\* block). Any other value refuses to boot — the selector decides the identity binding, so a typo must fail loudly, never silently bind `oss`. Also surfaced in discovery + usage events.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `HUB_ISSUER_URL`                    | string                                                       | —                       | Hub OIDC issuer, e.g. [https://account.antasphere.com](https://account.antasphere.com) — discovery, JWKS, and the authorize/token endpoints all derive from it. Required when EDITION=cloud; never read when EDITION=oss.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `HUB_CLIENT_ID`                     | string                                                       | —                       | OAuth client id from this tool's entry in the hub TOOL\_REGISTRY (e.g. tool-slideless-cloud). Required when EDITION=cloud.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `HUB_CLIENT_SECRET`                 | string                                                       | —                       | OAuth client secret matching the hub registry entry (confidential client; PKCE stays on regardless). Also authenticates the per-user refresh grant — there is NO service key: every hub read between logins presents the USER's own grant (internal/federation.md). Required when EDITION=cloud.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `HUB_HINT_COOKIE_NAME`              | string                                                       | —                       | Name of the hub-set shared SSO hint cookie the dashboard reads client-side (internal/federation.md; NEVER a security input — it only gates whether a silent connect is attempted). Cloud-only; unset = the cross-repo default `ant_sso_hint`. Never read when EDITION=oss.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `HUB_HINT_COOKIE_DOMAIN`            | string                                                       | —                       | Domain the hint cookie lives on (the hub sets it, tools clear it — both sides must agree). Cloud-only; unset = the hub issuer host minus its first label (account.antasphere.com → antasphere.com). Never read when EDITION=oss.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `EDITION_CHANGE_ALLOWED`            | string                                                       | `false`                 | R7 escape hatch (internal/federation.md): acknowledge an EDITION change on an already-set-up instance. Without it, boot refuses an EDITION that differs from the one stamped at setup — flipping editions under existing users/workspaces changes identity semantics and must be a conscious operator act.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `APP_VERSION`                       | string                                                       | `0.3.0`                 | Reported version. Defaults to the code's own baked-in package version (PRDCT-1844) — the image knows its version intrinsically, CI injects nothing. The env var remains as a deliberate operator override only.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `OAUTH_DYNAMIC_CLIENT_REGISTRATION` | string                                                       | `true`                  | RFC 7591 dynamic client registration on the built-in authorization server: unauthenticated `POST /api/v1/auth/oauth2/register`, which is how MCP clients self-register. Default true (the connector-friendly posture, rate-limited in api/index.ts). Set false on an instance whose OAuth clients are provisioned by hand — the endpoint then refuses every caller instead of minting client records for anyone who asks.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `HSTS_MAX_AGE`                      | number                                                       | `15552000`              | `Strict-Transport-Security` max-age in seconds, sent on every response when PUBLIC\_BASE\_URL is https (browsers ignore HSTS over plain http per RFC 6797 §7.2, so an http instance is unaffected). Default 180 days; 0 disables the header — the escape hatch for an operator who is not yet certain every subdomain can serve TLS.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `MAX_FILE_SIZE_MB`                  | number                                                       | `100`                   | Instance-level cap read by the default AllowAllEntitlements.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `API_RATE_LIMIT_PER_MINUTE`         | number                                                       | `600`                   | General per-principal API quota: sustained requests/minute allowed to every authenticated /api/v1 principal (API key, OAuth token, session). 0 disables the general limiter.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `API_RATE_LIMIT_BURST`              | number                                                       | `100`                   | Spike cap for the general API quota: max requests per principal in any 1-second burst. 0 disables burst smoothing (the per-minute window still applies).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `EMAIL_DRIVER`                      | `none` \| `smtp` \| `resend`                                 | `none`                  | Email delivery. `none` (default) never blocks a flow: links stay copyable.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `SMTP_URL`                          | string                                                       | —                       | smtp(s)://user:pass\@host:port — required when EMAIL\_DRIVER=smtp.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `RESEND_API_KEY`                    | string                                                       | —                       | Required when EMAIL\_DRIVER=resend.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `EMAIL_FROM`                        | string                                                       | —                       | Sender, e.g. `Slideless <noreply@slideless.app>`. Required when a driver delivers.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `REDIS_URL`                         | string                                                       | —                       | When set, rate limits (and later caches) are shared across replicas.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `STORAGE_DRIVER`                    | `local` \| `s3`                                              | `local`                 | File storage: local (default; DATA\_DIR volume, single replica) or s3 (MinIO/AWS/R2).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `S3_BUCKET`                         | string                                                       | —                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `S3_REGION`                         | string                                                       | —                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `S3_ENDPOINT`                       | string                                                       | —                       | Endpoint override for MinIO/R2; leave unset for AWS.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `S3_ACCESS_KEY_ID`                  | string                                                       | —                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `S3_SECRET_ACCESS_KEY`              | string                                                       | —                       |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `S3_FORCE_PATH_STYLE`               | string                                                       | `true`                  | Path-style addressing — required by MinIO and most S3-compatibles.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `TRUST_PROXY`                       | string                                                       | `false`                 | Trust x-forwarded-for for client IPs (rate limits, audit). The app reads the RIGHTMOST hop — the one your proxy appended or set (Caddy ≥2.5 discards client-supplied X-Forwarded-\* by default). Enable ONLY behind a reverse proxy you control; when false the socket address is used and spoofed headers are ignored.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `OTEL_EXPORTER_OTLP_ENDPOINT`       | string                                                       | —                       | OTLP/HTTP endpoint for trace export. Unset (default) = no export, zero phone-home.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `METRICS_TOKEN`                     | string                                                       | —                       | GET /metrics requires `Authorization: Bearer <token>`; unset = /metrics disabled (401).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `AUDIT_RETENTION_DAYS`              | number                                                       | `365`                   | Days of audit\_log to keep (nightly purge at 03:00). 0 = keep forever.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `VIEW_EVENTS_RETENTION_DAYS`        | number                                                       | `90`                    | Days of per-view share-link analytics events (share\_token\_views: when a link was opened, referring site host, placement label, browser family — never IPs or full URLs) to keep. Nightly purge at 03:00; 0 = keep forever.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| `ORPHAN_USER_RETENTION_HOURS`       | number                                                       | `72`                    | Grace period for orphaned users (accounts with ZERO workspace memberships, e.g. setup-race losers): the nightly 03:00 sweep deletes them once older than this many hours. A user with ANY membership row — even deactivated — is never touched. 0 = sweep disabled.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `LOG_LEVEL`                         | `fatal` \| `error` \| `warn` \| `info` \| `debug` \| `trace` | `info`                  | pino level.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `NODE_ENV`                          | `development` \| `test` \| `production`                      | `production`            |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
