Install with exo-install
The recommended path. One binary applies the CRDs, the operator, and the platform through your own kubectl, with pre-flight checks and generated secrets.
exo-install installs the whole platform. Embedded Helm charts are rendered with Helm and applied through your existing kubectl, so your kubeconfig auth (exec plugins, OIDC, cloud IAM) works unchanged. It never talks to the API server directly; it runs kubectl apply, so dry-runs, RBAC, and audit behave exactly as they do for your own manifests.
exo-install on your PATH.curl -fsSL https://exo.assets.adaptive.live/exo-install/install.sh | bash
exo-install version
make build-exo-install (→ bin/exo-install), or make build-exo-install-all to cross-compile for darwin/linux × amd64/arm64.What exo-install does
It installs CRDs, the operator, and the platform. Helm is required to render the embedded charts under exo/exo-install/charts/, synced from helm/ by scripts/sync-exo-install-manifests.sh. Image defaults depend on the installer release; check exo-install install --help.
Set EXO_ENCRYPTION_KEY
EXO_ENCRYPTION_KEY is the 32-byte AES-256 root key that wraps every encrypted column, and the backend won't start without it. The installer auto-generates one when you don't pass --encryption-key (or leave the interactive prompt blank). Back up the generated key from exo-secrets; there is no separate one-time key printout.
To supply your own key, save it securely and pass --encryption-key.
openssl rand -hex 16 (32 hex chars = 32 bytes). openssl rand -base64 32 is 44 chars and is rejected. Losing or changing the key after data is written is unrecoverable: decryption fails with unwrap kek: message authentication failed. Store it in a vault, separate from the database. See Config & secrets.Commands
1(none) Launch the guided full-terminal installer2precheck Verify toolchain, cluster reachability, and RBAC (alias: check)3install Install CRDs + operator + platform (alias: apply, up)4crds Install the bundled autonomic CRDs5operator Install CRDs + operator (manager, RBAC, webhook)6platform Install only the backend/UI (+ optional Postgres)7render Print rendered manifests to stdout, apply nothing (alias: template)8config Write a config file via the interactive wizard9uninstall Remove selected components in reverse order (alias: down)10version Print the installer versioninstall runs the pre-flight checks first unless you pass --skip-precheck. Configuration resolves in three layers, each overriding the last: built-in defaults → --config file → CLI flags.
Pre-flight checks
exo-install precheck validates the environment before you touch the cluster. Hard failures abort the install; advisory ones only warn.
1Binaries kubectl (required) · helm (required for rendering and installation) · docker, git (advisory)2Cluster current context set (required) · API reachable via cluster-info (required)3 server version (advisory)4RBAC can-i create: customresourcedefinitions, clusterroles,5 namespaces, deployments (advisory — warns, does not block)Interactive mode
Run it with no arguments for a guided full-terminal installer: arrow-key menus, inline validation, masked secret entry. It walks namespaces and images → database choice → secrets & operator mode → cluster connection → component selection → pre-flight → plan → apply. It starts the application automatically; for a fresh database, use the scripted sequence below to migrate first.
exo-install
Scripted install
For a fresh install, check the prerequisites and install with the application stopped:
exo-install precheck
exo-install install --yes --replicas 0
Run exo-server --migrations using the target image and the installed configuration, as described in Database migrations. Stop if it fails. After success, start the application:
kubectl -n exo scale deployment/exo-app --replicas=2
kubectl -n exo rollout status deployment/exo-app
To validate an install without applying it:
exo-install install --dry-run
--yes skips confirmation prompts; --dry-run sends kubectl apply --dry-run=server so the API server validates without mutating. --timeout (default 5m) bounds each rollout wait.
Installing individual pieces
Each component has its own subcommand, useful for split-cluster topologies:
exo-install crds
exo-install operator --managed --base-url https://exo.example.com
exo-install platform --namespace exo --replicas 0 --image 'adaptivelive/exo:<release-tag>'
exo-install render crds
--managed tells the operator to phone home to the platform over the WebSocket (so deployments, sessions, and statuses show in the dashboard) and reads its deployment token from the autonomic-auth Secret you pre-create. Without it, the operator runs local: agents still reconcile, nothing leaves the cluster. See Connecting to the control plane.What gets created
CRDs: the definitions bundled with your installer release. Use exo-install render crds to inspect the set before applying it.
1ServiceAccount/autonomic-manager2ClusterRole + ClusterRoleBinding/autonomic-manager (CRDs, deployments, pods/exec,3 secrets, leases, webhooks, RBAC)4Service/autonomic-manager 443 webhook · 8080 metrics · 8081 probes · 8082 invoke5Deployment/autonomic-manager --leader-elect, replicas=1, non-root6ValidatingWebhookConfiguration/autonomic-pods-exec (pods/exec + tool admission;7 omitted with --webhook=false)1Secret/exo-secrets EXO_ENCRYPTION_KEY · EXO_JWT_SECRET · EXO_DATABASE_DSN · EXO_CLAUDE_API_KEY2ConfigMap/exo-config EXO_PORT=9092 · EXO_JWT_EXPIRY3Service/exo-app 9092/TCP, type ClusterIP (default)4Deployment/exo-app replicas=2, /api/health probes, rolling update5StatefulSet/exo-postgres postgres:16-alpine + 10Gi PVC (omitted with --postgres=false)Flag reference
Connection & execution. These control kubectl and how the install runs.
1--kubeconfig <path> kubeconfig file (default: $KUBECONFIG / ~/.kube/config)2--context <name> kube-context (default: current-context)3--dry-run server-side validate, no mutations4--config <file> load config from JSON (flags still override)5--interactive prompt for config6--skip-precheck skip pre-flight checks (not recommended)7--yes assume yes to prompts8--timeout <dur> per-rollout wait (default: 5m)9--helm install the operator via its Helm chart10--helm-chart <path|ref> optional chart override (embedded chart by default)Operator. The autonomic-manager deployment.
1--operator-namespace autonomic-system2--manager-image docker.io/adaptivelive/autonomic-manager:<release-tag>3--manager-pull-policy IfNotPresent4--operator-replicas 15--managed false (phone home to --base-url)6--base-url https://exo.adaptive.live7--webhook true (pods/exec + tool admission webhook)8--webhook-failure-policy Fail (or Ignore)9--webhook-timeout 5 (seconds)Platform. The exo-app backend/UI deployment.
1--namespace exo2--image docker.io/adaptivelive/exo:<release-tag>3--pull-policy IfNotPresent4--replicas 25--service-type ClusterIP (or NodePort, LoadBalancer)6--jwt-expiry 24h7--jwt-secret "" (auto-generated if blank)8--encryption-key "" (EXO_ENCRYPTION_KEY, 32 bytes; auto-generated if blank)9--claude-api-key "" (platform-default Anthropic key, base64'd; optional)Database. In-cluster Postgres or an external instance.
1--postgres true (deploy in-cluster Postgres StatefulSet)2--db-dsn "" (external DSN, required when --postgres=false)3--pg-user exo4--pg-password "" (auto-generated if blank)5--pg-db exo6--pg-storage 10Gi (PVC size)Generated secrets
Any secret you don't supply is generated at apply time and written into the cluster Secrets. Rendered manifests and saved configuration may contain secrets; store them securely:
1EXO_ENCRYPTION_KEY 32 hex chars when --encryption-key is blank → Secret/exo-secrets (SAVE IT)2EXO_JWT_SECRET 64 hex chars when --jwt-secret is blank → Secret/exo-secrets3POSTGRES_PASSWORD 36 hex chars when --postgres and no pw → Secret/exo-postgres4EXO_DATABASE_DSN derived from the in-cluster Postgres → Secret/exo-secretsexo-secrets (or supply your own --jwt-secret and DSN). Losing EXO_JWT_SECRET invalidates every issued session; losing EXO_ENCRYPTION_KEY makes every encrypted row unrecoverable. See Config & secrets.Bring your own database
Skip the bundled Postgres and point the platform at a managed instance:
exo-install install --replicas 0 --postgres=false \--db-dsn "host=db.example.com user=exo dbname=exo sslmode=require"
Config files
Capture every knob in a JSON file and reuse it; flags still override the file.
exo-install config -o exo-install.json
exo-install install --config exo-install.json --namespace staging --replicas 0
1{2 "operatorNamespace": "autonomic-system",3 "managerImage": "docker.io/adaptivelive/autonomic-manager:<release-tag>",4 "operatorManaged": false,5 "operatorBaseURL": "https://exo.adaptive.live",6 "webhookEnabled": true,7 "platformNamespace": "exo",8 "platformImage": "docker.io/adaptivelive/exo:<release-tag>",9 "platformReplicas": 0,10 "serviceType": "ClusterIP",11 "jwtExpiry": "24h",12 "postgres": true,13 "postgresStorage": "10Gi"14}Helm for the operator
--helm to manage the operator as a Helm release. It uses the embedded chart unless you supply --helm-chart and runs helm upgrade --install with the image, managed flag, base URL, and webhook toggle passed through:exo-install install operator --helm
Uninstall
Removes components in reverse order: platform → operator → CRDs.
exo-install uninstall