Skip to main content

Overview

z3rno-server is a FastAPI application that exposes the Z3rno engine over HTTP. It imports z3rno-core for business logic and adds authentication, rate limiting, body-size limits, structured logging, request-ID propagation, and a Celery worker tier for async tasks (audit drain, lifecycle sweeps, Forge pipelines, refine scheduler). Current version: z3rno-server 0.20.0. See changelogs/V0-20-CHANGELOG.md for what’s new.

Endpoints

Endpoints fall into four groups: always-on (registered on every deploy), conversation memory (always-on, Phase G), opt-in (registered when an *_ENABLED flag is true), and public (no auth required).

Always-on

Conversation memory (Phase G slice 2 — always-on)

Opt-in

Each block registers only when its gating flag is true. With the flag off, the routes are absent from the OpenAPI surface and the corresponding worker tasks self-reject.

Public (no auth)

Middleware chain

Requests pass through these layers, outermost first:

Authentication

API keys are passed via either header:
Keys carry an z3rno_sk_* prefix. The dev default seeded on a fresh local server is z3rno_sk_test_localdevchange this for any non-localhost deploy. Production keys are generated via POST /v1/api-keys (returns the plaintext key once; only its hash is stored).

Rate limiting

Token bucket per API key, evaluated in the RateLimit middleware. Rate-limit response headers are returned on every authed call:
The shipped default is RATE_LIMIT_REQUESTS=100 per RATE_LIMIT_WINDOW=60 seconds with RATE_LIMIT_BURST=20. Self-hosters tune these per deploy; managed-cloud tiering lives ahead of v0.21.

Celery workers

Background tasks ride on Celery with Valkey as broker + result backend. Twelve shipped tasks: NOTIFY/LISTEN wake-up: when Z3RNO_AUDIT_LISTEN_ENABLED=true (v0.20.2), a dedicated z3rno-audit-listener console-script pod opens a Postgres LISTEN z3rno_audit_pending and fires z3rno.audit_drain on every write. Drains wake in ~50 ms instead of waiting for the next beat tick; the beat-driven poll stays as a fallback at a longer interval (60 s recommended).

Configuration

Required env vars:
Embedding (required for recall quality):
CORS + logging:
The Phase A/B/C/D/F/G opt-in flags (DISTILL_ENABLED, INGEST_ENABLED, REFINE_ENABLED, MEMORY_TIER_AUTO_ROUTE, RETRIEVAL_REDACTION_ENABLED, FORGET_PROOF_ENABLED, OTEL_ENABLED, DATABASE_READ_URL, Z3RNO_AUDIT_LISTEN_ENABLED, the USAGE_BUDGET_* family, multimodal, S3, Tavily, Playwright, codegraph, ontology, distributed-backends, etc.) all live alongside on the Self-hosting / Configuration page.

Running locally

Admin surface (v0.22.1, opt-in)

Cross-tenant management endpoints for managed-hosting providers. Sits alongside the regular tenant surface — not above it. Tenants still self-manage their own budgets via /v1/tenants/me/budgets; this surface lets a hosting operator set budgets on behalf of a tenant without holding that tenant’s auth.

Enabling the surface

Both env vars must be set — an empty key disables the surface even when the flag is true:
With either unset, the routes are not registered at all — they don’t show up in the OpenAPI spec and the auth middleware never stamps role="superadmin". This is the correct default for every deploy that isn’t a managed-hosting control plane.

Authentication model

Authentication is the env-keyed SUPERADMIN_API_KEY directly — there is no DB-stored superadmin role, no rotation API, no per-key auditing yet. Any caller presenting that key in Authorization: Bearer ... gets role="superadmin" attached to the request and is not tenant-bound (org_id stays None). Handlers SET LOCAL app.current_org_id to the URL-path org_id so the underlying SQL — same shape as /me/budgets — runs against the target tenant under RLS. Treat the key like a root password: deploy-time configured, kept out of git, rotated by config push. A dedicated rotation playbook is on the roadmap for v0.23+ (see Managed-hosting guide).

RBAC posture

The strict require_superadmin() dependency guards these routes — it rejects role=None (the backward-compat path that the regular require_role lets through for API-key callers). A misconfigured client presenting a normal tenant key gets a 403, not silent cross-tenant access.

Using it from the SDKs

Both Python and TypeScript SDKs expose a client.admin sub-namespace since v0.9.0:
The full ops playbook (key handling, rollout checklist, what to do when a customer asks for a budget bump) lives in Managed-hosting guide.

Error responses

Errors follow RFC 7807 (Problem Details):

Reference