Complete reference for every environment variable Pulse reads — server, storage, knowledge-graph runtime, MCP tracing, Docker-only — with defaults, ranges, and the field on CoreSettings each one maps to.
Field name → env var name. Every field on CoreSettings and CommunitySettings accepts an env var equal to the field name uppercased. data_dir ⇒ DATA_DIR, kg_base_dir ⇒ KG_BASE_DIR, etc.
Case-insensitive.DATA_DIR, data_dir, and Data_Dir are equivalent. We use uppercase throughout this page by convention.
.env is loaded automatically from the working directory of okto-pulse serve. Useful for local development; production should set vars in the process environment.
A small set of variables outside CoreSettings are read directly by the CLI, the MCP server, or the Docker image — they are called out explicitly in their sections below.For runtime tuning rationale, see Server configuration. For the on-disk layout these variables control, see Storage paths. Source-of-truth for the table below is 80-pulse-feature-inventory.md:178–211.
These variables gate the CLI itself — they are read by okto-pulse serve and friends, not by CoreSettings.
Env var
Default
Range / type
Purpose
OKTO_PULSE_PORT
8100
int
API + Web UI port. Set by cmd_serve from --api-portbefore importing okto_pulse.community.main. (community/cli.py:244, inventory:181)
OKTO_PULSE_MCP_PORT
8101
int
MCP server port. Set by cmd_serve from --mcp-port. (community/cli.py:245, inventory:182)
OKTO_PULSE_TERMS_ACCEPTED
unset
1 to pre-accept
Pre-accept the Terms of Use; equivalent to --accept-terms. Triggers write_acceptance("env"). (community/cli.py:252, acceptance.py:29, inventory:183)
OKTO_PULSE_NO_BANNER
unset
any non-empty
Suppress the ASCII banner on startup. Useful for JSON pipes. (community/cli.py:47, inventory:184)
OKTO_PULSE_HOME
~/.okto-pulse
path
Overrides the base directory used for persisted Terms of Use acceptance state. Source: community/acceptance.py:23.
OKTO_PULSE_STARTUP_TIMEOUT_SECONDS
120
float seconds, min 1
Timeout while waiting for the paired API/MCP uvicorn listeners to report startup. Source: community/main.py:62.
OKTO_PULSE_STARTUP_TIMEOUT
unset
float seconds, min 1
Legacy alias for OKTO_PULSE_STARTUP_TIMEOUT_SECONDS; read only when the _SECONDS variable is absent. Source: community/main.py:63.
OKTO_PULSE_SHUTDOWN_TIMEOUT_SECONDS
5
float seconds, min 1
Timeout for graceful shutdown of the paired API/MCP servers. Source: community/main.py:88.
OKTO_PULSE_SHUTDOWN_TIMEOUT
unset
float seconds, min 1
Legacy alias for OKTO_PULSE_SHUTDOWN_TIMEOUT_SECONDS; read only when the _SECONDS variable is absent. Source: community/main.py:89.
OKTO_PULSE_PORT and OKTO_PULSE_MCP_PORTmust be set before okto_pulse.community.main is imported — the module evaluates app = create_community_app() at import time and bakes the values into the Web UI’s /config.js. The CLI does this for you; if you embed Pulse in your own Python process, set both before any import okto_pulse.community.main.
These map to CoreSettings fields (config.py:22–60, inventory:751–765).
Env var
Default
Field
Notes
HOST
127.0.0.1 (community) / 0.0.0.0 (Docker)
host
API + Web UI bind. Loopback by default; Docker images set 0.0.0.0 so port forwards reach uvicorn. (CLAUDE.md “Env vars the runtime reads”, inventory:761)
MCP_HOST
127.0.0.1 (community) / 0.0.0.0 (Docker)
runtime
MCP uvicorn bind. Honored in bothcommunity/main.py (since v0.1.12) and core/mcp/server.py:run_mcp_server. Without it, MCP binds to 127.0.0.1 even with -p 8101:8101.
PORT
unset
fallback
Read beforeOKTO_PULSE_PORT in community/main.py:652. Useful for PaaS platforms (Heroku, Fly) that inject PORT.
MCP_PORT
unset
fallback
Read beforeOKTO_PULSE_MCP_PORT in community/main.py:655 and in core/mcp/server.py:12852.
ENVIRONMENT
development
environment
Free-form label. Surfaced in startup banner and /health. (inventory:754)
DEBUG
false
debug
Raises okto_pulse.* loggers from INFO to DEBUG; surfaces SQLAlchemy echo. (inventory:753)
Comma-separated allowed origins. The community edition’s _derive_paths validator overrides core to * so the bundled UI works regardless of port. (community/config.py:33, inventory:765)
PUBLIC_HOST
127.0.0.1
hostname/IP
Host value injected into /config.js for browser-side API and MCP URLs. Source: community/main.py:304.
PUBLIC_API_PORT
active API port
int
API port injected into /config.js; use when a reverse proxy or container publish port differs from the internal listener. Source: community/main.py:305.
PUBLIC_MCP_PORT
active MCP port
int
MCP port injected into /config.js; use when the browser should connect through a published/proxied MCP port. Source: community/main.py:306.
These map to CoreSettings and CommunitySettings fields (inventory:185–189).
Env var
Default
Field
Notes
DATA_DIR
~/.okto-pulse
CommunitySettings.data_dir
Single root for SQLite, attachments, and KG graph files. The community edition’s _derive_paths validator rebases DATABASE_URL and UPLOAD_DIR under it. (community/config.py:11)
KG_BASE_DIR
~/.okto-pulse
kg_base_dir
KG-only root; relocates per-board boards/{id}/graph.lbug and global/discovery.lbug independently of DATA_DIR. Defaults to DATA_DIR in the Docker image (KG_BASE_DIR=/data). (inventory:189)
DATABASE_URL
sqlite+aiosqlite:///{data_dir}/data/pulse.db
database_url
SQLAlchemy connection string. Override to point at an alternate SQLite path; non-SQLite backends are not supported in the community edition. (inventory:185)
Configures the embedding backend used for KG semantic search. (inventory:191–193)
Env var
Default
Field
Notes
KG_EMBEDDING_MODE
sentence-transformers (community) / stub (core)
kg_embedding_mode
Either sentence-transformers (real ~90 MB MiniLM model) or stub (deterministic hash, no model). The community edition’s CommunitySettings overrides core’s default to sentence-transformers.
KG_EMBEDDING_MODEL
sentence-transformers/all-MiniLM-L6-v2
kg_embedding_model
Hugging Face repo ID. Pulse ships with the model pre-baked into the Docker image at /opt/hf-cache.
KG_EMBEDDING_DIM
384
kg_embedding_dim
Vector dimension. Must match the model. The HNSW index in each graph.lbug is bound to this dimension at create time — changing it requires a graph rebuild.
Changing KG_EMBEDDING_MODEL or KG_EMBEDDING_DIM after a board has been created will not re-embed existing nodes. New nodes will be embedded with the new model, but similarity search will mix vector spaces. If you need to switch models, run okto-pulse kg backfill <board_id> to recompute everything; if the dimension changed, drop and rebuild the graph.
LadybugDB engine sizing. The legacy KUZU prefix is retained in env-var names because the underlying engine is the Kùzu-derived LadybugDB (Kuzu retired 2026-05-03). All three are validated by pydantic.Field with the ranges shown.
Env var
Default
Range
Field
Notes
KG_KUZU_BUFFER_POOL_MB
256
16–512 MB
kg_kuzu_buffer_pool_mb
LadybugDB buffer pool. The library’s own default (buffer_pool_size=0) maps to ~80 % of system RAM and caused 128 GB RSS with three pooled boards in field reports — hence the conservative cap. (inventory:194, config.py:71–73)
KG_KUZU_MAX_DB_SIZE_GB
1
1–64 GB
kg_kuzu_max_db_size_gb
Per-board graph size cap. The library default (1<<43 = 8 TB virtual address) is replaced with this saner default. (inventory:195)
KG_CONNECTION_POOL_SIZE
8
1–32
kg_connection_pool_size
LadybugDB connection pool per process. (inventory:196)
The KG worker pool that drains the SQLite consolidation queue and writes nodes/edges into LadybugDB. All KG_QUEUE_* settings hot-reload via APScheduler with a 5-second debounce — no restart required. (inventory:790–793, config.py:80–87)
Env var
Default
Range
Field
Notes
KG_SESSION_TTL_SECONDS
3600
int (s)
kg_session_ttl_seconds
Consolidation session TTL. Sessions older than this are reaped by the cleanup worker. (inventory:197)
Disable the cleanup worker entirely (rare; useful for replay tests). (inventory:199)
KG_QUEUE_MAX_CONCURRENT_WORKERS
4
1–16
kg_queue_max_concurrent_workers
Asyncio task concurrency inside the single uvicorn process. Not OS workers. (inventory:200)
KG_QUEUE_MIN_INTERVAL_MS
100
0–1000 ms
kg_queue_min_interval_ms
Floor between queue polls. Lower = more aggressive draining; higher = lower CPU. (inventory:201)
KG_QUEUE_CLAIM_TIMEOUT_S
300
60–3600 s
kg_queue_claim_timeout_s
After this, an in-flight queue entry is considered abandoned and reclaimed by another worker. (inventory:202)
KG_QUEUE_MAX_ATTEMPTS
5
1–10
kg_queue_max_attempts
Retries per entry before it dead-letters. Reprocess via okto_pulse_kg_dead_letter_reprocess. (inventory:203)
KG_QUEUE_ALERT_THRESHOLD
5000
100–100000
kg_queue_alert_threshold
Queue depth that surfaces as a yellow warning in okto_pulse_kg_health. (inventory:204)
KG_QUEUE_RECOVERY_SCAN_INTERVAL_S
60
10–600 s
kg_queue_recovery_scan_interval_s
Periodicity of the dead-entry recovery scan. Values below 30 s start to compete with normal traffic. (inventory:205)
KG_MAX_QUEUE_DEPTH is deprecated as of v0.1.14 and will be removed in v0.5.0. The settings_service maps the legacy value into KG_QUEUE_ALERT_THRESHOLD and emits a DeprecationWarning at startup. Source: config.py:67–70.
The decay tick recomputes node relevance scores so old, unread decisions sink. Hot-reloadable through PUT /settings/runtime — APScheduler reschedules the job in place. (inventory:206–208, config.py:90–95)
Env var
Default
Range
Field
Notes
KG_DECAY_TICK_INTERVAL_MINUTES
1440 (24 h)
5–10080 (5 min – 7 d)
kg_decay_tick_interval_minutes
Cron period for the decay worker. The 5-minute floor blocks accidental DoS-against-self; the 7-day ceiling blocks “forgot to schedule it”.
KG_DECAY_TICK_STALENESS_DAYS
7
1–365 d
kg_decay_tick_staleness_days
Nodes whose last_recomputed_at is older than this are recomputed on the next tick.
KG_DECAY_TICK_MAX_AGE_DAYS
0
0–365 d
kg_decay_tick_max_age_days
0 = no cap. When set, force-recompute “fresh” nodes older than this many days regardless of staleness.
KG_DECAY_TICK_BATCH_SIZE
200
int
module constant
Maximum stale KG nodes processed per decay tick batch, ordered by id so a tick does not revisit the same row. Source: events/handlers/kg_decay_tick.py:40.
KG_DAILY_TICK_DISABLED
unset
1 disables
runtime guard
Disables scheduled daily KG tick registration. Used by tests and controlled runtimes that trigger ticks manually. Source: core/app.py:164 and community/main.py:372.
$ ls ~/.okto-pulse/mcp_traces/session_2026-05-07T14-12-03_a3f9.jsonl$ head -1 ~/.okto-pulse/mcp_traces/session_2026-05-07T14-12-03_a3f9.jsonl{"ts":"2026-05-07T14:12:04Z","tool":"okto_pulse_get_active_board","args":{},"result_summary":"ok","ms":8}
Authentication for okto-pulse MCP tools is configured via MCPSettings (config.py:110–117) with env_prefix="MCP_" — these are the only Pulse env vars that take a prefix.
Env var
Default
Field
Notes
MCP_REQUIRE_AGENT_KEY
true
MCPSettings.require_agent_key
When true, every MCP request must carry a valid dash_<hex> API key (query param or Authorization: Bearer). Disabling this exposes the server unauthenticated — do not unless the listener is on a private socket.
MCP_AGENT_KEYS_ENV
unset
MCPSettings.agent_keys_env
Comma-separated list of agent keys for static validation. Normally agents are seeded into SQLite by okto-pulse init --agents; this override is for ephemeral CI environments.
Set inside the official ghcr.io/oktolabsai/okto-pulse image; not configurable from CoreSettings. Source: okto-pulse/Dockerfile:28–29.
Env var
Container default
Purpose
HF_HOME
/opt/hf-cache
Hugging Face cache root. Pre-warmed at build time with all-MiniLM-L6-v2; do not mount over this path.
SENTENCE_TRANSFORMERS_HOME
/opt/hf-cache/sentence_transformers
Sentence-transformers sub-cache.
Mounting a volume over /opt/hf-cache forces the container to re-download the embedding model on first run. The image is offline-capable only because the cache is pre-baked.
INFO okto_pulse Starting Okto Pulse Community...INFO okto_pulse.kg KG buffer pool=384MB, connection pool=12, max workers=8INFO uvicorn Uvicorn running on http://127.0.0.1:8100
Variables set in the process environment override values from .env. Production deployments should set vars in the systemd unit, the Docker --env/-e flag, or the orchestrator manifest — not check a .env into the repo.