Configuration
Ragz configuration is split across two layers that get set in different places, by different people, at different times:
- Bootstrap environment variables (
RAGZ_*) — read once at process start, from.env/ your Compose file / your orchestrator's secret store. These are the things a deployment needs before the app can even connect to its own database: connection strings, the encryption root key, the first superadmin's credentials, upload limits. - Superadmin app-settings — configured live, after the app is running,
from the Admin → Settings page in the web UI. These are the things an
operator tunes and re-tunes over the life of the install: which document
parser to use, which reranker, which web-search provider, whether
generative UI is on. They're stored in Postgres (the
app_settingstable) and take effect immediately — no restart, no redeploy.
Secrets never live in .env
Beyond the database connection string and the KEK source, no secret ever
belongs in .env. LLM provider keys, the Cohere/Tavily/LlamaParse API
keys, SMTP credentials — all of it is entered once through the admin API,
envelope-encrypted with AES-256-GCM, and stored in Postgres. Fields that
hold secrets are write-only: the API will tell you a key is configured
(*_key_set: true) but will never hand the value back, in a response, a
log line, or a trace.
Where each concern is configured
| Concern | Layer | Where |
|---|---|---|
| Database / Redis / Qdrant / MinIO connection | Bootstrap env var | .env, RAGZ_DATABASE_URL etc. |
| Encryption root key (KEK) | Bootstrap env var | RAGZ_KEK_FILE |
| First superadmin account | Bootstrap env var (one-time) | RAGZ_BOOTSTRAP_EMAIL / RAGZ_BOOTSTRAP_PASSWORD, python -m ragz.bootstrap |
| LiteLLM proxy admin credential | Bootstrap env var | RAGZ_LITELLM_MASTER_KEY + LITELLM_MASTER_KEY/LITELLM_SALT_KEY |
| Upload size limits | Bootstrap env var | RAGZ_MAX_UPLOAD_MB, RAGZ_INTERACTIVE_UPLOAD_MB |
| OCR kill-switch | Bootstrap env var | RAGZ_OCR_ENABLED |
| Trusted reverse-proxy CIDRs | Bootstrap env var | RAGZ_TRUSTED_PROXIES |
| LLM provider connections (OpenAI, Anthropic, Ollama, ...) | App-setting + secret | Admin → Models |
| Document parser (liteparse / anydoc / docling / llamaparse) | App-setting | Admin → Settings |
| Reranker (local TEI / Cohere) | App-setting + secret | Admin → Settings |
| Web search provider (DuckDuckGo / Tavily) | App-setting + secret | Admin → Settings |
| Generative UI on/off, web-result images | App-setting | Admin → Settings |
| Default chunking method | App-setting | Admin → Settings |
| Email delivery (SMTP / SES) | App-setting + secret | Admin → Settings |
The rest of this section works through each row in detail: the full environment variable reference, then models and providers, parsers and OCR, web search, and generative UI.
Why the split
Bootstrap env vars answer "how does this process find its own database and unlock its own secrets" — questions that have to be answered before a single line of application code runs, so they can't live in the database they describe. Everything else — which model to call, which parser to run, which search provider to hit — is a decision an operator revisits after the platform is live, often per environment or as new providers become available. Putting those behind a live admin UI means changing them is an audited API call, not a redeploy.
Per-workspace vs. global
Most Admin → Settings values (parser, reranker, web search, generative UI) are install-wide — one choice for the whole Ragz instance. Model selection (which model a workspace uses to generate and embed) is set per workspace under Admin → Models, layered on top of the provider connections configured globally.