Infrastructure setup
VELA deploys along a single spectrum — from a laptop, to a managed cloud cluster, to a fully air-gapped sovereign install — from one codebase. Tenancy is a configuration, not a fork.
Deployment options at a glance
| Target | Artifact | Stores | Network |
|---|---|---|---|
| Local dev | .venv + make serve |
in-memory | offline |
| Dev backends | docker-compose.yml |
Neo4j + Qdrant | local |
| Production (single host) | docker-compose.prod.yml |
Neo4j + Qdrant + Postgres | local |
| Cloud / on-prem cluster | charts/vela (Helm) |
in-cluster or managed | as configured |
| One-command on-prem | deploy/onprem (k3d) |
in-cluster Neo4j/Qdrant/Postgres | local cluster |
| Air-gapped | Helm + private registry mirror | in-cluster | no egress |
Local development
uv venv --python 3.12 && uv pip install -e ".[dev]"make serve # API with CORS open to the Vite dev origins, auth offmake seed # POST the reference scenarios so the console has real casescd apps/console && npm run devThe in-memory VELA-REF-1 path is the offline default — no Docker required.
Real stores with Docker Compose
docker compose up -d brings up Neo4j + Qdrant only (there is no Yamcs service — VELA is
read-only and ground-segment). Then:
uv pip install -e ".[backends]"VELA_STORE_BACKEND=neo4j VELA_DOC_SEARCH_BACKEND=qdrant VELA_NEO4J_PASSWORD=veladev \ python -m vela.kg.ingestdocker-compose.prod.yml additionally wires Postgres for durable investigation persistence and a
durable checkpointer (the in-process MemorySaver does not survive a restart).
Kubernetes (Helm)
The charts/vela chart deploys the API + ingest for cloud and air-gap clusters. Key values (see
charts/vela/values.yaml and charts/vela/README.md):
- image +
imagePullSecrets(mirror every image into a private registry for air-gap) config.mode(airgap/cloud),config.authMode(apikey/oidc/saml)- store backends (Neo4j / Qdrant / Postgres) and their connection settings
podSecurityContextruns as a non-root uid (10001)
helm lint charts/velahelm template charts/vela # render manifestsOne-command on-prem (k3d)
deploy/onprem/up.sh stands up a local k3d cluster with in-cluster Neo4j/Qdrant/Postgres
(stores.yaml), installs the Helm chart, runs KG ingest, and verifies an end-to-end cited
investigation on the in-cluster stores. down.sh tears it down. This path is verified on Apple-Silicon
k3d.
Air-gapped / sovereign install
The air-gap posture is the default for sovereign and defence customers:
- Mirror every image (including any operator) into a private registry — Harbor/Nexus is the
load-bearing dependency — or use a container-tarball
save/loadpath. - Install the Helm chart with
config.mode=airgap. VELA hard-fails any live telemetry source and any non-deterministic reasoning in airgap, and performs no external egress. - Identity via Keycloak (self-hostable OIDC/SAML) and secrets via Vault (Shamir unseal) both sit behind existing seams.
Decide the one-way doors up front
The tenancy model, per-tenant encryption keys, and audit design are hard to change later. Prefer per-tenant keys / residency as the isolation boundary; do not make row-level security the only boundary. See ADR 0015.
Configuration & modes
vela/config.py::load_settings resolves mode as explicit arg > VELA_MODE > airgap, merges
config/<mode>.yaml, then applies env overrides (VELA_STORE_BACKEND, VELA_DOC_SEARCH_BACKEND,
VELA_NEO4J_*, VELA_QDRANT_*, telemetry-source paths). Secrets (VELA_NEO4J_PASSWORD, API keys) are
read from env at connect time only. The API reads VELA_API_HOST|PORT, VELA_AUTH_ENABLED,
VELA_API_KEYS, VELA_AUTH_MODE, VELA_SCIM_TOKEN.
This documentation site
These docs are built with MkDocs Material and deployed to GitHub Pages by
.github/workflows/docs.yml on every push to main. Build locally with:
uv pip install mkdocs-materialmkdocs serve # live preview at http://127.0.0.1:8000mkdocs build # static site into ./site