# Configuration and secrets Customer runtime and control plane have separate server-only loaders under `configuration/`. They do not read `process.env` or Vite build variables. Pass Cloudflare Worker bindings to the appropriate loader. `FLAREBOT_MODE` is required and must match that entry. `FLAREBOT_ENV` defaults to `production`; the only other value is explicit `development`. Unknown `FLAREBOT_` bindings fail validation so misspellings and cross-boundary credentials cannot silently become settings. Platform bindings such as `AI` are outside this namespace. ## Customer runtime Set these nonsecret Worker variables when installing the immutable release: ```json { "FLAREBOT_MODE": "customer-runtime", "FLAREBOT_ENV": "production", "FLAREBOT_INSTALLATION": "{\"schemaVersion\":1,\"installationId\":\"0123456789abcdef0123456789abcdef\",\"ownerSubject\":\"authenticated-owner-subject\",\"runtimeOrigin\":\"https://customer.example.com\",\"controlPlaneOrigin\":\"https://control.example.com\"}" } ``` Installation IDs are generated once as 32 lowercase hexadecimal characters. Preserve the ID and stable authenticated owner subject across upgrades. Changing these settings is an ownership operation, not a local override. Origins must be exact HTTPS origins, without credentials, paths, query strings, fragments or a trailing slash. Schema version 1 accepts only the five fields shown above. Generate an independent random session secret for each installation (for example, `openssl rand -hex 32`), then set `FLAREBOT_SESSION_SECRET` with `wrangler secret put FLAREBOT_SESSION_SECRET --name flarebot-` or the Workers secrets API. It must contain at least 32 bytes. Length validation cannot certify entropy; never reuse the example or test values in production. This binding is the runtime session-auth foundation; this issue does not expose an auth route. Workers AI uses the native `AI` binding and needs no provider API key. The customer Worker validates config and required secrets on ingress before SSR. Invalid settings return a generic, uncached HTTP 503. Worker configuration logs identify the field and recovery action without including supplied values or raw JSON parse errors. Static assets may still be served by Cloudflare's asset router. SSR receives only `ASSETS`, not secret-bearing Worker bindings. Do not put loaded configuration/secrets in Agent `setState`, browser props or broadcast payloads. `loadCustomerConfig` returns the base `installation` and the `effectiveInstallation` after local overrides. Use `serializeInstallationConfig` at nonsecret persistence/export boundaries: it reparses unknown input, rejects extra or nested fields, and serializes only a valid installation. Neither loader persists anything. This schema protects against credential fields and wrappers; it cannot identify a secret deliberately supplied as an otherwise valid owner subject. Callers must source identity from authenticated ownership metadata. ## Local development Copy `.dev.vars.example` to `.dev.vars` and run `pnpm dev:worker`. Wrangler loads the local bindings at runtime. Keep credentials out of Vite `.env` files and `VITE_*` variables. `.dev.vars` and `.dev.vars.*` are ignored except the committed placeholder example. Do not use real production credentials locally. `FLAREBOT_DEV_OVERRIDES` accepts a JSON object containing only `runtimeOrigin` and/or `controlPlaneOrigin`. HTTP is permitted only for `localhost`, `127.0.0.1` or `[::1]` in development. Overrides never mutate the base installation record and cannot change the owner, installation ID, mode or secrets. Any override binding, including an empty object, fails in production. Vite's `pnpm dev` is only a frontend preview; use the Worker command to exercise these boundaries. When the effective runtime origin is loopback, `GET /auth/login` issues a local owner session. This development-only shortcut cannot activate in production or for a non-loopback runtime origin. ## Control plane `configuration/control-plane.ts` configures the separate control-plane entry/artifact; the customer bundle never imports it. See [OAuth onboarding](oauth-onboarding.md) for the required reviewed capability manifest, token authentication method, publisher setup and build commands. The small example below illustrates the base parser contract only; it cannot enable onboarding without those additional verified setup fields. It requires `FLAREBOT_MODE=control-plane` and a `FLAREBOT_CONTROL_PLANE` JSON string: ```json { "schemaVersion": 1, "publicOrigin": "https://control.example.com", "oauthClientId": "your-registered-cloudflare-client-id", "oauthRedirectUri": "https://control.example.com/auth/callback", "oauthScopes": ["openid", "account.read", "workers-platform.write"] } ``` The callback must be on `publicOrigin` without credentials, query or fragment. Scope syntax accepts dot-delimited identifiers; the example is not a complete installer permission set. The onboarding preflight must discover and validate the actual registered scopes. `serializeControlPlaneConfig` is the strict nonsecret serialization boundary. Control-plane config cannot contain installation data. `loadControlPlaneSecrets` independently loads `FLAREBOT_SESSION_SECRET` (at least 32 bytes), `FLAREBOT_CREDENTIAL_ENCRYPTION_KEY` (32 random bytes encoded as unpadded base64url, e.g. `node -e 'console.log(require("node:crypto").randomBytes(32).toString("base64url"))'`), and optional `FLAREBOT_OAUTH_CLIENT_SECRET` for a confidential OAuth client. These secrets must be independent of customer secrets and live only on the control-plane Worker. OAuth access/refresh tokens belong in a separate protected credential store, never either config schema or installation metadata. The separate control-plane Worker implements the OAuth flow and native encrypted AuthVault storage; these parsers themselves persist nothing. Secret values are wrapped with private storage; JSON, string interpolation and inspection produce redacted output. Call `.reveal()` only when passing a secret to the consuming crypto/provider API. Redaction is defense in depth, not a vault: never serialize or log revealed values, raw environments or credential responses. Provider keys are encrypted in customer-owned Durable Object storage and managed through Settings. See [model providers](model-providers.md) for OpenRouter's native AI Gateway transport, key and billing requirements, retirement migration from OpenCode, and provider-extension instructions. Cloudflare documents runtime secrets and local `.dev.vars` behavior in its [Workers secrets reference](https://developers.cloudflare.com/workers/configuration/secrets/).