Skip to content
kazma.
Search Kazma Documentation & Site
ع

Environment Variables

Complete env reference for local, Docker, and production. Prefer strong secrets; never commit .env with real keys. Also see Configuration for kazma.yaml and ConfigStore.

VariableDefaultPurpose
KAZMA_COMPUTER_USE10 disables the computer_use tool
KAZMA_LANGFUSE(unset)0 forces console tracing even when Langfuse keys exist
LANGFUSE_PUBLIC_KEY / LANGFUSE_SECRET_KEYWith logging.langfuse.enabled: auto, both set → Langfuse backend
KAZMA_EMBED_FLEET(unset)1 + OpenAI/Voyage key → hosted embeddings (issue #78)
KAZMA_DOCLING1An additional veto on local Docling salvage of weak PDF extracts, which documents.security.local_salvage (default on) governs: 0/false/off/no turns it off; no value of this variable turns it on. The salvage runs inside the bounded parser worker.
KAZMA_REMOTE_PARSEunset (no veto)Remote salvage is off by default. Remote PDF salvage (LlamaParse/Reducto) ships the original document to a third party, so it is governed by documents.security.remote_parse, which defaults to False. This variable is a veto, not a switch: 0/false/off/no disables salvage even where the policy allows it; unset or any other value leaves the policy alone and never enables salvage on its own. Policy and veto are read again before each provider. Having an API key configured is not consent — turn the policy on deliberately.
LLAMAPARSE_API_KEY / REDUCTO_API_KEYProvider keys for remote salvage, used only while documents.security.remote_parse is on: tried in the order LlamaParse, Reducto (one without a key is skipped, a failed one falls through to the next), each attempt audited before the upload. Read by the Kazma process, never the parser worker; a chat attachment’s transient read never uploads.
KAZMA_SILERO_VAD(unset)1 tries Silero VAD (falls back to energy)
KAZMA_LITELLM_URL(unset)LiteLLM proxy for OpenAI-compatible providers only (e.g. http://127.0.0.1:4000)
KAZMA_LITELLM10 disables the LiteLLM proxy even if a URL is set
KAZMA_LITELLM_LOCAL(unset)1 also routes loopback Ollama/LM Studio through the proxy
KAZMA_LITELLM_FALLBACK_DIRECT(unset)1 retries the original provider URL if the proxy is unreachable
LITELLM_MASTER_KEY / LITELLM_API_KEY / KAZMA_LITELLM_KEYBearer key sent to the proxy (else the provider key is reused)
LIVEKIT_URL(unset)LiveKit WebRTC URL for web duplex voice (e.g. wss://…livekit.cloud)
LIVEKIT_API_KEY / LIVEKIT_API_SECRETLiveKit API credentials (room tokens). All three required to enable duplex
KAZMA_VOICE_DUPLEX10 disables LiveKit duplex even if credentials are set
KAZMA_CUA_PLANNER10 keeps computer_use on vision-JSON (no Anthropic CUA / Gemini mapping)
KAZMA_MCP_SAMPLING01 allows MCP sampling/createMessage after a HITL card (no tools on that LLM call)
KAZMA_MCP_SAMPLING_TIMEOUT60Seconds to wait for the sampling HITL card
  1. Specific helpers may read env first (KAZMA_SECRET, vault, disclosure).
  2. ConfigStore DB wins for most runtime settings.
  3. kazma.yaml seeds missing DB keys.
  4. Hardcoded defaults last.

Generic ConfigStore.get() does not automatically overlay every env var — only documented keys below that code explicitly reads.

Document platform limits, OCR, workers, retention, capacity, and rollout flags are ConfigStore / kazma.yaml keys (live-read), not a parallel env matrix. Primary keys are nested, for example:

  • documents.enabled / documents.shadow / documents.default_authoritative
  • documents.intake.max_bytes, documents.intake.lease_seconds, documents.limits.max_pages
  • documents.ocr.* (including documents.ocr.tables, the cell-by-cell reading of ruled tables on scanned pages), documents.workers.*, documents.capacity.*
  • documents.retention.*, documents.gc.*, documents.security.*

See Document Intelligence — live configuration and kazma_core.documents.config.DocumentConfig. The strict execution profile security.execution.container_required (a setting, not a variable) refuses the process worker profile below (worker_isolation_required). Optional cert soak size: KAZMA_DOCUMENT_SOAK_ITERATIONS (used by scripts/certify_documents.py --soak).

VariableDefaultPurpose
KAZMA_DOCUMENTS_JOBS_BACKENDunsetsqlite (or sqlite3) forces the SQLite job queue; any other value follows the platform: Postgres when Kazma’s database is Postgres. A Postgres pool that cannot be reached at start falls back to SQLite, and readiness reports it as degraded.
KAZMA_DOCUMENTS_METADATA_BACKENDunset (auto)sqlite / postgres (also postgresql, pg) / auto (unset or auto: follow the jobs backend); any other value means SQLite. Postgres metadata enables multi-replica CRUD; GC mark/sweep is backend-agnostic (repository.gc_mark)
KAZMA_DOCUMENT_SOAK_ITERATIONS100Repetitions of the extended repeated-parse smoke of certify_documents.py --soak. It is not, and is not reported as, a multi-day soak.
KAZMA_DOCUMENT_FONT_DIRvendored documents/assets/fonts/Font directory for generated PDF/DOCX/HTML. A path that is not a directory is ignored with a warning, and the vendored IBM Plex Sans Arabic is used. Fonts are still chosen by verified glyph coverage.
KAZMA_DOCUMENT_WORKER_ISOLATIONunset (the admin’s setting, else process)Where the parser, mutation and renderer workers run, when set: it wins over the admin’s setting security.execution.document_worker_isolation (Settings → Documents), which decides otherwise. process: a local child process with time/output/resource limits and no filesystem or network isolation (readiness reports hostile_document_profile: unqualified); refused when security.execution.container_required is on. container: every run goes to the document worker broker, which runs it in a fresh attested container with no network and no mounts, and the engines Kazma reports are the ones the worker image reports; an unreachable, unattested or full broker refuses the run (worker_isolation_unavailable, retried; no fallback to process). Any other value refuses every run (worker_isolation_invalid).
KAZMA_OCR_MODEL_DIRunset (the data dir’s models/ocr)Where the neural OCR engine’s models are (documents.ocr.engine: neural or auto). python scripts/ocr_models.py install writes them there with a manifest.json; the document worker uses them only when every file matches its SHA-256 in that manifest, else Tesseract reads the pages. The worker image sets it to its own read-only copy (/opt/kazma/ocr-models).
KAZMA_DOCUMENT_BROKER_URLset by the guardThe broker for container isolation: unix:///path/to/broker.sock or tcp://host:port. The guard hands the server it spawns its own broker’s loopback address; a value from .env wins (another broker: compose, or one run by hand), and the guard then runs none. Without it container refuses every run. TCP belongs on a private network: the token is the only authentication.
KAZMA_DOCUMENT_BROKER_TOKEN_FILEset by the guardFile holding the shared broker token (at least 32 characters; the broker is started with the same file). The guard’s is .kazma/document_broker.token, made once and readable by the guard’s account only. Read per run, so a rotated token takes effect without a restart.

Test-only, opt-in qualification runs (each test skips without its variable; the document processing page says how to run them): KAZMA_TEST_DOCUMENT_WORKER_IMAGE (a built worker image: the real-Docker container profile), KAZMA_TEST_CONTAINER_LEASE_DRILL_IMAGE (the cross-host intake lease drill), KAZMA_TEST_RESTORE_DRILL_DOCUMENTS with KAZMA_TEST_RESTORE_DRILL_KIB (default 64) and KAZMA_TEST_RESTORE_DRILL_WRITERS (default 1) (the Postgres restore drill at scale), KAZMA_TEST_REAL_SCANS_MANIFEST (real-scan measurements).


VariableDefaultProd required?Purpose
KAZMA_HOST127.0.0.1Set deliberatelyBind address. Non-loopback requires KAZMA_SECRET.
KAZMA_PORT / serve arg9090 (CLI)NoHTTP port (kazma serve [port]). Docker images may differ — check compose.
KAZMA_SECRETgenerated on loopbackYes on public bindAuth shared secret / session material. Known-bad default refused.
KAZMA_PRODUCTIONunsetYes for prodEnables vault-required, workspace root, code_exec policy, YOLO hard-block, etc.
KAZMA_ENVunsetOptionalSome paths treat production specially.
KAZMA_PUBLIC_URLunsetRecommended behind proxyPublic origin for OAuth/OIDC redirects.
KAZMA_CORS_ORIGINSunsetIf browser cross-originExplicit comma-separated HTTP(S) origins trusted for credentialed CORS and API mutations. Scheme and port must match; wildcards are rejected. Local development ports are not trusted by default. Declare the reverse proxy’s external origin with KAZMA_PUBLIC_URL. Restart after changing these settings.
KAZMA_ENV_FILEunsetNoAbsolute path to an extra .env, loaded last so it wins. The .env ladder is: <kazma home>/.env → <cwd>/.env → this. kazma mcp and kazma ask, which other programs start in their own folders, read the installed checkout’s .env instead of the launch folder’s. Nothing outside the installation is read unless you name it here.
KAZMA_TRUSTED_PROXIESunsetYes behind any proxyComma-separated addresses or CIDR ranges the reverse proxy connects from (127.0.0.1 for same-host nginx/Caddy or Cloudflare Tunnel, the bridge IP or 172.17.0.0/16 under Docker). Only these peers may set X-Forwarded-For / X-Forwarded-Proto; * is ignored. See the warning below.
KAZMA_LOOPBACK_AUTOLOGIN0Keep 0Re-enables credential-less loopback login even with a proxy declared. Only for a host where 127.0.0.1 really is just you.
KAZMA_TRUST_LAN0Keep 0 unless neededLAN trust for auth middleware.
KAZMA_AUTH_DISABLEDunsetNever in prodDisables auth helpers — dev only.
KAZMA_ALLOW_YOLOunsetAvoidOnly way to re-enable YOLO when KAZMA_PRODUCTION=1.
KAZMA_VERBOSE_ERRORS0Keep 0Appends the real exception message to API errors (still redacted for paths and credentials). Dev only — production returns a code plus a correlation id.
KAZMA_BASE_URLunsetNoAn extra address the agent may use to reach this server’s own API (after KAZMA_PUBLIC_URL in the agent’s runtime note, and after the loopback candidates for local API calls).
KAZMA_GIT_SHAgit rev-parseNoCommit id shown in the version string (0.10.0+g<sha>). Read first, then GITHUB_SHA, then git; set it in images that ship without a .git directory.

:::danger KAZMA_TRUSTED_PROXIES is required behind a reverse proxy

Kazma treats a loopback client as the local operator and auto-issues an admin session to it — that is what makes single-operator localhost use work with no login.

Behind a same-host nginx/Caddy, request.client.host is 127.0.0.1 for every internet visitor. Without KAZMA_TRUSTED_PROXIES, each of them is therefore treated as the operator and handed an admin session on the first page load, over HTTP and WebSocket. This was audit finding F-01 (2026-08-29).

Set it to the proxy’s address and Kazma reads the real client from X-Forwarded-For instead, and stops treating peer address as a credential:

Terminal window
KAZMA_TRUSTED_PROXIES=127.0.0.1

Your proxy must send the forwarded headers and must overwrite rather than append a client-supplied value; the shipped deploy/nginx-ha.conf already does. Kazma applies this variable itself (an in-app middleware), and every launcher starts uvicorn with proxy_headers=False; launch it yourself with --no-proxy-headers.

Under Docker this is the proxy container’s bridge address (often 172.17.0.1 or the compose network gateway), not 127.0.0.1. Getting it wrong no longer fails open: a forwarded header from an undeclared peer disables peer-address trust for the process and logs the address to set.

Verify after deploy — authenticated must read false before login, and proxy.state should read declared (direct behind a proxy means the variable did not take; undeclared_proxy means it is set to the wrong address, and proxy.hint names the right one):

Terminal window
curl -s https://your.domain/api/auth/status

:::


VariableDefaultProd required?Purpose
KAZMA_VAULT_KEYunsetYes if productionAES vault master material.
KAZMA_JWT_SECRETunsetIf JWT paths usedJWT signing for tenant/API tokens.
KAZMA_DISCLOSURE_KEYunsetOptionalVulnerability disclosure crypto helper.

VariableDefaultProd required?Purpose
KAZMA_DATABASE_URLunset (SQLite)Multi-replica YesPostgres DSN → dual-backend stores + LangGraph checkpointer.
DATABASE_URLunsetAltAccepted by migrate script as alias.
KAZMA_DB_BACKENDautoOptionalForce postgres / sqlite.
KAZMA_DB_CONTAINERkazma-dbMigrationDocker container name for pg_dump / pg_restore discovery during kazma migrate. See Migration.
KAZMA_DB_INTERNAL_PORT5432MigrationContainer-internal Postgres port when pg_dump / pg_restore run via docker exec (the host’s forwarded port is unreachable from inside the container).
KAZMA_DOCKER_BINunsetOptionalAbsolute path of the docker CLI. Kazma looks for it here, then on PATH, then in Docker’s standard install folders (e.g. C:\Program Files\Docker\Docker\resources\bin). Needed only when docker lives somewhere else: the Postgres dump (pg_dump via docker exec), the python_exec Docker jail and the document worker broker (documents/worker_broker.py, which the broker image points at its CLI with this variable) all use it. A Docker Desktop update that drops its folder from PATH no longer stops backups (2026-09-25).
KAZMA_PG_POOL_RETRIES5OptionalConnection-pool creation retry count. Handles transient failures (Windows Docker-bridge, container mid-startup).
KAZMA_PG_POOL_RETRY_DELAY1.0OptionalSeconds between pool-creation retries.
KAZMA_PG_POOL_MIN1OptionalMinimum connections in the psycopg pool.
KAZMA_PG_POOL_MAX10OptionalMaximum connections in the psycopg pool.
KAZMA_PG_POOL_TIMEOUT5OptionalSeconds a caller waits for a free pool connection. A hang here used to freeze /health/ready on the event loop.
KAZMA_REPLICA_AFFINITYonMulti-replica0 stops setting the kazma-replica cookie (HttpOnly). Chat SSE and some swarm state live in one process, so behind a load balancer keep it on and make the balancer sticky on that cookie (or on a source-IP hash).
KAZMA_REPLICA_IDhostnameMulti-replicaThe value this node writes into the kazma-replica cookie.
KAZMA_SHARED_BREAKERSon in production / multi-userMulti-replicaKeep swarm circuit-breaker state in the settings store (swarm.breaker.<worker>) so every replica sees a breaker another one opened. 1 / 0 force it either way.
KAZMA_SWARM_MAX_ACTIVEswarm max_concurrent_tasks (10)NoHow many swarm tasks may run at once; the next one is refused (“Swarm at capacity”). Pipelines paused at a checkpoint do not count.
KAZMA_MIGRATE_CHECK_PORToffMigration1 makes kazma migrate import also refuse while something listens on KAZMA_PORT / PORT (default 9090). The main check is the running server’s heartbeat; the port probe is off by default because an unrelated dev server on that port would block every import.
KAZMA_DB_BACKEND_SOURCE—Not an inputWritten, never read: kazma migrate export records the source database backend under this name in the bundle’s meta.env.
KAZMA_PG_RESTORE_REHEARSALunset (on with Postgres)Optional0 turns OFF the weekly restore rehearsal (on by default since 2026-09-27), whatever the setting says; 1 turns it on over a setting of false. The rehearsal: the newest pg_dump is restored into a scratch database kazma_restore_rehearsal_<epoch> on the SAME server, checked (Kazma’s tables present, kazma_settings not empty) and dropped. The user needs CREATEDB; without it the drill reports UNVERIFIED with the grant to add. Leftover scratch databases older than a day are removed by the next run; nothing else is ever created or dropped.

Default remains Docker/local python_exec and in-process swarm. These are opt-in for untrusted code and multi-hour work. See Architecture and extras kazma[sandbox] / kazma[durable].

VariableDefaultProd required?Purpose
KAZMA_E2B_API_KEY / E2B_API_KEYunsetUntrusted / multi-user codeE2B Firecracker for HITL-approved python_exec.
KAZMA_E2Bauto if key setNo0 keeps Docker/local even with a key.
KAZMA_CODE_EXEC_DOCKERautoSingle-operator jail1/true/on/yes/docker/force/required require Docker without local fallback and block host shell unless explicitly granted. 0 requests local execution, which production/multi-user policy still refuses.
KAZMA_HOST_SHELLunsetEscape hatchProduction, multi-user and forced Docker profiles deny host shell by default. 1 explicitly grants it after HITL; this restores host capability, not isolation. Policy lookup failures deny it.
KAZMA_CODE_EXEC_IMAGEpython:3.12-slimNoImage for the Docker jail that runs python_exec / code_exec (no network, read-only work mount, tmpfs /tmp, memory cap).
KAZMA_LIVE_EVALunsetNo1 runs the opt-in live-model eval (tests/test_hands_live.py). CI skips.
KAZMA_TEMPORAL_HOST / TEMPORAL_ADDRESSunsetMulti-hour swarmTemporal frontend (localhost:7233). Each admitted swarm task runs through a Temporal workflow whose activity runs the engine’s own run in this process (swarm guide §1.0a).
KAZMA_TEMPORALauto if host setNo0 keeps in-process swarm.
KAZMA_TEMPORAL_REQUIREDunsetRequired durable execution1 = fail the task if Temporal/SDK is disabled or down, or this process’s worker is not running; an approval is then deferred with its checkpoint left open. Readiness also requires the running worker. After submission, no profile permits local fallback. Temporal never retries a task’s activity.
KAZMA_TEMPORAL_NAMESPACEdefaultNoTemporal namespace.
KAZMA_TEMPORAL_QUEUEkazma-swarmNoThe workflows’ task queue. Each process’s activities use <queue>-run-<tag>, a queue only that process polls (the tag is drawn at start).
KAZMA_CODE_INDEXonNo0 disables the workspace symbol index + codebase_search.
KAZMA_IDE_LSPonNo0 disables the /api/ide/lsp backend. The Web /ide editor is CodeMirror 5 (syntax only); hover/complete UI is not bound.

Test-only: KAZMA_TEST_TEMPORAL_REQUIRED=1 makes the durable path’s qualification (tests/test_swarm_temporal_durable.py, on Temporal’s time-skipping test server) fail instead of skip when the SDK is missing or the test server cannot start; its CI job sets it.


VariableDefaultProd required?Purpose
OPENAI_API_KEYunsetOne provider keyOpenAI-compatible key; also used for the dall-e image-gen backend.
KAZMA_API_KEYunsetFallbackGeneric API key fallback.
KAZMA_PROVIDERunsetOptional bootProvider id at startup.
KAZMA_MODELunsetOptional bootModel id at startup.
ANTHROPIC_API_KEYunsetFor ClaudeNative Anthropic Messages API (anthropic_llm.py).
AZURE_OPENAI_ENDPOINT / AZURE_OPENAI_API_KEY / AZURE_OPENAI_DEPLOYMENT / AZURE_OPENAI_API_VERSIONunsetFor AzureAzure OpenAI (azure_llm.py).
AWS_REGION / AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEYunsetFor BedrockAWS Bedrock via standard boto3 credential chain (bedrock_llm.py).
STABILITY_API_KEYunsetOptionalStability SDXL image-gen backend.
FAL_KEYunsetOptionalFlux image-gen backend (FAL.ai).
KAZMA_IMAGE_PROVIDERunsetOptionalForce an image backend (pollinations/dall-e/stability/flux); default auto.
KAZMA_STRICT_TOOLSunset (off)No1 stamps OpenAI function.strict: true on closed tool schemas (all properties required; optionals are T | null). Default is closed objects with additionalProperties: false only — local / Anthropic / Gemini often 400 on strict.
KAZMA_LLM_STREAMonNo0 falls back to blocking chat() (no token SSE).
KAZMA_TOOL_HOOKSonNo0 disables PreToolUse / PostToolUse (in-process and command). Empty agent.hooks.* lists are a no-op. Hooks cannot skip HITL.
KAZMA_PLAN_MODEonNo0 disables /plan enter/execute. Plan mode is not a HITL bypass.
GOOGLE_CALENDAR_TOKEN / MS_CALENDAR_TOKENunsetOptionalOverride only. Calendar tokens normally live in the vault (calendar.google.* / calendar.microsoft.*) via Settings → Email → Connect Calendar / Connect with Microsoft.
KAZMA_CALENDAR_PROVIDERautoNoCalendar backend when a call names none: auto picks Google if connected, else Microsoft, else the sandbox. google, outlook (also microsoft / graph) or sandbox force one; a forced provider with no credentials fails instead of falling back.
KAZMA_VISION_MODELSunsetNoComma-separated extra model-id patterns (shell wildcards, case-insensitive) to treat as vision-capable, e.g. so analyze_image can pick a model the built-in list does not know. The built-in text-only list still wins.
Provider-specific—As usede.g. DeepSeek, Groq, xAI, OpenRouter, Mistral, Together, Cohere, Fireworks, Perplexity, AI21, Google ADC — see Configuration.

VariableDefaultProd required?Purpose
KAZMA_WORKSPACEactive WorkspaceStore / data dirProd root policyAgent filesystem workspace root.
KAZMA_VECTOR_COLLECTIONagent_memoryNoChroma collection name.
KAZMA_VECTOR_MODELBAAI/bge-m3NoLegacy alias for the embedding model id (prefer KAZMA_EMBED_MODEL).
KAZMA_EMBED_PROVIDERlocalNoEmbedding provider (local or openai-compatible).
KAZMA_EMBED_MODELBAAI/bge-m3NoEmbedding model id (overrides memory.embedding.model).
KAZMA_EMBED_DIM1024NoEmbedding dimension (must match the model’s output).
KAZMA_EMBED_BASE_URLunsetRemote only/embeddings endpoint base URL for openai-compatible.
KAZMA_EMBED_API_KEYunsetRemote onlyAPI key for the remote /embeddings endpoint.
KAZMA_EMBEDDER_PREWARMunset (on)No0 skips loading the embedder at boot; the first recall that needs it loads it. The test suite sets it: every app a test built loaded the local model here.
KAZMA_DEMO_MODEunsetNoDemo fixtures — never enable in real prod.
KAZMA_MEMORY_ENFORCE_TENANTunsetMulti-tenant onlyWhen 1/true — and always under KAZMA_PRODUCTION=1 or multi-user — every /api/memory route scopes reads, counts, id-keyed mutations, undo tokens, hygiene and graph-clear by the request-scoped tenant (set by the auth middleware from verified JWT/opaque-session claims). Unset outside production and multi-user = single-tenant default.
KAZMA_MEMORY_STATE_ROLEunset (mirror)Multi-replica onlyprimary makes the Postgres state backend the recall SoT (fail-closed if down — no silent SQLite). Dense search is pgvector fused with ILIKE. Do not enable until python scripts/reconcile_memory_mirror.py --dry-run reports no dead-in-mirror / only-in-mirror rows.
KAZMA_PGVECTORauto when a Postgres DSN is setNo0 keeps sqlite-vec even if Postgres is on, without checking the server. Unset = pgvector auto-select from KAZMA_DATABASE_URL / memory.backends.state.url, used only if that Postgres ships the vector extension (checked at boot; postgres:16-alpine does not). Explicit Qdrant in Settings still wins.
KAZMA_WORKSPACE_ROOTunsetMulti-project hardeningWhen set, a workspace picked in the UI (Switch Repo, the path picker) must live under this directory. It is also a base under which cloned workspaces may be deleted.
KAZMA_CLONE_DIR~/kazma-reposNoWhere repositories cloned from the UI or /ide clone are put; cloned workspaces under it may be deleted from the UI.
KAZMA_MEMORY_STATE_REGIONunsetMulti-region onlyRegion id stamped on the rows this install mirrors to the Postgres state backend.
KAZMA_MEMORY_CONFLICT_POLICYlast_write_winsMulti-region onlyWhat a mirrored write does to a row that another region wrote first: last_write_wins overwrites it; origin_wins keeps the other region’s row, quietly (memory health counts it as kept_by_origin); fail_closed refuses the same write and reports it: memory health counts region_conflicts, and the mirror sync logs a warning each pass and pages the operator (memory.region_conflict, at most every 6 hours).
KAZMA_GRAPH_PROVIDERsqliteNoneo4j puts the knowledge graph on Neo4j, as does setting KAZMA_NEO4J_URL / NEO4J_URI or KAZMA_NEO4J_DEFAULT=1. These only fill settings that are empty: a provider already chosen in Settings wins.
KAZMA_NEO4J_URLbolt://localhost:7687NoNeo4j address (NEO4J_URI / NEO4J_URL are accepted too); setting it selects Neo4j.
KAZMA_NEO4J_USERneo4jNoNeo4j user (NEO4J_USER is accepted too).
KAZMA_NEO4J_PASSWORDunsetNoNeo4j password (NEO4J_PASSWORD is accepted too); fills an empty password only.
KAZMA_NEO4J_DEFAULTunsetNo1 selects Neo4j with the defaults above; the docker-compose.neo4j profile sets it.
KAZMA_AUTO_STORE_BELIEFSconservativeNoWhich facts the memory extractor saves from a conversation without being asked: off, conservative (default) or aggressive (every extracted belief — the old behaviour). Wins over memory.auto_store_beliefs.
KAZMA_TRANSCRIPT_RECALLonNo0 stops searching past Web chat transcripts when memory recall comes back empty (ConfigStore memory.transcript_fallback; the env value wins). Transcript text reaches the model fenced as untrusted data.

Test-only, opt-in: KAZMA_TEST_NEO4J_URL with KAZMA_TEST_NEO4J_USER (default neo4j) and KAZMA_TEST_NEO4J_PASSWORD run tests/test_neo4j_graph_cypher.py against a real Neo4j server. Point it at a throwaway one: the tests write and delete nodes of their own test tenant only, never anything else, but a live graph is not the place to try.


See Web research for playbooks. Tools are used from chat (no /research slash command).

VariableDefaultPurpose
KAZMA_SEARXNG_URLmulti-base auto-discoveryPreferred search backend for web_search (also ConfigStore search.searxng_url).
KAZMA_READ_URL_MAX_CHARS16000Default window size for one read_url / crawl_page response.
KAZMA_TOOL_RESULT_MAX_CHARS100000Characters of one ordinary tool result the model sees; the rest is truncated. 0 or less = no limit.
KAZMA_TOOL_RESULT_RESEARCH_MAX_CHARS200000Higher cap for research and exec tools (read_url, crawl_site, digests, web_search, shell_exec, python_exec, …).
KAZMA_RESEARCH_DIRresearchDefault workspace subfolder for auto-named read_url_to_file / crawl saves.
KAZMA_RESEARCH_DIGEST_MAX12000Max output size of digest_research_file.
KAZMA_CRAWL_MAX_PAGES50Hard ceiling for crawl_site max_pages.
KAZMA_CRAWL_MAX_DEPTH5Hard ceiling for crawl_site max_depth.
KAZMA_ACQUISITION_MODElocal_onlyLocal HTTP/extraction/Chromium by default. local_first_with_remote_fallback permits only named providers below.
KAZMA_ACQUISITION_REMOTE_PROVIDERSemptyComma-separated jina, firecrawl, proxy; requires the remote mode too. Keys and legacy flags cannot grant permission.
KAZMA_FETCH_DEADLINE_SECONDS90Complete text acquisition deadline including DNS, HTTP retries and rendering; 1–300 seconds.
KAZMA_REMOTE_JOB_REQUESTS256Durable remote request allowance per acquisition/research/crawl job, 0–1024. Failures and uncertain attempts consume allowance; nested requests share it. This is a request upper bound, not a financial spend cap.
KAZMA_REMOTE_DAY_REQUESTS1024Installation-wide durable remote request allowance per UTC day, 0–4096. Shared across providers and processes. Zero refuses remote dispatch. Provider credit usage/balances remain separate.
KAZMA_BROWSER_CGROUP_ROOTCurrent Linux cgroupAbsolute writable delegated cgroup v2 root for the local Chromium driver tree. Requires memory, swap, pids, CPU and group-kill controls. Missing controls refuse rendering; Kazma does not configure host controllers. Windows uses Job Objects.
KAZMA_FETCH_BACKENDautoLegacy remote selection: auto | httpx | jina | firecrawl; always subject to acquisition policy.
KAZMA_FIRECRAWL_API_KEYunsetOptional Firecrawl credential; used only after local failure when policy permits Firecrawl. A key alone is not permission.
KAZMA_FIRECRAWL_URLhttps://api.firecrawl.devFirecrawl API base (self-host OK).
KAZMA_JINA_READERunset0/off vetoes Jina. Other values cannot override the acquisition policy and provider allowlist.
JINA_API_KEY / KAZMA_JINA_API_KEYunsetOptional Jina Bearer token for higher rate limits.
KAZMA_FETCH_MAX_BYTES5000000Decoded response-body cap for direct HTTP and hosted scrape responses; clamped to 65536–20000000 bytes. Wire consumption and gzip/deflate expansion are bounded. Clipping is explicit; incomplete hosted payloads and JSON are refused. This is a per-response bound, not a whole-job/browser memory budget.
KAZMA_CRAWL_RESPECT_ROBOTS1Enforce KazmaBot robots policy for automated crawling, KB discovery/ingest and research saves. Failed checks refuse dispatch; 404/410 mean missing rules. Explicit 0 or crawl_site(respect_robots=False) is recorded as disabled by the operator. Only 0/1 are valid.
KAZMA_RESEARCH_ROUTEsoftFor a request worded as deep research, the first turn tells the agent to use run_research_pipeline once rather than chain many searches by hand. 0 removes the hint.
KAZMA_RESEARCH_SOFT_NUDGEdeepWhen the agent has searched but read fewer than KAZMA_RESEARCH_MIN_SOURCES full sources, it is told once not to answer from snippets: deep for deep-worded requests, any other value for every research request, 0 never.
KAZMA_RESEARCH_MIN_SOURCES2Full sources (read_url, read_url_to_file, crawls, digests) that count as enough for that nudge (1–8).
KAZMA_RESEARCH_ALLOW_THINunset1 lets a depth="deep" pipeline run finish with fewer sources than its minimum. Without it a deep run fails; a standard run only warns.
KAZMA_RESEARCH_EXPORT_DOCXunset1 exports every pipeline report as DOCX too, as if export_docx=True had been passed.
KAZMA_RESEARCH_GAP_LOOPonAfter a deep run’s first synthesis, a critic may ask for one more round of sources. 0 skips it.
KAZMA_RESEARCH_LLM_PLANNERon0 plans search queries by heuristic instead of an LLM call.
KAZMA_RESEARCH_LLM_CRITICon0 checks a draft for gaps by heuristic instead of an LLM call.
KAZMA_RESEARCH_SYNTH_MAX_IN48000Characters of research files one research_synthesize call reads (4000–200000).

Optional package: Playwright via pip install -e ".[web]" then playwright install chromium (bot walls / thin JS shells).

SearXNG ops: docker compose --profile search up -d searxng → http://127.0.0.1:8088 (JSON enabled in deploy/searxng/settings.yml).

VariableDefaultPurpose
KAZMA_KB_AUTO_INJECTonPassages from libraries marked auto-inject may be added to a turn’s context. 0 turns that off for every library.
KAZMA_KB_AUTO_INJECT_TOP_K3Passages injected per turn (1–10).
KAZMA_KB_SMART_SEARCHoff1 also injects from every active library that has content (not only auto-inject ones) when the message looks technical. ConfigStore knowledge.smart_search; the env value wins. Tenant and archive filters still apply.
KAZMA_KB_MAX_PAGES200Pages one library ingest job may fetch (1–1000).
KAZMA_KB_MAX_DEPTH10Link depth of an ingest crawl when the site has no sitemap (0–20).
KAZMA_KB_DELAY_MS300Pause between page fetches of one ingest job (0–5000 ms).
RAYON_NUM_THREADSset to 1 by Kazma when unsetNot a Kazma variable: the thread count of the Rust thread pool in chromadb (and tokenizers). Kazma sets it to 1 before the Knowledge Library’s vector store starts, because Chroma’s parallel replay of a library’s write log can crash the process. A value you set yourself is kept, with a WARNING in the log; leave it unset. See Knowledge Library.
KAZMA_KB_SCOPE_MODEtreeWhich links an ingest crawl follows: tree (same host and a shared topic path segment), prefix (strict path prefix), domain (same host, any path) or exact (the one page).
KAZMA_KB_JINA_FALLBACKpolicy-gatedJina discovery fallback requires remote mode plus jina allowlist permission. 0, or KAZMA_JINA_READER=0, vetoes it; 1 cannot grant permission.

VariableDefaultProd required?Purpose
KAZMA_OIDC_ISSUERunsetIf SSOOIDC issuer URL.
KAZMA_OIDC_CLIENT_IDunsetIf SSOClient id.
KAZMA_OIDC_CLIENT_SECRETunsetIf SSOClient secret (required for HS* id_token).
KAZMA_OIDC_TENANT_CLAIMunsetNoThe id_token claim naming the user’s Kazma tenant; bound to the session at login. Unset = every OIDC user shares the default tenant.
KAZMA_OIDC_REDIRECT_URI{KAZMA_PUBLIC_URL}/api/auth/oidc/callbackIf no public URLCallback address registered with the IdP. Login refuses to start when neither this nor KAZMA_PUBLIC_URL is set.
KAZMA_OIDC_SCOPESopenid profile emailNoScopes requested at login.
KAZMA_OIDC_ROLE_CLAIMroleNoid_token claim naming the user’s role (roles, then groups, are tried next). admin / operator / viewer are used as-is; owner, member, readonly and similar are mapped.
KAZMA_OIDC_DEFAULT_ROLEoperatorKeep operator or viewerRole for a user whose token names no recognized role. Setting admin makes every such user an administrator.
KAZMA_MULTI_USERunsetMulti-user1 applies the multi-user posture before any platform user exists: per-tenant filtering, opaque sessions always, and an RBAC check that cannot run denies the request instead of allowing it.
KAZMA_SESSION_TTL_SECONDS1209600 (14 days)NoLifetime of a browser session; at least 300.
KAZMA_TENANT_IDdefaultCLI onlyTenant the kazma CLI acts as.

See OIDC IdP Setup and Multi-user SaaS.


Native skill email-manager. Default provider auto: real account if configured, else sandbox.

VariablePurpose
EMAIL_DEFAULT_PROVIDERauto | sandbox | gmail | microsoft | imap | pop
EMAIL_GMAIL_ADDRESSGmail address (filled by OAuth or IMAP/POP)
EMAIL_GMAIL_APP_PASSWORDApp password for IMAP/POP (often blocked on Workspace)
EMAIL_GMAIL_AUTHoauth | imap | pop (set by Settings / OAuth)
EMAIL_GMAIL_CLIENT_ID / EMAIL_GMAIL_CLIENT_SECRETGoogle OAuth web client (recommended)
EMAIL_GMAIL_ACCESS_TOKEN / EMAIL_GMAIL_REFRESH_TOKENSet by OAuth callback / refresh
EMAIL_GMAIL_REDIRECT_URIOverride callback (default {public}/api/email/oauth/gmail/callback)
EMAIL_MS_ACCESS_TOKENGraph bearer token (short-lived)
EMAIL_MS_REFRESH_TOKENGraph refresh token
EMAIL_MS_CLIENT_IDAzure app client id
EMAIL_MS_CLIENT_SECRETAzure app secret (confidential clients)
EMAIL_MS_TENANT_IDTenant (common default)
EMAIL_MS_REDIRECT_URIOverride callback (default {public}/api/email/oauth/microsoft/callback)
EMAIL_MS_AUTHoauth | imap | pop
EMAIL_MS_ADDRESS / EMAIL_MS_PASSWORDMicrosoft IMAP/POP login
EMAIL_MS_IMAP_HOST / EMAIL_MS_POP_HOST / EMAIL_MS_SMTP_HOSTOverride M365 protocol hosts
KAZMA_PUBLIC_URLPublic origin for OAuth redirects behind proxy
EMAIL_ADDRESS / EMAIL_PASSWORDGeneric IMAP/POP user
EMAIL_PROTOCOLimap | pop for generic account
EMAIL_IMAP_HOST / EMAIL_IMAP_PORTIMAP (default 993)
EMAIL_POP_HOST / EMAIL_POP_PORTPOP3 SSL (default 995)
EMAIL_SMTP_HOST / EMAIL_SMTP_PORTSMTP (default 587 STARTTLS)
EMAIL_ACCOUNTSComma-separated multi-account aliases
EMAIL_ACCOUNT_{ALIAS}_TYPEgmail | microsoft | imap | pop
EMAIL_ACCOUNT_{ALIAS}_ADDRESS / _PASSWORDPer-account credentials
EMAIL_ACCOUNT_{ALIAS}_*IMAP_HOST, POP_HOST, REFRESH_TOKEN, CLIENT_ID, …

API: GET /api/email/status, GET /api/email/presets, POST /api/email/protocol/connect\|disconnect, OAuth start/callback routes.
HITL: email_send, email_delete, email_categorize. Guide: Email integration.


Native skill x-publisher. Credentials live in Settings → X (vaulted ConfigStore keys) or env. Compose and plan on X Studio (/x). Guide: X publisher.

VariableDefaultPurpose
KAZMA_X_POSTunset (on if Settings enabled)0 hard-disables posting (Studio, chat, scheduled fire, and auto-reply publishes).
KAZMA_X_SCHEDULEunset (on)0 disables scheduling only (book_x_post / Studio Schedule).
KAZMA_X_REPLYunset (on if Settings enabled)0 disables mention auto-reply only. Scheduled posts still work.
KAZMA_X_SHADOWunsetInternal guard set by the isolated scripts/x_shadow.py evaluation worker. 1 blocks every X network request and notification delivery; use the evaluation CLI rather than setting it on a running install.
X_API_KEYunsetOAuth 1.0a consumer key (else connectors.x.api_key).
X_API_KEY_SECRETunsetConsumer secret.
X_ACCESS_TOKENunsetUser access token.
X_ACCESS_TOKEN_SECRETunsetUser access token secret.

Do not use the app-only Bearer token. User authentication must be Read and write.


Safety guards & embedder downloads (2026-08-19)

Section titled “Safety guards & embedder downloads (2026-08-19)”

Opt-in hardening from the deep-structure audit (docs/audits/AUDIT_DEEP_STRUCTURE_2026-08-19.md) — all default OFF (current behavior preserved) unless noted.

VariableDefaultPurpose
KAZMA_HITL_CANONICAL_FLOORonThe effective require_approval_for always includes the canonical danger tools, so Settings/YAML cannot narrow it below them. 0 opts out and logs a warning; the drift warning repeats every 15 min either way. (Opt-in 1 until 2026-09-16; on by default since audit F-5.)
KAZMA_GATEWAY_STRICT_ALLOWLISTunset (compat)Stop forcing _allow_all on the Telegram/Discord/Slack adapters — an empty allowlist then fails closed (no messages). Without it, forced allow-all logs a WARNING naming both remediations when no allowlist is configured.
KAZMA_MCP_SCOPE_GUARD1 (on)Fail-close MCP tool calls when a per-task workspace_scope targets a different root than the process-bound MCP root (prevents silent wrong-repo operations). Set 0 only if the guard blocks a legitimate flow.
KAZMA_EMBED_ALLOW_DOWNLOADunset (contextual)Force-allow the local embedder to download its model from HuggingFace. Fallback embedders (unknown provider / broken remote config) never download — they check the local HF cache and degrade to no embeddings with an actionable warning instead of stalling on a ~2GB download. Deliberate local configs keep first-run download rights.
KAZMA_PERMISSIONS_ENFORCEunset1 enforces the per-user tool allowlists in kazma-permissions.yaml even before any users: entry exists, and denies every tool if the file cannot be read. Without it, enforcement starts once a user has an allow or deny list.
KAZMA_DIVISIONunset (ConfigStore agent.division)Runs this install as a division: MCP servers listed under divisions.<name>.denied_mcp_servers in kazma-permissions.yaml are blocked, and each blocked call files an access request. Unset = no division checks at all.
KAZMA_DIVISION_USERdefaultThe user id division access requests are filed for.
KAZMA_SELF_IMPROVEMENTon0 stops the self-improvement engine on the chat and swarm paths: no new Soul deltas are learned or injected. Read live.
KAZMA_BUS_BRIDGEonLets kazma mcp (a process with no approval bus) ask for approval through the gate registry, where the dashboard shows the card. 0 removes that path, so kazma mcp withholds every danger tool.
KAZMA_WATCHER_STALE_SECONDS120How recent the running server’s approval-watcher heartbeat must be for that bridge to engage. Without a fresh one nobody is reading approvals, so the tool is refused at once instead of after a timeout.

Every variable here turns a protection off. They are listed together, on the operator-facing page, because a switch nobody can discover is a switch nobody can audit — including the operator who set it two years ago. Each row says what stops protecting you, not just what the flag does.

tests/test_static_gates.py::test_security_env_vars_are_documented fails the build if the code reads one of these and it is missing from both .env.example and this table.

VariableDefaultWhat it turns OFFSafe to set when
KAZMA_ACQUISITION_MODE / KAZMA_ACQUISITION_REMOTE_PROVIDERSlocal_only / emptylocal_first_with_remote_fallback plus named providers admits hosted extraction or configured scraping proxies. URLs/content can leave the machine and paid services may charge.The operator deliberately permits those providers. Durable request reservations bound job/day dispatch; they are not financial caps or observed charges. Firecrawl balances require an explicit metered refresh; unsupported balances remain unknown. Keys alone grant nothing.
KAZMA_AUTH_DISABLEDunsetThe entire HTTP auth gate. A configured KAZMA_SECRET becomes irrelevant — the switch disables the check that reads it.Loopback only, with no proxy in front. Refused at boot on a non-loopback bind or behind a declared proxy (KAZMA_TRUSTED_PROXIES, security/boot_guard.py). While it is set, a request that came through a proxy is answered 503. Refused outright with KAZMA_PRODUCTION=1.
KAZMA_DEV_WS_BYPASSunsetAuthentication on every WebSocket handshake, including the chat socket that carries the turn stream. HTTP auth is unaffected, which is what makes it easy to miss.Loopback only, with no proxy in front. Refused at boot on a non-loopback bind or behind a declared proxy, same guard as KAZMA_AUTH_DISABLED.
KAZMA_DEMO_MODEunsetThe auth gate, deliberately, for a public throwaway demo (fly.toml). Allowed on a public bind and announced loudly at boot.A throwaway instance with no real data, credentials or vault. Never on an install you care about.
KAZMA_AUTOLOGIN_HOSTSloopback setRestricts which hosts may be auto-issued a session cookie without presenting the secret. Widening it grants silent admin sessions to those hosts.You control every host in the list. Adding a non-loopback host is equivalent to publishing the secret to it.
KAZMA_GATEWAY_ADMINSunsetWho may run privileged chat-platform commands. Empty means the adapter’s own allowlist is the only gate.Set it explicitly on any multi-user chat platform.
KAZMA_GATEWAY_STRICT_ALLOWLISTunset (compat)Enables fail-closed adapters. Leaving it unset keeps the legacy forced _allow_all when no allowlist is configured.Set to 1 on any deployment more than one person can message.
KAZMA_HITL_CANONICAL_FLOORon0 turns the floor off: Settings/YAML may then narrow require_approval_for below the canonical danger list. Those tools stay gated by their tier, but the graph interrupt and the swarm bus read the list itself.Never — no deployment needs a narrower list.
KAZMA_MCP_ALLOW_UNGATEDunsetHITL approval for MCP tools that were not classified as safe. An MCP server’s tool names are untrusted input.Never, on an install with real credentials. Debugging a single trusted local server at most.
KAZMA_MCP_SAFE_ALLOWLISTbuilt-inWidens the set of MCP tools that skip HITL by name. Names come from the server, so this is a list of names you are trusting a third party to choose honestly.Only for tools you have read the implementation of.
KAZMA_MCP_TRUSTED_IN_PRODunsetThe production refusal for MCP servers not marked trusted.You own every listed server.
KAZMA_CODE_EXEC_ALLOW_LOCALunsetThe ban on running python_exec as a host subprocess when Docker is absent. The local fallback has an import blocklist; it is not a jail.A lab box with nothing worth stealing. Production and multi-user ban it regardless — see KAZMA_CODE_EXEC_DOCKER=force.
KAZMA_SHELL_ALLOW_MUTATEunsetThe restricted PATH/allowlist applied to shell_exec after the human approves. Approval is consent; the allowlist is the containment.You accept that an approved shell command runs unconstrained.
KAZMA_YOLO_TTL_SECONDS3600Lengthens the window in which further danger tools auto-approve after one YOLO grant. A long TTL turns one approval into an open session. off / none / infinite = no expiry; numbers are seconds, at least 60 (0 means 60).Short values only. This is a blast-radius dial.
KAZMA_DISABLE_COST_BREAKERunsetThe spend ceiling that stops a runaway loop.Never unattended.
KAZMA_CHAOS_ENABLEDunsetEnables fault-injection routes. Off by default; the router does not mount without it.Test environments only — must stay off in production.
KAZMA_WS_ORIGIN_CHECKon0 turns off the Origin check on WebSocket handshakes. A page on any other site, opened in the operator’s browser, can then open an authenticated socket to Kazma from a loopback or trusted-LAN address (cross-site WebSocket hijacking).Never on an install a browser can reach.
KAZMA_WS_EXTRA_ORIGINSunsetAdds origins the WebSocket Origin check accepts (exact scheme://host[:port], comma-separated). Every listed origin may open an authenticated socket.You serve the UI from that origin yourself (a tunnel, a second domain).
KAZMA_OPAQUE_SESSIONSon0 makes the browser cookie carry the shared KAZMA_SECRET itself instead of a random server-side session id: sessions cannot be revoked one at a time, and a stolen cookie is the install’s secret. Multi-user mode ignores it.Never on a network-reachable install.
KAZMA_RATE_LIMIT_ENABLEDon when auth is on0 removes the per-client rate limits on chat streams, voice, research sessions, swarm dispatch and system flush. (They are already off with no KAZMA_SECRET and in demo mode.)A single-operator loopback install.
KAZMA_TENANT_FILTERon0 stops scoping knowledge-base libraries and swarm task lists to the caller’s tenant in production / multi-user mode, so every tenant reads every tenant’s rows.A single-tenant install, where it changes nothing.
KAZMA_SESSION_OPEN_TAKEOVERunsetThe owner check on /session <id> in chat platforms. With 1 any allowlisted sender can switch onto another user’s session, continue it, and answer the approval cards waiting on it (audit H-3).Every allowlisted sender belongs to one team that shares everything.
KAZMA_SEMANTIC_CACHEretiredNothing: the semantic LLM response cache was removed on 2026-09-30. It keyed on the whole conversation, whose embedding the shared system prompt dominates, so it replayed one turn’s answer and tool calls for later, different requests (audit AUD-001). Setting it only logs a warning at boot.—
KAZMA_MCP_INHERIT_ENVunsetThe environment allowlist for stdio MCP servers. With 1 every MCP server process receives Kazma’s whole environment — KAZMA_SECRET, KAZMA_VAULT_KEY, provider API keys — instead of PATH, TEMP, HOME and similar. A server’s own env / auth config is passed either way.Practically never; pass what one server needs in its config instead.
KAZMA_CHILD_ENV_ALLOWunsetNames (comma-separated) let through the secret filter on the processes tools start — pytest, pip/npm installs, ruff, git (security/child_env.py). Those children run a repository’s tests and hooks and packages’ install scripts; by default they get the server’s environment without any KAZMA_* variable, credential-named variable (*_TOKEN, *_API_KEY, *_PASSWORD, …) or URL carrying a password. A listed name reaches every such child. KAZMA_* names are never let through.One name a child genuinely needs, such as a private npm registry’s NPM_TOKEN.
KAZMA_ALLOW_PRIVATE_LLMunsetThe SSRF check on model discovery for custom OpenAI-compatible providers. With 1, listing a provider’s models may call a private or internal address, sending that provider’s API key to it. Ollama and LM Studio discovery are separate and unaffected.The model server is on a private network and only administrators can edit providers.
KAZMA_CLONE_HOSTSunset (github.com only)The github.com-only rule for clones from the UI. A listed host is accepted over any scheme, plain http:// included.GitHub Enterprise or your own git server, reached over https.
KAZMA_UPDATE_REMOTE_ALLOWLISTgithub.com/mubder/kazmaWhich origin remotes kazma update trusts, as comma-separated substrings. The updater hard-resets the install to that remote and runs its installer, so this list decides whose code runs.A fork you control; make each entry specific enough that it cannot match someone else’s repository.
KAZMA_HITL_GRANT_TTL_SECONDS1800How long a “for this tool” approval lasts on a thread; until then that tool runs without asking. off / none / infinite keep it until it is cleared; numbers are seconds, at least 60 (0 means 60).Short values. Like KAZMA_YOLO_TTL_SECONDS, a blast-radius dial.
KAZMA_UNRESTRICTED_TTL_SECONDS3600How long /unrestricted (mission mode, and every danger tool without approval) stays on after the last user message. 0 / off keep it on until /unrestricted off; other numbers are at least 60.Short values; never 0 on an install other people can message.
KAZMA_SHELL_STRICTon in production0 in production lets an approved shell_exec look up its (allowlisted) program on the whole process PATH instead of the system directories, so a same-named executable planted earlier in any PATH directory runs instead. 1 turns strict lookup on outside production.Never 0 in production.
KAZMA_SHELL_ALLOW_ARCHIVEunsetPuts tar, gzip, gunzip, zip and unzip back on the shell_exec allowlist in production strict mode. An archive can write outside the working directory through absolute or ../ member paths.You need archives in production and accept extraction anywhere the process can write.
KAZMA_GATE_REGISTRYon0 turns off approval lifecycle projections. Web, platform and timeout execution decisions then stay paused because durable decision recording is required.Diagnosis only; restoring the registry is necessary before resuming tools.
KAZMA_COMMITMENT_ENABLEDon0 removes the commitment layer: reminders are no longer checked against memory (a date the model invented is scheduled as written), the exec denylist no longer stops catastrophic commands before the approval card, protected settings keys and the outbound allowlist stop applying, and swarm workers lose their scope cap.Never on a real install; it exists to rule the layer out while diagnosing.
KAZMA_COMMITMENT_SWARM_SCOPE_ENFORCEon0 lifts the cap on dispatched swarm workers: they may then attempt exec, outbound, config and identity acts, Soul changes included (approval cards still apply).Never with workers you did not write.
KAZMA_COMMITMENT_SOUL_REQUIRES_CONFIRMoff; on in production / multi-user0 in production or multi-user mode lets self-improvement Soul changes apply without an operator confirming them. 1 requires the confirmation anywhere.A single-operator install that reviews Soul changes another way.
KAZMA_COMMITMENT_MODEbalancedyolo skips the reminder and cancel checks, so a reminder is scheduled at whatever time the model wrote — the incident class the layer exists for; autonomous stops asking when a reminder is ambiguous and takes the from-now date. Approval cards and the exec denylist still apply. strict asks more often.balanced or strict; yolo for testing only.

VariableDefaultPurpose
KAZMA_TURN_TIMEOUT_SECONDSthe setting (no limit)Wall-clock budget for one running stretch of a turn, in whole seconds, on every surface: the web chat, the chat apps, kazma ask, reminders and the agent runner (kazma_core/agent/turn_budget.py, since 2026-10-15; the web chat had none before, and the agent runner kept its own 600 s default). Wins over agent.turn_timeout_seconds (Settings → System); 0 is no limit, and a value that is not a whole number from 0 to 86400 is ignored, with one warning. A stretch runs from a new message, or the resume after an approval, until the turn answers or pauses: the wait for an approval is never counted. A turn past it is cancelled, ends with an honest ⚠️ Turn timed out reply on every surface, and the turn.timed_out ops alert is sent. A chat with /long active has no limit.
KAZMA_TOOL_TIMEOUT_SECONDS120Wall-clock limit for one tool call; 0 or less disables it. ConfigStore agent.tool_timeout_seconds wins.
KAZMA_TOOL_RESULT_FILE_MAX_CHARS32000Cap for file tools (file_read, file_search, codebase_search, the filesystem MCP reads, …) — tighter than the research cap, so a file read cannot re-inflate a prompt that was just trimmed.
KAZMA_NO_TRUNCATEunset1 turns tool-result truncation off entirely; one large result can then fill the context window.
KAZMA_COMPACT_PRESERVE_TOOL_RESULTS12Tool results kept when a conversation is compacted. Dropping them all made the agent repeat the same calls.
KAZMA_SEMANTIC_COMPACTonWhen history is trimmed (/compact, the 80% budget, a context-overflow error), the dropped part is summarized back into the conversation. 0 drops it without a summary.
KAZMA_SUMMARIES_MAX_ENTRIES500Conversation summaries held in memory, one per thread; the least recently used go first.
KAZMA_PROMPT_CACHEonPacks system notes into one stable prefix plus one per-turn block, so provider prompt caches hit (Anthropic gets explicit cache breakpoints). 0 restores the old one-message-per-note layout.
KAZMA_DETACHED_TTL_S300A turn whose client disconnected is cancelled after this many seconds, so nobody pays for LLM calls no one will read. The clock starts when the client leaves, not when the turn began.
KAZMA_TURN_DURABLE_INTERVAL_S2.0While an answer streams, its text is saved to the turn journal at least this often (that is what a refresh or reconnect recovers) …
KAZMA_TURN_DURABLE_CHARS600… or after this many new characters, whichever comes first.
KAZMA_TURN_LIVENESS_GRACE_S600How long a reply turn may sit open with nothing working on it and no approval pending before it is reported (at least 60).
KAZMA_TURN_LIVENESS_HEALoff1 also closes such a turn. Off by default: closing is what the original bug did wrong, so turn it on only once the reports show what accumulates.
KAZMA_INTENT_ENGINEonThe intent engine classifies each turn and may route it to a handler or add a plan note. 0 sends every turn straight to the agent loop (ConfigStore agent.intent.enabled).
KAZMA_INTENT_EXECUTEon0 keeps the classification and plan notes but never runs a handler directly (agent.intent.execute_enabled).
KAZMA_INTENT_TIER2on0 skips the LLM refinement of borderline classifications, leaving heuristics only (agent.intent.tier2_enabled).
KAZMA_PERSONALITYdefaultPersonality when neither a runtime switch nor agent.personality names one: default, friendly_expert, concise, gulf_engineer, creative_partner, sysadmin, teacher or code_reviewer. An unknown name falls back to default with a warning.
KAZMA_LONG_TASK_TTL_SECONDS1800How long a /long budget stays on a thread. off / none / infinite keep it until turned off; numbers are seconds, at least 60 (0 means 60).
KAZMA_LONG_TASK_MAX_ITER100Most iterations a /long budget may ask for (5–100).
KAZMA_LONG_TASK_MAX_RECURSION500Most graph steps a /long turn may take (50–500).
KAZMA_MISSION_MAX_ROUNDS500Tool rounds one mission-mode turn may run before it must stop (40–2000).
KAZMA_MISSION_RECURSION5 × roundsGraph steps for a mission turn (500–5000); follows KAZMA_MISSION_MAX_ROUNDS unless set.

VariableDefaultPurpose
KAZMA_MCP_TIMEOUT_MS90000Request timeout, in milliseconds, for MCP servers whose config sets no timeout (which is in seconds, and wins).
KAZMA_MCP_STDIO_LIMIT16777216 (16 MiB)Largest single message a stdio MCP server may send (256 KiB–64 MiB). A bigger one used to break the pipe for every later call.
KAZMA_MCP_TOOLSunset (all)Comma-separated names of the tools kazma mcp publishes to MCP clients. Danger tools still need an approval path (KAZMA_BUS_BRIDGE).
KAZMA_MCP_IDE_ENABLEDtrueAnything but 1 / true / yes makes the gateway’s MCP IDE server (write_file, run_tests, … behind KAZMA_SECRET and the safety check) refuse tool calls.

The switches that loosen MCP (KAZMA_MCP_INHERIT_ENV, KAZMA_MCP_ALLOW_UNGATED, …) are in the security table.


Each of these moves one file or directory. A store moved outside the data directory is not in the universal backup or the migration bundle, which both work from the data directory — to relocate data, move KAZMA_DATA_DIR as a whole.

VariableDefaultPurpose
KAZMA_DATA_DIR<install>/kazma-dataEvery store, attachment and backup.
KAZMA_USER_HOME<install>/.kazmaLogs, guard state, the hub registry, the restic passphrase. A legacy ~/.kazma is moved here once at startup.
KAZMA_SKILLS_HOMEthe user’s home folderThe folder whose skill folders Kazma reads and installs Agent Skills to: .agents/skills (shared with other agentskills.io clients), .claude/skills, .cursor/skills and the legacy .kazma/agent-skills. Set it when Kazma runs as a service account that should read another user’s skills; the test suite sets it so a test run never reads or changes the real ones.
KAZMA_PROJECT_ROOTfound by walking up to pyproject.tomlInstall root, used only when that walk finds nothing (the working directory is the last resort). kazma mcp pins it when set.
KAZMA_LOG_FILE<.kazma>/kazma.logApplication log file. The agent’s read_system_logs, Settings → System → Logs and the weekly resilience report all read this file.
KAZMA_BACKUPS_DIR<data>/backupsUniversal backups.
KAZMA_EXPORTS_DIR<data>/exportsJSONL / GraphML memory exports.
KAZMA_FTS5_PATH<data>/memory.dbFull-text memory store.
KAZMA_VECTOR_PATH<data>/vector_memoryChromaDB vector memory.
KAZMA_VECTOR_DB<data>/vector.dbsqlite-vec vector store.
KAZMA_KNOWLEDGE_GRAPH_DB<data>/knowledge_graph.dbKnowledge graph (SQLite provider).
KAZMA_MEMORY_STATE_DB<data>/memory_state.dbV2 memory: beliefs, episodes, entities (the hot read path).
KAZMA_MEMORY_OPS_DB<data>/memory_ops.dbV2 memory task queue and audit log (kept apart so background writes never contend with chat reads).
KAZMA_ARTIFACTS_DB<data>/agent_artifacts.dbSaved drafts and scratchpad findings.
KAZMA_FILE_CHECKPOINTS_DB<data>/file_checkpoints.dbCheckpoints that undo the agent’s workspace file edits.
KAZMA_HUB_DB<.kazma>/hub/registry.dbSkill-hub registry (kazma hub --registry-path wins).

VariableDefaultPurpose
KAZMA_BACKUP_RETENTION7Universal backups kept (at least 1). Wins over backups.retention.
KAZMA_PG_BACKUP_ENABLEDon with Postgres0 stops the 6-hourly pg_dump of Kazma’s Postgres tables, whatever backups.pg.enabled says.
KAZMA_PG_BACKUP_RETENTION3Local Postgres dumps kept (restic keeps the history). Wins over backups.pg.retention.
KAZMA_RESTIC_PASSWORD<.kazma>/restic.passPassphrase of the restic repository; wins over that file. A missing passphrase is reported as an error — Kazma does not invent one, since a key kept only on the disk the backup protects is no key. Keep a copy off this machine.
KAZMA_CHECKPOINT_RETENTION_DAYSthe setting (30)Days a chat’s step history (its LangGraph checkpoints) is kept in full after the chat’s last message; wins over checkpoints.retention_days (Settings → System). Every chat keeps its newest 200 checkpoints and a chat idle that long its newest 10, on SQLite and Postgres (since 2026-09-27; Postgres was never pruned before); 0 keeps every checkpoint. A value that is not a whole number from 0 to 3650 is ignored, with one warning.

VariableDefaultPurpose
KAZMA_TZUTCTime zone for cron schedules when cron.timezone (Settings) is empty.
KAZMA_CRON_STALE_HOURSthe setting (60 minutes)The catch-up window in hours, used only when cron.catchup_minutes (Settings) is not set: a reminder or task that fell due while Kazma was down still fires if it is at most this late, and says how late. Past it the job is missed: it does not run, and one notice says so (since 2026-10-14; before, a job up to 24 hours late ran as if on time and an older one was skipped without a word). A window given when the job is booked wins over both.

VariableDefaultPurpose
KAZMA_LOG_LEVELINFODEBUG, INFO, WARNING, ERROR or CRITICAL. logging.level in Settings wins.
KAZMA_LOG_FORMATtextjson writes one JSON object per line. logging.format: json in Settings wins.
KAZMA_LOG_RETENTION_DAYS7Daily log files kept before the oldest is deleted. logging.retention_days in Settings wins.
KAZMA_OPS_ALERTSon0 mutes operational alerts (backups, offsite, MCP, persistence, failed turns). Startup and shutdown notices are separate and stay on.
KAZMA_OPS_ALERT_COOLDOWN_S900Quiet period before the same alert may fire again.
KAZMA_DAILY_DIGESTonA short daily summary of what ran, failed and recovered, sent through the alert channel, so silence means healthy rather than dead. 0 stops it.
KAZMA_DIGEST_INTERVAL_HOURS24Hours between digests.
KAZMA_LOOP_STALL_WATCHDOGonWrites every thread’s stack to .kazma/stall-*.txt when the event loop stops responding for 15 s. 0 turns it off (the test suite does).
KAZMA_OTLP_ENDPOINTunsetOTLP/HTTP collector (e.g. http://localhost:4318); swarm spans are posted as JSON to <endpoint>/v1/traces.

VariableDefaultPurpose
KAZMA_UPDATE_VERIFY_SIGNATURESunset1 makes kazma update refuse a target commit whose signature git verify-commit cannot verify.
KAZMA_HUB_URLhttps://hub.kazma.aiSkill-hub API for kazma hub (--hub-url wins).

Which remotes kazma update trusts at all is KAZMA_UPDATE_REMOTE_ALLOWLIST, in the security table.


Guard (supervisor, scripts/service/kazma_guard.py)

Section titled “Guard (supervisor, scripts/service/kazma_guard.py)”
VariableDefaultPurpose
KAZMA_GUARD_CMDserve.pyCommand the guard runs and supervises.
KAZMA_GUARD_CWDrepo rootWorking directory for it.
KAZMA_GUARD_HEALTH_URLhttp://127.0.0.1:9090/health/readyProbe target.
KAZMA_GUARD_START_TIMEOUT900Seconds allowed to first ready.
KAZMA_GUARD_INTERVAL30Seconds between probes.
KAZMA_GUARD_PROBE_TIMEOUT—Per-probe timeout.
KAZMA_GUARD_FAILURES3Consecutive failed probes before a restart. Probes that cannot get a local port (WinError 10048/10055) never count — see Deployment §6.
KAZMA_GUARD_DEPENDENCY_OUTAGE_S600Seconds Kazma may answer “not ready” (a 503 naming a failing dependency, such as the database) before the guard restarts it. A restart cannot bring a database back, so such an outage is paged once and ridden out; KAZMA_GUARD_FAILURES counts only probes that get no answer.
KAZMA_GUARD_PAGE_COOLDOWN_S—Minimum gap between identical pages.
KAZMA_GUARD_GRACEFUL_STOP_S60Seconds a deliberate stop (reload, maintenance pause, guard shutdown) waits for the server to shut itself down before it is killed.
KAZMA_GUARD_LOG / KAZMA_GUARD_STATE<install>/.kazma/Guard log, and the state file: child PID, the guard’s heartbeat, reload acknowledgements.
KAZMA_GUARD_RELOAD_FILE / KAZMA_GUARD_PAUSE_FILE<install>/.kazma/The --reload request and the --pause flag.
KAZMA_GUARD_STATE_FILEset by the guardGiven to the server the guard spawns: the path of the guard’s state file. The server’s supervisor watch reads the guard’s heartbeat there and pages when it stops; document readiness reads the guard’s record of the document broker there.
KAZMA_GUARD_BROKER_REQUEST_FILEset by the guardGiven to the server the guard spawns: where the server asks for the document worker broker (.kazma/document_broker.request.json). The server writes whether it needs one (the container profile) at boot, on a profile change and every maintenance pass; the guard starts or stops the broker within a second.
KAZMA_GUARD_DOCUMENT_BROKERautoWhether the guard runs the document worker broker beside Kazma. auto: when Kazma asks for it (the container profile). on: always. off: never, and the server is handed no broker address. An unknown value means auto. Set in the guard’s environment (the KazmaAgent task’s), not .env.
KAZMA_GUARD_BROKER_PORTchosen onceThe loopback port of the guard’s broker. Unset, the guard keeps the port it used before, else takes the first free of 64 derived from the install folder, between 20000 and 29999 (below the ephemeral ranges).
KAZMA_GUARD_BROKER_IMAGEthe build for the code on diskPin the worker image the guard’s broker serves. Unset, it asks for kazma-document-worker:src-<16 hex> (scripts/document_worker_image.py build) and serves the newest build while that one is missing; pinned, it serves exactly this one.
KAZMA_GUARD_BROKER_SCRIPTkazma_core/documents/worker_broker.pyThe broker program the guard runs (the guard’s tests run a stand-in).
KAZMA_PROCESS_PRIORITYnormalWindows: the server and the guard raise themselves, never lower, to an interactive program’s priority as they start (CPU class, memory priority, I/O priority). A Scheduled Task registered without a priority starts them below every normal program. keep leaves both as they were started; scripts/fast_test.py sets it for the test processes it deliberately lowers.
KAZMA_GUARD_TELEGRAM_TOKEN / KAZMA_GUARD_TELEGRAM_CHATvault / SWARM_*Direct Telegram paging, independent of the app.
VariableDefaultPurpose
KAZMA_MAX_COSTcost breaker defaultUSD budget ceiling.
KAZMA_HARD_MAX_COST15.00USD ceiling that halts the agent at once, whatever the silence window (KAZMA_MAX_COST only trips after the user has been silent). Wins over safety.hard_max_cost.
KAZMA_TEST_BACKGROUND_SCHEDULERSunsetTest-only: 1 starts the memory worker’s background schedulers under pytest, where they otherwise never run.
KAZMA_SILENCE_WINDOWcost breaker defaultSilence window seconds.
KAZMA_CHAOS_ENABLEDunsetChaos routes (must stay off in prod).
KAZMA_SMOKE_BASEhttp://127.0.0.1:9090Smoke test base URL.
KAZMA_TEST_FORCE_OUTPUT_ROUTINGunsetTest-only gateway output routing.
KAZMA_CODE_EXEC_DOCKERpolicyforce in hardened Docker compose for code_exec jail.
KAZMA_MARKET_STUB0Example skill market data stub.

VariablePurpose
GITHUB_TOKEN / OAuth pathNative git tools & GitHub client (prefer OAuth→PAT chain in app).
KAZMA_BOT_NAME / KAZMA_BOT_EMAILCommit identity for the agent’s git commits (default kazma-agent[bot]@users.noreply.github.com). Setting either turns the bot identity on, as git.bot_identity.enabled does; an explicit email also wins over the one derived from a GitHub App.
KAZMA_GITHUB_APP_ID / KAZMA_GITHUB_APP_INSTALLATION_IDCommit and authenticate as a GitHub App; with both set the app identity is on (overrides connectors.github.app_*).
KAZMA_GITHUB_APP_PRIVATE_KEY / KAZMA_GITHUB_APP_PRIVATE_KEY_PATHThe app’s private key, inline or as a file path.
KAZMA_GITHUB_APP_SLUGThe app’s slug, used to find the app’s own bot email (the one that carries its avatar).
KAZMA_CLONE_DIRSee Workspace, memory, demo. KAZMA_CLONE_HOSTS is in the security table.

Terminal window
# Loopback; secret auto-generated if missing
KAZMA_HOST=127.0.0.1
# optional OPENAI_API_KEY=...
kazma serve 9090
Terminal window
KAZMA_HOST=0.0.0.0
KAZMA_SECRET=<strong-random>
KAZMA_PRODUCTION=1
KAZMA_VAULT_KEY=<strong-random>
KAZMA_PUBLIC_URL=https://your.domain
KAZMA_TRUSTED_PROXIES=127.0.0.1 # REQUIRED — the proxy's address, not the client's
KAZMA_TRUST_LAN=0
KAZMA_CODE_EXEC_DOCKER=force

Under Docker, KAZMA_TRUSTED_PROXIES is the proxy container’s address on the bridge network (often 172.17.0.1 or the compose network’s gateway), not 127.0.0.1.

Terminal window
KAZMA_DATABASE_URL=postgresql://…
KAZMA_RUNTIME_HA=1
KAZMA_PRODUCTION=1
KAZMA_SECRET=…
KAZMA_VAULT_KEY=…
KAZMA_PUBLIC_URL=https://…
KAZMA_TRUSTED_PROXIES=<load-balancer / ingress address>
# optional OIDC_*

KAZMA_RUNTIME_HA defaults to 0. Set 1 for database ownership admission before services start: a dedicated Postgres session holds the runtime lock, and session loss exits the process without reconnecting. The database is paired with the complete state volume through its .runtime-state-id. Use a direct database endpoint or session pooling, never transaction pooling. This requires one runtime and a storage system with verified fencing; it does not enable multiple active replicas. See Deployment.


VariableDefaultBehavior
KAZMA_BROWSER_NETWORK_MODErequiredRequire Linux isolated network namespace and cgroup controls; strict launch unavailable on Windows. compatibility explicitly uses the weaker broker/deny-proxy boundary.
KAZMA_JINA_TOKEN_BUDGET50000Reader token ceiling, integer 500–50000; provider rejection is visible.
KAZMA_ACQUISITION_MAX_COST_USDunsetOptional nonnegative monetary cap; remote dispatch refuses while its charging upper bound is unsupported.