Skip to main content
Install in three steps, from a terminal with kubectl access to the cluster. Check the prerequisites first. Options such as an external data tier, the executor fleet and models are on Configure and Models and local inference.

Install in three steps

1

Receive the license files and pull token by email

The xpander.ai team emails you:Details: Two-File Licensing.
2

Run the one-liner

A legacy v1 install passes --license-file ./license.json instead of the three flags.The wizard runs preflight checks, installs with Helm and seeds an admin login. It prompts for:
  • Registry
  • Chart source (OCI pull or local path)
  • Data tier
  • Admin email
  • Organization display name
  • StorageClass
  • Agent code execution (--code-execution / --no-code-execution). The runner embeds dockerd, so its pod is privileged, and a restricted PodSecurity policy refuses it
  • A base domain for the public hosts
  • LLM provider keys, for any hosted providers your egress policy allows
Image tags come from the release.If your registry has no xpander images yet, the wizard offers to mirror them right there with the pull token from step 1, and creates ECR repositories itself. On a sealed network, use Sealed / manual mirroring.
3

Sign in as the seeded admin

The first install creates your organization and a bootstrap admin in your in-cluster Supabase. The closing summary prints how to sign in: see Signing In.
Non-interactive (image tags resolve from the mirror unless pinned):
To review every command first, bash install.sh --edition airgap --manual prints a personalized runbook and runs nothing: see Advanced: review-first / manual install. Pipelines: Automation & CI.

What happens when you run the installer

The installer runs eight phases. Steps 1 to 6 take a few minutes. Step 7 takes 10–20 minutes. Each phase prints a [N/8] name: ... line for scripts to grep (Automation & CI). Every hook failure names the Job, prints its last 30 log lines, and ends with a FIX: line and a RERUN: line that resumes the install.
1

Resolve: load the latest release

One release manifest lists the version and SHA-256 digest of every xpander image, including llm-gw and tool-repo-seed. The installer passes those pins to Helm. To repeat a release or install offline, pass --release-manifest ./release-manifest.json. A missing or invalid manifest stops the run. How releases work.
2

Checklist: preconditions verified before anything changes

The registry answers /v2/ (401 counts as up), agent-controller and deployment-manager exist at their pinned tags, an RWO StorageClass exists, the image pins are in place, --org-name and --admin-email are set, and a chart source exists. Any failure stops here with nothing to clean up.
3

License: validated locally, applied as a Secret

Two xpander-license/v2 envelopes, one kind: install and one kind: activation, bound to --org (a legacy v1 file: envelope, expiry and org id). They become the xpander-license Secret. The Ed25519 signature is verified in the preflight hook and again at deployment-manager boot.
4

Chart: pulled over OCI

The xpander-airgap chart comes from the gated OCI registry, your own mirror, or a .tgz via --chart-path.
5

Values: secrets never touch the command line

Configuration goes to a temporary values file (mode 600, removed on exit), never to the helm command line, shell history or process list.
6

Install: helm, without --atomic on purpose

The first install runs without --atomic, because --wait would hold the seed hooks that the api and agent-controller pods are waiting on. The smoke hook is the readiness gate. Upgrades always run with --atomic, so a failed upgrade rolls back and the previous revision keeps serving.
7

Pipeline: the cluster comes up, hook by hook (10–20 min)

The installer watches the hook pipeline live:
8

Summary: URLs, password, logs

The closing box prints the derived URLs (with a base domain: https://chat.<domain>, https://api.<domain>, https://supabase.<domain>), the bootstrap admin password, and how to read it later (see Signing in).The secret-scrubbed session log (mode 600) is under ~/.xpander/logs/, with latest.log pointing at the last run.

When the mirror is empty, the wizard offers to fill it

Choose Mirror them now, give the xpander pull credentials and any destination credentials, and let the copy finish. ECR repositories are created when your AWS credentials allow. Non-interactively: --mirror now|guide|skip (now needs the credentials). Sealed networks use the archive flow below.

Sealed or manual mirroring

Mirror with the current image_sync.sh: it includes llm-gw and tool-repo-seed, and stops on a release without the gateway image. It needs skopeo and Python 3. The Docker pull/tag/push fallback does not preserve release digests. On a connected workstation, download the manifest once and use that file for both the copy and the upgrade:
Pass registry credentials with the source/destination flags or registry auth. --dry-run prints the plan. Keep the JSON manifest: a single --tag or a legacy service-only manifest is not a complete release. Tag flags and repository retention: Releases. Fully sealed network? Archive outside, carry the whole directory in, import inside:
Carry install.sh, image_sync.sh and their release_manifest.py with the bundle. Get the validator from the immutable release_manifest-<sha256>.py URL in the scripts and save it as release_manifest.py beside them. The scripts verify its checksum. Import validates the full image set and digests first. Complete an incomplete archive on the connected side. Legacy archives need the previous importer. The chart is an OCI artifact. Mirror it with the images (--chart-version <X.Y.Z> --chart-source registry-1.docker.io/xpanderaihub/xpander-airgap, landing at oci://<your-registry>/xpander/charts/xpander-airgap), or hand-carry the .tgz:
Hosted repository: mirror into it. Use it as --registry, and fill it with the wizard or image_sync.sh. --dest-user / --dest-token handle Basic auth:
Then install with --registry nexus.corp.example:5000/xpander.Pull-through proxy, no mirror step. Create a Docker proxy repository upstream of Docker Hub (https://registry-1.docker.io) with the xpander read token as its upstream credentials, and keep the org path in the registry value:
Images cache on first pull. Keep the xpanderaihub segment: the chart builds <registry>/<name>, so <proxy-repo>/xpanderaihub/agent-controller maps to xpanderaihub/agent-controller upstream. A fully sealed network cannot use a proxy: use the archive flow into a hosted repository.
bash install.sh --edition airgap --guide prints this runbook personalized with your registry and namespace (also printed when no cluster is reachable). --manual prints the whole install as commands and runs nothing.

The license

New installs use two sealed files (install.json + activation.json, xpander-license/v2): see Two-File Licensing for caps, expiry and renewal. The installer validates both and creates the xpander-license Secret:
The preflight hook verifies the Ed25519 signature against global.license.publicKey, and deployment-manager refuses to start on a bad one.
  • Your own --values file displaces the installer’s license block: also pass --set global.license.installKey=install.json --set global.license.activationKey=activation.json --set global.license.publicKey=<license public key>.
  • Renewing replaces only activation.json and redeploys. See Renewing: re-activate.
  • Expired activation: the installer warns and preflight refuses a fresh install. A running install degrades in stages. GET /v1/license/status returns valid, expiring, grace or expired. Alert on anything past expiring.
  • Single-tenant: one license, one organization.
  • Legacy single file (xpander-license/v1): --license-file ./license.json creates a Secret with one license.json key, wired through global.license.key. Renew by replacing that file and redeploying.

Next steps

Publish the hosts and sign in

Domains, ingress, DNS, TLS and the first sign-in.

Configure the install

Data tier, executor fleet, skill generation and skill credentials.

Connect your models

Your LLM endpoint, Amazon Bedrock or a local vLLM server.