Environments & Operations
pixi features
The backend uses pixi with a shared base plus feature-specific overlays (ai/pyproject.toml):
| Feature | Purpose | Key pins |
|---|---|---|
| base | Shared runtime (implicit) — FastAPI, uvicorn, pydantic, supabase, weasyprint, pandas, the test/lint tools, and the two editable local packages. | — |
| adk | Google ADK 1.x parity (byte-identical with KavApps kavai_server). Orion does not run here. |
google-adk >=1.26,<2, google-genai >=1.61,<2, starlette <1 |
| adk2 | Google ADK 2.x main line. | google-adk >=2.5,<3, google-genai >=2.9,<3, starlette >=1.3.1,<2 |
| kawa | Fully isolated (no-default-feature); pins the Kawa/hermes tree exactly so it never conflicts with adk. |
python 3.12.*, hermes-agent >=0.18,<0.19 |
Environments
[tool.pixi.environments]
default = { features = ["adk2"], solve-group = "adk2" } # runs dataadk, argus, orion, kawa
adk = { features = ["adk"], solve-group = "adk1" }
kawa = { features = ["kawa"], no-default-feature = true, solve-group = "kawa" }Each environment has its own solve group, so the isolated kawa tree (e.g. pillow) can never clash with the ADK environments.
Tasks
Serve
| Task | Runs |
|---|---|
pixi run serve-all |
Runtime + gateway together (scripts/start-all.sh). |
pixi run serve-gateway |
Gateway on :8080 (scripts/start-gateway.sh). |
pixi run serve |
ADK Runtime on :50052 (scripts/start-runtime-adk.sh, adk2 feature). |
pixi run serve-kawa-adapter |
Kawa AG-UI adapter on :8082 (kawa env, HERMES_PROFILE=kavai). |
pixi run serve-argus-web |
The ADK Web trace UI (scripts/start-dataadk-web.sh). |
pixi run serve-monolith |
Legacy: all systems in one process on :8080. |
Test & verify
pixi run pytest(depends onensure-jwt), plustest-core,test-orion,test-kawa,test-kawa-adapter.- Engine-axis:
test-engine-dataadk/test-engine-orion/test-engine-kawa, andtest-cross-engine(-m all_systems). - Package suites:
test-agent-contract,test-dataadk-package. certify-engines,benchmark-engines,universal-tests.ensure-jwt(scripts/ensure-jwt.py) validates/regenerates the JWT before test tasks.
Evaluate & maintain
- Evals:
eval-argus,eval-argus-user-sim,eval-argus-all,eval-orion-user-sim,eval-orion-all. format→black . && isort .;lint→flake8 . && mypy ..
Add an ADK dep under [tool.pixi.feature.adk2.pypi-dependencies] (or .adk), a shared dep under the base [tool.pixi.pypi-dependencies], then pixi update.
Running it locally
pixi run serve-all # Gateway (:8080) + ADK Runtime (:50052)
# separately, for the Kawa engine:
pixi install -e kawa
HERMES_PROFILE=kavai pixi run serve-kawa-adapter # :8082KAVAI_SYSTEMS selects which systems the runtime loads (default argus,orion,kawa); the gateway targets the runtime via ADK_BACKEND_URL and the Kawa adapter via KAWA_ADAPTER_URL.
With compose
docker compose up runs web, the gateway and Kawa on the kavai-network bridge, where each service is reachable by its service name — not on localhost, which inside a container is that container itself.
Kawa needs this in both directions: the gateway calls it, and it calls the gateway’s image-skill endpoint for surface-analysis (ADR-007, docs/adr/). The second direction is set explicitly, because Kawa’s built-in default (http://127.0.0.1:8080) resolves to Kawa’s own container:
kawa:
environment:
- KAVAI_GATEWAY_URL=http://ai-server:8080 # by service name, not localhostRun the two separate processes above instead of compose and the same rule applies in reverse — there 127.0.0.1:8080 is the gateway, so the default is correct and nothing needs setting.
On Cloud Run
The three run as containers in one service (kap-dev) and share a network namespace, so there localhost is right again — see the runtime chapter for the address table and why Kawa is co-located rather than a service of its own.
One thing does run as a service of its own: kap-render, the GPU render worker behind /datasets/{slug}/render/{scene,cad} (Cloud Run, us-east4, one NVIDIA L4 without zonal redundancy, 4 vCPU / 16 GiB, min instances 0, max 1). kap-dev has no GPU — Cloud Run offers L4s in us-east4 and us-central1, not us-west1 — and a render on the software rasteriser costs ~48 s a frame, so the web container’s two render routes hand the request to kap-render right after their own auth when KAP_RENDER_SERVICE_URL names it (web/lib/render/proxy.ts; the URL, the bearer, the validators and every X-* provenance header are unchanged for the caller, and X-Render-Service says where it was drawn). It is the same backend image on a glibc base with Playwright’s Chromium (web/Dockerfile.render), because the driver libraries Cloud Run mounts are glibc builds; web/scripts/render-entrypoint.sh writes the EGL and Vulkan vendor manifests the mount does not bring, without which Chromium never finds the GPU. Deploy with pixi run deploy-render (cloudbuild.render.yaml); it is not part of the dev push, so a change to the render worker or its pages is deployed by hand. It scales to zero: the first request after idle pays the container, browser and model load (about 25 s), which the X-Settled and X-Render-Ms headers report; a warm twin renders in well under a second. Measured on 2026-09-27 in the render-endpoints plan.