Configuration Reference
This document summarizes the most important runtime configuration knobs in OpenKeep.
The source of truth for config parsing is:
packages/config/src/index.ts
The starter environment file is:
.env.example
Core App
NODE_ENV: runtime modePORT: API portAPI_BASE_URL: base URL used by web and client integrationsLOG_LEVEL: application logger level
Docs Site and Typesense DocSearch
DOCS_SITE_URL: canonical docs URL used when building the Docusaurus siteTYPESENSE_COLLECTION_NAME: collection alias used by the docs UI and scraperTYPESENSE_ADMIN_API_KEY: admin key used by the self-hosted Typesense node and scraperTYPESENSE_PUBLIC_HOST: browser-reachable Typesense hostname for the docs UITYPESENSE_PUBLIC_PORT: browser-reachable Typesense port for the docs UITYPESENSE_PUBLIC_PROTOCOL: browser-reachable Typesense protocol for the docs UIDOCSEARCH_START_URL: scraper start URL, defaults to the compose-hosted docs serviceDOCSEARCH_SITEMAP_URL: scraper sitemap URL, defaults to the compose-hosted docs sitemapDOCSEARCH_STOP_URL: optional URL pattern to exclude from scraping
Operational notes:
- the docs container uses a search-only key generated at runtime by
typesense-bootstrap; that key is not stored in.env TYPESENSE_PUBLIC_*values must point to an address the browser can reach, not the internal Docker service name
Database and Queue
DATABASE_URL: PostgreSQL connection stringPG_BOSS_SCHEMA: pg-boss schema name
Operational note:
- API, worker, and migrations all depend on a correct
DATABASE_URL
Object Storage
MINIO_ENDPOINTMINIO_PORTMINIO_USE_SSLMINIO_ACCESS_KEYMINIO_SECRET_KEYMINIO_BUCKET
These settings control access to the S3-compatible object store used for binaries and derived artifacts.
Authentication
JWT_ACCESS_SECRETJWT_REFRESH_SECRETACCESS_TOKEN_TTLREFRESH_TOKEN_TTLOWNER_EMAILOWNER_PASSWORDOWNER_NAME
Operational note:
- both JWT secrets must be long, unique, and environment-specific
OWNER_*values matter most for initial bootstrap and seed behavior
Bootstrap and External Init
SKIP_EXTERNAL_INIT
When enabled, startup initialization that touches external systems is skipped. This is mainly useful for tests and special development scenarios, not for normal production operation.
Processing Mode
PROVIDER_MODE
Current value is still exposed in configuration and UI, but the more important practical control points today are parse-provider and embedding-provider selection.
Parse Provider Selection
ACTIVE_PARSE_PROVIDERFALLBACK_PARSE_PROVIDER
Supported parse provider ids:
local-ocrgoogle-document-ai-enterprise-ocrgoogle-document-ai-gemini-layout-parseramazon-textractazure-ai-document-intelligencemistral-ocr
Fallback provider behavior:
- only used on hard parse failures
- not intended as dynamic quality arbitration between providers
OCR and Parse Limits
OCR_LANGUAGESPARSE_PROVIDER_TIMEOUT_SECONDSPARSE_PROVIDER_MAX_PAGESPARSE_PROVIDER_MAX_BYTES
These determine practical upper bounds and timeout behavior for document parsing.
Review and Retry Thresholds
REVIEW_CONFIDENCE_THRESHOLDOCR_EMPTY_TEXT_THRESHOLDPROCESSING_RETRY_LIMITPROCESSING_RETRY_DELAY_SECONDSPROCESSING_STALE_MINUTES(default30)ANSWER_MIN_CHUNK_SCORE(default0.4)
These values affect:
- review routing sensitivity
- empty-text handling
- retry count for processing jobs
- retry backoff timing
- stale-processing recovery: documents stuck in
processinglonger thanPROCESSING_STALE_MINUTESwithout an active queue job are markedfailed(lastProcessingError = "stale_processing_reaped") by a periodic worker reaper and can then be reprocessed - RAG answer relevance: chunks below
ANSWER_MIN_CHUNK_SCOREare not fed to the LLM; a near miss (within 0.1 below the threshold) answers low-confidence from the top 3 chunks, anything worse returns an honest, localized "insufficient evidence" refusal. Cosine-score distributions differ per embedding provider, so tune this per provider.
API Limits
MAX_UPLOAD_BYTESSEARCH_DEFAULT_PAGE_SIZESEARCH_MAX_PAGE_SIZE
These control upload size and search pagination limits.
Embedding and LLM Providers
ACTIVE_CHAT_PROVIDERACTIVE_EMBEDDING_PROVIDEROPENAI_API_KEYOPENAI_MODELOPENAI_EMBEDDING_MODELGEMINI_API_KEYGEMINI_MODELGEMINI_EMBEDDING_MODELVOYAGE_API_KEYVOYAGE_API_BASE_URLVOYAGE_EMBEDDING_MODELMISTRAL_API_KEYMISTRAL_MODELMISTRAL_EMBEDDING_MODELMISTRAL_API_BASE_URL(defaulthttps://api.mistral.ai): base URL for all Mistral surfaces — chat, embeddings, files, OCRMISTRAL_OCR_BASE_URL(deprecated): OCR-only override; falls back toMISTRAL_API_BASE_URLwhen unset. Chat and embeddings no longer read this variable.MISTRAL_OCR_MODELMISTRAL_OCR_INCLUDE_BLOCKS(defaulttrue): paragraph blocks with real bounding boxesMISTRAL_OCR_TABLE_FORMAT(markdown|none, defaultmarkdown)MISTRAL_OCR_CONFIDENCE_GRANULARITY(page|word|none, defaultpage); pages below the confidence threshold flag the document for review (ocr_low_confidence)MISTRAL_OCR_EXTRACT_HEADER_FOOTER(defaulttrue): headers/footers become blocks taggedmetadata.regionso boilerplate can be deprioritizedMISTRAL_OCR_UPLOAD_STRATEGY(auto|inline|files, defaultauto): inline base64 below ~8MB, Files API (upload + signed URL, deleted in a finally) above — base64 inflates payloads ~33% and large inline bodies risk request-size rejectionsMISTRAL_OCR_DOCUMENT_ANNOTATIONS(defaultfalse): request a structured document annotation inside the OCR call and feed it to the extraction pipeline as a hint — skips the routing, title/summary, and (when complete) typed-extraction LLM calls. See Agentic Document Intelligence.
Timeouts and resilience:
LLM_TIMEOUT_SECONDS(default45): hard timeout for non-streaming LLM completions; 429/5xx responses are retried once before giving upLLM_STREAM_TIMEOUT_SECONDS(default120): hard timeout for streaming completions, applied once across the whole provider fallback chain (not per provider)- streaming answers fail over to the next configured provider when a provider fails before its first token; after the first token the error is surfaced instead (no silent mid-answer restarts)
- closing the client (SSE disconnect) aborts the upstream LLM request; SSE responses send comment-frame heartbeats every 15s so idle proxies keep the connection open
Operational notes:
- chat uses the configured
ACTIVE_CHAT_PROVIDERfirst when set; the remaining configured providers stay available as failover candidates (order:openai->gemini->mistral). The agentic extraction pipeline and correspondent resolution derive from the same order instead of hardcoding their own. - semantic indexing is effectively off until
ACTIVE_EMBEDDING_PROVIDERand the matching provider config are set - agentic document intelligence becomes available when at least one supported LLM provider is configured
Cloud Parse Providers
Google Cloud Document AI
GOOGLE_CLOUD_PROJECT_IDGOOGLE_CLOUD_LOCATIONGOOGLE_CLOUD_ACCESS_TOKENGOOGLE_CLOUD_SERVICE_ACCOUNT_JSONGOOGLE_DOCUMENT_AI_ENTERPRISE_PROCESSOR_IDGOOGLE_DOCUMENT_AI_GEMINI_PROCESSOR_ID
Amazon Textract
AWS_REGIONAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_SESSION_TOKEN
Azure AI Document Intelligence
AZURE_DOCUMENT_INTELLIGENCE_ENDPOINTAZURE_DOCUMENT_INTELLIGENCE_API_KEY
Watch Folder
WATCH_FOLDER_PATH
This must be configured for watch-folder scan operations to work.
If it is missing, /api/archive/watch-folder/scan will fail with a configuration error.
Practical Configuration Profiles
Minimal Local OCR Setup
Use:
ACTIVE_PARSE_PROVIDER=local-ocr- no embedding provider
- no cloud AI provider
This is the simplest archive mode.
Search-Enabled Setup
Use:
- one parse provider
- one embedding provider
This enables semantic search and chunk embedding.
Full Intelligence Setup
Use:
- one parse provider
- one embedding provider
- one or more LLM providers
This enables semantic search plus the full agentic extraction and AI assistance surface.
Related Documents
Deadlines and Email Digest
ARCHIVE_TIMEZONE: IANA zone date-only deadlines are interpreted in; unset means the server's own zoneDEADLINE_UPCOMING_DAYS: how many days ahead the "upcoming" window arms (default 7)SMTP_HOST/SMTP_PORT/SMTP_SECURE/SMTP_USER/SMTP_PASSWORD/SMTP_FROM: the email channel; without host and from-address the digest reports itself unconfigured instead of erroringEMAIL_DIGEST_CRON: daily digest schedule (default0 7 * * *), evaluated inARCHIVE_TIMEZONEPUBLIC_URL: absolute web-app base URL used for links in outbound email
Email Ingestion (IMAP)
IMAP_HOST/IMAP_PORT/IMAP_SECURE/IMAP_USER/IMAP_PASSWORD: the archive mailbox; without host+user+password the channel is offIMAP_FOLDER: mailbox folder to poll (defaultINBOX)EMAIL_INGEST_CRON: poll schedule (default*/5 * * * *)EMAIL_INGEST_ALLOWED_SENDERS: comma-separated addresses or whole domains allowed to feed the archive; empty accepts everyone, reasonable only while the address is privateEMAIL_INGEST_LOG_LIMIT: rejected/skipped ledger rows kept before pruning (default 500); imported rows are never pruned — they are the idempotency ledger
Operational notes:
- use a dedicated mailbox: the poller flags handled messages as read, so a human reading the same mailbox hides messages from it
MAX_UPLOAD_BYTESbounds attachment size for email ingestion too