Skip to content

Installing with Helm

Labtagon AI OS is installed with one Helm chart, deploy/helm/ai-os. This page goes through the values you have to set, the keys and the sign-in. The chart refuses to render when a required value is missing or two values contradict each other, so most mistakes show up before anything reaches the cluster.

  • Kubernetes 1.30 or later, with a metrics server if you keep the autoscalers on.
  • A Gateway API implementation with a Gateway for your host, or an Ingress controller.
  • The CloudNativePG operator (postgres.operatorNamespace, default cnpg-system), or a Postgres of your own with pgvector 0.8 or later.
  • An OpenID Connect provider. The examples use Keycloak.
  • DNS and a TLS certificate for your host on the Gateway or Ingress.
  • If you switch on sandboxes or sandboxed tool servers: the RuntimeClass gvisor on the nodes that run them (instances.sandboxedRuntimeClass, sandboxes.runtimeClass).
Value What
global.host The public host of the console and of the MCP endpoint, for example ai.example.com.
global.imageRegistry Where AI OS’s own component images are released.
keycloak.issuer Your provider’s issuer, for Keycloak https://<keycloak>/realms/<realm>.
keycloak.* The clients, scopes and claims, if yours are named otherwise than the defaults (below).
routes.kind, routes.parentRefs httproute (default) with the Gateway(s) to attach to, or ingress with ingressClassName and tlsSecretName. routes.fromNamespace names the namespace of the Gateway or ingress controller for the network policies (default envoy-gateway-system).
keys.existingSecret The Secret with the platform’s keys (default ai-os-keys), or keys.externalSecret.enabled: true to have the chart create an ExternalSecret.
postgres.* create: true (default) makes a CloudNativePG cluster with instances: 2 and storage: 10Gi. With create: false, existingSecret names a Secret with the key uri, and port the port the network policy opens.
storage.* Where files’ bytes go: garage (default, the chart runs Garage), external (any S3, with endpoint, region and a Secret with access-key-id and secret-access-key) or postgres (no object store).

Optional, and described on its own page: global.appHost, see App host.

A small values file:

values.yaml
global:
host: ai.example.com
imageRegistry: registry.example.com/ai-os
keycloak:
issuer: https://id.example.com/realms/example
routes:
kind: httproute
parentRefs:
- { name: platform, namespace: envoy-gateway-system, sectionName: https }
keys:
existingSecret: ai-os-keys
postgres:
create: true
instances: 2
storage: 10Gi
storage:
mode: garage
Terminal window
helm lint deploy/helm/ai-os -f values.yaml
helm upgrade --install ai-os deploy/helm/ai-os -n ai-os-system --create-namespace -f values.yaml

After the install, the chart’s notes list what still has to be done outside it.

One Secret holds the platform’s keys. Create them once; each component mounts only what it needs.

Key What it is Made with
age-identity, age-recipient Decrypts and encrypts the stored sign-ins and keys of tool servers (age). Only the egress gateway holds the identity. age-keygen
approval-signing-key, approval-verify-key The control API signs approvals, the controller checks them before it runs anything. The keys of LLM providers are encrypted with a key derived from the signing key. Ed25519 key pair
agent-token-key Signs the access tokens AI OS issues to clients (ADR 0059). EC P-256 key, PKCS #8
session-key Random bytes, mounted into the MCP gateway. random bytes
egress-ca.crt, egress-ca.key The CA the egress gateway issues a certificate per host with; instances trust it. a CA certificate and its key

The repository’s deploy/openbao/seed-ai-os.sh keys <mount> creates all of them straight into OpenBao without printing them, and refuses to overwrite existing ones.

Further Secrets, each optional:

  • storage.encryption: the storage key that wraps the keys of files. Without existingSecret the chart makes one once and keeps it (see Backups and restore).
  • push.secretName (ai-os-push): the VAPID key pair for browser notifications. Without it there are none.
  • fileLinks.secretName (ai-os-file-links): the key of file preview links in clients that show widgets (link-key). Without it there are no previews.
  • modelKeys.*: API keys of the safety, decision and personal-data models the gateway asks.

People sign in at the console through your OpenID Connect provider. Set up there:

  • The console’s client keycloak.consoleClientId (ai-os-console), confidential, with the redirect address https://<app host>/api/auth/callback (without an app host: global.host). Its secret goes into the Secret keycloak.consoleClientSecretName (ai-os-console-oidc), key client-secret.
  • The clients’ sign-in. keycloak.agentClients lists the clients the console’s connect dialog shows, one tab each: by default Claude Code, Codex, Cursor, claude.ai, Hermes and AI OS Workbench. Each entry names a client id, a title and a built-in guide (claude-code, codex, claude-ai, cursor, generic, workbench). As long as the provider issues the clients’ tokens, each id is a public client with PKCE at the provider, and the client scope keycloak.mcpScope (ai-os-mcp) puts the audience keycloak.audience into its tokens.
  • AI OS as the clients’ authorization server (ADR 0055, 0059): with profiles.signInChooser: true AI OS issues the clients’ tokens itself and people choose a profile when a client signs in. The provider then only signs people in at the console; no client per tool and no extra redirect address is needed. profiles.agentTokens says whose tokens the gateway accepts: ai-os, upstream or both (default, while an installation moves over).
  • Claims. keycloak.rolesClaim (roles) carries realm roles; the role keycloak.adminRole (ai-os-admin) opens the administration. keycloak.groupsClaim (groups) carries group paths such as /sales: map them with Keycloak’s group membership mapper, full paths on, into the console’s ID token and into the ai-os-mcp scope. Groups in the Control Panel are made from them.
  • Organisations. orgs.source places people in an organisation by the domain of their verified e-mail address (domain, default) or by a claim (claim, Keycloak’s organization). orgs.bootstrap creates organisations at the first start. See Organisations and sign-in.
  • A provider for the whole platform (signIn.platform, ADR 0078): besides your own, for example Microsoft Entra ID for organisations without a provider of their own.
  • “Sign in with AI OS” for tool servers (ADR 0020): the confidential client keycloak.connectionsClientId (ai-os-connections) with offline access and token exchange; only the token broker in the egress gateway reads its secret. Without it, this one built-in sign-in is off; other providers still work.
  • AI OS’s components run by tag (default: the chart’s appVersion) unless you pin them: components.<name>.digest, bundles.fetchDigest and checks.digest, each sha256: and 64 hex digits. Once one component is pinned, every enabled one and the bundle fetcher must be; the chart refuses to render otherwise.
  • Build checks need checks.digest (or checks.tag locally). Without it, builds run without checks and Admin → Platform says so.
  • A mirror for third-party images: global.mirror, a prefix laid out as Harbor’s proxy caches are, or {prefix, registries}. Runtimes, Presidio, Postgres, Garage, SearXNG, Docling and the images people give their servers are pulled through it. allowedRegistries lists the upstream registries pods may pull from, always by digest.

Most of AI OS’s behaviour is in settings that administrators change in the console. settings: in the values fixes some for every organisation; the console then shows them locked. For example:

settings:
instances.idleTimeout: 15m
instances.idleTimeoutMax: 4h
builds.allowHosts: "registry.npmjs.org,pypi.org,files.pythonhosted.org"

The chart refuses an idle default that is longer than the longest allowed.

global.installation names an installation (for example staging) and labels everything it makes. It also needs its own release name, namespace, instances.namespacePrefix, instances.orgNamespacePrefix and builds.namespace.

  1. The controller applies the database migrations at start; wait until its pods are ready.
  2. Open https://<host>/ and sign in with an account that has the role ai-os-admin.
  3. Under Administration → Platform you see the components, the database, builds and namespaces as the controller sees them (every 15 seconds, observe.interval).
  4. Set up the first model provider: see Models and providers.