Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt

Use this file to discover all available pages before exploring further.

KaireonAI reads ~169 environment variables across the platform API process, the background worker, the MCP server, the license-generator script, and the Python ml-worker. This page is the canonical index — every variable below has been audited against the running code.

What it documents

Each variable below has a name, the subsystem that reads it, default value (literal fallback in the code, or when there is none), and a one-line purpose. Variables are grouped by domain so an operator can configure a single subsystem without scrolling the whole page. Subsystem deep-dives live on /self-host/configure/configuration-reference and /self-host/deploy/helm-reference; this page indexes everything in one place and cross-links to the deep-dive where one exists.

Quick start

The minimum to boot the platform locally:
DATABASE_URL=postgresql://user:pass@localhost:5432/kaireon
NEXTAUTH_SECRET=<random 32+ char string>
JWT_SIGNING_SECRET=<random 32+ char string>
CONNECTOR_ENCRYPTION_KEY=<random 32+ char string>
WEBHOOK_SIGNING_SECRET=<random 32+ char string>
API_KEY_PEPPER=<random 32+ char string>
DATABASE_URL is the only variable required outside production; the other five become required when NODE_ENV=production. Production checklist (in addition to the six above):
  • REDIS_URL — required for caching, rate limiting, and the background worker queue.
  • CORS_ALLOWED_ORIGINS — must be a non-empty, non-wildcard list in production or env validation logs a warning.
  • EVENT_PUBLISHER + the matching backend group (KAFKA_*, MSK_*, EVENTBRIDGE_*, KINESIS_*) — defaults to redis.
  • INTERACTION_STORE + the matching backend group (SCYLLA_*, DYNAMODB_*, KEYSPACES_*) — defaults to pg.
  • SEARCH_INDEX + OPENSEARCH_* when running OpenSearch — defaults to pg.
  • OTEL_EXPORTER_OTLP_ENDPOINT — when shipping traces.
  • A SIEM block (SIEM_BACKEND + SIEM_ENDPOINT + optional SIEM_API_KEY/SIEM_SOURCETYPE/SIEM_INDEX) — when shipping audit logs to Splunk, Datadog, or Elastic.

How it works

Env validation runs at process startup (eagerly invoked from the database layer). Two passes:
  1. Presence — the validator iterates the required-vars list. Production-required keys missing → throw. Development-required keys missing → warn-only.
  2. Format — the validator checks DATABASE_URL starts with postgresql://, REDIS_URL starts with redis:// or rediss://, the listen port is in the legal range [1, 65535], CORS_ALLOWED_ORIGINS is non-empty and non-wildcard in production, and any optional-boolean vars are literally the string "true" or "false".
The Next.js build phase (when NEXT_PHASE === "phase-production-build") skips validation entirely so next build does not need production secrets. Subsystem env reads happen lazily at first use:
  • The platform’s dependency-injection container reads EVENT_PUBLISHER, INTERACTION_STORE, and SEARCH_INDEX once-per-process to pick the backend, then reads the backend-group vars to construct the client.
  • The Postgres pool reads PG_POOL_MAX once at module load.
  • Per-request env reads (such as NEGOTIATION_GLOBAL_KILL and ALLOW_UNSIGNED_WEBHOOKS) hit process.env on every call. Operators changing those vars need a process restart only when the read is module-scoped, not per-request.
Tier behavior:
NODE_ENVWhat changes
productionRequired keys throw on missing. CORS wildcard rejected. CSP unsafe-eval removed. Encryption fallback key disabled.
developmentRequired keys warn-only. CSP allows unsafe-eval for React stack traces. Deterministic encryption fallback key allowed.
testSame as development plus rate limiter is disabled and RLS_AUTO_ENABLE is force-skipped.

Reference

Database and migrations

Env VarDefaultRead byPurpose
DATABASE_URLDatabase layer; also the cleanup cron jobPostgreSQL connection string. Required in all tiers.
PG_POOL_MAX50Database layerPostgres pool max connection count.
RLS_AUTO_ENABLEenabled (skipped only when "false")Database layerAuto-enable Postgres Row-Level Security on all tenant tables at boot. Set to "false" to skip; never disable in production.

Auth and MFA

Env VarDefaultRead byPurpose
NEXTAUTH_URLhttps://playground.kaireonai.comAuth verify endpoint and outbound email composerPublic canonical URL for NextAuth callbacks and outbound email links.
NEXTAUTH_SECRETEdge middleware (session cookie verification)NextAuth.js session-cookie signing secret. Required in production.
JWT_SIGNING_SECRETOAuth2 token issuerHMAC key for OAuth2 JWT issue + verify. Required in production. Falls back to NEXTAUTH_SECRET when unset.
API_KEY_PEPPEROAuth2 client-secret hasherHMAC pepper for client-secret hashing. Required in production.
AUTH_URLhttp://localhost:3000Auto-seed dispatcherAuth.js base URL used by the auto-seed dispatcher when NEXTAUTH_URL is unset.
GOOGLE_CLIENT_IDNextAuth provider configGoogle OAuth client id (sign-in via Google).
GOOGLE_CLIENT_SECRETNextAuth provider configCompanion to GOOGLE_CLIENT_ID.
MFA_ENFORCEMENT_DISABLEDEdge middlewareTest-only flag. Disables MFA gate so integration tests can write without TOTP. Never set in production.
CONNECTOR_ENCRYPTION_KEY— (required in prod)Platform settings + encryption layerAES-256 raw key for encrypting connector secrets at rest. SHA-256 derived to a 32-byte AES key.
CONNECTOR_ENCRYPTION_KEY_VERSION1Encryption layerVersioned-secret rotation pointer for the active key.
CONNECTOR_ENCRYPTION_KEY_PREVIOUSEncryption layerPrevious key, used to decrypt rows still tagged with the prior version.
CONNECTOR_ENCRYPTION_KEY_PREVIOUS_VERSION0Encryption layerVersion number paired with CONNECTOR_ENCRYPTION_KEY_PREVIOUS.
WEBHOOK_SIGNING_SECRET— (required in prod)Journey callback receiver and webhook deliveryHMAC-SHA256 secret for outbound + inbound webhook signature verification. Also gates the delivery webhook endpoint.
ALLOW_UNSIGNED_WEBHOOKSWebhook delivery endpointDev-only override. When "true" and NODE_ENV !== "production", accepts unsigned webhooks. Hard-blocked in production.

Network, CORS, and CSP

Env VarDefaultRead byPurpose
NODE_ENVEdge middlewareStandard Node runtime tier (production / development / test). Drives env-validation strictness, CSP, encryption fallback.
NEXT_PHASEEnv validatorNext.js framework env. phase-production-build skips env-validation so next build does not need secrets.
NEXT_RUNTIMEInstrumentation bootstrapNext.js framework env. Differentiates Edge runtime vs Node runtime when wiring instrumentation.
NEXT_PUBLIC_APP_URLhttp://localhost:3000Studio AI toolsPublic app URL exposed to the browser bundle. Used by Studio AI tools for internal fetch base.
NEXT_PUBLIC_BASE_URLhttp://localhost:3000Data AI toolsCompanion to NEXT_PUBLIC_APP_URL used by Data AI tools.
CORS_ALLOWED_ORIGINS— (deny all cross-origin)Edge middlewareComma-separated allowlist of cross-origin domains. Wildcard * rejected in production.
CSP_DISABLEDEdge middlewareSet to "true" to skip CSP header (dev only).
CSP_POLICYcomputed defaultEdge middlewareOverride the default Content Security Policy string.
INTERNAL_SERVICE_SECRETEdge middlewareShared secret for service-to-service requests inside the cluster.
INTERNAL_API_URLSeed executorBase URL for service-to-service API calls from the worker back into the platform. Falls back to NEXTAUTH_URL, then http://localhost:3000.
API_KEYEdge middlewareOutbound system API key used by internal jobs that talk to themselves over HTTP.
PORT
number
HTTP listen port for the platform process. Defaults to Next.js’ 3000 when unset. Validated to be an integer in the legal port range [1, 65535].

Redis, caching, and rate limits

Env VarDefaultRead byPurpose
REDIS_URL— (cache disabled)Env validator and the background worker (default redis://localhost:6379 on the worker side)Redis/Valkey connection string. Required for the background worker; optional for the platform (cache falls back to in-memory). Format: rediss://default:<password>@<host>:6379 (TLS) or redis://... (plain). For Upstash, use the standard Redis URL form, not the REST URL.
RATE_LIMIT_TIERRate-limiterPer-tenant rate-limit tier override. Used by the unified sliding-window limiter.
SLOW_API_THRESHOLD_MS150API instrumentationPer-route warn threshold in milliseconds. Routes exceeding this log a slow_api warn.
UPSTASH_REDIS_REST_URL
string
Upstash REST API base URL (https://<id>.upstash.io). Distinct from REDIS_URL, which is the standard Redis-protocol connection. Set when you provision an Upstash database; not currently read by platform code (reserved for future REST-API features), but safe to leave configured.
UPSTASH_REDIS_REST_TOKEN
string
Upstash REST API token. Companion to the REST URL; not currently read by platform code.
Upstash quota awareness: the free tier is 500K Redis commands/month. With WORKER_INPROCESS=1 and idle queues, five BullMQ workers polling Upstash burn ~1.3M ops/month with zero useful work. See worker-mode-and-cron-drain runbook for the cost math and the WORKER_INPROCESS=0 + cron-driven drain pattern that fits inside the free tier.

Event publisher (Kafka / MSK / EventBridge / Kinesis / Redpanda)

EVENT_PUBLISHER selects the backend; only the matching group is read.
Env VarDefaultRead byPurpose
EVENT_PUBLISHERredisDependency-injection containerBackend selector — redis / kafka / redpanda / msk / eventbridge / kinesis.
KAFKA_BROKERSKafka publisher backendComma-separated host:port list.
KAFKA_CLIENT_IDKafka publisher backendKafkaJS client id.
KAFKA_TLS_ENABLEDKafka publisher backend"true" to enable TLS.
KAFKA_SASL_MECHANISMKafka publisher backendplain / scram-sha-256 / scram-sha-512.
KAFKA_SASL_USERNAMEKafka publisher backendSASL username.
KAFKA_SASL_PASSWORDKafka publisher backendSASL password.
KAFKA_CONSUMER_GROUP_IDKafka publisher backendConsumer group id (for inbound consumer wiring).
MSK_BROKERSMSK publisher backendAWS MSK bootstrap broker list.
MSK_REGIONus-east-1MSK publisher backendAWS region.
MSK_AUTH_MODEiam_roleMSK publisher backendiam_role / sasl.
MSK_ROLE_ARNMSK publisher backendIAM role ARN when MSK_AUTH_MODE=iam_role.
MSK_SASL_USERNAMEMSK publisher backendSASL username when MSK_AUTH_MODE=sasl.
MSK_SASL_PASSWORDMSK publisher backendSASL password when MSK_AUTH_MODE=sasl.
MSK_CONSUMER_GROUP_IDMSK publisher backendConsumer group id.
MSK_TOPIC_PREFIXMSK publisher backendTopic name prefix.
EVENTBRIDGE_AUTH_MODEiam_roleEventBridge publisher backendiam_role / access_key.
EVENTBRIDGE_REGIONus-east-1EventBridge publisher backendAWS region.
EVENTBRIDGE_ROLE_ARNEventBridge publisher backendIAM role ARN.
EVENTBRIDGE_ACCESS_KEY_IDEventBridge publisher backendStatic credentials when auth_mode=access_key.
EVENTBRIDGE_SECRET_ACCESS_KEYEventBridge publisher backendCompanion to access key id.
EVENTBRIDGE_BUS_NAMEEventBridge publisher backendTarget event bus name.
EVENTBRIDGE_DETAIL_TYPE_PREFIXEventBridge publisher backendPrepended to every emitted detail-type.
KINESIS_AUTH_MODEiam_roleKinesis publisher backendiam_role / access_key.
KINESIS_REGIONus-east-1Kinesis publisher backendAWS region.
KINESIS_ROLE_ARNKinesis publisher backendIAM role ARN.
KINESIS_ACCESS_KEY_IDKinesis publisher backendStatic credentials when auth_mode=access_key.
KINESIS_SECRET_ACCESS_KEYKinesis publisher backendCompanion to access key id.
KINESIS_STREAM_NAMEkaireon-eventsKinesis publisher backendTarget stream.
KINESIS_PARTITION_KEYKinesis publisher backendField name extracted from event payload as the partition key.

AI providers

The platform uses generic env keys (provider, model, API key, base URL) rather than vendor-native keys. Vendor-native names like the OpenAI or Anthropic API-key environment variables are not read directly — instead, the configured key is passed into the SDK constructor from the generic env key after a Settings-UI override check. Tenant-level overrides in the Settings UI take precedence over env. The four generic AI env keys are dereferenced via a constant map at runtime — the static drift checker can’t trace this indirection, so the keys are documented below as <ParamField> entries (the same is true for several others on this page).
AI_PROVIDER
string
default:"google"
Provider selector. Acceptable values: google, anthropic, openai, ollama, lm_studio, bedrock.
AI_MODEL
string
default:"gemini-2.5-flash"
Model id passed to the provider SDK.
AI_API_KEY
string
API key for the selected provider.
AI_BASE_URL
string
Override base URL — required for Ollama (default http://127.0.0.1:11434/api) and LM Studio.
Env VarDefaultRead byPurpose
ML_WORKER_URLAI analyze endpointPython ml-worker base URL (FastAPI service hosting ONNX scoring + LightGBM training).
ML_WORKER_API_KEYml-worker HTTP clientBearer token for ml-worker requests.
ML_WORKER_TIMEOUT_MSml-worker HTTP clientRequest timeout for ml-worker calls.

Scoring and ONNX

Env VarDefaultRead byPurpose
ONNX_BLOB_STORE_URLONNX BYO model storeONNX BYO model store URL. Supports file:// and s3:// schemes. Unset = inline storage in the model state JSON. Throws on unrecognized schemes.
ONNX_INLINE_BYTES_LIMIT10485760 (10 MB)ONNX BYO model storeThreshold above which model bytes are offloaded to the blob store rather than inlined into the model state.
RETRAIN_EVERY_N100Respond endpointPer-tenant outcome-debounce. Bayesian, Thompson, epsilon-greedy, and online-learner models recompute every Nth outcome. Set to 1 for true real-time.
ATTRIBUTION_TIMEOUT_MS5000Respond endpointTimeout for the recommendation lookup that backs outcome attribution.

Interaction store (Postgres / DynamoDB / Keyspaces / ScyllaDB)

INTERACTION_STORE selects the backend; only the matching group is read.
Env VarDefaultRead byPurpose
INTERACTION_STOREpgDependency-injection containerBackend selector — pg / dynamodb / keyspaces / scylla / cassandra.
SCYLLA_CONTACT_POINTSlocalhostScyllaDB interaction-store backendComma-separated host list.
SCYLLA_LOCAL_DATACENTERdatacenter1ScyllaDB interaction-store backendLocal datacenter for token-aware routing.
SCYLLA_KEYSPACEkaireonScyllaDB interaction-store backendTarget keyspace name.
SCYLLA_USERNAMEScyllaDB interaction-store backendAuth username.
SCYLLA_PASSWORDScyllaDB interaction-store backendAuth password.
SCYLLA_TLS_ENABLEDScyllaDB interaction-store backend"true" to enable TLS.
SCYLLA_REPLICATION_FACTORScyllaDB interaction-store backendKeyspace replication factor (integer).
SCYLLA_CONSISTENCY_LEVELScyllaDB interaction-store backendCassandra/ScyllaDB consistency level (e.g. local-quorum, quorum, one).
SCYLLA_POOL_SIZEScyllaDB interaction-store backendDriver connection pool size.
SCYLLA_REQUEST_TIMEOUT_MSScyllaDB interaction-store backendPer-request timeout.
DYNAMODB_TABLE_NAMEkaireon-interactionsDynamoDB interaction-store backendTarget DynamoDB table.
DYNAMODB_AUTH_MODEiam_roleDynamoDB interaction-store backendiam_role / access_key.
DYNAMODB_REGIONus-east-1DynamoDB interaction-store backendAWS region.
DYNAMODB_ROLE_ARNDynamoDB interaction-store backendIAM role ARN.
DYNAMODB_ACCESS_KEY_IDDynamoDB interaction-store backendStatic credentials.
DYNAMODB_SECRET_ACCESS_KEYDynamoDB interaction-store backendCompanion to access key id.
KEYSPACES_KEYSPACEkaireonAWS Keyspaces interaction-store backendAWS Keyspaces target keyspace.
KEYSPACES_USERNAMEAWS Keyspaces interaction-store backendService-specific credentials username.
KEYSPACES_PASSWORDAWS Keyspaces interaction-store backendService-specific credentials password.
KEYSPACES_REGIONus-east-1AWS Keyspaces interaction-store backendAWS region.
KEYSPACES_AUTH_MODEaccess_keyAWS Keyspaces interaction-store backendaccess_key / iam_role.
KEYSPACES_REQUEST_TIMEOUT_MSAWS Keyspaces interaction-store backendPer-request timeout.

Search index (Postgres / OpenSearch)

Env VarDefaultRead byPurpose
SEARCH_INDEXpgDependency-injection containerBackend selector — pg / opensearch.
OPENSEARCH_NODE_URLhttps://localhost:9200OpenSearch search-index backendOpenSearch node URL.
OPENSEARCH_USERNAMEOpenSearch search-index backendBasic auth username.
OPENSEARCH_PASSWORDOpenSearch search-index backendBasic auth password.
OPENSEARCH_TLS_ENABLEDenabled (skip when "false")OpenSearch search-index backendTLS toggle.
OPENSEARCH_TLS_REJECT_UNAUTHORIZEDenabled (skip when "false")OpenSearch search-index backendCert-validation toggle.
OPENSEARCH_INDEX_PREFIXkaireon-OpenSearch search-index backendPrepended to every index name.
OPENSEARCH_REQUEST_TIMEOUT_MSOpenSearch search-index backendPer-request timeout.
OPENSEARCH_MAX_RETRIESOpenSearch search-index backendSDK-level retry count.
OPENSEARCH_AUTH_MODEbasicOpenSearch search-index backendbasic / iam_role.
OPENSEARCH_REGIONOpenSearch search-index backendAWS region (for iam_role mode against AWS-managed OpenSearch).
OPENSEARCH_ROLE_ARNOpenSearch search-index backendIAM role ARN.
OPENSEARCH_ACCESS_KEY_IDOpenSearch search-index backendStatic credentials.
OPENSEARCH_SECRET_ACCESS_KEYOpenSearch search-index backendCompanion to access key id.

Storage and attachments

Env VarDefaultRead byPurpose
STORAGE_BACKENDlocalAI-import attachment storage factoryAI-import attachment backend — local or s3. Unrecognized values throw.
ATTACHMENT_S3_BUCKETAI-import attachment storage factoryS3 bucket for attachments when STORAGE_BACKEND=s3. Required when backend is s3.
ATTACHMENT_STORAGE_PATH/var/kaireon/attachmentsAI-import attachment storage factoryLocal filesystem base path when STORAGE_BACKEND=local.
AWS_REGIONus-east-1Email + S3 SDK clientsDefault AWS region for SES + S3 SDK clients.

Email and outbound

Env VarDefaultRead byPurpose
SES_FROM_EMAILsupport@kaireonai.comEmail senderFrom-address used by all SES-sent transactional emails.

Governance, approvals, and license

Env VarDefaultRead byPurpose
APPROVAL_MAX_AGE_HOURS168 (7 days)Approvals-expire cron jobPending approvals older than this are auto-expired by the cron sweep. Falls back on invalid input rather than failing.
NEGOTIATION_GLOBAL_KILLAgent-negotiation apply endpointGlobal kill switch for the agent-negotiation apply path. Set to "true" to reject every apply across all tenants.
KAIREON_LICENSE_PRIVATE_KEY
string
RSA private key (PEM, PKCS8) for signing customer licenses. Read by the license-generator script — script-side only, not by the running platform. When unset, the script auto-generates a fresh RSA key pair on each run rather than failing. The matching public key ships embedded in the platform for verification.

Worker, outbox, and seed

Env VarDefaultRead byPurpose
WORKER_CONCURRENCY5Background workerBackground-worker concurrency per process.
WORKER_METRICS_PORT9091Background workerWorker Prometheus exporter listen port (only bound when running the dedicated kaireon-worker container).
WORKER_INPROCESS1 (legacy default, may change to 0 in a future release)Instrumentation bootstrap and background workerWhen 1, the API process also runs the background workers continuously — same Redis queues, same handlers, no extra container. Recommended =0 for free-tier Redis (Upstash 500K-ops/month limit): five idle workers polling Upstash with a blocking pop-and-push burn ~1.3M ops/month with zero queued work, blowing the quota. With =0, schedule POST /api/v1/cron/drain-queues every 5 minutes via cron-job.org / EventBridge / GitHub Actions instead — see worker-mode-and-cron-drain runbook. Set =1 only when you have paid Redis or a dedicated kaireon-worker container with WORKER_INPROCESS=0 on the API.
WORKER_SECRETworker-internalSeed executorWorker→API shared secret (X-Worker-Secret header). The default is a known string — override in production.
_SEED_FROM_WORKERSeed executorInternal flag the seed-executor sets while dispatching its internal HTTP call and deletes once the call returns. Currently has no reader — reserved for future API-side reentrancy detection. Operators should not set this.
OUTBOX_LIVENESS_FILE/tmp/outbox-publisher.aliveOutbox publisher workerLiveness file the outbox publisher touches each loop. K8s liveness probe reads its mtime.
OUTBOX_REAPER_STALENESS_SECONDS300Outbox-reaper cron jobOutbox rows older than this are reset by the reaper sweep. Falls back on invalid input.
OUTBOX_POLL_INTERVAL_MS
number
default:"2000"
Outbox polling interval in milliseconds. Read by the outbox publisher worker via the positive-int env helper.
OUTBOX_SHUTDOWN_DRAIN_TIMEOUT_MS
number
default:"15000"
Max time (ms) to wait for in-flight publishes to drain on shutdown. Read by the outbox publisher worker via the positive-int env helper.

Cron tier

Env VarDefaultRead byPurpose
CRON_SECRETAll /api/v1/cron/* endpointsBearer token gating shared /api/v1/cron/* endpoints (cleanup, dsar-purge, approvals-expire, drain-queues fallback, etc.). One secret covers them all when an internal scheduler is the only caller. For external schedulers (cron-job.org, EventBridge, GitHub Actions), prefer the per-endpoint DRAIN_QUEUES_TOKEN so a leak doesn’t compromise this shared secret.
CRON_TOKENLegacy cron-tick endpoint and drain-queues fallbackBearer token gating the legacy /api/cron/tick endpoint AND accepted as a backwards-compat fallback by drain-queues. Distinct from CRON_SECRET.
DRAIN_QUEUES_TOKEN(falls back to CRON_SECRET then CRON_TOKEN)Drain-queues endpointNarrow token scoped to /api/v1/cron/drain-queues only. Recommended for external schedulers (cron-job.org, EventBridge, GitHub Actions). A leak grants the attacker only this one endpoint instead of the broader /api/v1/cron/* surface. Use a 32-byte random hex value.
DRAIN_QUEUES_RATE_LIMIT12Drain-queues endpointPer-IP sliding-window rate limit (requests per minute) on the drain endpoint. The default fits cron-job.org’s 5-min cadence + retries with headroom; reduce on aggressive abuse. Returns 429 with Retry-After when exceeded.
CRON_ALLOWED_IPS(off — token-only auth)Drain-queues endpointComma-separated IP allowlist for the drain endpoint, matched against the left-most X-Forwarded-For entry. Off by default since cron-job.org doesn’t publish a stable IP list (worker IPs added over time, e.g. 91.99.23.109 in 2025-06, 128.140.8.200 in 2023-05). Set when you’ve pinned the current IP set.

Observability — tracing, metrics, logs

Env VarDefaultRead byPurpose
LOG_LEVELinfoStructured loggerLog level threshold for the structured logger (silent / error / warn / info / debug).
OTEL_EXPORTER_OTLP_ENDPOINTTracing initializerOTLP traces+metrics exporter endpoint. Tracing disabled when unset.
The structured logger pairs with the platform’s per-call error-logging helper. The helper mints a per-call UUID errorId, sanitizes the error message, attaches an optional meta block, and returns the errorId for the caller to surface (HTTP response body, downstream worker telemetry, audit row). Use it for any caught error a SIEM or operator may need to correlate later. Adoption is incremental — the API-route layer and the Outbox publisher worker already mint errorId per failed tick; other workers still emit bare logger error calls and are tracked for migration in the engineering residuals list.

Audit + SIEM

Env VarDefaultRead byPurpose
SIEM_BACKENDAudit SIEM sinkSIEM target — splunk / datadog / elastic. Unset = no SIEM ship-out. Unknown values warn-and-disable.
SIEM_ENDPOINTAudit SIEM sinkSIEM ingest endpoint URL. Required when SIEM_BACKEND is set.
SIEM_API_KEYAudit SIEM sinkBearer token for SIEM ingest (Splunk HEC token, Datadog API key, etc.).
SIEM_SOURCETYPEAudit SIEM sinkSplunk-only sourcetype name.
SIEM_INDEXAudit SIEM sinkElastic-only index name (Splunk uses sourcetype).

Provenance, supply chain, and signing

Env VarDefaultRead byPurpose
GIT_SHADecision provenance endpointBuild-time git SHA stamped into Decision Provenance Bundles. SLSA attestation skipped when missing.
GIT_REPODecision provenance endpointBuild-time git repo URL.
IMAGE_NAMEDecision provenance endpointContainer image name (e.g. ghcr.io/kaireonai/platform).
IMAGE_DIGESTDecision provenance endpointContainer image digest (sha256:…).
SBOM_DIGEST_SHA256Decision provenance endpointHex digest of the published SBOM. Pinned into the SLSA statement.
BUILDER_IDkaireon.platform.runtimeDecision provenance endpointSLSA builder.id.
BUILDER_VERSIONunknownDecision provenance endpointSLSA builder.version.
BUILD_STARTED_ONrequest-time fallbackDecision provenance endpointSLSA metadata.buildStartedOn.
BUILD_FINISHED_ONrequest-time fallbackDecision provenance endpointSLSA metadata.buildFinishedOn.
GITHUB_RUN_IDrequest id fallbackDecision provenance endpointSLSA invocationId.
COSIGN_BINARYcosignSupply-chain Cosign signerCosign CLI binary path. Override when not on PATH.
COSIGN_KEY
string
Cosign-format private key bytes (the contents of cosign.key, not a file path). Cosign itself dereferences the bytes via the env:// URI scheme passed on its CLI; the platform passes the env-var name through. When unset, every /api/v1/decisions/:id/provenance response returns X-Provenance-Signature: unsigned. Required for production. Install via AWS Secrets Manager (cloud) or local key file (self-host) — see Provenance signing install guide.
COSIGN_PASSWORD
string
Passphrase paired with the cosign key. Required when the key was generated with a passphrase (the default for cosign generate-key-pair). Set in env so the cosign subprocess inherits it; the platform itself does not read it.

Webhooks and inbound channels

Env VarDefaultRead byPurpose
WHATSAPP_APP_SECRETWhatsApp inbound webhookMeta WhatsApp app secret used to verify the X-Hub-Signature-256 header on inbound.
WHATSAPP_WEBHOOK_VERIFY_TOKENWhatsApp inbound webhookToken returned during the Meta hub.verify_token handshake.

Multi-region and tenant routing

Env VarDefaultRead byPurpose
KAIREON_REGIONus-east-1Multi-region tenant routerRegion binding for the running process (e.g. us-east-1). Used by the multi-region router to decide whether a tenant request is local or must redirect.
MULTI_REGION_ENABLEDMulti-region tenant router"true" enables multi-region routing.
PLATFORM_OWNER_TENANT_IDPlatform-settings endpointTenant id treated as the platform owner — gates write access to platform-wide settings.
SINGLE_TENANT_MODETenant resolverSingle-tenant build mode toggle (test-asserted; production semantics depend on caller).

MCP server (CLI / SDK side)

Env VarDefaultRead byPurpose
KAIREON_API_URLhttp://localhost:3000MCP server auth layerKaireonAI API base URL the MCP tools call.
KAIREON_API_KEYMCP server auth layerAPI key used by the MCP server when calling v1 routes.
KAIREON_TENANT_IDdefaultMCP server auth layerTenant id sent in the X-Tenant-Id header by MCP tool calls.
MCP_ALLOW_WRITESMCP server tool routerSet to "true" to enable write-mode MCP tools. Read-only by default. See /integrations/mcp for the full tool list.

Flow streaming

Env VarDefaultRead byPurpose
FLOW_STREAMING_ENABLEDFlow streaming feature flagFeature flag for Flow streaming consumers (Kafka / Kinesis / Pulsar). Phase 6.4 — disabled by default; enable only on self-host with a running broker.

External AI/transform endpoints (Flow runtime)

These four endpoint names are declared in the registry the external-model-call transform consults at runtime. The actual process.env lookup happens inside the call helper, dispatched off the registry entry’s name field — the static drift checker can’t trace this through the indirection. Operators must set the corresponding env var before invoking the transform; if unset, the transform throws a missing-endpoint error and the row fails fast.
GEO_RESOLVE_ENDPOINT
string
External geo-resolution model URL.
LANGUAGE_DETECT_ENDPOINT
string
External language-detection model URL.
SENTIMENT_SCORE_ENDPOINT
string
External sentiment-scoring URL.
VECTOR_EMBED_ENDPOINT
string
External embedding-vector URL.

Playground and demo

Env VarDefaultRead byPurpose
PLAYGROUND_MODEAuto-seed dispatcher"true" triggers Starbucks auto-seed for new tenants on registration.
DEMO_MODETenant status endpointDemo-environment toggle. Validated as a boolean by the env validator (must be the literal string "true" or "false").

Python ml-worker

The Python FastAPI service for ML training and ONNX scoring reads only two env vars.
Env VarDefaultRead byPurpose
DATABASE_URLpostgresql://localhost:5432/kaireonPython ml-worker configPostgres connection string for the ml-worker process. Distinct from the platform’s DATABASE_URL only in that it can be overridden per-process.
ML_WORKER_PORT
number
default:"8000"
FastAPI listen port for the Python ml-worker (Python-side; not read by the TypeScript platform).

Test-only

These keys are read only by the test runner. Operators should not set them in production.
TEST_API_KEY
string
default:"test-ch7-key"
Integration-test API key. Read by the decision-flow integration test suite.
TEST_TENANT_ID
string
default:"5a9904b9-4f75-4c4b-a04d-ff826…"
Integration-test tenant id. Read by the decision-flow integration test suite.
TEST_BASE_URL
string
default:"http://localhost:3000"
Base URL used by integration-test HTTP calls. Read by the sample-data end-to-end integration test.
VITEST
string
Set by the Vitest test runner. Production code branches on its presence to skip side effects in tests.

Configuration

Loading order

Next.js picks up env files in this order, last-write-wins (per Next.js framework defaults):
  1. .env
  2. .env.local (gitignored — local overrides)
  3. .env.${NODE_ENV} (e.g. .env.production)
  4. .env.${NODE_ENV}.local
  5. Process environment (process.env)
A repo-root .env.example template ships with the platform — copy it to .env.local for local dev and to a secret manager (Kubernetes Secret, AWS SSM, etc.) for production.

Kubernetes — ConfigMap vs Secret

The shipped Helm chart splits non-secret runtime config from secrets:
  • Non-secret runtime config (NODE_ENV, LOG_LEVEL, EVENT_PUBLISHER, INTERACTION_STORE, SEARCH_INDEX, RLS_AUTO_ENABLE, WORKER_CONCURRENCY, OUTBOX_*, SLOW_API_THRESHOLD_MS, RETRAIN_EVERY_N, OPENSEARCH_INDEX_PREFIX, OPENSEARCH_TLS_ENABLED) lives in the chart’s ConfigMap template.
  • Secrets (DATABASE_URL, REDIS_URL, NEXTAUTH_SECRET, JWT_SIGNING_SECRET, CONNECTOR_ENCRYPTION_KEY*, WEBHOOK_SIGNING_SECRET, API_KEY_PEPPER, WORKER_SECRET, INTERNAL_SERVICE_SECRET, CRON_SECRET, CRON_TOKEN, KAFKA_SASL_PASSWORD, MSK_SASL_PASSWORD, *_SECRET_ACCESS_KEY, *_PASSWORD, SIEM_API_KEY, WHATSAPP_APP_SECRET, plus the KAIREON_LICENSE_PRIVATE_KEY and COSIGN_KEY documented above) live in the chart’s Secret template.
See /self-host/deploy/helm-reference for the full chart values map.

Rotation guidance

VariableRotation strategy
CONNECTOR_ENCRYPTION_KEYSet the new key as CONNECTOR_ENCRYPTION_KEY + bump CONNECTOR_ENCRYPTION_KEY_VERSION. Keep the old key as CONNECTOR_ENCRYPTION_KEY_PREVIOUS + matching _PREVIOUS_VERSION until all rows are re-encrypted by a background sweep.
JWT_SIGNING_SECRETRotate inside a maintenance window. All issued tokens become invalid the moment the new secret takes effect.
API_KEY_PEPPERCannot be rotated without invalidating every stored API-key hash. Plan for a hard cutover.
WEBHOOK_SIGNING_SECRETRotate by overlapping — accept either old or new for the rotation window via a transitional verifier (currently single-key; overlap window is an open op).
NEXTAUTH_SECRETLogs out every active session. Rotate during low traffic.
Cloud provider keys (AWS_*, *_ACCESS_KEY_ID)Rotate through the cloud provider’s secret manager; pod restart picks up the new value (no in-process rotation).

Honest limits

  • TS-only vs Python ml-worker — Of the documented variables, only DATABASE_URL is read by both the TypeScript platform and the Python ml-worker. The ml-worker port (documented above as a <ParamField>) is Python-only. The platform talks to the ml-worker via ML_WORKER_URL + ML_WORKER_API_KEY (HTTP); the two processes do not share env vars beyond DATABASE_URL.
  • Once-at-boot vs per-request reads — Most env vars are read once during module load (DI container, database pool, AI provider config, encryption keys). A handful are read per-request: NEGOTIATION_GLOBAL_KILL and ALLOW_UNSIGNED_WEBHOOKS. For the rest, a process restart is required after changing the value.
  • Deprecated / soft-deprecatedCRON_TOKEN is the legacy auth token for /api/cron/tick. New cron endpoints under /api/v1/cron/* use CRON_SECRET; both are kept until the legacy tick is removed.
  • Internal-only flags — operators should not set_SEED_FROM_WORKER is set by the seed-executor itself before its internal HTTP call. Setting it manually breaks reentrancy detection.
  • Test-only flags in productionMFA_ENFORCEMENT_DISABLED, ALLOW_UNSIGNED_WEBHOOKS, plus the four test-only <ParamField> entries above (test API key, tenant id, base URL, and the Vitest runner-detection flag) must not appear in any production environment. ALLOW_UNSIGNED_WEBHOOKS is hard-blocked when NODE_ENV=production; the others are not enforced — operator discipline only.
  • License private key is script-side — Read only by the license-generator script, never by the running platform (see the KAIREON_LICENSE_PRIVATE_KEY <ParamField> above). The platform verifies licenses with the matching public key embedded in source. When unset, the script auto-generates a fresh RSA key pair on each run rather than failing.
  • AI provider env keys are tenant-overridable — Tenant-level AI settings in the Settings UI take precedence over the four AI-provider env keys documented as <ParamField> entries above (provider, model, API key, base URL). The env vars are only the fallback when no DB-level setting is configured.
  • Environment variables not yet wired for the AI sidebar metadata — Two AI-sidebar reserved keys are declared in the AI-env constant map but currently have no read in the platform. They are reserved keys; <ParamField> entries for both follow.
AI_SIDEBAR_ENABLED
boolean
Reserved AI-sidebar feature flag. No reader in the platform yet.
AI_RATE_LIMIT_PER_MINUTE
number
Reserved AI-sidebar rate-limit knob. No reader in the platform yet.