Configuration Guide & Reference¶
Cortex provides a unified, multi-format configuration architecture supporting YAML, JSON, TOML, and Environment Variables (CORTEX_*).
1. Precedence Model¶
Configuration values are resolved strictly in the following order (highest precedence wins):
┌───────────────────────────────────────────────────────────┐
│ 1. Explicit CLI Flags (e.g. --config, --mode, --token) │
├───────────────────────────────────────────────────────────┤
│ 2. Environment Variables (CORTEX_* / Process Environment) │
├───────────────────────────────────────────────────────────┤
│ 3. Active Configuration File (cortex.yaml, .json, .toml) │
├───────────────────────────────────────────────────────────┤
│ 4. Built-in Compiled Defaults (Zero-Bloat Baseline) │
└───────────────────────────────────────────────────────────┘
- Environment Variable Matching: Viper automatically translates dot-notated paths to uppercase snake_case prefixed by
CORTEX_(e.g.llm.provider$\rightarrow$CORTEX_LLM_PROVIDER,http.port$\rightarrow$CORTEX_HTTP_PORT). - Environment Overrides: An environment variable always overrides the corresponding value in the configuration file or TUI state.
- Zero-Bloat Model: The configuration manager automatically trims default and empty sections when writing to disk, keeping local configuration files clean (typically under 15 lines) and preventing serialization of internal SQLite pragmas or server-specific storage parameters.
2. Configuration Methods¶
A. Environment Files (.env / Docker)¶
Copy the provided template to configure containers, CI/CD, or local deployments:
cp .env.example .env
B. CLI Configuration Commands¶
Programmatically inspect and update configuration keys:
# Initialize a clean configuration file
cortex config init --format=yaml --force
# Inspect active configuration values
cortex config get ai.provider
cortex config get http.port
# Update configuration properties
cortex config set ai.provider ollama
cortex config set ai.model qwen3-embedding:8b
cortex config set http.port 7438
# Interactive setup wizard and file path lookup
cortex config wizard
cortex config path
C. CLI Authentication Management¶
# Authenticate session with Bearer Token
cortex auth login --token=ctx_secret_token_123456
# Inspect active authentication status and subject identity
cortex auth status
# Logout and clear credentials
cortex auth logout
D. TUI Visual Center¶
Launch the interactive Terminal User Interface:
cortex tui
- Press
tto cycle dynamic themes (Dark, Light, High Contrast). - Press
Lto open the authentication modal. - Navigate to Local settings to configure database, HTTP, MCP, and replication parameters interactively.
3. Comprehensive Configuration Reference¶
Infrastructure & Server Storage¶
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
server.storage.driver |
CORTEX_SERVER_STORAGE_DRIVER |
postgres |
Persistence driver: postgres (server) or sqlite (local). |
server.storage.dsn |
CORTEX_SERVER_STORAGE_DSN |
(None) | Non-privileged runtime PostgreSQL DSN (NOSUPERUSER, NOBYPASSRLS). |
server.storage.migration_dsn |
CORTEX_SERVER_STORAGE_MIGRATION_DSN |
(None) | Privileged migration DSN. Applied during startup preflight and closed immediately. |
server.storage.max_conns |
CORTEX_SERVER_STORAGE_MAX_CONNS |
10 |
Maximum open database pool connections. |
Single-Tenant Server Identity & Privileges¶
Server mode (cortex --mode server) runs one self-hosted tenant. Every request is
authenticated as a single synthetic constant principal assembled from configuration,
and tenant/workspace scope is a configuration constant that client input can never
override.
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
server.bootstrap_development |
CORTEX_SERVER_BOOTSTRAP_DEVELOPMENT |
false |
Development-only mode that reuses the runtime DSN when a dedicated migration role is not separated. |
server.tenant_id |
CORTEX_SERVER_TENANT_ID |
(None) | Configured tenant UUID (UUIDv4) bound to the synthetic principal. Required: startup fails closed when empty. |
server.workspace_id |
CORTEX_SERVER_WORKSPACE_ID |
(None) | Configured default workspace UUID (UUIDv4) bound to the synthetic principal. Required: startup fails closed when empty. |
server.principal_subject |
CORTEX_SERVER_PRINCIPAL_SUBJECT |
(None) | Subject UUID of the synthetic constant principal bound to every authenticated request. Required: startup fails closed when empty. |
server.roles |
CORTEX_SERVER_ROLES |
[] |
Comma-separated roles for the configured principal (the synthetic server principal carries owner). |
server.scopes |
CORTEX_SERVER_SCOPES |
[] |
Comma-separated authorized scopes (e.g. workspaces:read,workspaces:write). |
server.grant_digest |
CORTEX_SERVER_GRANT_DIGEST |
"" |
Deprecated. Retained for backward compatibility only; grant integrity is calculated dynamically by PostgreSQL in cortex_bootstrap_service_principal. |
server.grant_version |
CORTEX_SERVER_GRANT_VERSION |
0 |
Deprecated. Retained for backward compatibility only; the grant version is provisioned dynamically by PostgreSQL. |
A configuration file that still carries the removed multi_tenant key loads without
error: the key is unknown to the schema, no code path branches on it, and it is dropped
by the zero-bloat writer on the next save.
HTTP API, MCP Transport & Logging¶
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
http.enabled |
CORTEX_HTTP_ENABLED |
true |
Enables HTTP REST API (/api/*) and Streamable HTTP MCP (/mcp). |
http.host |
CORTEX_HTTP_HOST |
localhost |
Network interface to bind (0.0.0.0 for containers/all interfaces). |
http.port |
CORTEX_HTTP_PORT |
7438 |
Port to listen on. (Note: CORTEX_PORT is intentionally rejected). |
http.token |
CORTEX_HTTP_TOKEN |
"" |
Static Bearer token. Authenticates local HTTP/MCP and, in server mode, is the single credential verified on every request before the synthetic constant principal is bound. Required for non-loopback bindings. |
http.allowed_origins |
CORTEX_HTTP_ALLOWED_ORIGINS |
[] |
Comma-separated list of allowed CORS browser origins. |
logging.level |
CORTEX_LOGGING_LEVEL |
info |
Log verbosity: debug, info, warn, error. |
logging.format |
CORTEX_LOGGING_FORMAT |
json |
Log output format: json, text, plain. |
Embedded Web UI (web.*)¶
Cortex serves the compiled Next.js operator UI from the same binary and the same
HTTP listener as the API: there is no separate web container and no second port.
The web.* namespace overrides that surface; when a value is unset it inherits the
HTTP listener (http.host / http.port), so a default configuration mounts the UI
wherever the API listens. See embedded-web.md for the key
lifecycle, at-rest format, and rotation semantics.
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
web.enabled |
CORTEX_WEB_ENABLED |
true |
Enable the embedded web UI. Only an explicit false disables it, and the code-owned default is never written back to a saved config file. |
web.host |
CORTEX_WEB_HOST |
inherits http.host (localhost) |
Listener host for the web surface. Empty inherits http.host; accepts an IP literal or bare hostname (no scheme, path, userinfo, or port). |
web.port |
CORTEX_WEB_PORT |
inherits http.port (7438) |
Listener port for the web surface. 0 inherits http.port; valid range 1–65535. |
web.key_file |
CORTEX_WEB_KEY_FILE |
~/.cortex/web.key |
Path to the embedded web access-key store. Empty or blank resolves to the default inside the Cortex config directory. |
| (Credential) | CORTEX_WEB_KEY |
"" |
Pinned web access key, environment-only. Replaces the key-file lifecycle entirely: no key is minted, no file is read or written, and verification uses the pinned value in memory. Must match the minted format (ctx_ + 43 base64url characters); an invalid value aborts startup (fail closed) instead of silently regenerating. While pinned, cortex web key show reports the pin and cortex web key regenerate refuses (file rotation is disabled). |
The web access key is an independent ctx_-prefixed credential: it is never used
as, defaulted to, or derived from http.token, and the /api/* endpoints never
accept it. On first boot Cortex mints the key and prints the plaintext exactly once
(or, when CORTEX_WEB_KEY is pinned, verification uses the pinned value and no
plaintext is ever printed);
afterwards the plaintext is never shown again. Manage it with
cortex web key show and cortex web key regenerate (both accept
--key-file PATH).
Standardized AI Configuration (Strict Separation)¶
Cortex strictly separates configuration and API credentials between Embeddings and LLM so they never unintentionally cross-pollinate or override each other:
1. Embedding Tier: CORTEX_EMBEDDING_* / CORTEX_EMBEDDING_API_KEY for semantic search and vector indexing.
2. LLM Tier: CORTEX_LLM_* / CORTEX_LLM_API_KEY for agent reasoning, synthesis, and extraction.
3. Strict Decoupling: Third-party vendor variables (such as OPENAI_API_KEY, ANTHROPIC_API_KEY), legacy variables (such as CORTEX_SEARCH_EMBEDDING_*), and unified CORTEX_AI_* variables are not accepted. Each subsystem requires its own explicit Cortex credential.
Embeddings (Semantic Search & Vector Indexing)¶
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
embedding.provider / search.embedding_provider |
CORTEX_EMBEDDING_PROVIDER |
(Unset ⇒ embeddings disabled) | Embedding provider preset: none (disabled), ollama, openai, openai-compatible. Any other value is rejected at configuration load. |
embedding.model / search.embedding_model |
CORTEX_EMBEDDING_MODEL |
"" (provider default) |
Embedding model identifier. Provider defaults: nomic-embed-text (ollama), text-embedding-3-small (openai / openai-compatible). |
embedding.base_url / search.embedding_base_url |
CORTEX_EMBEDDING_BASE_URL |
"" (provider default) |
Endpoint override. Defaults: http://localhost:11434 (ollama), https://api.openai.com/v1 (openai); explicit URL required for openai-compatible. |
| (Credential) | CORTEX_EMBEDDING_API_KEY |
"" |
Embedding API credential, environment-only. Never read from YAML/JSON/TOML files. |
search.ollama_auto_start |
CORTEX_SEARCH_OLLAMA_AUTO_START |
false |
Automatically starts local Ollama daemon when needed. |
search.fusion_k |
CORTEX_SEARCH_FUSION_K |
60 |
Reciprocal Rank Fusion (RRF) rank constant. |
When no embedding provider is configured (unset or none), no embedder is
constructed: search runs on FTS5/BM25 alone, the embedding outbox worker is not
started, and the local save path stays byte-for-byte identical to a
zero-embedding build.
Embedding providers¶
search.embedding_provider accepts exactly four presets. Unknown values fail
closed at load time (invalid search.embedding_provider) instead of silently
disabling embeddings.
| Provider | Modes | Default base URL | Default model | Credential |
|---|---|---|---|---|
none / (unset) |
local, server | — | — | — |
ollama |
local, server | http://localhost:11434 |
nomic-embed-text (768 dims) |
none |
openai |
local, server | https://api.openai.com/v1 |
text-embedding-3-small (1536 dims) |
CORTEX_EMBEDDING_API_KEY |
openai-compatible |
server only | (none — explicit URL required) | text-embedding-3-small unless search.embedding_model is set |
CORTEX_EMBEDDING_API_KEY |
ollama(local default) — the local-mode embedding provider: it dials the loopback daemon and needs no credential.search.ollama_auto_startcan launch it, andsearch.embedding_base_urloverrides the endpoint.openai— first-party OpenAI embeddings over{base_url}/embeddingswith Bearer authentication; the key comes only fromCORTEX_EMBEDDING_API_KEY.openai-compatible(server-mode, Tier 2) — any OpenAI-compatible/embeddingsendpoint. The local composition refuses it fail-closed (no embedder, no outbound dial); it is constructed only in server mode through the outbound policy allowlist. It requires an explicitsearch.embedding_base_urlbecause a generic compatible endpoint has no safe default host — a missing URL fails at construction (embedding: openai-compatible requires an explicit base URL).none— embeddings disabled; native BM25/FTS5 only.- API keys are resolved exclusively from
CORTEX_EMBEDDING_API_KEYat runtime and must never appear in a configuration file.
Server-mode construction additionally approves the destination through the outbound policy: HTTPS is required off-loopback, the host and port are allowlisted, and redirect hops and response size are bounded.
Worked example: nan.builders (OpenAI-compatible endpoint)¶
search:
embedding_provider: openai-compatible
embedding_model: qwen3-embedding-8B
embedding_base_url: https://api.nan.builders/v1
# Placeholder only — export the real credential at run time; never commit it.
export CORTEX_EMBEDDING_API_KEY="<nan-builders-api-key>"
The same three keys are readable/settable as search.embedding_provider,
search.embedding_model, and search.embedding_base_url (aliases:
embedding.provider, embedding.model, embedding.base_url) and are mirrored
by CORTEX_EMBEDDING_PROVIDER, CORTEX_EMBEDDING_MODEL, and
CORTEX_EMBEDDING_BASE_URL.
Vector dimensions and corpus re-ingestion¶
- Dimensions are reported from live service state. The dimension is cached
from the first embedding response, and server ModelInfo / admin AI status read
that live value (
liveEmbeddingDimensions) instead of a static provider-to-dimension map, so status cannot drift from the endpoint. Before the first response,ollamareports768,openaireports1536, andopenai-compatiblereports no guess (0) precisely because an arbitrary endpoint has no trustworthy default. - Mismatched dimensions are rejected, never stored. A vector whose length
differs from the declared model dimension fails with
domain.ErrDimensionMismatch(vector dimension mismatch): it is neither written to the vector index nor scored as zero. The embedding outbox worker classifies validation failures such as a dimension mismatch as terminal, non-retryable, and dead-letters the intent instead of consuming retries. - Changing the model dimension requires corpus re-ingestion. Switching from
a 768-dim model (
nomic-embed-text) to a 4096-dim model (qwen3-embedding-8B) leaves existing vectors at the old dimension, so every observation must be re-embedded through the durable outbox worker. In the TUI, save the embedding configuration (a provider/model change raises the reindex warning) and pressxto Reindex all embeddings; the worker drains the outbox asynchronously and reports progress.
Reranking¶
Reranking reorders the fused candidate set before the final result limit is
applied (post-fusion, pre-limit). It is resolved once per process/store from
search.rerank_* and is disabled by default: with no rerank keys set,
search.rerank_provider resolves to none, zero rerank machinery is
constructed, and search output is byte-identical to a build without the feature.
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
search.rerank_provider |
CORTEX_RERANK_PROVIDER |
none |
Rerank preset: none (disabled), late-interaction (local), openai-compatible (server only). Unknown values are rejected at load. |
search.rerank_model |
CORTEX_RERANK_MODEL |
"" |
Rerank model identifier (e.g. qwen3-Reranker-8B). |
search.rerank_base_url |
CORTEX_RERANK_BASE_URL |
"" |
Endpoint base URL. Required when search.rerank_provider is openai-compatible, and validated as a bearer destination at load. |
| (Credential) | CORTEX_RERANK_API_KEY |
"" |
Rerank credential, environment-only. Never read from configuration files; without it the HTTP reranker cannot be constructed. |
none(default) — no reranker is constructed anywhere; results are byte-identical to the unreranked fusion order.late-interaction— the local, zero-network reranker: a 60% rank / 40% MaxSim late-interaction blend over the vectors already in the store. Valid in both local and server mode.openai-compatible(server only) — the HTTP/v1/rerankreranker. It requires an explicitsearch.rerank_base_urlplusCORTEX_RERANK_API_KEY, and the destination is approved through the outbound policy. Local mode refuses to construct it (rerank: openai-compatible is server-mode only) and degrades to rerank-off with a warning instead of failing the query.- Provider budgets are enforced client-side, not assumed: candidate
documents are sent in batches of at most 32, requests are paced to at most
60 requests/minute,
429responses are retried at most 3 times, redirects are capped at 3 hops, and responses are capped at 4 MiB. - Failures degrade, never corrupt: a rerank error, a timeout, or a provider response that changes the candidate set keeps the unreranked fusion order (with a warning) and never drops or fails a search.
Shared provider rate budget (CORTEX_PROVIDER_RPM)¶
When embedding, rerank, and agent chat are configured against the same
provider base URL (e.g. one Nan API key advertising 60 rpm), each subsystem
pacing independently still oversubscribes the shared key: agent traffic can
starve hybrid searches of their quota. CORTEX_PROVIDER_RPM composes one
shared token-bucket budget per provider base URL in the server composition,
drawn by all three subsystems (rerank batches, embedding requests, chat
completions — streaming and non-streaming).
| Environment Variable | Default | Description |
|---|---|---|
CORTEX_PROVIDER_RPM |
0 |
Shared outbound provider budget in requests per minute, keyed by provider base URL. 0 (unset) = unlimited: rerank keeps its historical private 60-rpm pacing and embedding/chat are unpaced. Malformed or negative values fail startup. |
Set it to the provider's advertised rpm (e.g. 60 for Nan) whenever more than
one subsystem shares a provider key. Budgets are enforced client-side with the
same token-bucket semantics as the rerank pacer (burst capped at one minute's
worth, callers never serialized within budget) and are unit-tested against a
fake clock.
LLM (Agent Reasoning, Extraction & Synthesis)¶
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
llm.provider |
CORTEX_LLM_PROVIDER |
openai |
Generative provider: openai, anthropic, gemini, ollama, groq, deepseek. |
llm.model |
CORTEX_LLM_MODEL |
gpt-4o-mini |
LLM model identifier. |
llm.base_url |
CORTEX_LLM_BASE_URL |
"" |
Custom provider base URL. |
| (Credential) | CORTEX_LLM_API_KEY |
(Secret) | Standard LLM API credential (strictly isolated; vendor keys like OPENAI_API_KEY are ignored). |
Outbound Network & Security Bounds (SEC-02)¶
| Environment Variable | Default | Constraint / Description |
|---|---|---|
CORTEX_LLM_PROVIDER |
"" |
Preset: openai, anthropic, google, gemini, ollama, generic. |
CORTEX_LLM_MODEL |
"" |
Model identifier override. |
CORTEX_LLM_API_KEY |
"" |
Outbound authentication key. Must be explicitly provided. |
CORTEX_LLM_BASE_URL |
"" |
Destination endpoint. Must be HTTPS unless loopback HTTP switch is enabled. |
CORTEX_LLM_ALLOWED_HOSTS |
[] |
Comma-separated list of approved destination hostnames (max 64). |
CORTEX_LLM_ALLOWED_PORTS |
[443] |
Comma-separated list of approved TCP ports (max 16). |
CORTEX_LLM_ALLOW_LOOPBACK |
false |
Explicit switch permitting loopback HTTPS destinations. |
CORTEX_LLM_ALLOW_LOOPBACK_HTTP |
false |
Explicit switch permitting plain HTTP to strict loopback (127.0.0.1, localhost). |
CORTEX_LLM_MAX_CONCURRENT |
4 |
Maximum concurrent outbound provider requests (1–64). |
CORTEX_LLM_MAX_REDIRECTS |
3 |
Maximum allowed HTTP redirect hops (1–10). |
CORTEX_LLM_MAX_RESPONSE_BODY_BYTES |
4194304 (4MB) |
Maximum accepted response payload size (up to 64MB). |
CORTEX_LLM_MAX_ERROR_BODY_BYTES |
4096 (4KB) |
Maximum error response payload retained for diagnostics. |
CORTEX_LLM_TIMEOUT |
45s |
Outbound request timeout (max 5m). |
CORTEX_LLM_CA_FILE |
"" |
Path to custom PEM CA root certificates for enterprise TLS proxies. |
External Vector Adapters (Server-Only)¶
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
server.provider.vector |
CORTEX_SERVER_PROVIDER_VECTOR |
none |
Vector provider: none (FTS5/BM25 only), pgvector, qdrant. |
vector.pgvector.dsn |
CORTEX_VECTOR_PGVECTOR_DSN |
(None) | Runtime connection string for pgvector table. |
vector.pgvector.schema |
CORTEX_VECTOR_PGVECTOR_SCHEMA |
cortex_vector |
PostgreSQL schema name for vector storage. |
vector.pgvector.table |
CORTEX_VECTOR_PGVECTOR_TABLE |
embeddings |
Table storing dense vector embeddings. |
vector.pgvector.index_type |
CORTEX_VECTOR_PGVECTOR_INDEX_TYPE |
hnsw |
Vector index type: hnsw or ivfflat. |
vector.qdrant.host |
CORTEX_VECTOR_QDRANT_HOST |
localhost |
Qdrant gRPC/HTTP host address. |
vector.qdrant.port |
CORTEX_VECTOR_QDRANT_PORT |
6334 |
Qdrant port. |
vector.qdrant.collection |
CORTEX_VECTOR_QDRANT_COLLECTION |
cortex |
Target Qdrant collection name. |
vector.qdrant.api_key |
CORTEX_VECTOR_QDRANT_API_KEY |
"" |
Qdrant API key for authenticated cloud/cluster deployments. |
Local Client, Sync Replication & Remote MCP¶
| Configuration Key | Environment Variable | Default | Description |
|---|---|---|---|
database.path |
CORTEX_DATABASE_PATH |
~/.cortex/cortex.db |
Local SQLite database file path. |
sync.enabled |
CORTEX_SYNC_ENABLED |
false |
Enables background bidirectional SQLite-to-Server replication. |
sync.url |
CORTEX_SYNC_URL |
"" |
Cortex Server base URL (strictly HTTPS off-loopback). |
sync.token_env |
CORTEX_SYNC_TOKEN_ENV |
CORTEX_REMOTE_TOKEN |
Name of environment variable holding the replication Bearer token. |
sync.interval |
CORTEX_SYNC_INTERVAL |
30s |
Background replication synchronization frequency. |
mcp.remote.enabled |
CORTEX_MCP_REMOTE_ENABLED |
false |
Proxies local stdio MCP commands to a remote Streamable HTTP server. |
mcp.remote.url |
CORTEX_MCP_REMOTE_URL |
"" |
Remote MCP endpoint URL (including /mcp). |
mcp.remote.token_env |
CORTEX_MCP_REMOTE_TOKEN_ENV |
CORTEX_REMOTE_TOKEN |
Name of environment variable containing the remote MCP Bearer token. |
4. Bearer Transport Policy¶
Every remote destination transmitting credentials (sync.url, mcp.remote.url, server.llm.base_url) enforces strict transport security (internal/transportpolicy):
- HTTPS Required Off-Loopback: Non-loopback endpoints must use HTTPS. Any plain HTTP connection to a public/remote address is rejected at startup before credentials can be sent.
- Strict Loopback Exceptions: Plain HTTP is permitted only for:
- IPv4 loopback literal (
127.0.0.0/8) - IPv6 loopback literal (
[::1]) - Exact hostname
localhost - Downgrade Rejection: HTTP redirects are never followed if they downgrade an HTTPS connection to plain HTTP or change the origin (scheme + host + port).
5. Troubleshooting & Diagnostics¶
- Configuration validation: Run
cortex doctorto inspect configuration health, database compatibility, and vector indexing status. - Inspect loaded path: Run
cortex config pathto identify which configuration file is currently being read. - Overrides not reflected: Remember that
CORTEX_*environment variables take precedence over settings saved incortex.yaml. Check running process environment variables. - Port binding issues: Ensure you use
CORTEX_HTTP_PORT(e.g.7438). LegacyCORTEX_PORTis rejected to prevent configuration ambiguity.