Skip to main content
Everything an operator does after the runtime works on a laptop: self-host it from the distribution bundle, run and observe it, and wire the shipped plugins an install needs.

Deploy

Run a server for real.

Observe

Collect metrics and traces.

Manage a fleet

Read the worker census and drive fleet-wide operations.

Plugin setup

Backends, storage, accounts, identity, and monitoring.

Self-host with the distribution bundle

tai-distribution packages the whole platform as one batteries-included container image plus a Docker Compose bundle and a Helm chart. The image installs the first-party plugin set and bakes the built Studio in, so a self-hosted install is one image and the services it talks to. The image entrypoint is tai and its default command is serve. Three long-lived processes come out of the same image: A one-shot db-init step runs tai db apply, and serve and backend wait for it to complete before they start. The DDL is additive and IF NOT EXISTS, so re-running it is safe.
The distribution’s first release is in preparation, so the published docker.io/tai42/tai image (mirrored at ghcr.io/tai42ai/tai) is not on the registries yet. Build it locally from the repo with the source build below until it is.

Boot the Compose bundle

config/ is bind-mounted at /app in the three long-lived services, so config/manifest.yml is the manifest the runtime loads and config/.env is the app-side environment. Create config/.env even when it is empty — the config-reload path treats a missing file as an error. Only serve publishes a port (${TAI_SERVE_PORT:-8000}). Postgres, Redis, and the optional MinIO and RabbitMQ services stay on the Compose network.

Build the image from source

compose/docker-compose.local.yml layers a SOURCE=local build onto every app service, building the image from sibling checkouts instead of pulling it:
The siblings build context defaults to the parent of the checkouts (../..) and is overridable with TAI_SIBLINGS. Because that context can hold untracked secrets, the source build is for a local builder only — never CI, never a shared registry.

Configure the bundle

The Compose bundle reads a small set of variables from .env; everything else is fixed in the file and points the services at each other.
POSTGRES_PASSWORD has no default: Compose refuses to start until it is set. The minio and celery service profiles add MINIO_ROOT_USER, MINIO_ROOT_PASSWORD, STORAGE_S3_BUCKET, RABBITMQ_USER, and RABBITMQ_PASSWORD. Five Postgres-backed stores and every Redis-backed feature store are already pointed at the bundled postgres and redis services, so the schema-admin connection, the access-control store, the connector store, the marketplace store, and the versioning store all resolve without further configuration.
.env.example ships ACCESS_CONTROL_ENABLE=false — the quickstart shape. Turn it on before anything but a laptop, and register an identity provider in the same change: with access control on and no provider, the runtime refuses to boot.

Turn on access control

Set ACCESS_CONTROL_ENABLE=true and register a provider in the manifest. The bundled default is the Redis-backed API-key provider, which the image already installs:
manifest.yml
Then mint the first key with tai keys and write the policy that key resolves to — access control covers the policy model, and the access-control guide walks the first key end to end. ACCESS_CONTROL_ALWAYS_PUBLIC_PATH_PREFIXES selects the paths served without a key. The bundle’s default covers the login route and the Studio’s static assets:
Setting it replaces the app’s own default wholesale rather than adding to it. /health and /ready are deliberately absent: the app already serves them public by route-level declaration, and listing them here is rejected at boot as a conflict. For human sign-in — sessions, roles, invites, and the first admin — add the accounts provider described in Accounts.

Run on Kubernetes

The repo ships a real Helm chart at charts/tai. Its release publishes the chart as an OCI artifact alongside the image, so the same “in preparation” caveat applies — until then, install from the checkout with helm install tai ./charts/tai.
The chart deploys serve and backend as separate Deployments, each with the metrics endpoint as a native sidecar, and installs Postgres and Redis StatefulSets by default. Point it at managed datastores instead by disabling both:
serve.replicaCount scales the API; running serve.workers above one requires serve.statelessHttp=true, because a stateful HTTP transport refuses a multi-worker boot. A schemaInit hook Job runs tai db apply around install and upgrade. The chart requires Kubernetes 1.29 or newer, because the metrics sidecar is a native sidecar container. It integrates with cluster add-ons but never installs them: an Ingress controller, cert-manager for ingress.tls, the prometheus-operator for metrics.serviceMonitor, and a StorageClass for persistence.

TLS and the front door

serve speaks plain HTTP on its published port, and the Compose bundle puts nothing in front of it. Terminate TLS at your own reverse proxy or load balancer and forward to that port. On Kubernetes the chart’s Ingress is single-host, single-path — the Studio and the /api surface share one origin, so there is nothing to split — and passes ingress.tls straight through to the Ingress resource:
values.yaml
Some features need the public origin spelled out rather than inferred: connectors accept an OAuth redirect only when its origin is listed in CONNECTORS_REDIRECT_URI_ALLOWLIST, and tai42-accounts-oidc requires an https TAI_ACCOUNTS_OIDC_PUBLIC_BASE_URL.

See also