Production Checklist
Production checklist
Section titled “Production checklist”Use this before exposing Kazma beyond loopback. Aligns with
AUDIT_DEEP_2026-09-01_EXEC.md
(waves 0–8 shipped) and the historical
REMEDIATION_PLAN_2026-07-21.md
(Phases 0–4). Invariants: AGENTS.md.
Feature smoke (research / KB / proxy / memory explain): see Smoke test matrix — run after related deploys.
Is the install actually alive? Full-system battery — chat tools (A), HTTP/ops (B), one HITL write (C). A green Part A is not a green Kazma.
P0 — Secrets & bind
Section titled “P0 — Secrets & bind”-
KAZMA_HOSTis intentional (127.0.0.1or proxy-only0.0.0.0) -
KAZMA_SECRETis strong, unique, not the historicalkazma-local-dev-secret - Non-loopback bind fails closed without secret (CLI / serve)
-
KAZMA_PRODUCTION=1 -
KAZMA_VAULT_KEYset - Healthcheck uses
/health/live(process) and/health/ready(critical deps)./health/detailsis auth (leaks model/MCP). Poll/health/deepas the silent-no-op canary (open, TTL 30s)
P0 — Lifecycle & fail-closed
Section titled “P0 — Lifecycle & fail-closed”- Graceful shutdown drains swarm/cron (no orphan tasks)
- NullBus denies danger tools (no headless auto-approve)
- YOLO disabled unless
KAZMA_ALLOW_YOLO=1(avoid in real prod) - Circuit breaker half-open probe semantics intact (
_probe_in_flight) - Deploy via
kazma_guard.py --reload— never hand-kill python/uvicorn (the guard respawns the old port holder) - Behind nginx/Caddy/Docker:
KAZMA_TRUSTED_PROXIESset; peer127.0.0.1is not a credential - CSRF on: mismatched Origin/Referer host → 403 on non-GET
/api/*
P1 — Security depth
Section titled “P1 — Security depth”- Auth default-deny on
/api/* - Discovery SSRF protections enabled
-
code_execDocker force where required (KAZMA_CODE_EXEC_DOCKER=force; host-local disabled in prod/multi-user) - Untrusted / multi-user code: E2B Firecracker (
E2B_API_KEY+pip install -e ".[sandbox]";KAZMA_E2B=0to disable) - Multi-hour swarm: Temporal (
KAZMA_TEMPORAL_HOST+pip install -e ".[durable]") - HA preparation: one active runtime, dedicated Postgres ownership session and complete fenced state volume; target-cluster drills passed before a recovery claim
- Shell allowlist + env scrub active
- Workspace root confinement in production
- Cron concurrency / stop / stale RUNNING handled
- Multi-operator: platform allowlists set +
KAZMA_GATEWAY_STRICT_ALLOWLIST=1(2026-08-19; adapters otherwise run allow-all for backward compat) -
KAZMA_HITL_CANONICAL_FLOORis not set to0(the floor is on by default since 2026-09-16: the danger list cannot narrow below canonical) - Offsite/cloud-sync backups verify TLS (WebDAV default ON since 2026-08-19;
backups.offsite.webdav.tls_verify=falseonly for self-signed labs) - Offsite restic: write probe succeeds (
rclone:ands3:— a read-only remote is a failed backup) - New tools have a
TOOL_TIERSentry (read/write/danger); unclassified = gated - Scraping: pin-IP on the direct path; do not pin through
proxy=
Persisted workspace and execution policies
Section titled “Persisted workspace and execution policies”An administrator can use the authenticated PUT /api/settings atomic batch
instead of editing an installation’s environment file:
[ {"key": "security.workspace_roots", "value": ["/srv/kazma-projects"]}, {"key": "security.execution.container_required", "value": true}]Choose existing absolute directories on the server. Multiple explicit roots
can retain an existing workspace and confine new repositories separately.
Resolved symlinks must stay inside a configured root. If
KAZMA_WORKSPACE_ROOT is present, a path must also stay inside that environment
root; a Settings save cannot expand it. Production without either policy
refuses workspace creation and switching. Missing or invalid policy storage
fails closed.
The strict container profile requires Docker for python_exec, skips E2B,
disables shell_exec, and forbids local fallback even when legacy environment
flags allow it. It also refuses the local process profile for document
parsing, OCR, conversion and PDF mutation (worker_isolation_required):
choose the container profile in Settings → Documents (on a native install the
guard runs the document worker broker; see Document processing, “Isolated
document workers”). Native file and Git tools retain their approval gates. Check
the actual Docker daemon and run an approved disposable snippet before
qualifying execution; daemon readiness alone does not verify the image or
mount permissions. The strict profile makes code_execution a required
readiness capability automatically; an unavailable Docker daemon refuses traffic.
These install policies are protected from agent config tools and excluded
from portable settings backups with the other security.* values.
Runtime approval notes distinguish an authorization from a successful tool result. Workspace-bound MCP servers use separate scoped instances when a task targets a different root; the global binding does not describe that instance. This supplies verified facts to the model, without guaranteeing every freeform answer it generates.
Multi-user / active-passive recovery (if applicable)
Section titled “Multi-user / active-passive recovery (if applicable)”-
KAZMA_DATABASE_URLset; migrate script run - Opaque sessions / RBAC admin user created
- OIDC vars if SSO
-
KAZMA_PUBLIC_URLcorrect for redirects - HA compose / LB retains one active owner; Postgres and the complete state volume are backed up and restored together
- Memory: tenant scoping is automatic with
KAZMA_PRODUCTION=1; setKAZMA_MEMORY_ENFORCE_TENANT=1for a multi-tenant install that is not flagged production - Before
KAZMA_MEMORY_STATE_ROLE=primary:python scripts/reconcile_memory_mirror.py --dry-runis clean (no dead-in-mirror rows) - Document catalog, job and intake tables are on
KAZMA_PG_TABLESwhen the document store is on Postgres (H-13)
Document Intelligence (if enabled)
Section titled “Document Intelligence (if enabled)”-
documents.enabledintentional (default compatibility: enabled, not default-authoritative) - Document metadata readiness verified with
GET /api/documents/ops/readiness; Postgres metadata alone does not qualify concurrent active runtimes - Readiness
degraded_reasonsempty, or each one understood (stranded_intake_reservationsis 0) - Execution profile chosen deliberately: the default
processprofile has no filesystem or network isolation (readinesshostile_document_profile: unqualified); for documents you do not trust, deploy the container broker (Document processing → Isolated document workers) and confirmworker_isolation.readyandimage_code_matchesare true -
documents.capacity.storage_free_floor_bytesset conservatively (default 512 MiB) - Document backup path known (the 6-hourly backup:
kazma-data/backups/document-store-*on SQLite,document-pg-*on Postgres) and a restore drilled once; document metadata and jobs on the same backend (SQLite metadata beside Postgres jobs has no coordinated document backup) - Migration plan includes
documents.db+ content tree (Migration); a Postgres document store moves withscripts/document_pg_backup.py, not the bundle - Optional engines understood (fitz / WeasyPrint / LibreOffice may be CONDITIONAL)
- PDF Arabic / electronic text:
pip install -e ".[document-platform]"(PyMuPDF + pypdfium2); parser readiness (GET /api/documents/health) should be ready, not text-only degraded - Scanned Arabic PDFs: system Tesseract +
ara(andeng) traineddata on PATH; Arabic OCR is not qualified for release (Arabic-Indic digits are not read) - Malware: install ClamAV (
clamscan/clamdscanon PATH) and check readinessmalware.available. WithKAZMA_PRODUCTION=1the scan is fail-closed by default: without a scanner every upload is refused - Remote parsing (
documents.security.remote_parse) left off unless sending original documents to a third party is intended - Cert smoke:
python scripts/certify_documents.pyexits non-FAIL; record report if promoting canary
Guide: Document Intelligence · Ops: Document processing.
Upgrades (git install)
Section titled “Upgrades (git install)”- Operators use
kazma update(not ad-hocgit pull) — see Kazma Update - After update:
kazma --version/ HEAD matchesorigin/main;import kazma_cliworks;kazma servestarts - Optional extras still present (rag / document-platform); use
kazma update --reinstall -yif wiped
& .venv\Scripts\python.exe scripts\smoke_production.py --base http://127.0.0.1:9090 --secret $env:KAZMA_SECRET# Document platform (optional but recommended when documents.enabled):& .venv\Scripts\python.exe scripts\certify_documents.py# Optional industry smoke (HITL card, health/deep):# scripts\industry_smoke.ps1Confirm GET /health/deep is 200 after reload. HITL: one Approve card, second click 409.
Also run document rows in the Smoke matrix.
Related ops
Section titled “Related ops”- Postgres & SaaS
- Multi-replica & SaaS residual
- Disaster recovery
- Multi-region
- OIDC
- Document processing
- Environment variables
Commitment Layer
Section titled “Commitment Layer”- Kill-switch verified:
KAZMA_COMMITMENT_ENABLED=0disables the gate (fail-open) - GC cadence running:
_start_commitment_gc_schedulerevery 15 min (check logs forcommitment GC:summary) - Flags:
swarm_scope_enforcedefaults ON (workers capped at HIGH since 2026-08-15);enforce_unknown_mutatorsdefaults ON;soul_requires_confirmdefaults OFF on a lab and auto-ON in production / multi-user — operators toggle via ConfigStore / env - Metrics endpoint:
GET /metricsshowskazma_commitment_decisions_total{decision=...}+kazma_commitment_pending - Soul confirm queue:
GET /api/commitment/soul/pendinglists held deltas;POST /api/commitment/soul/{cid}/confirmapproves - Semantic-tool exceptions fail closed (kill-switch still fail-open)
HITL Gate Registry & Turn Delivery
Section titled “HITL Gate Registry & Turn Delivery”-
kazma-data/hitl_gates.dbis writing rows (pending → claimed → settled) - Web paints from
_serverGates— no ghost Approved stamp; second claim is 409 - Swarm FanOut (2+ platforms) is tri-state (Deny is a vote, not an instant settle)
-
KAZMA_GATE_REGISTRY=0is not set in prod (thin execution fallback only) -
close_turnkeeps the turn open while a pending row exists
Backup & ops alerting
Section titled “Backup & ops alerting”- Universal +
native_pg_backupcadence is 6h (not 24h); local PG staging retention default 3 (restic keeps history) - With Postgres, the weekly deep drill’s restore rehearsal is on (default since 2026-09-27) and the database role has
CREATEDB; the drill log namespostgres:restore - Chat step history retention is what you want (Settings → System; default 30 days, 0 keeps every checkpoint). An install upgrading with years of history: set it before the upgrade if you want to keep them
- Universal backup checks PG dump freshness — a missing/stale dump is not
"ok": true -
ops_alertsreach Telegram (and FanOut if Discord/Slack configured): Settings → Adapters & Routes → Send a test alert names each route that took it; kill-switchKAZMA_OPS_ALERTS=0only during a noisy incident - Guard Telegram is separate (child-down). 503 cause-quality (
database: …vsService Unavailable) is deferred:GUARD_OPS_ALERTING_CAUSE_QUALITY.md

