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.
1. Configuration sources & precedence
Section titled “1. Configuration sources & precedence”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]
| # | Layer | Wins? | Notes |
|---|---|---|---|
| 1 | Env var | Only in specific helpers (get_kazma_secret, get_or_create_disclosure_key) — not in the generic get(). | e.g. KAZMA_SECRET |
| 2 | ConfigStore DB (SQLite or PostgreSQL) | Yes for runtime reads via get(). | Saved settings override YAML. |
| 3 | kazma.local.yaml | Overrides shipped YAML. | Optional machine-local file; its values seed missing settings on first boot. |
| 4 | kazma.yaml | Shipped baseline. | Merged with local YAML before reconcile_from_yaml() seeds missing keys. |
| 5 | Hardcoded default | Last resort. | e.g. gpt-4o-mini, DEFAULT_DANGER_TOOLS. |
Override precedence (detailed)
Section titled “Override precedence (detailed)”ConfigStore.get(key)(config_store.py:471-516): checks the in-process_cachefirst (with a_MISSINGsentinel for known-absent keys), then an exact DB row, then a DB child-key re-merge via_collect_prefixed(rows whose key starts withkey.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 — singleBEGIN/COMMIT, rollback on any failure (config_store.py:538-568). Always prefer it for multi-key updates.ConfigStore.transaction()is a@contextmanageryielding the raw connection for caller-driven multi-op transactions (config_store.py:572).reconcile_from_yaml()seeds missing DB keys from shipped YAML merged withkazma.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_DEFAULTSupdate 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 migratecarries 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 constructConfigStore()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.
Backing up and restoring settings
Section titled “Backing up and restoring settings”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 holds | What a restore does |
|---|---|
| A setting | Writes 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 now | Keeps yours. It is never replaced. |
| A key you no longer have | Brings 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 accounts | Merges 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, credentials | Never written. |
| The Soul Kazma learned | Restored only where the install has none. |
| A default Kazma changed since the backup | Keeps today’s value (config_defaults.RETIRED_DEFAULTS). |
| A setting the backup does not name | Stays. 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.
2. kazma.yaml — complete reference
Section titled “2. kazma.yaml — complete reference”The full default file (kazma.yaml) with every key, type, and default, section by section.
| Key | Type | Default | Description |
|---|---|---|---|
agent.name | string | kazma | Bot display name. |
agent.version | string | 0.2.0 | Note: diverges from pyproject.toml (0.3.0). Not auto-synced. |
agent.language | string | ar | UI/agent language. ar → RTL + Arabic; en → English. |
agent.rtl | bool | true | Master 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.
| Key | Type | Default | Description |
|---|---|---|---|
agent.topic_drift.enabled | bool | true | Embedding topic-drift detection on/off. Does not affect regex/heuristic shift classifiers. |
agent.topic_drift.threshold | float | 0.55 | Cosine 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()).
| Key | Type | Default | Description |
|---|---|---|---|
agent.nonstop.enabled | bool | false | Master switch for non-stop execution & watchdog. |
agent.nonstop.watchdog.stall_threshold_seconds | int | 60 | Watchdog stall detection threshold in seconds. |
agent.nonstop.tool_timeout_seconds | int | 120 | Per-tool execution timeout (asyncio.wait_for). |
agent.nonstop.healing.max_recovery_attempts | int | 3 | Max recovery & resume attempts before escalating. |
agent.nonstop.healing.backoff_base_seconds | float | 2.0 | Exponential backoff base for watchdog recovery. |
agent.nonstop.healing.backoff_max_seconds | float | 30.0 | Max backoff wait between recovery attempts. |
agent.nonstop.failover.enabled | bool | false | Enable model failover chain on primary LLM failure. |
agent.nonstop.failover.chain | list/str | [] | Ordered list or comma-separated string of failover model IDs. |
agent.nonstop.failover.cooldown_seconds | int | 300 | Cooldown period in seconds before retrying a failed model in chain. |
agent.nonstop.ledger.enabled | bool | true | Enable durable per-call LLM execution logging (kazma-data/llm_calls.db). |
models
Section titled “models”| Key | Type | Default | Description |
|---|---|---|---|
models.default | string | gpt-4o-mini | Default model id. |
models.router | string | kazma | Label for Kazma’s own router. Not an import litellm. Point base_url at a LiteLLM proxy if you run one. |
models.fallback | string | gpt-4o-mini | Model used on retry when the primary HTTP call fails. |
| Key | Type | Default | Description |
|---|---|---|---|
llm.base_url | string | https://api.openai.com/v1 | OpenAI-compatible endpoint. /v1 is auto-appended if missing (except Ollama :11434 and LiteLLM :4000). |
llm.api_key | string | '' | Leave empty to load from env (OPENAI_API_KEY → KAZMA_API_KEY → "not-needed" for local). |
llm.model | string | gpt-4o-mini | Model id sent in the payload. |
llm.max_tokens | int | 4096 | Completion token cap. |
llm.temperature | float | 0.7 | Sampling temperature. |
llm.timeout | float | 60.0 | Per-request timeout (seconds). |
llm.input_cost_per_1m | float | 0.15 | USD per 1M input tokens — used for cost accounting. |
llm.output_cost_per_1m | float | 0.6 | USD per 1M output tokens. |
llm.gateway.url | string | '' | Optional LiteLLM proxy for OpenAI-compatible providers. Env KAZMA_LITELLM_URL wins. Native four-branch never uses this. |
llm.gateway.api_key | string | '' | Proxy master key (LITELLM_MASTER_KEY). Vault-encrypted. |
llm.gateway.include_local | bool | false | Also send Ollama/LM Studio through the proxy (KAZMA_LITELLM_LOCAL=1). |
llm.gateway.fallback_direct | bool | false | If the proxy is down, retry the original URL once (KAZMA_LITELLM_FALLBACK_DIRECT=1). |
| Key | Type | Default | Description |
|---|---|---|---|
mcp.servers | list | see below | MCP server definitions. |
mcp.servers[].name | string | — | Server identifier. |
mcp.servers[].transport | string | stdio | stdio, 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[].trust | string | trusted | Plain config string — not consumed by any trust-tier code. |
mcp.servers[].command | list | — | argv for stdio spawn. |
mcp.ide_server.enabled | bool | true | Enable the in-process IDE/file MCP server. |
mcp.ide_server.root | string | . | Workspace root. |
mcp.ide_server.max_file_size | int | 1048576 | 1 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: 1048576system_prompt
Section titled “system_prompt”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.
storage
Section titled “storage”| Key | Type | Default | Description |
|---|---|---|---|
storage.engine | string | sqlite | Checkpointer engine. |
storage.path | string | kazma-data/checkpoints.db | LangGraph checkpointer DB. |
storage.vector_dim | int | 1024 | Declared vector dimension (informational — should match memory.embedding.dim; default BGE-M3 is 1024). |
memory
Section titled “memory”| Key | Type | Default | Description |
|---|---|---|---|
memory.enabled | bool | true | Master switch (per-turn RAG, auto-store, consolidator). ConfigStore overlays yaml. |
memory.per_turn_retrieval | bool | true | Inject top-k memories on every user turn. |
memory.auto_store | bool | true | Heuristic durable / turn writes after each reply. |
memory.auto_store_mode | str | both | durable | turns | both. |
memory.max_context_tokens | int | 1000000 | The 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_k | int | 5 | Top-K for per-turn RAG and compaction. |
memory.provenance | bool | true | Tag memories with source metadata. |
memory.consolidation.enabled | bool | true | Post-turn librarian (facts + graph triples). |
memory.consolidation.use_llm | bool | true | LLM extract; heuristic fallback if fail/off. |
memory.consolidation.every_n_turns | int | 1 | Cost control: run consolidator every N turns. |
memory.consolidation.skip_llm_in_demo | bool | true | No LLM under KAZMA_DEMO_MODE. |
memory.embedding.provider | str | local | local or remote OpenAI-compatible embed API. |
memory.embedding.model | str | BAAI/bge-m3 | Embedding model id (multilingual, 1024-dim). |
memory.embedding.dim | int | 1024 | Must match the embedder. |
memory.embedding.base_url | str | unset | /embeddings endpoint for remote providers. |
memory.embedding.api_key_env | str | KAZMA_EMBED_API_KEY | Env 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.
skills
Section titled “skills”| Key | Type | Default | Description |
|---|---|---|---|
skills.path | string | kazma-skills/manifests/ | Skill manifest directory. |
skills.auto_discover | bool | true | Auto-load manifests on startup. |
connectors
Section titled “connectors”| Key | Type | Default | Token env var |
|---|---|---|---|
connectors.telegram.enabled | bool | true | TELEGRAM_BOT_TOKEN |
connectors.discord.enabled | bool | false | DISCORD_BOT_TOKEN |
connectors.slack.enabled | bool | false | SLACK_BOT_TOKEN + SLACK_APP_TOKEN |
gateway
Section titled “gateway”| Key | Type | Default | Description |
|---|---|---|---|
gateway.rate_limits.telegram | int | 30 | Messages 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.discord | int | 30 | The 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.slack | int | 30 | The 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.enabled | bool | true | Telegram, 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.enabled | bool | false | Voice (STT inbound + TTS outbound) across all platforms (Telegram, Discord, Slack) + Web. Also settable at runtime via Settings → Voice. |
gateway.voice.stt_provider | string | openai | Speech-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_language | string | auto | STT language (auto, ar, en, …). Settings uses the same form-select as the other Voice fields. |
gateway.voice.stt_model | string | default | Whisper / transcribe model id for the chosen STT provider. |
gateway.voice.tts_provider | string | edgetts | Text-to-speech provider: edgetts (free, default), openai, nvidia, kokoro (local), coqui (local). |
safety.hitl
Section titled “safety.hitl”| Key | Type | Default | Description |
|---|---|---|---|
safety.hitl.enabled | bool | true | Master HITL switch (graph path). |
safety.hitl.require_approval_for | list | see below | Danger tools for the graph path. |
safety.hitl.approval_timeout_seconds | int | 300 | How 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_timeout | bool | true | Auto-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: trueThe 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 (unlessKAZMA_HITL_CANONICAL_FLOOR=0), so this file cannot narrow it. The MCP path classifies dynamically by name pattern. See Security & Safety → danger-tool lists.
notifications.lifecycle
Section titled “notifications.lifecycle”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.
| Key | Type | Default | Description |
|---|---|---|---|
notifications.lifecycle.enabled | bool | true | Master switch. |
notifications.lifecycle.events | list | [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_seconds | int | 60 | A 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: 60Notifications 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.
| Key | Type | Default | Description |
|---|---|---|---|
ui.host | string | 127.0.0.1 | Bind host. Switches to 0.0.0.0 under kazma serve only if KAZMA_SECRET is set. |
ui.port | int | 8000 | Bind port. |
ui.rtl | bool | true | UI RTL. |
ui.title | string | Kazma Dashboard | Page title. |
logging
Section titled “logging”| Key | Type | Default | Description |
|---|---|---|---|
logging.level | string | INFO | Log level. |
logging.format | string | json | json or plain. |
logging.langfuse.enabled | auto / bool | auto | auto = Langfuse when public+secret keys exist. false / KAZMA_LANGFUSE=0 = off. |
logging.langfuse.public_key | string | '' | |
logging.langfuse.secret_key | string | '' |
time_travel
Section titled “time_travel”| Key | Type | Default | Description |
|---|---|---|---|
time_travel.enabled | bool | true | Enable /replay. |
time_travel.max_snapshots | int | 50 | Snapshot 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_days | int | 30 | Prune 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_maintain | bool | true | Enable the daily snapshot prune + VACUUM loop. ConfigStore override time_travel.auto_maintain is read live, same as retention_days. |
time_travel.db_path | string | kazma-data/snapshots.db | Snapshot DB. |
| Key | Type | Default | Description |
|---|---|---|---|
swarm.enabled | bool | true | Master swarm switch. |
swarm.group_chat_id | int | 0 | Real value read from SWARM_CHAT_ID env. |
swarm.default_pattern | str | dispatch | Fallback pattern: dispatch | pipeline | consult | fan_out | broadcast. |
swarm.auto_route | bool | true | Enable semantic auto-routing (UnifiedRouter) for workers=["auto"]. |
swarm.max_concurrent_tasks | int | 10 (1–100) | Max concurrent swarm tasks. |
swarm.max_concurrent | int | 5 | Fan-out / broadcast / consult worker concurrency. |
swarm.orchestrator.name | string | Kazma Orchestrator | Orchestrator display name. |
swarm.orchestrator.profile | string | default | Orchestrator profile id. |
swarm.workers | list | [] | Populated at runtime via Web UI / POST /api/swarm/workers. |
swarm.output_target | obj | none | \{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.
| Key | Type | Default (range) | Description |
|---|---|---|---|
cron.timezone | string | empty (KAZMA_TZ, else UTC) | The zone a naive time and a clock time (“daily at 9am”) are read in. |
cron.catchup_minutes | int | 60 (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_seconds | int | 300 (30–3600) | How long a fired agent task’s turn may run. |
cron.max_jobs_per_tenant | int | 500 (1–10000) | Jobs still holding work per tenant; a booking past it is refused. |
cron.max_jobs_per_thread | int | 50 (1–1000) | The same, per conversation. |
safety.cron_fire_without_hitl | bool | false | Fire 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.
pipelines
Section titled “pipelines”Two predefined pipelines (lists of stages, each with worker, depends_on, system_prompt):
standard— 4 stages:researcher(workercore) →refiner(workerbridge) →builder(workercore) →validator(workerbridge).quick— 2 stages:researcher(workercore) →builder(workercore).
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/singlewith a nested key, for every other key- optional
kazma.yamlseed under adocuments: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 prefix | Purpose |
|---|---|
documents.enabled / shadow / default_authoritative | Rollout mode (disabled / shadow / compatibility / authoritative) |
documents.storage_root | Where 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_fonts | Inline 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):
| Variable | Default | Purpose |
|---|---|---|
KAZMA_DOCUMENTS_JOBS_BACKEND | unset | sqlite forces SQLite job queue; else Postgres when platform uses PG |
KAZMA_DOCUMENTS_METADATA_BACKEND | unset (auto) | sqlite / postgres / auto (auto follows jobs) |
KAZMA_DOCUMENT_WORKER_ISOLATION | process | process (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_ITERATIONS | 100 | Repetitions 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.
3. Environment variables
Section titled “3. Environment variables”3.1 Documented in .env.example
Section titled “3.1 Documented in .env.example”| Variable | Purpose | Default |
|---|---|---|
TELEGRAM_BOT_TOKEN | Telegram adapter token. | placeholder |
DISCORD_BOT_TOKEN | Discord adapter token. | empty |
SLACK_BOT_TOKEN | Slack bot token. | empty |
SLACK_APP_TOKEN | Slack app token (Socket Mode). | empty |
OPENAI_API_KEY | OpenAI key (also generic LLM fallback #2). | empty |
DEEPSEEK_API_KEY | Declared in .env.example but not read by code — set the key via the provider list instead. | empty |
ANTHROPIC_API_KEY | Declared in .env.example but not read by code. | empty |
GOOGLE_CLOUD_PROJECT | GCP project for Vertex AI (if ADC lacks a default). | commented out |
SWARM_CHAT_ID | Swarm group chat id (feeds swarm.group_chat_id). | empty |
KAZMA_SECRET | HITL shared secret; binds serve to 0.0.0.0; hub write-auth; kazma hub sign. | commented out |
KAZMA_VECTOR_PATH | Vector memory dir. | ~/.kazma/vector_memory |
KAZMA_VECTOR_COLLECTION | ChromaDB collection name. | agent_memory |
KAZMA_VECTOR_MODEL | Embedding model (legacy alias — prefer KAZMA_EMBED_MODEL). | BAAI/bge-m3 |
3.2 Read in code, not in .env.example
Section titled “3.2 Read in code, not in .env.example”| Variable | Purpose | Location |
|---|---|---|
KAZMA_AUTH_DISABLED | If true/1/yes, get_kazma_secret() returns "" (auth disabled). | config_store.py:52 |
KAZMA_DISCLOSURE_KEY | Disclosure HMAC key; auto-generated if unset. | config_store.py:95 |
KAZMA_API_KEY | LLM key fallback #3. | llm_provider.py:142 |
KAZMA_MAX_COST | Cost breaker ceiling (default $0.50). | cost_breaker.py:42 |
KAZMA_HARD_MAX_COST | Hard max cost ceiling for immediate trip (default 3x soft max, $15.0). | cost_breaker.py:46 |
KAZMA_SILENCE_WINDOW | Cost breaker silence window (default 300s). | cost_breaker.py:44 |
KAZMA_SEMANTIC_CACHE | Retired 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_BYTES | Streamed response byte limit for read_url (default 5242880 / 5 MB). | tools/read_url.py |
KAZMA_CRAWL_RESPECT_ROBOTS | Default 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_ROOT | Linux 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_ENDPOINT | OTLP HTTP JSON trace collector endpoint. | swarm/tracing.py |
KAZMA_TOOL_TIMEOUT_SECONDS | Per-tool execution timeout in seconds (default 120). | agent/graph_builder.py |
KAZMA_HUB_DB | Hub SQLite registry path. | hub/cli.py:109 |
KAZMA_HUB_URL | Hub API base (default https://hub.kazma.ai). | hub/cli.py:115 |
KAZMA_PORT | Server port override (default 8000). | gateway.py:36 |
HF_HUB_DISABLE_SYMLINKS_WARNING / HF_HUB_DISABLE_TELEMETRY | Silence 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 orkazma.yaml.
4. API keys
Section titled “4. API keys”LLMProvider._resolve_api_key() (llm_provider.py:136-146) resolves in this order:
self.config.api_key(fromLLMConfig)os.getenv("OPENAI_API_KEY")os.getenv("KAZMA_API_KEY")"not-needed"(for local LM Studio/Ollama)
Provider-specific dummy keys for local servers (url_utils.py:138-172):
| Server | Dummy key |
|---|---|
| LM Studio (:1234) | sk-lm-studio-dummy-key |
| Ollama (:11434) | ollama |
| LiteLLM proxy (:4000) | sk-litellm-dummy-key |
| other localhost | not-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).
5. The Model Registry
Section titled “5. The Model Registry”ModelRegistry (model_registry.py:81) is a process-wide singleton (module global _registry, thread-safe via threading.RLock()). Backward-compat alias: UnifiedModelRegistry (line 950).
5.1 Lifecycle
Section titled “5.1 Lifecycle”| Function | Purpose |
|---|---|
initialize_model_registry(config_store) | Construct + deserialize + seed presets. |
get_model_registry() | Retrieve singleton (raises RuntimeError if uninitialized). |
reset_model_registry() | Teardown. |
5.2 Built-in provider presets
Section titled “5.2 Built-in provider presets”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).
| Key | Display name | base_url | auth_header | Native class? |
|---|---|---|---|---|
openai | OpenAI | https://api.openai.com/v1 | Bearer | no |
anthropic | Anthropic | https://api.anthropic.com/v1 | x-api-key | yes — AnthropicProvider |
deepseek | DeepSeek | https://api.deepseek.com/v1 | Bearer | no |
google | Google Gemini | (computed per project/location) | Bearer | yes — GeminiProvider |
xai | xAI / Grok | https://api.x.ai/v1 | Bearer | no |
openrouter | OpenRouter | https://openrouter.ai/api/v1 | Bearer | no |
groq | Groq | https://api.groq.com/openai/v1 | Bearer | no |
mistral | Mistral AI | https://api.mistral.ai/v1 | Bearer | no |
together | Together AI | https://api.together.xyz/v1 | Bearer | no |
cohere | Cohere | https://api.cohere.ai/v1 | Bearer | no |
fireworks | Fireworks AI | https://api.fireworks.ai/inference/v1 | Bearer | no |
perplexity | Perplexity | https://api.perplexity.ai | Bearer | no |
ai21 | AI21 Labs | https://api.ai21.com/studio/v1 | Bearer | no |
nvidia | NVIDIA NIM | https://integrate.api.nvidia.com/v1 | Bearer | no |
azure | Azure OpenAI | (computed from resource + deployment) | api-key | yes — AzureProvider |
bedrock | AWS Bedrock | (computed from region) | Bearer (SigV4) | yes — BedrockProvider |
ollama | Ollama (Local) | http://127.0.0.1:11434/v1 | (none) | no |
lm-studio | LM Studio (Local) | http://localhost:1234/v1 | (none) | no |
custom | Custom Endpoint | (blank) | Bearer | no |
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
enabled=Trueout of the box (model_registry_store.py:117). All others must be configured before use.customis excluded from preset seeding.
5.3 Model discovery
Section titled “5.3 Model discovery”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.
5.4 ConfigStore keys (registry)
Section titled “5.4 ConfigStore keys (registry)”| Key | Purpose |
|---|---|
providers.list | Stored 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_key | Legacy fallbacks. |
registry.active_provider, registry.active_model, registry.discovered_models | Active selection + cache. |
6. retry keys
Section titled “6. retry keys”The retry/backoff helpers read overrides from ConfigStore (retry.py):
| Key | Default | Description |
|---|---|---|
retry.max_attempts | 3 | Max retry attempts. |
retry.min_wait | 2 (s) | Min backoff. |
retry.max_wait | 10 (s) | Max backoff. |
Retries fire only on network/timeout exceptions (
ConnectionError,TimeoutError,asyncio.TimeoutError, httpxTimeoutException/ConnectError/RemoteProtocolError). 4xx errors are never retried (retry.py:107-109). There is no 429 backoff.
7. Security config files
Section titled “7. Security config files”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). Seedocs/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: true7.2 kazma-security.yaml
Section titled “7.2 kazma-security.yaml”| Section | Key options |
|---|---|
scanning | enabled, interval: "24h", sources: [osv, github_advisories, nvd], auto_create_issues, severity_threshold: medium, ignore. |
disclosure | enabled, response_window: "48h", assessment_window: "7d", security_txt_url (RFC 9116 contact file, not a PGP key), encrypted_channels (email + GitHub private reporting). |
bug_bounty | enabled: false — no paid program. Payout fields are reserved/zeroed; do not advertise tiers as active. See root SECURITY.md. |
hardening | run_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. Itsscanningandhardeningkeys schedule nothing; the hardening report and the dependency scan run on demand throughGET /api/security/hardeningandGET /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.
| Key | Default | Purpose |
|---|---|---|
proxy.provider | none | none (direct) | anyip |
proxy.host | portal.anyip.io | Proxy endpoint host |
proxy.port | 1080 | Proxy endpoint port |
proxy.username | (empty) | anyip username (e.g. user_YOURID) |
proxy.password | _(empty, vault) | anyip password |
proxy.network | mixed | residential | mobile | mixed |
proxy.country | (empty) | Optional ISO country code (e.g. US) |
proxy.session_sticky | false | true = same IP across requests (logins); false = rotate per request |
See Web research → Bulletproof scraping.
Settings durability and outage recovery
Section titled “Settings durability and outage recovery”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.
Research and crawler alerts
Section titled “Research and crawler alerts”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.
| Control | Default | Allowed value |
|---|---|---|
| Monitoring enabled | true | Boolean |
| Completion notifications | true | Boolean |
| No observed progress threshold | 180 seconds | Integer, 30–3600 |
| Fresh low-credit threshold | 100 | Integer, 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.
Documentation Audit Notes
Section titled “Documentation Audit Notes”- Version drift:
pyproject.tomlis0.3.0;kazma.yamlagent.versionis0.2.0; the CLI--helptext printsv0.2.0. These are independent and unsynchronized — a known wart. - Memory flags are read via
kazma_core.memory.config(ConfigStore ← yaml). See Memory & RAG anddocs/plans/MEMORY_REMAINING.md. .env.examplelistsDEEPSEEK_API_KEY/ANTHROPIC_API_KEYbut no code reads them — flagged to prevent user confusion.mcp.servers[].trustis a plain YAML string with no enforcing consumer — not a cryptographic trust tier.

