Skip to content

Configuration

Raven is configured entirely via environment variables. There is no central runtime config file — every binary reads its environment at startup, validates required values, and fails fast if the set is incomplete.

Three runtimes consume those variables:

  • Go API and Asynq workerViper loads defaults, optional config.yaml, then env overrides. Defined in internal/config/config.go. All keys are bound under the RAVEN_ prefix (with a few legacy bindings such as GOOGLE_CLIENT_ID, AWS_SES_*, TMDB_API_KEY).
  • Python AI workerpydantic-settings reads the same RAVEN_ prefix. Defined in ai-worker/raven_worker/config.py with env_prefix="RAVEN_".
  • Frontend (Vue 3 + Vite)import.meta.env.VITE_* substitutions are baked in at build time. Defined per build in frontend/.env.example, frontend/.env.production, and the deploy config at deploy/cloudflare-pages.json.

Precedence

For the Go binaries, Viper resolves each key in this order (later wins):

  1. Built-in SetDefault value in config.go.
  2. Optional config.yaml under . or ./config. Missing file is not an error.
  3. Process environment (the Compose stack mounts .env into containers and relies on Compose's variable substitution + env_file loading).
  4. Explicit BindEnv mappings — both RAVEN_* and the legacy aliases noted above.

Frontend VITE_* values are read once at vite build and frozen into the JS bundle; you cannot change them without a rebuild.

Secrets handling

  • All secrets are environment-only. The repo ships .env.example files; there is no committed .env.
  • The Compose stack supports dotenvx-encrypted .env files: each service bind-mounts ./.env:/app/.env:ro and receives DOTENV_PRIVATE_KEY. Never commit .env.keys.
  • Required secrets fail loudly via Compose's ${VAR:?...} syntax — see RAVEN_ENCRYPTION_AES_KEY and DATABASE_URL in docker-compose.yml and docker-compose.edge.yml.
  • For production, push .env into a secrets manager (Vault, SSM Parameter Store, 1Password Connect) and inject at boot — see the hardening guide.

Quick start

The minimum env vars to bring up the full Compose stack:

bash
# postgres + valkey
POSTGRES_USER=raven
POSTGRES_PASSWORD=changeme
POSTGRES_DB=raven
DATABASE_URL=postgresql://raven:changeme@postgres:5432/raven?sslmode=disable
VALKEY_URL=redis://valkey:6379/0

# Raven API
RAVEN_DATABASE_URL=${DATABASE_URL}
RAVEN_VALKEY_URL=${VALKEY_URL}
RAVEN_GRPC_WORKER_ADDR=python-worker:50051
RAVEN_ENCRYPTION_AES_KEY=<base64 32-byte key>

# auth
SUPERTOKENS_API_KEY=supertokens-dev-key-replace-me

# at least one LLM provider for the AI worker
ANTHROPIC_API_KEY=sk-ant-...

Generate RAVEN_ENCRYPTION_AES_KEY with openssl rand -base64 32. Without it the API container refuses to start (Compose enforces this with :?required).

Go API — cmd/api

The API binary loads config via config.Load() in internal/config/config.go.

Server

Env varTypeDefaultRequiredDescription
RAVEN_SERVER_PORTint8081noHTTP listener port (Server.Port).
RAVEN_SERVER_MODEstringdebugnoGin mode (debug or release). Server.Mode.
RAVEN_HTTP_READ_HEADER_TIMEOUTduration5snohttp.Server.ReadHeaderTimeout.
RAVEN_HTTP_READ_TIMEOUTduration30snoFull request read timeout.
RAVEN_HTTP_WRITE_TIMEOUTduration60snoFull response write timeout.
RAVEN_HTTP_IDLE_TIMEOUTduration120snoKeep-alive idle timeout.
RAVEN_AI_WORKER_TIMEOUTduration5snoPer-call gRPC deadline against the Python worker.
RAVEN_AI_WORKER_BREAKER_THRESHOLDuint5noConsecutive AI-worker failures that open the circuit breaker.
RAVEN_AI_WORKER_BREAKER_COOLDOWNduration30snoCooldown before the breaker probes again.
RAVEN_SINGLE_USERboolfalsenoRaven Local / desktop mode. Injects a synthetic user_id=local, org_id=local session and disables /auth/*.
RAVEN_CORS_ALLOWED_ORIGINScsvhttp://localhost:5173,https://raven-frontend.pages.devnoComma-separated origin allowlist.

Durations accept Go time.Duration syntax (5s, 500ms, 2m).

Database & cache

Env varTypeDefaultRequiredDescription
RAVEN_DATABASE_URLURLyesPostgreSQL DSN (with pgvector). Validated as non-empty in Load().
RAVEN_DB_AUTO_MIGRATEboolfalsenoWhen true, the API runs all pending goose migrations against RAVEN_DATABASE_URL on startup before serving traffic. Migrations are embedded in the binary via //go:embed; no on-disk migrations/ directory required. Leave off in multi-replica production; see Upgrades — Auto-migrate.
RAVEN_VALKEY_URLURLnoValkey/Redis DSN, used by Asynq + rate-limit buckets + cache.

config.Load() returns an error if RAVEN_DATABASE_URL is unset: database.url is required.

gRPC client (AI worker)

Env varTypeDefaultRequiredDescription
RAVEN_GRPC_WORKER_ADDRhost:portlocalhost:50051no (yes in Compose)Address of the Python AI worker gRPC server. No scheme prefix.

Auth — SuperTokens

Env varTypeDefaultRequiredDescription
RAVEN_SUPERTOKENS_CONNECTION_URIURLhttp://supertokens:3567noSuperTokens core URI.
RAVEN_SUPERTOKENS_API_KEYstring(empty)yes (prod)SuperTokens core API key. Never commit.
RAVEN_SUPERTOKENS_API_DOMAINURLhttp://localhost:8081noPublic API domain that frontend calls.
RAVEN_SUPERTOKENS_WEBSITE_DOMAINURLhttp://localhost:5173noPublic frontend domain (used for cookie scoping + CORS).
GOOGLE_CLIENT_IDstring(empty)noGoogle OAuth client ID for SuperTokens social login.
GOOGLE_CLIENT_SECRETstring(empty)noGoogle OAuth client secret. Never commit.

Encryption

Env varTypeDefaultRequiredDescription
RAVEN_ENCRYPTION_AES_KEYbase64(32 bytes)yesAES-256-GCM key for at-rest encryption of tenant LLM API keys (BYOK). Never commit.

Compose enforces this with ${RAVEN_ENCRYPTION_AES_KEY:?... is required}.

Rate limits

All values are requests-per-minute unless noted. Tier limits override default_* for orgs on that tier.

Env varTypeDefaultRequiredDescription
RAVEN_RATELIMIT_DEFAULT_USER_LIMITint1000noPer-user fallback (must be > 0).
RAVEN_RATELIMIT_DEFAULT_ORG_LIMITint10000noPer-org fallback (must be > 0).
RAVEN_RATELIMIT_FREE_GENERAL_RPMint60noFree-tier general endpoints.
RAVEN_RATELIMIT_FREE_COMPLETION_RPMint10noFree-tier LLM completions.
RAVEN_RATELIMIT_PRO_GENERAL_RPMint600noPro tier general.
RAVEN_RATELIMIT_PRO_COMPLETION_RPMint120noPro tier completions.
RAVEN_RATELIMIT_ENTERPRISE_GENERAL_RPMint6000noEnterprise general.
RAVEN_RATELIMIT_ENTERPRISE_COMPLETION_RPMint-1noEnterprise completions; -1 means unlimited.
RAVEN_RATELIMIT_WIDGET_RPMint30noPublic widget endpoints.
RAVEN_RATELIMIT_APIKEY_HASH_SECRETstring(empty)yes (prod)HMAC-SHA-256 key for deriving Valkey bucket IDs from raw API keys. Must be stable across nodes; never commit.

Load() returns an error if either default_user_limit or default_org_limit is zero or negative.

Asynq queue (used by the API to enqueue, by the worker to consume)

Env varTypeDefaultRequiredDescription
RAVEN_QUEUE_CONCURRENCYint10noWorker concurrency.
RAVEN_QUEUE_MAX_RETRYint5noMax retries per task.

Storage — SeaweedFS

Env varTypeDefaultRequiredDescription
RAVEN_SEAWEEDFS_MASTER_URLURLhttp://seaweedfs-master:9333noSeaweedFS master node URL.

Uploads

Env varTypeDefaultRequiredDescription
RAVEN_UPLOAD_MAX_SIZE_BYTESint6452428800 (50 MB)noMax upload size in bytes.
RAVEN_UPLOAD_ALLOWED_TYPEScsvPDF, DOCX, PPTX, HTML, MD, TXT, CSVnoMIME allowlist (Viper accepts a comma list).

LLM provider keys (BYOK + summary job)

These are not bound by Viper; they are read directly by the AI worker (and by the dev-agent script). The Go API receives tenant-scoped keys via the /api/v1/byok endpoints and stores them encrypted with RAVEN_ENCRYPTION_AES_KEY.

Env varTypeDefaultRequiredDescription
ANTHROPIC_API_KEYstringyes (one provider)Anthropic key. Never commit.
OPENAI_API_KEYstringnoOpenAI key. Never commit.
COHERE_API_KEYstringnoCohere key (rerank + embeddings). Never commit.

Voice — LiveKit

Env varTypeDefaultRequiredDescription
RAVEN_LIVEKIT_API_URLURLhttp://localhost:7880noLiveKit server HTTP(S) URL for RoomService API calls.
RAVEN_LIVEKIT_WS_URLURLws://localhost:7880noWebSocket URL returned to clients (use wss:// in production).
RAVEN_LIVEKIT_API_KEYstringdevkeyyes (prod)LiveKit API key. Never commit.
RAVEN_LIVEKIT_API_SECRETstringdevsecretyes (prod)LiveKit API secret. Never commit.

Voice — TTS (text-to-speech)

Env varTypeDefaultRequiredDescription
RAVEN_TTS_PROVIDERenumcartesianocartesia or piper.
RAVEN_TTS_CARTESIA_API_KEYstring(empty)yes (cartesia)Cartesia Sonic API key. Never commit.
RAVEN_TTS_CARTESIA_VOICE_IDstring(empty)noCartesia voice UUID.
RAVEN_TTS_CARTESIA_MODELstringsonic-2noCartesia model id.
RAVEN_TTS_CARTESIA_BASE_URLURL(empty)noOverride Cartesia API base.
RAVEN_TTS_PIPER_ENDPOINTURLhttp://localhost:5000noSelf-hosted Piper HTTP endpoint.
RAVEN_TTS_PIPER_VOICEstringen_US-amy-mediumnoPiper voice file id.

Voice — STT (speech-to-text)

Env varTypeDefaultRequiredDescription
RAVEN_STT_PROVIDERenum(empty)nodeepgram, whisper, or empty. Empty falls back to Deepgram if a key is set, otherwise Whisper.
RAVEN_STT_DEEPGRAM_API_KEYstring(empty)yes (deepgram)Deepgram key. Never commit.
RAVEN_STT_DEEPGRAM_MODELstringnova-2noDeepgram model id.
RAVEN_STT_DEEPGRAM_BASE_URLURLhttps://api.deepgram.comnoDeepgram API base.
RAVEN_STT_WHISPER_ENDPOINTURLhttp://localhost:8000noSelf-hosted Whisper HTTP endpoint.
RAVEN_STT_WHISPER_MODELstringlarge-v3noWhisper model id.

Retrieval (hybrid search tuning)

Tunables for SearchService.HybridSearch and the RRF fusion step. All values are validated at startup (config.Load rejects non-positive integers, negative weights, and max_limit < default_limit). See Hybrid Retrieval for what each value does.

Env varTypeDefaultRequiredDescription
RAVEN_RETRIEVAL_DEFAULT_LIMITint10notopK returned when the caller omits top_k.
RAVEN_RETRIEVAL_MAX_LIMITint100noHard ceiling on both topK and the per-leg candidateK. Must be >= RAVEN_RETRIEVAL_DEFAULT_LIMIT.
RAVEN_RETRIEVAL_RRF_Kint60noRRF smoothing constant. Lower → top-ranked agreement matters more; higher → smoother distribution. Mirrored by the Python ai-worker.
RAVEN_RETRIEVAL_CANDIDATE_MULTIPLIERint3noPer-leg candidate set is sized as topK * multiplier (then clamped to MAX_LIMIT) so RRF has enough overlap signal.
RAVEN_RETRIEVAL_HYBRID_VECTOR_WEIGHTfloat1.0noMultiplier on the vector leg's RRF contribution. 0 disables the leg's influence on the fused score; both weights at 0 fall back to 1.0/1.0.
RAVEN_RETRIEVAL_HYBRID_BM25_WEIGHTfloat1.0noMultiplier on the BM25 leg's RRF contribution.

ClickHouse (large-tenant vector backend)

ClickHouse is opt-in. The API uses pgvector by default and switches per-org once the chunk count exceeds chunk_threshold.

Env varTypeDefaultRequiredDescription
RAVEN_CLICKHOUSE_HOSThost(empty)noEmpty disables ClickHouse entirely.
RAVEN_CLICKHOUSE_PORTint9000noNative protocol port.
RAVEN_CLICKHOUSE_DATABASEstringravennoClickHouse database name.
RAVEN_CLICKHOUSE_USERstringdefaultnoClickHouse user.
RAVEN_CLICKHOUSE_PASSWORDstring(empty)yes (if host set)ClickHouse password. Never commit.
RAVEN_CLICKHOUSE_VECTOR_BACKENDenumpgvectornoDefault vector backend: pgvector or clickhouse.
RAVEN_CLICKHOUSE_CHUNK_THRESHOLDint645000000noPer-org chunk count above which ClickHouse is preferred.

Telemetry — OpenTelemetry / OpenObserve

Env varTypeDefaultRequiredDescription
RAVEN_OTEL_ENABLEDboolfalsenoMaster switch for OTEL exporters.
RAVEN_OTEL_ENDPOINThost:port(empty)yes (if enabled)OTLP gRPC endpoint, e.g. openobserve:5081.
RAVEN_OTEL_SERVICE_NAMEstringraven-apinoservice.name resource attribute.

Payments — Hyperswitch + Razorpay

Raven uses Hyperswitch as the payment orchestrator with Razorpay underneath for Indian rails (UPI, RuPay, cards).

Env varTypeDefaultRequiredDescription
RAVEN_HYPERSWITCH_BASE_URLURLhttp://localhost:8090yes (billing)Hyperswitch API base. Use https://sandbox.hyperswitch.io for testing.
RAVEN_HYPERSWITCH_API_KEYstring(empty)yes (billing)Hyperswitch API key. Never commit.
RAVEN_HYPERSWITCH_WEBHOOK_SECRETstring(empty)yes (billing)HMAC-SHA-256 secret for webhook verification. Never commit.
RAVEN_HYPERSWITCH_RAZORPAY_KEY_IDstring(empty)yes (Razorpay)Razorpay public key id (surfaced to the frontend checkout SDK).

Email — AWS SES (SMTP)

Credentials are SES SMTP credentials, not IAM access keys. Generate via AWS Console → SES → SMTP settings.

Env varTypeDefaultRequiredDescription
AWS_SES_REGIONstringap-south-1noSES region.
AWS_SES_FROM_ADDRESSemail(empty)yes (email)Verified SES identity used as the From address.
AWS_SES_FROM_NAMEstringRavennoFriendly From name.
AWS_SES_SMTP_USERNAMEstring(empty)yes (email)SES SMTP username. Never commit.
AWS_SES_SMTP_PASSWORDstring(empty)yes (email)SES SMTP password. Never commit.

Email summary job (M9 #257)

Required when the post-session summary email pipeline is on. Setting RAVEN_UNSUBSCRIBE_BASE_URL flips the pipeline on; that requires UNSUBSCRIBE_TOKEN_SECRET to be at least 32 bytes — Load() rejects shorter secrets at startup.

Env varTypeDefaultRequiredDescription
RAVEN_FRONTEND_BASE_URLURL(empty)yes (email)Public frontend URL used to build deep-links in emails.
RAVEN_SUPPORT_ADDRESSemailsupport@ravencloak.ionoReply-To / footer contact.
RAVEN_UNSUBSCRIBE_BASE_URLURL(empty)yes (email)Public URL of the one-click unsubscribe endpoint, proxied by the API.
UNSUBSCRIBE_TOKEN_SECRETstring (≥ 32 bytes)(empty)yes (email)HMAC-SHA-256 key for unsubscribe tokens. Generate with openssl rand -hex 32. Never commit.
RAVEN_AI_WORKER_HTTP_URLURLhttp://ai-worker:8090noAI-worker FastAPI base for POST /internal/summarize.

PostHog (server-side, opt-in)

Env varTypeDefaultRequiredDescription
RAVEN_POSTHOG_API_KEYstring(empty)noPostHog project API key. Empty disables event capture.
RAVEN_POSTHOG_HOSTURLhttps://us.i.posthog.comnoPostHog ingestion host (use https://eu.i.posthog.com for the EU region).

Meta WhatsApp Business API

Env varTypeDefaultRequiredDescription
RAVEN_META_ACCESS_TOKENstring(empty)yes (WhatsApp)Permanent access token. Never commit.
RAVEN_META_PHONE_NUMBER_IDstring(empty)yes (WhatsApp)WhatsApp Cloud API phone-number id.
RAVEN_META_APP_SECRETstring(empty)yes (WhatsApp)App secret used to verify webhook HMAC signatures. Never commit.
RAVEN_META_WEBHOOK_TOKENstring(empty)yes (WhatsApp)hub.verify_token for webhook subscription handshake.

Note: the variables above match the field names on MetaConfig in config.go and Viper's default RAVEN_<SECTION>_<FIELD> derivation (SetEnvPrefix("RAVEN") + EnvKeyReplacer(".", "_")). They are not additionally bound via BindEnv.

TMDB (demo seed)

The demo knowledge base uses TMDB. Both names work because the legacy TMDB_API_KEY is bound via BindEnv.

Env varTypeDefaultRequiredDescription
TMDB_API_KEYstring(empty)yes (demo seed)TMDB API key. Never commit.
RAVEN_TMDB_BASE_URLURLhttps://api.themoviedb.org/3noTMDB API base.

Seed endpoint

Env varTypeDefaultRequiredDescription
RAVEN_SEED_KEYstring(empty)yes (admin seed)Value required in the X-Seed-Key header to call the protected seed endpoint. Never commit.

eBPF (Linux ≥ 5.8 with CONFIG_DEBUG_INFO_BTF=y)

All flags default to false. The subsystem is a no-op on non-Linux platforms regardless. Load() rejects RAVEN_EBPF_AUDIT_RING_BUFFER_SIZE values that are not a power of two when RAVEN_EBPF_ENABLED=true.

Env varTypeDefaultRequiredDescription
RAVEN_EBPF_ENABLEDboolfalsenoMaster switch. When false, all sub-flags are ignored.
RAVEN_EBPF_OBSERVABILITY_ENABLEDboolfalsenoEnable eBPF-based observability hooks.
RAVEN_EBPF_AUDIT_ENABLEDboolfalsenoEnable eBPF audit.
RAVEN_EBPF_AUDIT_IP_ALLOWLISTcsv(empty)noIPs excluded from audit logging.
RAVEN_EBPF_AUDIT_EXEC_ALLOWLISTcsv(empty)noExec paths excluded from audit logging.
RAVEN_EBPF_AUDIT_RING_BUFFER_SIZEint (power of 2)1048576noBPF ring buffer size in bytes.
RAVEN_EBPF_XDP_ENABLEDboolfalsenoEnable XDP rate-limit dataplane.
RAVEN_EBPF_XDP_INTERFACEstringeth0noNetwork interface to attach XDP to.

Asynq worker — cmd/worker

The Asynq worker (cmd/worker/main.go) calls config.Load() and reuses every variable above. The environment is identical to the API's. The worker additionally consumes:

  • RAVEN_QUEUE_CONCURRENCY, RAVEN_QUEUE_MAX_RETRY — Asynq runtime knobs.
  • AWS_SES_* and RAVEN_* summary keys — the post-session summary job runs inside this binary (M9 #257).
  • RAVEN_AI_WORKER_HTTP_URL — used to call POST /internal/summarize on the Python worker.

When SES SMTP credentials are unset and the binary is in debug server mode, the worker falls back to a stub email sender; in release mode it returns an init error from email.Config.Validate().

AI worker — Python (ai-worker)

Defined in ai-worker/raven_worker/config.py as a pydantic_settings.BaseSettings subclass with SettingsConfigDict(env_prefix="RAVEN_"). Version 0.3.0 (ai-worker/pyproject.toml).

Env varTypeDefaultRequiredDescription
RAVEN_GRPC_PORTint50051nogRPC listen port.
RAVEN_GRPC_MAX_WORKERSint10nogRPC server thread-pool size.
RAVEN_DATABASE_URLURLpostgresql://raven:raven@localhost:5432/ravenyesSame DSN the Go API uses.
RAVEN_VALKEY_URLURLredis://localhost:6379/0yesSame Valkey/Redis URL.
RAVEN_OTEL_ENDPOINThost:port(empty)noOTLP endpoint (if enabled).
RAVEN_OTEL_ENABLEDboolfalsenoToggle OTEL exporters.
RAVEN_LOG_LEVELstringINFOnoPython logging level.
RAVEN_LITEPARSE_PATHpathliteparsenoPath to the liteparse binary used for document parsing.
RAVEN_ENCRYPTION_KEYbase64(32 bytes)(empty)yes (BYOK)Same key used by the Go API to decrypt tenant LLM keys. Never commit.
RAVEN_LIVEKIT_URLURLws://localhost:7880yes (voice)LiveKit WebSocket URL.
RAVEN_LIVEKIT_API_KEYstring(empty)yes (voice)LiveKit API key. Never commit.
RAVEN_LIVEKIT_API_SECRETstring(empty)yes (voice)LiveKit API secret. Never commit.
RAVEN_MEMORY_DIRpath(empty)noPer-session memory directory. Empty disables memory. In Compose this is mounted from a named volume.
RAVEN_ENABLE_WEB_SEARCHboolfalsenoAllow Anthropic web_search tool in RAG responses.
RAVEN_HTTP_PORTint8090noFastAPI internal endpoints (POST /internal/summarize).
RAVEN_HTTP_ENABLEDbooltruenoToggle the FastAPI side-server.
RAVEN_HTTP_BIND_HOSTstring127.0.0.1noBinds loopback by default; override only when callers live on a separate node and a network policy gates external access.
RAVEN_SEMANTIC_CACHE_ENABLEDbooltruenoToggle the pgvector semantic-response cache (M9 #256). When false the exact-match Valkey cache still applies.
RAVEN_RETRIEVAL_RRF_Kint60noRRF smoothing constant used by reciprocal_rank_fusion on the RAG path. Shares the env var with the Go API so both code paths stay in lock-step.
RAVEN_RETRIEVAL_DEFAULT_TOP_Nint10noSize of the fused list emitted by RRF before optional reranking / context build.

In addition, the AI worker reads provider keys directly from the environment at request time (not via pydantic-settings):

  • ANTHROPIC_API_KEY, OPENAI_API_KEY, COHERE_API_KEY — used as fallbacks when a tenant has not provided a BYOK key.

Frontend — Vite (frontend)

Vite substitutes import.meta.env.VITE_* at vite build. Defaults defined in frontend/.env.example, production overrides in frontend/.env.production, and the canonical Cloudflare Pages build env in deploy/cloudflare-pages.json.

Env varTypeDefault (build)RequiredWhere usedDescription
VITE_API_URLURLhttp://localhost:8081/apinofrontend/src/api/client.tsLegacy/base API URL fallback.
VITE_API_BASE_URLURLhttp://localhost:8081/api/v1yesAPI store + auth callback wiringThe /api/v1 prefix used by the bulk of the SPA.
VITE_API_DOMAINURLhttp://localhost:8081yesSuperTokens apiDomain config in the SPAPublic API origin (no path).
VITE_LIVEKIT_URLURL(empty)noVoice room joiningwss:// LiveKit endpoint.
VITE_POSTHOG_API_KEYstring(empty)noFrontend PostHog clientEmpty disables client-side analytics.
VITE_POSTHOG_HOSTURLhttps://us.i.posthog.comnoFrontend PostHog clientEU region: https://eu.i.posthog.com.
VITE_WIDGET_URLURLhttps://cdn.raven.example/widget.jsnoEmbed widget loaderOverride for self-hosted CDN.
VITE_KEYCLOAK_URLURL(empty)noLegacy auth path (kept in .env.production)Pre-SuperTokens Keycloak base URL.
VITE_KEYCLOAK_REALMstring(empty)noLegacy auth pathKeycloak realm.
VITE_KEYCLOAK_CLIENT_IDstring(empty)noLegacy auth pathKeycloak client id.

Reminder: Vite freezes these values into the bundle. To change them in production you must rebuild the frontend image (or redeploy Cloudflare Pages with new build env). They cannot be overridden at container start.

Edge variant differences — docker-compose.edge.yml

The edge compose file (docker-compose.edge.yml) ships only the Go API, a local PostgreSQL, and Traefik. The Python AI worker runs remotely. Env differences vs the full stack:

Env varEdge value / behaviourNotes
RAVEN_SERVER_PORT${RAVEN_SERVER_PORT:-8080}Edge default is 8080 (vs API default 8081).
RAVEN_DATABASE_URL${DATABASE_URL:?required}Compose enforces required; uses local Postgres.
RAVEN_GRPC_WORKER_ADDR${GRPC_AI_WORKER_ADDR:?required}Points to a remote AI worker; required and validated by Compose.
RAVEN_EDGE_MODE"true" (set in compose)Signals the API to skip local-worker checks.
RAVEN_API_IMAGEghcr.io/ravencloak-org/raven-api:latest (default)Override for pinned tags, e.g. :latest-arm64.
DOMAIN, ACME_EMAILoptionalUsed by Traefik for HTTPS.

What is not present in the edge compose: SuperTokens, OpenObserve, SeaweedFS, LiveKit, Asynq worker. Voice + WhatsApp + email + storage features are not available on the edge profile; configure them only when you bring up the full stack.

Validation — how invalid configs fail

Go API and worker (config.Load()):

  • RAVEN_DATABASE_URL empty ⇒ returns database.url is required and the binary exits non-zero on startup (log.Fatalf in cmd/api/main.go and cmd/worker/main.go).
  • RAVEN_RATELIMIT_DEFAULT_USER_LIMIT ≤ 0 ⇒ explicit error.
  • RAVEN_RATELIMIT_DEFAULT_ORG_LIMIT ≤ 0 ⇒ explicit error.
  • RAVEN_EBPF_ENABLED=true and RAVEN_EBPF_AUDIT_RING_BUFFER_SIZE not a power of 2 ⇒ explicit error (bits.OnesCount check).
  • RAVEN_UNSUBSCRIBE_BASE_URL set and UNSUBSCRIBE_TOKEN_SECRET shorter than 32 bytes ⇒ explicit error.

Compose (docker-compose.yml, docker-compose.edge.yml):

  • ${VAR:?...} syntax aborts docker compose up with the message before any container starts. Used for RAVEN_ENCRYPTION_AES_KEY, DATABASE_URL, and GRPC_AI_WORKER_ADDR (edge).

Python AI worker (pydantic-settings):

  • Type-mismatch (e.g. non-int into grpc_port) raises ValidationError at import time and the gRPC process exits with a non-zero code.

Frontend (Vite):

  • No runtime validation. Missing VITE_* values fall back to the ?? defaults in source. Misconfiguration manifests as runtime API errors in the browser console.

Secrets handling — recommendations

  • Local dev — copy .env.example to .env, fill values, never commit. .gitignore excludes .env, .env.* (except .env.example).
  • CI — use repo secrets and inject only what the job needs.
  • Production — use a secrets manager (Vault, AWS Secrets Manager, SSM Parameter Store, 1Password Connect, Doppler). The Compose stack supports encrypted .env files via dotenvx — pass the decryption key as DOTENV_PRIVATE_KEY and bind-mount the encrypted .env read-only. Never mount .env.keys into a container.
  • RotationRAVEN_ENCRYPTION_AES_KEY, RAVEN_RATELIMIT_APIKEY_HASH_SECRET, and UNSUBSCRIBE_TOKEN_SECRET are sticky: rotating them invalidates encrypted BYOK keys, existing rate-limit buckets, and outstanding unsubscribe tokens respectively. Plan rotations explicitly.

See also