Skip to content

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.

Get the binary
No source checkout needed: the install script downloads the prebuilt binary from the asset server and puts exo-install on your PATH.
terminal· bash
curl -fsSL https://exo.assets.adaptive.live/exo-install/install.sh | bash
exo-install version
From a source checkout instead: 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.

CRD coverage
The bundle reviewed on 11 November 2026 contains 13 CRDs and omits App and WebAgent. Install those definitions from the matching operator release before using them. See Installing the CRDs.
Migrate before starting the platform
The installer does not run database migrations. Install with zero platform replicas, run the migration step, and start the application only after it succeeds.

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.

Back it up, treat it as a root credential
Generate with 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

exo-install <command>· text
1(none) Launch the guided full-terminal installer
2precheck Verify toolchain, cluster reachability, and RBAC (alias: check)
3install Install CRDs + operator + platform (alias: apply, up)
4crds Install the bundled autonomic CRDs
5operator 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 wizard
9uninstall Remove selected components in reverse order (alias: down)
10version Print the installer version

install 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.

what precheck verifies· text
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.

terminal· bash
exo-install

Scripted install

For a fresh install, check the prerequisites and install with the application stopped:

terminal· bash
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:

terminal· bash
kubectl -n exo scale deployment/exo-app --replicas=2
kubectl -n exo rollout status deployment/exo-app

To validate an install without applying it:

terminal· bash
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:

terminal· bash
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 vs unmanaged operator
--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.

operator → ns autonomic-system (default)· text
1ServiceAccount/autonomic-manager
2ClusterRole + ClusterRoleBinding/autonomic-manager (CRDs, deployments, pods/exec,
3 secrets, leases, webhooks, RBAC)
4Service/autonomic-manager 443 webhook · 8080 metrics · 8081 probes · 8082 invoke
5Deployment/autonomic-manager --leader-elect, replicas=1, non-root
6ValidatingWebhookConfiguration/autonomic-pods-exec (pods/exec + tool admission;
7 omitted with --webhook=false)
platform → ns exo (default)· text
1Secret/exo-secrets EXO_ENCRYPTION_KEY · EXO_JWT_SECRET · EXO_DATABASE_DSN · EXO_CLAUDE_API_KEY
2ConfigMap/exo-config EXO_PORT=9092 · EXO_JWT_EXPIRY
3Service/exo-app 9092/TCP, type ClusterIP (default)
4Deployment/exo-app replicas=2, /api/health probes, rolling update
5StatefulSet/exo-postgres postgres:16-alpine + 10Gi PVC (omitted with --postgres=false)

Flag reference

Connection & execution. These control kubectl and how the install runs.

global flags· text
1--kubeconfig <path> kubeconfig file (default: $KUBECONFIG / ~/.kube/config)
2--context <name> kube-context (default: current-context)
3--dry-run server-side validate, no mutations
4--config <file> load config from JSON (flags still override)
5--interactive prompt for config
6--skip-precheck skip pre-flight checks (not recommended)
7--yes assume yes to prompts
8--timeout <dur> per-rollout wait (default: 5m)
9--helm install the operator via its Helm chart
10--helm-chart <path|ref> optional chart override (embedded chart by default)

Operator. The autonomic-manager deployment.

operator flags (defaults)· text
1--operator-namespace autonomic-system
2--manager-image docker.io/adaptivelive/autonomic-manager:<release-tag>
3--manager-pull-policy IfNotPresent
4--operator-replicas 1
5--managed false (phone home to --base-url)
6--base-url https://exo.adaptive.live
7--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.

platform flags (defaults)· text
1--namespace exo
2--image docker.io/adaptivelive/exo:<release-tag>
3--pull-policy IfNotPresent
4--replicas 2
5--service-type ClusterIP (or NodePort, LoadBalancer)
6--jwt-expiry 24h
7--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.

database flags (defaults)· text
1--postgres true (deploy in-cluster Postgres StatefulSet)
2--db-dsn "" (external DSN, required when --postgres=false)
3--pg-user exo
4--pg-password "" (auto-generated if blank)
5--pg-db exo
6--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:

auto-generated· text
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-secrets
3POSTGRES_PASSWORD 36 hex chars when --postgres and no pw → Secret/exo-postgres
4EXO_DATABASE_DSN derived from the in-cluster Postgres → Secret/exo-secrets
Capture them
Back up the generated values in exo-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:

terminal· bash
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.

terminal· bash
exo-install config -o exo-install.json
exo-install install --config exo-install.json --namespace staging --replicas 0
exo-install.json (excerpt)· json
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

Manage the operator as a Helm release
Use --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:
terminal· bash
exo-install install operator --helm
See Manual install for the chart's values.

Uninstall

Removes components in reverse order: platform → operator → CRDs.

terminal· bash
exo-install uninstall
CRDs and data
Removing the CRDs deletes every Agent/Tool/etc. object with them, and dropping the platform's Postgres volume discards all tenant state. Uninstall is for tearing down a trial. For production, snapshot the database first.