Quickstart — self-hosted cell
Bring up a single OpenDome cell that serves the OSL API, with no control-plane and no phone-home. This is the path a self-hoster takes; the OpenDome-operated product layers the central control-plane and console on top of the exact same charts.
Everything below comes from the public
opendome.eu/platform repository —
clone it and run the commands from its root. The engineering-depth version of
this walk is
docs/quickstart-oss.md.
Prerequisites
Section titled “Prerequisites”- A Kubernetes cluster (kind works) with:
- A CNI that enforces
NetworkPolicy— Cilium recommended. kind’s default kindnet does not enforce it. With Cilium, install it with--set 'policyCIDRMatchMode={nodes}'; without it, Cilium ignoresipBlockrules covering node/apiserver IPs and the bundled Postgres dead-locks at “Setting up primary”. (scripts/cluster-create.shdoes this for you on kind.) - An Ingress controller to reach the OSL API, e.g.
helm install ingress-nginx ingress-nginx/ingress-nginx -n ingress-nginx --create-namespace --version 4.11.3. OSL identity is carried only byAuthorization: Bearer <jwt>— no trusted identity header, no ingress header-rewrite configuration needed. - A default StorageClass (for the bundled object store + Postgres PVCs).
- The CloudNativePG operator cluster-wide — only if you use the bundled
Postgres:
helm install cnpg cnpg/cloudnative-pg -n cnpg-system --create-namespace --version 0.27.1.
- A CNI that enforces
helm≥ 3.12 andkubectl.
Bring up the cell
Section titled “Bring up the cell”-
The cell shell + bundled infra (object store + Postgres).
standard-tenantcreates the namespace, a deny-allNetworkPolicy(no control-plane allow rules), quotas, and — in the standalone profile — an in-namespace object store (RustFS) and CloudNativePG Postgres, plus thetenant-object-storageSecret.Terminal window # The deny-all NetworkPolicy only lets pods reach the Kubernetes API through# this allowlist (CNPG's init needs it). Derive both addresses from YOUR# cluster — no per-distro guessing:APISERVER_VIP=$(kubectl get svc kubernetes -o jsonpath='{.spec.clusterIP}')APISERVER_EP=$(kubectl get endpoints kubernetes -o jsonpath='{.subsets[0].addresses[0].ip}')helm install demo charts/standard-tenant \-n tenant-demo --create-namespace \--set tenant=demo \--set "apiServerEgress.cidrs[0]=$APISERVER_VIP/32" \--set "apiServerEgress.endpointCidrs[0]=$APISERVER_EP/32"With no explicit values the chart mints random credentials on first install and reuses them on upgrades. Recover them any time:
Terminal window kubectl -n tenant-demo get secret tenant-object-storage -o jsonpath='{.data.accessKey}' | base64 -dkubectl -n tenant-demo get secret postgres-postgresql -o jsonpath='{.data.password}' | base64 -dPrefer your own S3 / Postgres? Flip
objectStore.bundled=false/postgres.bundled=falseand supply credentials — the bundled RustFS is pre-GA and intended for dev/standalone; use a GA S3 for production. See Charts & topologies. -
The OSL engine — the consumption surface.
Terminal window helm install osl charts/tenant-semantic-api \-n tenant-demo \--set tenant.id=demo \--set ingress.host=osl.tenant-demo.127.0.0.1.nip.ioGoverned reads accept identity only from a verified
Authorization: Bearer <jwt>(an ActorToken v2). Headers likeX-Actor-Rolesare always ignored — there is no header-trust switch. The standalone chart provides an HS256 signing Secret; a production self-hoster can configure a verifying key for their own OIDC issuer instead. -
Verify the cell is usable via its API — no control-plane.
Terminal window HOST=osl.tenant-demo.127.0.0.1.nip.iocurl -fsS "http://$HOST/health" # {"status":"ok",...}curl -fsS "http://$HOST/osl/conformance" # engine + declared conformancecurl -fsS "http://$HOST/osl/schema" # compiled manifest (empty until you author facets) -
Mint a token and make a governed call.
scripts/osl-token.shreads the chart-generated HS256 Secret viakubectland signs an ActorToken v2 (defaults:sub=local-admin,acl_roles=analyst, TTL 300 s):Terminal window TOKEN=$(scripts/osl-token.sh demo)# The single consumption endpoint. This structural example requires the# referenced model and a matching subject grant in the manifest/policy:curl -fsS "http://$HOST/osl/query" \-H "Authorization: Bearer $TOKEN" \-H 'Content-Type: application/json' \-d '{"osql":"SELECT customer_id, name FROM osl.entities.customer LIMIT 5"}'# RETRIEVE is another form of the same endpoint, not a separate route:curl -fsS "http://$HOST/osl/query" \-H "Authorization: Bearer $TOKEN" \-H 'Content-Type: application/json' \-d '{"osql":"SELECT text, source FROM RETRIEVE(facet => '\''call_transcripts'\'', query => '\''renewal risk'\'', top_k => 5)"}' -
Connectors + orchestration — the management cell. (optional)
To ingest (sync a source → land → curate) add
tenant-mgmt-apiin dagster mode: the cell owns connectors/runs and an in-namespace Dagster daemon schedules and launches the pipeline Jobs. Requires the structured leg (charts/lakehouse) before driving a sync.Terminal window helm install mgmt charts/tenant-mgmt-api \-n tenant-demo \--set tenantId=demo \--set runLauncher.mode=dagster \--set dagster.enabled=trueSee Orchestration (in-cell Dagster) for how runs fire, and keep the management API private behind your own administrative gateway — it is operational control, not an OSL data surface.
If the health/metadata calls return 200 with no opendome-system namespace
present, the cell is standalone-usable. The query examples become runnable after
loading the named models/facets and granting the token subject. Run
scripts/oss-gate.sh to assert the installation end-to-end.
Optional layers
Section titled “Optional layers”- Structured leg (Trino + Nessie + Iceberg) —
charts/lakehouse. Defaults to in-namespace endpoints with credentials from thetenant-object-storageSecret; needs the bundled/external Postgres from step 1. - Config API (allowlist / pipeline / discovery) —
charts/tenant-config. Already standalone: uses the cell’s own Postgres.
Verify the published images (cosign)
Section titled “Verify the published images (cosign)”Released images are pinned by immutable digest and signed keyless with the GitLab CI OIDC identity. Verify before deploying:
IMAGE=registry.gitlab.com/opendome.eu/platform/tenant-semantic-apiDIGEST=$(git show <tag>:charts/tenant-semantic-api/values.yaml | yq '.image.digest')
cosign verify "${IMAGE}@${DIGEST}" \ --certificate-oidc-issuer "https://gitlab.com" \ --certificate-identity-regexp "^https://gitlab.com/opendome.eu/platform//.gitlab-ci.yml@refs/(heads/main|tags/.*)$"The full procedure is on the Security posture page.
Rebuilding images into your own registry
Section titled “Rebuilding images into your own registry”Released charts pin images by immutable digest (image.digest: sha256:…),
which takes precedence over the tag. That digest identifies OpenDome’s
published image — it is meaningless in any other registry. If you rebuild the
cell images into your own registry, clear the shipped digest or every pod
will ImagePullBackOff:
helm install osl charts/tenant-semantic-api \ --set image.repository=myreg.example/tenant-semantic-api \ --set image.digest="" # ← REQUIRED when you change the repositoryDo the same for tenant-mgmt-api.runnerImages.* (pinned to
repo:<ver>@sha256:…).
Load real data
Section titled “Load real data”To serve real retrievals: create the bucket (tenant-demo) in your object
store, author OSL facets (UnstructuredFacet / JointEntity YAML under the
engine’s manifest.facets), and ingest Lance datasets — the
documents pipeline does this for you from real sources.
See Concepts for the manifest model and the
API reference for how consumption is called.