Configuration
Configure durable backends, security, sidecars, capacity, and feature switches.
Deeplinq reads process environment variables. It does not auto-load .env
files. Use your deployment platform's secret manager and environment injection.
Configuration is fail-closed: malformed values, incomplete credential pairs, unknown DSN parameters, unsafe production switches, and invalid numeric ranges refuse startup.
Production mode
Set:
ENVIRONMENT=productionProduction rejects in-memory fallback and development fixtures. ENVIRONMENT,
ENV, and GO_ENV are aliases; the first set value wins.
Durable backends
| Variable | Purpose |
|---|---|
DATABASE_MIGRATION_URL | Schema-owner DSN used only for startup migrations |
DATABASE_APP_URL | engine_app DSN for tenant requests under forced RLS |
DATABASE_SYSTEM_URL | engine_system DSN for workers and control plane |
S3_URL | Source and derived object storage |
VECTOR_URL | Weaviate retrieval storage |
REDIS_URL | Durable admin-session validity |
The three PostgreSQL URLs are all-or-nothing and must name distinct roles.
DATABASE_URL is a shared development/test fallback and is not a production
substitute.
DSN examples:
postgres://engine_app:pass@db:5432/deeplinq?sslmode=require
s3://ACCESS:SECRET@storage.example.com/deeplinq?region=us-east-1
weaviates://:API_KEY@weaviate.example.com:443?hybrid_alpha=0.75
rediss://:PASSWORD@redis.example.com:6379/0Percent-encode reserved characters in DSN credentials. URL fragments and unknown query parameters are rejected.
Root security
| Variable | Purpose | Default |
|---|---|---|
SECRETS_KEY | Versioned AES-256-GCM keyring for sealed credentials and admin-cookie key derivation | required in production |
AUDIT_ANCHOR_KEY | HMAC key for signed audit-chain anchors | required in production |
ADMIN_USERNAME, ADMIN_PASSWORD | Break-glass browser and Basic-auth admin | disabled unless both set |
ADMIN_UI | Embedded console switch; 0 disables | on when admin credentials exist |
ADMIN_SESSION_TTL | Browser session lifetime | 12h |
ADMIN_SESSION_REFRESH | Maximum age of a non-break-glass session's authorization snapshot before re-authentication | 15m |
OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET | Console SSO relying party; set all three or none | disabled |
OIDC_GROUPS_CLAIM | ID-token claim read for console role mapping | groups |
OIDC_ROLE_MAPPING | JSON allowlist from claim value to engine role; only platform-admin is accepted | required with console SSO |
TRUSTED_PROXY_CIDRS | Proxies trusted to supply client IP for login throttling | unset |
AUTH_FAILURES_PER_CLIENT, AUTH_FAILURES_GLOBAL | Authentication failures allowed per one-minute client and process-wide window | 10, 200 |
BILLING_TOKEN | Reserved billing-service credential | disabled |
MEMORY_TOKEN | Memory-sidecar credential toward the engine | disabled |
TENANT_PROVISIONER_CLIENT_ID, TENANT_PROVISIONER_CLIENT_SECRET | The engine's own standing identity-provider service account. Used to run per-org identity setup (/v1/admin/orgs/{id}/identity-setup) and to reset the console operator's password, both with no operator-supplied credential | disabled — the setup route refuses with a precondition until both are set, and the operator password reset fails with a 401 from the provider |
TENANT_OIDC_ISSUER, TENANT_OIDC_AUDIENCE (was TENANT_OIDC_PROJECT_ID, still read) | Override only. By default the tenant issuer and project are read from the console's own single sign-on configuration, set through the admin console — set these only if tenants authenticate against a different identity provider than the console does | — |
PLATFORM_ROLES_CLAIM / PLATFORM_EXTRA_SCOPES | The platform identity provider's vocabulary: an RFC 6901 JSON Pointer to the claim carrying OPERATOR authority (default /groups), and the provider-specific scopes advertised in the RFC 9728 document (default organization:*). Both default to Keycloak's shapes; set them when the platform provider is something else. A tenant's roles are never read from a claim under any setting. | |
IDP_ALLOW_PRIVATE | Lets the identity-provider metadata and JWKS fetcher reach private and loopback addresses. Off by default. Set it when the identity provider runs on the same private network as the engine, which is the common self-hosted topology — unlike the other *_ALLOW_PRIVATE guards this one is legitimate in production. Link-local and cloud-metadata addresses stay refused in every mode. | |
TENANT_OIDC_JWKS_CACHE | File mirror used to verify known signing keys through an identity-provider outage and after a cold start | memory-only cache |
TENANT_ENDUSER_ACCEPTANCE_AGE | Maximum age accepted for an end-user token, independent of its expiry | 1h |
PRINCIPAL_LINKING_ENABLED | Exact 1 enables first-sight resolution to engine principals | disabled |
PRINCIPAL_MAX_PER_ORG | Just-in-time principal enrollment ceiling; 0 is unbounded | 10000 |
SECRETS_KEY accepts one base64 32-byte key or a rotation keyring such as:
2:<new-base64-key>,1:<old-base64-key>The highest version seals new values; all listed versions may decrypt.
Optional sidecars
| Variable | Capability when set |
|---|---|
DOCLING_URL | Real document extraction and chunking |
CRAWLER_URL | JavaScript-capable website crawling |
CRAWLER_ALLOWED_HOSTS | Production hostname allowlist for crawling |
DUCKDB_URL | CSV/XLSX ingestion and Text-to-SQL |
MEMORY_URL | Optional Graphiti compatibility sidecar; absence uses native memory |
MEMORY_BACKEND | Explicit native, graphiti, or off authority selection |
MEMORY_SIDECAR_TOKEN | Distinct engine-to-memory credential |
GUARDRAIL_URL, GUARDRAIL_TOKEN | Environment-provisioned safety classifier |
Do not reuse MEMORY_TOKEN as MEMORY_SIDECAR_TOKEN; they protect opposite
trust directions.
Product and capacity controls
| Variable | Default | Purpose |
|---|---|---|
MAX_INFLIGHT_PER_ORG | 16 | Concurrent model calls before immediate 429 |
AUTH_FAILURES_PER_CLIENT | 10 | Authentication-failure budget per client and minute |
AUTH_FAILURES_GLOBAL | 200 | Process-wide authentication-failure budget per minute |
INGEST_WORKERS | 2 | Durable ingestion worker concurrency |
JOB_MAX_EXECUTION_TIME | 30m | One worker-attempt ceiling |
JOB_RESCUE_STUCK_AFTER | 31m | Abandoned-work recovery horizon; must be at least the execution ceiling |
KNOWLEDGE_AGENT_ENABLED | 0 | Exact 1 enables knowledge-agent runtime |
GUARDRAIL_MODEL | llama-prompt-guard-2-86m | Model sent to the environment guardrail endpoint |
SCHEDULE_ORG_CAP | 1000 | Active schedule ceiling |
SCHEDULE_EVENTS_RETENTION_DAYS | 90 | Terminal schedule-event retention |
SCHEDULE_SWEEP_INTERVAL | 1m | Due-work, timeout, recovery, and pruning sweep cadence |
PROJECTS_ORG_CAP | 1000 | Project ceiling |
DATASETS_ORG_CAP | 1000 | Standalone dataset ceiling |
TEAMS_ORG_CAP | 200 | Team ceiling |
TEAM_MEMBERS_CAP | 1000 | Members per team |
AGENTS_ORG_CAP | 500 | Agent ceiling |
CONNECTIONS_INVOKE_CONCURRENCY | 4 | Concurrent connection tools per org |
CHUNK_TOKENIZER | embedding-model mapping | Tokenizer used by Docling for chunk budgets; changing it requires re-ingestion |
RERANK_CANDIDATES | 30 | Hybrid candidates scored before trimming to the retrieval result set |
INGEST_EMBED_BATCH | 16 | Chunks per embedding request |
INGEST_STATUS_TIMEOUT | 5s | Deadline for detached status and run-accounting writes |
INGEST_MAX_RETRIES | 5 | Shared retry ceiling for failed and stranded document work |
INGEST_RUN_RETENTION_DAYS | 90 | Finished ingestion-run retention |
BILLING_HOLD_SWEEP_INTERVAL | 5m | Expired authorization-hold release cadence |
BILLING_HOLD_RETENTION_DAYS | 90 | Settled billing-hold retention; active holds are never age-pruned |
AGENT_RUN_MAX_TURNS | 16 | Default durable-run turn bound |
AGENT_RUN_WALL_CLOCK_MINUTES | 10 | Default run deadline |
AGENT_RUN_APPROVAL_TIMEOUT_HOURS | 24 | Approval parking limit |
AGENT_RUN_DEFAULT_BUDGET_MICRO_USD | 0 | Default run budget; 0 means no dedicated cap |
AGENT_RUN_TOOL_RESULT_MAX_BYTES | 262144 | Maximum result passed back to a model |
Capacity values have validated inclusive ranges. Tune from observed production load, not by disabling the ceilings.
Conversations and memory
| Variable | Default |
|---|---|
CONVERSATION_COMPACT_TRIGGER_TOKENS | 24000 |
CONVERSATION_KEEP_VERBATIM_TURNS | 20 |
CONVERSATION_COMPACT_MODEL | auto |
MEMORY_BLOCK_TOKEN_BUDGET | 1000 |
MEMORY_TIMEOUT | 120s |
MEMORY_SEARCH_TIMEOUT | 5s |
Networking and telemetry
| Variable | Purpose |
|---|---|
ADDR | HTTP listen address, default :8080 |
HTTP_BODY_READ_TIMEOUT | Request-body deadline without cutting off SSE |
PUBLIC_URL | HTTPS base used to build OAuth callbacks |
PROVIDER_REQUEST_TIMEOUT_SECONDS | Provider wall-clock timeout, including queue wait; default 900, range 30–1800 |
LOG_LEVEL | debug, info, warn, or error |
OTEL_EXPORTER_OTLP_ENDPOINT | Enables OpenTelemetry export |
OTEL_EXPORTER_OTLP_PROTOCOL | OTLP transport, default http |
OTEL_SERVICE_NAME | Trace service, default deeplinq-engine |
Development-only switches
SEED, FAKE_LLM, FAKE_KNOWLEDGE_AGENT_SCENARIO,
FAKE_LLM_RECORDER_URL, CRAWLER_ALLOW_PRIVATE, WEBHOOK_ALLOW_HTTP,
WEBHOOK_ALLOW_PRIVATE, CONNECT_ALLOW_HTTP, MCP_ALLOW_PRIVATE,
IDP_ALLOW_HTTP_ISSUERS,
CONNECT_PROVIDER_ENDPOINT_OVERRIDE, and
CONNECT_PROVIDER_ENDPOINT_OVERRIDE_OUTLOOK are rejected in production.
IDP_ALLOW_HTTP_ISSUERS admits plain http:// issuers at external
application registration, for a development console running beside the engine
with no TLS — it is deliberately separate from IDP_ALLOW_PRIVATE, which
production legitimately sets.
Never commit environment files, credentials, or generated secret values.