Skip to content

Deployment

Reference for the supported deployment shapes. For a guided zero-to-running walkthrough on Docker Compose with PostgreSQL, see tutorial_postgres_deployment.md. For copy-paste quick shapes (local poke, operator pull-and-run, one-shot CLI in the image), see run_recipes.md. For every environment variable referenced below, see environment.md.

The service supports three shapes:

  • Container — a single kneo-serv image with a database you supply.
  • Compose — the bundled stack that starts the API plus PostgreSQL.
  • Embeddedkneo_serv.service.app:create_app() mounted in your own ASGI server (covered in tutorial_custom_tool.md § 7).

Container

Pull the published image from GitHub Container Registry:

docker pull ghcr.io/kneo-agent/kneo-serv:latest

Tag conventions: <version> (e.g. 1.0.0), <major>.<minor> (1.0), and latest. amd64-only; arm64 is deferred to 2.0. From 0.3.0 onward the image is keyless-signed via cosign and ships with a CycloneDX SBOM attestation; from 0.4.0 onward the release pipeline also runs a blocking Trivy CVE scan against the pushed digest under the CVSS≥7 policy (security_hardening.md § Image vulnerability scanning) — verification commands in supply_chain_review.md § Verification commands. The image installs the kneo-serv[deploy] extra (psycopg + SDK telemetry).

Run it against PostgreSQL:

docker run --rm -p 8000:8000 \
  -e KNEO_SERV_DATABASE_URL=postgresql://kneo_serv:change-me@host.docker.internal:5432/kneo_serv \
  -e KNEO_SERV_AUTH_ENABLED=true \
  -e KNEO_SERV_API_KEYS='operator:replace-token:operator' \
  ghcr.io/kneo-agent/kneo-serv:latest

For local builds from a source checkout (contributor / pre-publish):

docker build -t kneo-serv:local .

Compose

The bundled Compose stack starts the API plus PostgreSQL:

cp deploy/production.env.example deploy/production.env
docker compose --env-file deploy/production.env up --build

Replace every placeholder token and database password before binding the service to a network. The stack defaults to port 8000; set KNEO_SERV_PORT to change the host-side port.

For a staging rehearsal, use the staging env example:

cp deploy/staging.env.example deploy/staging.env
KNEO_SERV_ENV_FILE=./deploy/staging.env \
  docker compose --env-file deploy/staging.env up --build

deploy/staging.env is gitignored. Keep SDK telemetry argument/result capture (KNEO_SERV_OTEL_RECORD_ARGUMENTS, KNEO_SERV_OTEL_RECORD_RESULTS) disabled in staging unless the deployment's data classification has explicitly approved payload capture.

TLS and reverse proxy

The service speaks bare HTTP and does not terminate TLS itself. For any deployment exposed beyond 127.0.0.1, place a reverse proxy (nginx, Caddy, AWS ALB, or similar) in front and terminate TLS there. See tls_and_proxy.md for topology, bind-address guidance, and trusted-proxy header handling.

Choosing a persistence backend

Backend When to use
SQLite Local dev or single-process service. Default when KNEO_SERV_DATABASE_URL is unset.
PostgreSQL Any multi-process or production deployment. Set KNEO_SERV_DATABASE_URL. Requires kneo-serv[postgres] or kneo-serv[deploy].

When KNEO_SERV_DATABASE_URL is set, the service uses PostgreSQL for run state, checkpoints, idempotency records, queue leases, locks, audit events, and workflow continuations. Without it, the service falls back to SQLite for state and file-backed continuations.

Multi-process SQLite is not a supported topology; see troubleshooting.md § 2.3.

For the throughput and latency trade-offs between the two backends — including why SQLite write throughput does not scale with concurrency — and a bench harness to size your own deployment, see performance.md.

Readiness and liveness

Wire these endpoints into your supervisor or load balancer:

GET /livez      # process liveness
GET /readyz     # readiness: all dependencies healthy
GET /healthz    # lightweight overall health

/livez and /readyz are intentionally unauthenticated for probe integration. /readyz returns 503 with a structured not_ready payload when any dependency check fails — see troubleshooting.md § 1.2 for the failure shape.

The Prometheus scrape endpoint GET /metrics (since 0.5.0) is also unauthenticated — restrict it to your monitoring network or disable it with KNEO_SERV_METRICS_ENABLED=false. See observability.md § Prometheus /metrics.

Workers, scaling, and graceful shutdown

A single process runs a pool of KNEO_SERV_WORKER_CONCURRENCY worker threads (default 1) draining the run queue. Raise it for provider-bound workloads; for write-concurrent scale on PostgreSQL, run multiple service processes — each leases queued runs safely via FOR UPDATE SKIP LOCKED. A starting CPU/RAM/worker floor to deploy against (and the SQLite single-writer caveat) is in performance.md § Minimum sizing.

On SIGTERM (e.g. a rolling deploy) the service drains the worker pool: workers stop claiming new work and finish the run they are currently executing, and the service waits up to KNEO_SERV_SHUTDOWN_TIMEOUT_SECONDS (default 30) for them to exit. A run still executing when that timeout elapses is interrupted by process exit — but it stays claimed and is automatically re-leased and retried by another worker once its KNEO_SERV_WORKER_LEASE_SECONDS lease expires, so it is not lost, only restarted. To drain in-flight runs without that restart, set KNEO_SERV_SHUTDOWN_TIMEOUT_SECONDS (and your orchestrator's termination grace period) at least as long as your longest expected run step. Set KNEO_SERV_MAX_QUEUE_DEPTH to shed load with 503 under overload, and KNEO_SERV_QUEUE_MAX_ATTEMPTS (default 5) to dead-letter poison runs rather than retry them forever.