Skip to content
kazma.
Search Kazma Documentation & Site
ع

Configuration

The exhaustive reference. Every key in kazma.yaml, every environment variable, the ConfigStore override model, the provider/model registry, and the security config files — all traceable to source.


Kazma resolves configuration from three layers. For the generic ConfigStore.get(key), the order is:

flowchart LR
    C[In-process cache] -->|miss| DB[(SQLite or PostgreSQL settings)]
    DB -->|miss / child-merge| YAML["kazma.yaml + kazma.local.yaml"]
    YAML -->|fallback| DEFAULT[hardcoded default]
#LayerWins?Notes
1Env varOnly in specific helpers (get_kazma_secret, get_or_create_disclosure_key) — not in the generic get().e.g. KAZMA_SECRET
2ConfigStore DB (SQLite or PostgreSQL)Yes for runtime reads via get().Saved settings override YAML.
3kazma.local.yamlOverrides shipped YAML.Optional machine-local file; its values seed missing settings on first boot.
4kazma.yamlShipped baseline.Merged with local YAML before reconcile_from_yaml() seeds missing keys.
5Hardcoded defaultLast resort.e.g. gpt-4o-mini, DEFAULT_DANGER_TOOLS.
  • ConfigStore.get(key) (config_store.py:471-516): checks the in-process _cache first (with a _MISSING sentinel for known-absent keys), then an exact DB row, then a DB child-key re-merge via _collect_prefixed (rows whose key starts with key. are de-dotted into a nested dict), then a YAML dotted-key lookup.
  • ConfigStore.set(key, value) writes one row and clears the cache for that key (config_store.py:518-536).
  • ConfigStore.batch_set(items) is the atomic multi-key write — single BEGIN/COMMIT, rollback on any failure (config_store.py:538-568). Always prefer it for multi-key updates.
  • ConfigStore.transaction() is a @contextmanager yielding the raw connection for caller-driven multi-op transactions (config_store.py:572).
  • reconcile_from_yaml() seeds missing DB keys from shipped YAML merged with kazma.local.yaml, using the same precedence as fallback reads. Local provider/model choices remain stored when startup aligns the active workspace. A local-only file can seed settings even without shipped YAML. Existing saved settings continue to win; later YAML edits do not replace them.
  • Declared one-time migrations in config_defaults.RETIRED_DEFAULTS update pre-existing copies of retired shipped defaults before new keys are seeded. They use the shipped baseline, not local overrides. A fresh local choice that equals an old default is preserved. Retirement is deferred when no valid shipped mapping is available.
  • export_yaml() / import_yaml() round-trip every DB row merged into YAML; kazma migrate carries settings this way (config_store.py:632, 650). The Settings page’s backup is a different file, below.
  • reset_all() deletes all DB rows → reverts to YAML defaults (config_store.py:732). No page offers it: it would also delete keys and sign-in.

Singleton rule: Always use get_config_store(), never construct ConfigStore() directly for shared settings. If SQLite or PostgreSQL initialization fails, production boot stops; no writable memory fallback is used. See Settings durability and outage recovery.

Settings → System → Download settings backup saves a YAML file named with today’s date; Settings → Import/Export → Export gives the same file as YAML or JSON. It holds:

  • every setting this install stores, one line each (agent.language: ar), not kazma.yaml’s defaults, so a restore never pins an old default;
  • keys only by name, as references to this install’s vault (vault://cfg:providers.list.deepseek.api_key), never the keys themselves. A key kept in plain text (no vault) and a password inside a URL are written as ****;
  • nothing of Kazma’s own state (approval grants, a chat’s long-task record, boot stamps) and no credential (the sign-in secret, the password, signed-in browsers, who may use the install).

Restore settings backup… (and Import/Export → Import, which can restore chosen sections) first shows what will change, and writes only after you confirm:

What the backup holdsWhat a restore does
A settingWrites the backup’s value, through the same checks as a Settings save. A value Settings would refuse is listed and left as it is.
A key you have nowKeeps yours. It is never replaced.
A key you no longer haveBrings it back from this install’s vault when the backup’s reference still opens, so you enter nothing. Otherwise it is listed for you to enter again in Settings.
Providers, MCP servers, mail accountsMerges by name. Entries and fields added since the backup stay, and each keeps its keys. A mail account comes back only while the vault still holds its sign-in.
Kazma’s own state, credentialsNever written.
The Soul Kazma learnedRestored only where the install has none.
A default Kazma changed since the backupKeeps today’s value (config_defaults.RETIRED_DEFAULTS).
A setting the backup does not nameStays. A restore deletes nothing.

If your settings change between the preview and the confirmation, nothing is written and the preview is shown again. Undo last restore puts back what the last restore changed, except a setting changed again since and a key it brought back. Kazma then offers a restart, because providers, models and chat apps are read at start.

Older files restore too: the earlier backup (every row, nested) and Import/Export’s earlier export (rows grouped by category). Their credentials and Kazma’s own state are left out the same way.

Source: kazma_core/settings_restore.py. Every key is classed there (KEY_RULES); tests/test_settings_restore_classes.py fails on a key the code writes that no rule names. The value checks are kazma_core/settings_validation.py, shared with every save.


The full default file (kazma.yaml) with every key, type, and default, section by section.

KeyTypeDefaultDescription
agent.namestringkazmaBot display name.
agent.versionstring0.2.0Note: diverges from pyproject.toml (0.3.0). Not auto-synced.
agent.languagestringarUI/agent language. ar → RTL + Arabic; en → English.
agent.rtlbooltrueMaster RTL switch.

agent.topic_drift — embedding topic-shift detection

Section titled “agent.topic_drift — embedding topic-shift detection”

Read live on every turn check (no restart needed to tune). Fail-open: if the embedder is unavailable or encode errors, embedding drift never forces a shift — regex/explicit and heuristic classifiers still apply.

KeyTypeDefaultDescription
agent.topic_drift.enabledbooltrueEmbedding topic-drift detection on/off. Does not affect regex/heuristic shift classifiers.
agent.topic_drift.thresholdfloat0.55Cosine distance (1 − similarity) at which a turn is flagged as a topic shift. Clamped [0.05, 0.95]. Higher = only more dissimilar turns count as a shift.

Tuning direction:

  • False shift (agent abandons a legit multi-step task mid-flow) → raise the threshold.
  • Missed shift (agent resumes the old task after a real pivot) → lower the threshold.

Both keys are read via topic_drift_config() from ConfigStore and overlay kazma.yaml.

agent.nonstop — Non-Stop & Self-Healing Execution Engine

Section titled “agent.nonstop — Non-Stop & Self-Healing Execution Engine”

Configurable via Settings UI (Settings → Agent → Non-Stop & Self-Healing), ConfigStore (agent.nonstop.*), or kazma.yaml. Read live on every turn execution (get_nonstop_config()).

KeyTypeDefaultDescription
agent.nonstop.enabledboolfalseMaster switch for non-stop execution & watchdog.
agent.nonstop.watchdog.stall_threshold_secondsint60Watchdog stall detection threshold in seconds.
agent.nonstop.tool_timeout_secondsint120Per-tool execution timeout (asyncio.wait_for).
agent.nonstop.healing.max_recovery_attemptsint3Max recovery & resume attempts before escalating.
agent.nonstop.healing.backoff_base_secondsfloat2.0Exponential backoff base for watchdog recovery.
agent.nonstop.healing.backoff_max_secondsfloat30.0Max backoff wait between recovery attempts.
agent.nonstop.failover.enabledboolfalseEnable model failover chain on primary LLM failure.
agent.nonstop.failover.chainlist/str[]Ordered list or comma-separated string of failover model IDs.
agent.nonstop.failover.cooldown_secondsint300Cooldown period in seconds before retrying a failed model in chain.
agent.nonstop.ledger.enabledbooltrueEnable durable per-call LLM execution logging (kazma-data/llm_calls.db).
KeyTypeDefaultDescription
models.defaultstringgpt-4o-miniDefault model id.
models.routerstringkazmaLabel for Kazma’s own router. Not an import litellm. Point base_url at a LiteLLM proxy if you run one.
models.fallbackstringgpt-4o-miniModel used on retry when the primary HTTP call fails.
KeyTypeDefaultDescription
llm.base_urlstringhttps://api.openai.com/v1OpenAI-compatible endpoint. /v1 is auto-appended if missing (except Ollama :11434 and LiteLLM :4000).
llm.api_keystring''Leave empty to load from env (OPENAI_API_KEY → KAZMA_API_KEY → "not-needed" for local).
llm.modelstringgpt-4o-miniModel id sent in the payload.
llm.max_tokensint4096Completion token cap.
llm.temperaturefloat0.7Sampling temperature.
llm.timeoutfloat60.0Per-request timeout (seconds).
llm.input_cost_per_1mfloat0.15USD per 1M input tokens — used for cost accounting.
llm.output_cost_per_1mfloat0.6USD per 1M output tokens.
llm.gateway.urlstring''Optional LiteLLM proxy for OpenAI-compatible providers. Env KAZMA_LITELLM_URL wins. Native four-branch never uses this.
llm.gateway.api_keystring''Proxy master key (LITELLM_MASTER_KEY). Vault-encrypted.
llm.gateway.include_localboolfalseAlso send Ollama/LM Studio through the proxy (KAZMA_LITELLM_LOCAL=1).
llm.gateway.fallback_directboolfalseIf the proxy is down, retry the original URL once (KAZMA_LITELLM_FALLBACK_DIRECT=1).
KeyTypeDefaultDescription
mcp.serverslistsee belowMCP server definitions.
mcp.servers[].namestring—Server identifier.
mcp.servers[].transportstringstdiostdio, sse, or streamable_http (alias http). SSE and streamable_http support an auth field (bearer/custom header); streamable_http also tracks Mcp-Session-Id for resumable sessions (MCP 2025-03-26 spec).
mcp.servers[].truststringtrustedPlain config string — not consumed by any trust-tier code.
mcp.servers[].commandlist—argv for stdio spawn.
mcp.ide_server.enabledbooltrueEnable the in-process IDE/file MCP server.
mcp.ide_server.rootstring.Workspace root.
mcp.ide_server.max_file_sizeint10485761 MB file size cap.

Shipped default server:

mcp:
servers:
- name: filesystem
transport: stdio
workspace_bound: true
trust: approval_required
command: [npx, -y, '@modelcontextprotocol/server-filesystem', '${KAZMA_ACTIVE_WORKSPACE}']
ide_server:
enabled: true
root: .
max_file_size: 1048576

Multi-line string. The default is Arabic-aware: “You are Kazma (كاظمه), an autonomous AI agent framework…” and instructs the model to respond in the user’s language/dialect.

KeyTypeDefaultDescription
storage.enginestringsqliteCheckpointer engine.
storage.pathstringkazma-data/checkpoints.dbLangGraph checkpointer DB.
storage.vector_dimint1024Declared vector dimension (informational — should match memory.embedding.dim; default BGE-M3 is 1024).
KeyTypeDefaultDescription
memory.enabledbooltrueMaster switch (per-turn RAG, auto-store, consolidator). ConfigStore overlays yaml.
memory.per_turn_retrievalbooltrueInject top-k memories on every user turn.
memory.auto_storebooltrueHeuristic durable / turn writes after each reply.
memory.auto_store_modestrbothdurable | turns | both.
memory.max_context_tokensint1000000The context window: compaction fires at 80 %, the history trim at 95 %. Which window applies, first match wins: models.context_window.<model> (one model’s own window), Settings → Agent → Context Window (context.max_context_tokens), this key, then 1,000,000. agent.trim.token_budget (settings store) sets the trim budget instead (kept between 4,000 and 95 % of the window). A chat that still outgrows it keeps your earlier requests and Kazma’s plain replies, newest first (up to 16, each cut to 1,500 characters), so the conversation’s thread survives the trim.
memory.retrieval_top_kint5Top-K for per-turn RAG and compaction.
memory.provenancebooltrueTag memories with source metadata.
memory.consolidation.enabledbooltruePost-turn librarian (facts + graph triples).
memory.consolidation.use_llmbooltrueLLM extract; heuristic fallback if fail/off.
memory.consolidation.every_n_turnsint1Cost control: run consolidator every N turns.
memory.consolidation.skip_llm_in_demobooltrueNo LLM under KAZMA_DEMO_MODE.
memory.embedding.providerstrlocallocal or remote OpenAI-compatible embed API.
memory.embedding.modelstrBAAI/bge-m3Embedding model id (multilingual, 1024-dim).
memory.embedding.dimint1024Must match the embedder.
memory.embedding.base_urlstrunset/embeddings endpoint for remote providers.
memory.embedding.api_key_envstrKAZMA_EMBED_API_KEYEnv var holding the remote API key.

The embedder is also configurable from the Web UI: Settings → Embedder (save there takes effect after a server restart, and includes a one-click background “Rebuild embeddings” action + the vector-space composition of your memory DB). The ConfigStore override (embedding.*) takes precedence over kazma.yaml; env vars (KAZMA_EMBED_*) win over both. After a model switch, run the rebuild so every row lives in the same vector space.

KeyTypeDefaultDescription
skills.pathstringkazma-skills/manifests/Skill manifest directory.
skills.auto_discoverbooltrueAuto-load manifests on startup.
KeyTypeDefaultToken env var
connectors.telegram.enabledbooltrueTELEGRAM_BOT_TOKEN
connectors.discord.enabledboolfalseDISCORD_BOT_TOKEN
connectors.slack.enabledboolfalseSLACK_BOT_TOKEN + SLACK_APP_TOKEN
KeyTypeDefaultDescription
gateway.rate_limits.telegramint30Messages one person may send per minute on Telegram. Past it Kazma answers “Slow down” (at most every 30 s) and leaves the rest unanswered; each one is logged and shows in the platform’s Test. A flood guard, not Telegram’s own send limit.
gateway.rate_limits.discordint30The same for Discord. Shipped as 5 until 2026-10-01; an install still holding 5 moves to 30 at its next start.
gateway.rate_limits.slackint30The same for Slack. Shipped as 1 until 2026-10-01, which allowed one Slack message a minute; an install still holding 1 moves to 30 at its next start.
gateway.suggestions.enabledbooltrueTelegram, Discord and Slack: after a turn in which the agent used no tool, up to two ”💡” hints when your message looks like a job for a tool (a link to read, something to search). false sends none. Read at startup.
gateway.voice.enabledboolfalseVoice (STT inbound + TTS outbound) across all platforms (Telegram, Discord, Slack) + Web. Also settable at runtime via Settings → Voice.
gateway.voice.stt_providerstringopenaiSpeech-to-text name: openai, groq, cohere, nvidia, or faster-whisper. API keys come from Settings → Providers, not this block. Whisper is not a chat model.
gateway.voice.stt_languagestringautoSTT language (auto, ar, en, …). Settings uses the same form-select as the other Voice fields.
gateway.voice.stt_modelstringdefaultWhisper / transcribe model id for the chosen STT provider.
gateway.voice.tts_providerstringedgettsText-to-speech provider: edgetts (free, default), openai, nvidia, kokoro (local), coqui (local).
KeyTypeDefaultDescription
safety.hitl.enabledbooltrueMaster HITL switch (graph path).
safety.hitl.require_approval_forlistsee belowDanger tools for the graph path.
safety.hitl.approval_timeout_secondsint300How long an approval card waits for an answer. The tool is then not run, and the model and the chat are told the approval expired. Also the swarm bus’s request deadline.
safety.hitl.auto_deny_on_timeoutbooltrueAuto-reject paused tasks on timeout.

Default require_approval_for:

safety:
hitl:
enabled: true
require_approval_for:
- file_write
- file_delete
- shell_exec
- code_exec
- python_exec
- spawn_agent
- spawn_agents
- schedule_task
- cancel_scheduled
approval_timeout_seconds: 300
auto_deny_on_timeout: true

The swarm bus uses _EXTENDED_DANGER, a copy of the canonical list (CANONICAL_DANGER_TOOLS) with the same contents, not a broader one. The canonical list is always added to the list above (unless KAZMA_HITL_CANONICAL_FLOOR=0), so this file cannot narrow it. The MCP path classifies dynamically by name pattern. See Security & Safety → danger-tool lists.

Server status messages — one card each time Kazma is back up (how long it was down, whether each chat app connected, the build and the model) and one when startup fails. Sent where alerts go. Settings → Providers & Connectors → Platform Connectors → Adapters & Routes → Server status messages. See Deployment → Lifecycle notifications.

KeyTypeDefaultDescription
notifications.lifecycle.enabledbooltrueMaster switch.
notifications.lifecycle.eventslist[started, startup_failed]Which messages are sent: started (the card when Kazma is back up), startup_failed, starting, shutting_down. An empty list sends none. Until 2026-09-29 the default was all four — three messages per restart — and an install still holding that stored default is moved to the new one once at boot.
notifications.lifecycle.restart_window_secondsint60A clean stop followed by a start within this window reads “Kazma restarted” instead of “Kazma started”. 0 turns restart detection off (no downtime line either).

Default:

notifications:
lifecycle:
enabled: true
events:
- started
- startup_failed
restart_window_seconds: 60

Notifications route through the SwarmMessageBus (no parallel path). Set connectors.<platform>.swarm_chat_id to the chat ID where messages should land. Without it, the bus is NullBusAdapter and messages are dropped silently.

KeyTypeDefaultDescription
ui.hoststring127.0.0.1Bind host. Switches to 0.0.0.0 under kazma serve only if KAZMA_SECRET is set.
ui.portint8000Bind port.
ui.rtlbooltrueUI RTL.
ui.titlestringKazma DashboardPage title.
KeyTypeDefaultDescription
logging.levelstringINFOLog level.
logging.formatstringjsonjson or plain.
logging.langfuse.enabledauto / boolautoauto = Langfuse when public+secret keys exist. false / KAZMA_LANGFUSE=0 = off.
logging.langfuse.public_keystring''
logging.langfuse.secret_keystring''
KeyTypeDefaultDescription
time_travel.enabledbooltrueEnable /replay.
time_travel.max_snapshotsint50Snapshot cap (per thread). ConfigStore override time_travel.max_snapshots (Settings → Embedder → Time travel) takes precedence over this value; effective resolution is store > yaml > default. Applies at server startup.
time_travel.retention_daysint30Prune snapshots older than this many days (1–3650). ConfigStore override time_travel.retention_days (Settings → Embedder → Time travel) is read LIVE by the daily maintenance loop — no restart needed.
time_travel.auto_maintainbooltrueEnable the daily snapshot prune + VACUUM loop. ConfigStore override time_travel.auto_maintain is read live, same as retention_days.
time_travel.db_pathstringkazma-data/snapshots.dbSnapshot DB.
KeyTypeDefaultDescription
swarm.enabledbooltrueMaster swarm switch.
swarm.group_chat_idint0Real value read from SWARM_CHAT_ID env.
swarm.default_patternstrdispatchFallback pattern: dispatch | pipeline | consult | fan_out | broadcast.
swarm.auto_routebooltrueEnable semantic auto-routing (UnifiedRouter) for workers=["auto"].
swarm.max_concurrent_tasksint10 (1–100)Max concurrent swarm tasks.
swarm.max_concurrentint5Fan-out / broadcast / consult worker concurrency.
swarm.orchestrator.namestringKazma OrchestratorOrchestrator display name.
swarm.orchestrator.profilestringdefaultOrchestrator profile id.
swarm.workerslist[]Populated at runtime via Web UI / POST /api/swarm/workers.
swarm.output_targetobjnone\{bot_token, chat_id, platform, enabled\} — when set, the token must match the active Telegram bot token.

cron.* — scheduled reminders and tasks (ConfigStore)

Section titled “cron.* — scheduled reminders and tasks (ConfigStore)”

Read live by the scheduler; a value out of range is refused when it is saved (PUT /api/settings/single). The time zone has its own control (Settings, cron.timezone); these keys have none on a page yet.

KeyTypeDefault (range)Description
cron.timezonestringempty (KAZMA_TZ, else UTC)The zone a naive time and a clock time (“daily at 9am”) are read in.
cron.catchup_minutesint60 (1–10080)How late a job may still fire after Kazma was down. A later one is missed, with one notice. KAZMA_CRON_STALE_HOURS is used when this is unset.
cron.task_budget_secondsint300 (30–3600)How long a fired agent task’s turn may run.
cron.max_jobs_per_tenantint500 (1–10000)Jobs still holding work per tenant; a booking past it is refused.
cron.max_jobs_per_threadint50 (1–1000)The same, per conversation.
safety.cron_fire_without_hitlboolfalseFire agent tasks while approvals (HITL) are off. Off: tasks do not fire then (reminders still do). Under safety., so the agent cannot set it.

What a fired job may do: Scheduled reminders and tasks.

Two predefined pipelines (lists of stages, each with worker, depends_on, system_prompt):

  • standard — 4 stages: researcher (worker core) → refiner (worker bridge) → builder (worker core) → validator (worker bridge).
  • quick — 2 stages: researcher (worker core) → builder (worker core).

documents.* — Document Intelligence (ConfigStore / Settings UI)

Section titled “documents.* — Document Intelligence (ConfigStore / Settings UI)”

Not every key is in the shipped kazma.yaml skeleton; the authoritative defaults live on DocumentConfig (kazma_core/documents/config.py) and are read live via get_document_config(): each operation takes one snapshot of the documents settings and keeps it to the end. Configure with:

  • Settings → Documents (/settings?tab=documents): durable writes, shadow and authoritative mode, intake size and file count, worker timeout and memory, the storage free-space floor, malware scan mode and fail-closed, OCR, reading ruled tables on scanned pages (documents.ocr.tables), GC and indexing; it also shows whether a malware scanner was found
  • GET/PUT /api/settings/documents (those same fields)
  • PUT /api/settings/single with a nested key, for every other key
  • optional kazma.yaml seed under a documents: section

A saved value that cannot be read as its type is not replaced by a default: document operations answer 503 document_policy_unavailable until it is corrected, and a settings store that cannot be read refuses document work too. Nothing checks the value when it is saved through these routes.

Key prefixPurpose
documents.enabled / shadow / default_authoritativeRollout mode (disabled / shadow / compatibility / authoritative)
documents.storage_rootWhere documents, uploads in progress and worker scratch live (restart to change)
documents.intake.*Max bytes/files, remote fetch limits, lease_seconds (300: how long an upload may go without renewing its reservation before another process may take it over)
documents.limits.*Pages, cells, archive members, compression, pixels, …
documents.security.*Malware scan mode (auto) and fail-closed (off, but on by default under KAZMA_PRODUCTION=1), fence, encrypted/external-resource policy, remote_parse (third-party salvage, default off), local_salvage (Docling inside the worker, default on)
documents.render.embed_html_fontsInline the pinned font in HTML exports (default on)
documents.ocr.*Enable, languages, DPI, confidence, concurrency, timeouts, output limit; tables (default on): ruled tables on scanned pages are read cell by cell, at most 600 cells and 120 s a page; a table not read within those bounds keeps the page’s own reading
documents.workers.*Timeout, memory, concurrency, lease, heartbeat, retries, result size
documents.indexing.*Chunk tokens, overlap, preserve tables/pages
documents.retention.* / documents.gc.*Retention windows + GC schedule / bounds
documents.capacity.*Queue caps, rate/byte windows, storage free floor, max_concurrent_uploads (4 uploads received at once per process)
documents.quotas.*Per-tenant byte / daily page quotas

Seven keys are bound to stores and workers built at start and take effect after a restart: documents.storage_root, documents.quotas.tenant_bytes, and concurrency, lease_seconds, heartbeat_seconds, retry_base_seconds and retry_max_seconds under documents.workers.. Until then readiness reports policy.restart_required with the configured and effective values, and the Documents page says some saved settings need a restart.

security.execution.container_required (the strict execution profile, not a documents.* key) also refuses the local process document worker profile.

Env (backend selection and worker isolation):

VariableDefaultPurpose
KAZMA_DOCUMENTS_JOBS_BACKENDunsetsqlite forces SQLite job queue; else Postgres when platform uses PG
KAZMA_DOCUMENTS_METADATA_BACKENDunset (auto)sqlite / postgres / auto (auto follows jobs)
KAZMA_DOCUMENT_WORKER_ISOLATIONprocessprocess (local child, no filesystem or network isolation) or container (the document worker broker); with KAZMA_DOCUMENT_BROKER_URL and KAZMA_DOCUMENT_BROKER_TOKEN_FILE
KAZMA_DOCUMENT_SOAK_ITERATIONS100Repetitions of the certification script’s extended parse smoke (--soak); not a multi-day soak

Every document variable: Environment variables.

Full product guide: Document Intelligence. Ops: Document processing.


VariablePurposeDefault
TELEGRAM_BOT_TOKENTelegram adapter token.placeholder
DISCORD_BOT_TOKENDiscord adapter token.empty
SLACK_BOT_TOKENSlack bot token.empty
SLACK_APP_TOKENSlack app token (Socket Mode).empty
OPENAI_API_KEYOpenAI key (also generic LLM fallback #2).empty
DEEPSEEK_API_KEYDeclared in .env.example but not read by code — set the key via the provider list instead.empty
ANTHROPIC_API_KEYDeclared in .env.example but not read by code.empty
GOOGLE_CLOUD_PROJECTGCP project for Vertex AI (if ADC lacks a default).commented out
SWARM_CHAT_IDSwarm group chat id (feeds swarm.group_chat_id).empty
KAZMA_SECRETHITL shared secret; binds serve to 0.0.0.0; hub write-auth; kazma hub sign.commented out
KAZMA_VECTOR_PATHVector memory dir.~/.kazma/vector_memory
KAZMA_VECTOR_COLLECTIONChromaDB collection name.agent_memory
KAZMA_VECTOR_MODELEmbedding model (legacy alias — prefer KAZMA_EMBED_MODEL).BAAI/bge-m3
VariablePurposeLocation
KAZMA_AUTH_DISABLEDIf true/1/yes, get_kazma_secret() returns "" (auth disabled).config_store.py:52
KAZMA_DISCLOSURE_KEYDisclosure HMAC key; auto-generated if unset.config_store.py:95
KAZMA_API_KEYLLM key fallback #3.llm_provider.py:142
KAZMA_MAX_COSTCost breaker ceiling (default $0.50).cost_breaker.py:42
KAZMA_HARD_MAX_COSTHard max cost ceiling for immediate trip (default 3x soft max, $15.0).cost_breaker.py:46
KAZMA_SILENCE_WINDOWCost breaker silence window (default 300s).cost_breaker.py:44
KAZMA_SEMANTIC_CACHERetired 2026-09-30 (the semantic response cache was removed, audit AUD-001); setting it only logs a warning.kazma_ui/app.py
KAZMA_FETCH_MAX_BYTESStreamed response byte limit for read_url (default 5242880 / 5 MB).tools/read_url.py
KAZMA_CRAWL_RESPECT_ROBOTSDefault 1: enforce bounded KazmaBot checks for automated crawl/KB/research saves. Explicit 0 is visible; failed checks refuse crawling. Only 0/1 are valid.web_acquire/robots.py
KAZMA_BROWSER_CGROUP_ROOTLinux only: absolute writable delegated cgroup v2 root; defaults to the service’s current cgroup. Requires memory/pids/CPU/group-kill controls. Rendering refuses missing controls; host delegation is operator-managed.web_acquire/browser_cgroup.py
KAZMA_OTLP_ENDPOINTOTLP HTTP JSON trace collector endpoint.swarm/tracing.py
KAZMA_TOOL_TIMEOUT_SECONDSPer-tool execution timeout in seconds (default 120).agent/graph_builder.py
KAZMA_HUB_DBHub SQLite registry path.hub/cli.py:109
KAZMA_HUB_URLHub API base (default https://hub.kazma.ai).hub/cli.py:115
KAZMA_PORTServer port override (default 8000).gateway.py:36
HF_HUB_DISABLE_SYMLINKS_WARNING / HF_HUB_DISABLE_TELEMETRYSilence HuggingFace telemetry (set by CLI).main.py:9-10

No dedicated per-provider env vars for DeepSeek/Anthropic/xAI/Groq/Gemini are read by kazma_core. Key those providers through the ConfigStore provider list or kazma.yaml.


LLMProvider._resolve_api_key() (llm_provider.py:136-146) resolves in this order:

  1. self.config.api_key (from LLMConfig)
  2. os.getenv("OPENAI_API_KEY")
  3. os.getenv("KAZMA_API_KEY")
  4. "not-needed" (for local LM Studio/Ollama)

Provider-specific dummy keys for local servers (url_utils.py:138-172):

ServerDummy key
LM Studio (:1234)sk-lm-studio-dummy-key
Ollama (:11434)ollama
LiteLLM proxy (:4000)sk-litellm-dummy-key
other localhostnot-needed

Google Vertex AI uses Application Default Credentials only — no API key. GeminiProvider._resolve_api_key() returns "adc-placeholder" and the real bearer token is fetched per-call via google.auth.default() + credentials.refresh() (google_llm.py:232-252). Project resolution: explicit project_id= > GOOGLE_CLOUD_PROJECT > google.auth.default() > ADC quota_project_id > gcloud config_default.

Keys are stored per-provider in ConfigStore providers.list (each entry has api_key, base_url, models, …). Masked placeholders (***) are rejected on upsert unless a real key already exists (model_registry.py:646-652); keys are masked in all read-backs (_mask_profile).


ModelRegistry (model_registry.py:81) is a process-wide singleton (module global _registry, thread-safe via threading.RLock()). Backward-compat alias: UnifiedModelRegistry (line 950).

FunctionPurpose
initialize_model_registry(config_store)Construct + deserialize + seed presets.
get_model_registry()Retrieve singleton (raises RuntimeError if uninitialized).
reset_model_registry()Teardown.

From kazma-core/kazma_core/providers.py. Most presets speak the OpenAI Chat Completions wire format and work through the generic LLMProvider (Bearer auth). Four providers have dedicated native classes (see LLM Providers) because their auth/schema differs: google → GeminiProvider, anthropic → AnthropicProvider (native /messages API), azure → AzureProvider (api-key header + api-version), bedrock → BedrockProvider (AWS SigV4 + Converse API).

KeyDisplay namebase_urlauth_headerNative class?
openaiOpenAIhttps://api.openai.com/v1Bearerno
anthropicAnthropichttps://api.anthropic.com/v1x-api-keyyes — AnthropicProvider
deepseekDeepSeekhttps://api.deepseek.com/v1Bearerno
googleGoogle Gemini(computed per project/location)Beareryes — GeminiProvider
xaixAI / Grokhttps://api.x.ai/v1Bearerno
openrouterOpenRouterhttps://openrouter.ai/api/v1Bearerno
groqGroqhttps://api.groq.com/openai/v1Bearerno
mistralMistral AIhttps://api.mistral.ai/v1Bearerno
togetherTogether AIhttps://api.together.xyz/v1Bearerno
cohereCoherehttps://api.cohere.ai/v1Bearerno
fireworksFireworks AIhttps://api.fireworks.ai/inference/v1Bearerno
perplexityPerplexityhttps://api.perplexity.aiBearerno
ai21AI21 Labshttps://api.ai21.com/studio/v1Bearerno
nvidiaNVIDIA NIMhttps://integrate.api.nvidia.com/v1Bearerno
azureAzure OpenAI(computed from resource + deployment)api-keyyes — AzureProvider
bedrockAWS Bedrock(computed from region)Bearer (SigV4)yes — BedrockProvider
ollamaOllama (Local)http://127.0.0.1:11434/v1(none)no
lm-studioLM Studio (Local)http://localhost:1234/v1(none)no
customCustom Endpoint(blank)Bearerno

Hardcoded GEMINI_MODELS (Vertex AI has no static /models endpoint): gemini-2.5-flash, gemini-2.5-pro, gemini-2.0-flash, gemini-2.0-flash-lite.

Default-enabled provider: Only google is enabled=True out of the box (model_registry_store.py:117). All others must be configured before use. custom is excluded from preset seeding.

discover_models(provider_name) (model_registry.py:427) hits \{base_url\}\{models_endpoint\} (default /models), parses the OpenAI \{"data":[\{"id":...\}]\} shape, with an SSRF guard (kazma_core.security.ssrf.validate_url). Results cached in _discovered_models.

KeyPurpose
providers.listStored provider array.
providers.health.*Per-provider health.
models.saved.*Saved model profiles.
models.defaults.*Per-task defaults (chat, code, research, fast, vision, general). Wins over keyword ModelRouter.classify (e.g. "code" in a prompt cannot override models.defaults.code). Env KAZMA_MODEL still wins.
llm.model, llm.base_url, llm.api_keyLegacy fallbacks.
registry.active_provider, registry.active_model, registry.discovered_modelsActive selection + cache.

The retry/backoff helpers read overrides from ConfigStore (retry.py):

KeyDefaultDescription
retry.max_attempts3Max retry attempts.
retry.min_wait2 (s)Min backoff.
retry.max_wait10 (s)Max backoff.

Retries fire only on network/timeout exceptions (ConnectionError, TimeoutError, asyncio.TimeoutError, httpx TimeoutException/ConnectError/RemoteProtocolError). 4xx errors are never retried (retry.py:107-109). There is no 429 backoff.


7.1 kazma-permissions.yaml — library only (not runtime-enforced)

Section titled “7.1 kazma-permissions.yaml — library only (not runtime-enforced)”

Status: PermissionManager + this YAML describe an enterprise division RBAC design that is not enforced on the live tool execute path. Runtime authorization is HITL + shell allowlist + MCP classification + optional platform RBAC (KAZMA_MULTI_USER). See docs/audits/UNWIRED_INVENTORY.md.

Example shape (for future wiring / offline policy docs only):

divisions:
gas_oil:
allowed_mcp_servers: [oil-pricing-api, contract-manager, supplier-directory]
denied_mcp_servers: [tourism-booking-api, general-inventory-api]
tourism:
allowed_mcp_servers: [booking-engine, hotel-api, flight-search]
denied_mcp_servers: [oil-pricing-api, contract-manager]
general_trading:
allowed_mcp_servers: [inventory-api, supplier-directory, procurement-api]
denied_mcp_servers: [oil-pricing-api, booking-engine]
cross_division_rules:
require_explicit_approval: true
max_approval_duration_hours: 24
notify_admins: true
audit_all_access: true
SectionKey options
scanningenabled, interval: "24h", sources: [osv, github_advisories, nvd], auto_create_issues, severity_threshold: medium, ignore.
disclosureenabled, response_window: "48h", assessment_window: "7d", security_txt_url (RFC 9116 contact file, not a PGP key), encrypted_channels (email + GitHub private reporting).
bug_bountyenabled: false — no paid program. Payout fields are reserved/zeroed; do not advertise tiers as active. See root SECURITY.md.
hardeningrun_on_startup, fail_on_critical, auto_fix: false, checks (8: secrets_in_logs, input_validation, rbac_enforcement, tls_required, dependency_audit, least_privilege, audit_trail, config_integrity).

No code reads kazma-security.yaml (checked 2026-09-27): it declares the security program (disclosure contacts, no paid bounty) for people. Its scanning and hardening keys schedule nothing; the hardening report and the dependency scan run on demand through GET /api/security/hardening and GET /api/security/deps. See Security & Safety.

7.3 proxy.* keys (scraping proxy provider addon)

Section titled “7.3 proxy.* keys (scraping proxy provider addon)”

Opt-in. Configured via Settings → System → Proxy Provider (the values below live in ConfigStore under proxy.*; proxy.password auto-vault-encrypts). The active provider is re-read live on every fetch — no restart needed.

KeyDefaultPurpose
proxy.providernonenone (direct) | anyip
proxy.hostportal.anyip.ioProxy endpoint host
proxy.port1080Proxy endpoint port
proxy.username(empty)anyip username (e.g. user_YOURID)
proxy.password_(empty, vault)anyip password
proxy.networkmixedresidential | mobile | mixed
proxy.country(empty)Optional ISO country code (e.g. US)
proxy.session_stickyfalsetrue = same IP across requests (logins); false = rotate per request

See Web research → Bulletproof scraping.


Settings must be stored in the configured SQLite or PostgreSQL database. If initialization fails, Kazma stops before workers or automation start; it does not substitute a writable memory store. The managed guard remains responsible for restarting the server once storage is available.

An operational settings-write failure returns HTTP 503 with code: config_store_unavailable and Retry-After: 5. Save controls show the error and keep the entered values. They do not automatically resend writes. An acknowledgement can be lost after a commit, so the error does not prove that the database rolled back. Restore storage, reload the settings, review what was persisted, then retry only the changes still needed.

For PostgreSQL, failed pool attempts are closed and pool retries are bounded; the settings initialization loop does not multiply them. Boot schema checkout and statements each have a five-second timeout. Normal queries retain their existing timeout policy. SQLite initialization makes up to four attempts.

See Settings save failed and the operator recovery and evaluation workflow.

Settings → System → Web acquisition → Read alert settings configures the local progress/result monitor. Monitoring and completion alerts default on; the no-progress warning defaults to 180 seconds and the fresh low-credit threshold to 100. Settings are persisted in the existing settings database. External delivery follows Adapters & Routes; the local bell retains observations independently of external delivery. See Progress and result alerts for outcomes, retention, delivery receipts and local-first scope.

ControlDefaultAllowed value
Monitoring enabledtrueBoolean
Completion notificationstrueBoolean
No observed progress threshold180 secondsInteger, 30–3600
Fresh low-credit threshold100Integer, 0–1000000000

The administrator API is GET/PUT /api/settings/acquisition/monitor. Save the complete settings object; invalid fields or types return 422. The monitor reads local evidence every 15 seconds and never refreshes provider balances. Acquisition policy is configured separately through the documented environment variables; these alert controls do not grant hosted-service permission.

  • Version drift: pyproject.toml is 0.3.0; kazma.yaml agent.version is 0.2.0; the CLI --help text prints v0.2.0. These are independent and unsynchronized — a known wart.
  • Memory flags are read via kazma_core.memory.config (ConfigStore ← yaml). See Memory & RAG and docs/plans/MEMORY_REMAINING.md.
  • .env.example lists DEEPSEEK_API_KEY / ANTHROPIC_API_KEY but no code reads them — flagged to prevent user confusion.
  • mcp.servers[].trust is a plain YAML string with no enforcing consumer — not a cryptographic trust tier.