Skip to main content
Configuration is read from the environment, usually through a .env file created from .env.example.

What this server has configured

apowerb starts with almost nothing configured and says so rather than failing. A feature nobody has set up answers « not configured yet, contact your administrator » — never a 4xx or a 5xx. The server is the source of truth about its own state:
The same answer feeds the interface: Admin → Configuration lists every capability, and the sidebar badge counts what is still missing.
missing holds variable names, never values, and the server sends it to administrators only. Everyone else sees which features work — enough to know it is not their mistake, and nothing that helps an attacker.
Every setting below is read at startup. Restart the backend after changing one, then reload Admin → Configuration. A value written where the process never reads it changes nothing — check the environment of the container, not the shell that started it.

Required

Five settings, and the server refuses to boot without them — the list is RUNTIME_REQUIRED_FIELDS in configs/settings.py, which the boot check reads.
On the Quickstart path, none of these are yours to fill in: the Compose stack runs its own Postgres and generate-secrets.sh writes the key. This page is for an installation that brings its own database.
Two neighbours in the same block are not required, each carrying a default: DB_PORT (5432) and DB_SCHEMA (public).
.env.example may still carry TEST_TOKEN. It is not required: the only code that reads it is a middleware mounted nowhere. Setting it changes nothing, leaving it out breaks nothing.Earlier versions did refuse to start without it, which meant inventing a “test token” to run in production. That requirement is gone.
ENCRYPT_KEY encrypts the OAuth tokens of every connected integration. Changing it makes all previously connected integrations unreadable. Back it up with your other secrets — see Secrets.

Security and JWT

API schema

FastAPI serves these three routes to anyone by default, with the full inventory of paths, parameters and response shapes — no credentials required, since Swagger UI cannot send a bearer token on its first load. apowerb removes them instead of guarding them, unless this flag is set.
Since 0.1.18, /docs and /openapi.json answer 404 by default. Set PUBLISH_API_SCHEMA=true to get a browsable schema back — typically for local development only. WORKING_MODE=production hides the schema regardless of this flag.

CORS

Set CORS_ALLOWED_ORIGINS whenever the front end lives on a different domain than the API. ADK 2.6 added an origin-check middleware that rejects any state-changing request (POST, PUT, PATCH, DELETE) carrying an Origin header it was not told about — with a 403 raised before authentication runs. GET requests are unaffected, which makes the symptom easy to misread: the app looks half-broken (browsing works, every submit fails) rather than looking like a CORS problem. List every origin the browser will call the API from directly, comma-separated.

OAuth — workspace integrations

These OAuth applications carry the scopes agents need to read Drive, send mail, or list Teams chats. They authorise an agent to act on a service — they are not how a user signs in.
Signing in with an identity provider — GitHub, Google, Microsoft, LinkedIn — is part of a commercial edition and is absent here. The open-source build authenticates with email and password. See Editions.

Gmail Pub/Sub webhooks

See Gmail webhooks for the full setup.

RAG and webhooks

POST /rag/webhook sits outside the auth middleware and trusts this HMAC signature instead — it is the only credential guarding the route. Since 0.1.8, the server refuses to start when WORKING_MODE=production and RAG_WEBHOOK_SECRET is still empty or the shipped placeholder. Generate one before deploying: openssl rand -hex 32.

Notifications

All four default to empty, and the mailer is simply off until they are set — one log line, no error, no email. There is no hardcoded fallback address: an installation that leaves these unset sends nothing, rather than mailing a third party by default.

Storage (optional)

Orchestrator

With ORCHESTRATOR=mage (the default), the server talks to Mage AI: With ORCHESTRATOR=th2etl, it talks to th2etl instead: Both clients expose the same surface, so only these settings change. See Orchestrator.
Unset means mage. A deployment meant to run on th2etl must say so explicitly — silence selects the other backend, and the schedules land where nobody is looking.

Default LLM provider

Agents with no model of their own fall back to this provider.

Sign-up and sign-in

Database, beyond the required settings

Runtime directories

Where the server writes on disk. S3 keys keep their own namespace and are unaffected.

Organisations

Development-only switches

Both must stay false in production. The first is refused at boot when WORKING_MODE is production; the second must never run unattended — use the migration CLI explicitly instead.

Declared here, used by bricks

The core declares these so a brick can read them. In a core-only install they are inert: setting them changes nothing, and the matching routes still answer 404.
These are the sign-in credentials, not the workspace ones. Connecting Google Drive or Outlook for an agent uses the *_INTEGRATION_* variables above, which are part of this edition.

Extensions

Empty means no extension: the core runs on its own. See Editions.