Skip to main content
The aisquared Helm chart deploys the AI Squared platform into a Kubernetes cluster. The platform is cloud-agnostic and runs on any conformant cluster, including Amazon EKS, Azure AKS, Google GKE, and MicroK8s.
The chart was renamed from multiwoven to aisquared in version 0.117.0 and is still served from the same Helm repository. If you already run the multiwoven chart, follow Upgrading from the multiwoven chart instead of doing a fresh install.

What gets deployed

The chart also creates:
  • An Ingress for every public hostname.
  • cert-manager Issuers for Let’s Encrypt (when NGINX ingress is used).
  • HorizontalPodAutoscalers for each application component (hpa.enabled: true).
  • The namespace set in kubernetesNamespace (default aisquared).
The chart does not install an ingress controller or cert-manager. You install those first.

Prerequisites

  • A Kubernetes cluster and kubectl configured to reach it
  • Helm 3
  • A domain you control, with permission to create DNS records
  • An email address for Let’s Encrypt registration (example.com addresses are rejected)
  • (Optional) A Temporal Cloud namespace, recommended for production

Hostnames

The platform is exposed on several subdomains. The chart defaults are example.com placeholders, so you must set every one of them:

Install

1

Install an ingress controller

With the default settings, the chart’s Ingress uses the nginx ingress class. Install the NGINX ingress controller:
On AWS, you can use the AWS Load Balancer Controller instead. See Ingress options.
The Kubernetes project retired ingress-nginx in March 2026. It still works, but it no longer gets releases or security fixes. The chart currently expects the nginx ingress class (or ALB or Kong), so ingress-nginx is still the default path. For new production clusters on AWS, consider the ALB option.
2

Install cert-manager

cert-manager requests and renews the Let’s Encrypt certificates.
3

Create your values file

my-values.yaml
railsEnv, secretKeyBase, and jwtSecret are required even though the chart has defaults for them:
  • secretKeyBase: if it’s empty, the server and workers fail at startup.
  • jwtSecret: if it’s empty, the server signs sign-in tokens with a key that’s published in its source code.
  • railsEnv: the default, development, ignores your file storage settings and keeps uploads on the pod’s own disk. Email sending fails, and error pages show stack traces.
Generate secretKeyBase and jwtSecret once and keep them. Changing secretKeyBase later makes encrypted data unreadable, and changing jwtSecret signs everyone out.
See the Helm configuration reference for the other values you can set, such as SMTP, branding, and AI model endpoints.
4

Install the chart

Don’t pass --namespace/--create-namespace. The chart creates the namespace in kubernetesNamespace itself and deploys everything there.
You can use any release name. With the release name aisquared, resources are named aisquared-server, aisquared-postgresql, and so on. Other release names give <release>-aisquared-server. The in-cluster addresses for PostgreSQL, Temporal, and Lightning are worked out from the release name automatically.
5

Point DNS at the ingress controller

Find the external IP address (or hostname) of the ingress controller. It can take a minute or two to appear.
Create an A record (or a CNAME if your provider returns a hostname) for each hostname in Hostnames, pointing at that address. See your DNS provider’s documentation:
6

Verify the staging certificate

Run the following until the certificate shows Ready: True:
Then open https://app.your-domain.com. The browser will warn that the certificate is not trusted; this is expected for the Let’s Encrypt staging issuer. Confirm that the certificate was issued by (STAGING) Let's Encrypt.
7

Switch to the production certificate

Once everything works on the staging certificate, set platformConfig.tlsCertIssuer: letsencrypt-prod in my-values.yaml and upgrade:
Repeat the previous step until a valid certificate is issued. Your deployment is ready at https://app.your-domain.com.
Let’s Encrypt’s production server enforces rate limits that can lock you out for up to a week after repeated failures. Only switch to letsencrypt-prod after the staging certificate has been issued successfully.

Temporal

By default the chart runs Temporal and the Temporal UI in the cluster (temporal.enabled: true). This is fine for development and evaluation. For production, we strongly recommend Temporal Cloud. To use Temporal Cloud:
  1. Download your Temporal Cloud namespace’s client certificate and key, and create a secret named temporal-cloud in the platform namespace:
    The namespace exists only after the first helm install. If you’re configuring Temporal Cloud from the start, create the namespace with kubectl create namespace aisquared first.
  2. Add the following to your values file:
    platformConfig.temporalUiHost isn’t used when in-cluster Temporal is disabled.

Ingress options

Choose one ingress option: An ALB example:
The ALB option requires the AWS Load Balancer Controller in the cluster. Set externalDNS.enabled: true if you run ExternalDNS and want the DNS records created for you. To restrict access by source IP, set platformConfig.allowedSourceIP (NGINX only; default 0.0.0.0/0).

External databases

To use a managed PostgreSQL instance (for example Amazon RDS or Azure Database for PostgreSQL) instead of the in-cluster one:
If the platform, Temporal, and Temporal visibility databases live on different hosts, set multipleDbHosts.enabled: true and fill in multipleDbHosts.platformDBHost, temporalDbHost, and temporalVisibilityDbHost (and the matching *Name keys).

Secrets

By default, the credentials in your values file (database passwords, API keys, SMTP passwords) are rendered into a ConfigMap. For production on AWS, the chart can load them from AWS Secrets Manager instead, through the Secrets Store CSI Driver.

How it works

Credentials are split into groups, and you turn each group on separately. For each group you turn on:
  1. You create one JSON secret in AWS Secrets Manager holding that group’s keys.
  2. The chart creates a SecretProviderClass that tells the CSI driver which JSON keys to read from that secret.
  3. When a pod that uses the group starts, the driver fetches the secret. It copies the values into a Kubernetes Secret in the platform namespace. That Secret is named by the group’s alias.
  4. The pods read their environment variables from that Kubernetes Secret. The matching plaintext keys are left out of the ConfigMap, and the values in your values file are ignored.
Groups that you leave off keep using the plaintext values from your values file.

Groups

All keys in the table are under secretsStore.
The alias is the name of the Kubernetes Secret the driver creates. The defaults work as they are. Change an alias only if the name would clash with an existing Secret in the namespace, for example when two releases share a namespace.

What to put in each secret

Each Secrets Manager secret is a JSON object. Every key listed for a group must be present, even if you don’t use that feature. Set unused keys to an empty string (""). If a key is missing, the CSI driver can’t mount the volume, and the pods using that group stay in ContainerCreating. The three database groups each use two short keys, u (username) and p (password):
The other groups use the same key names as the matching values in values.yaml. For example, the application group’s smtpPassword replaces platformConfig.smtpPassword.
Replaces the matching keys under platformConfig.
Replaces the matching keys under sandboxConfig.
Replaces the matching keys under lightningConfig.
Replaces boxConfig.boxApiKey, boxConfig.boxEncryptionKey, boxConfig.dbUsername, boxConfig.dbPassword, and the coding-agent keys under sandboxConfig.
The key lists above are for chart 0.118.0. To get the exact list for the chart version you’re installing, render that group’s SecretProviderClass and read the path: entries. Each path is a JSON key your secret must contain.
Swap app for sandbox, lightning, box, mw, temporal, temporal-visibility, or temp-store (and the matching toggle and name values) to check the other groups.

Set it up

1

Install the CSI driver and the AWS provider

Install these once per cluster. syncSecret.enabled=true is required: without it the driver never creates the Kubernetes Secrets, and the pods fail to start.
(Optional) Install Reloader. The chart already adds Reloader annotations to its deployments, so when a rotated value reaches the Kubernetes Secret, the pods using it restart automatically. Without Reloader, restart the pods yourself after rotating a secret.
2

Create the secrets in AWS Secrets Manager

Create one secret for each group you’re turning on. Prefix the names with the environment, such as prod-aisquared/app, so you can scope IAM to that prefix and keep environments apart:
Use file:// for anything with real values, so the secrets don’t end up in your shell history.
3

Grant the pods read access

Create an IAM role that the platform’s service account can assume through IRSA, with this policy:
If the secrets are encrypted with a customer-managed KMS key, also allow kms:Decrypt on that key.Box uses its own service account. To use the Box group, give Box a separate role through box.serviceAccount.annotations.
4

Configure the chart

secretRegion must match the region the secrets are in. Enabling a group without its *CredsSecretName makes the install fail with an error naming the missing value.
5

Verify

After installing or upgrading, check that the driver created the Kubernetes Secrets:
If a pod is stuck in ContainerCreating, look at its events:
The usual causes are:
  • AccessDenied: the IAM role or policy doesn’t cover the secret name, or the service account annotation is missing.
  • A JMES path error: the secret is missing one of the group’s keys.
  • Failed to fetch secret from all regions: secretRegion is wrong.

App Builder

App Builder (called agentic coding in the chart and the code) lets users build apps by chatting with a coding agent. Self-hosting it involves three pieces:
Sandboxes run on Modal by default, so App Builder works without extra cluster setup once you add a Modal token. Choose Box if the generated code must stay inside your own cluster.

Coding agent

  • Choosing the provider: the prefix of codingAgentModel selects it, for example anthropic/, openai/, google/, groq/ or amazon-bedrock/.
  • API key: codingAgentModelApiKey is the key for that provider. It’s required when the sandbox runtime is Box.
  • Amazon Bedrock: set codingAgentModel to an amazon-bedrock/... value and codingAgentBedrockModelId to your Bedrock inference profile. Bedrock uses AWS credentials from the pod instead of an API key.

Sandbox runtime: Modal (default)

Sandbox runtime: Box (in your cluster)

Box is a small service that creates sandbox pods in your cluster. It gives each one a persistent volume and an ingress URL, snapshots idle sandboxes, and promotes finished apps to long-running releases. Cluster requirements
  • The VolumeSnapshot CRDs and snapshot-controller.
  • A CSI storage driver that supports snapshots, with a VolumeSnapshotClass matching boxConfig.boxSnapshotClass.
  • A StorageClass matching boxConfig.boxStorageClass.
  • An ingress controller (boxConfig.boxIngressClass, in boxConfig.boxIngressNamespace).
  • A wildcard DNS record *.<boxIngressDomain> pointing at that ingress controller.
  • A PostgreSQL database for Box’s own state.
  • API key: platformConfig.boxApiKey (used by the platform) and boxConfig.boxApiKey (checked by Box) must be the same value.
  • Encryption key: boxEncryptionKey must be exactly 64 hex characters. It encrypts the secrets Box stores, so keep it stable; changing it makes existing sandbox secrets unreadable.
  • Namespaces and permissions: the chart creates the box-sandboxes namespace (boxConfig.boxK8sNamespace), a ClusterRole, a RoleBinding in that namespace, and the box-critical PriorityClass. Box runs under its own service account. For AWS access, give it a role through box.serviceAccount.annotations; it doesn’t share the platform’s role.
  • Restricted clusters: where you can’t create namespaces or RBAC (for example GovCloud), set box.namespaces.create: false and box.rbac.create: false, and have a cluster admin create them.
The chart doesn’t yet create the releases namespace (boxConfig.boxReleasesNamespace, default box-releases) or the Box permissions inside it, and Box doesn’t create it either. Until it does, published apps can’t be released. Create both yourself after installing (shown here for a release named aisquared in the aisquared namespace):

Storage and databases for generated apps

Apps that users build can get their own file storage and Postgres database: Set either to none to turn that capability off.
Storage for generated apps needs release 0.126.0 or later. On earlier releases, storage in published apps stops working when its credentials expire (12 hours by default), because published apps can’t refresh them. With IRSA on releases before 0.124.0, storage can’t be turned on at all. On earlier releases, set sandboxConfig.agenticCodingStorageProvider: none.
The storage role (agenticCodingStsRoleName) needs:
  • A trust policy for the cluster’s OIDC provider. From 0.124.0, the platform assumes the role with its IRSA web identity token. If you use static AWS keys instead of IRSA, trust the IAM principal those keys belong to.
  • A MaxSessionDuration of at least agenticCodingStsDuration. That’s 12 hours by default; AWS’s own default is 1 hour.

Published apps

Published apps are served at <app-label>.<appgenPublishedDomain> and proxied through the platform API. To turn this on:
  1. Create a wildcard DNS record, *.apps.your-domain.com, pointing at your ingress controller.
  2. Provide a wildcard TLS certificate.
    • NGINX: the HTTP-01 issuers this chart creates can’t issue wildcard certificates. Create the tlsSecretName secret in the platform namespace yourself, or issue it with a cert-manager DNS-01 issuer.
    • ALB: cover the wildcard in your ACM certificate. Leave appbuilderIngress.groupOrder higher than awsIngress.groupOrder, so that exact hostnames are matched before the wildcard.

GitHub integration (optional)

This lets users push App Builder apps to GitHub repositories.
  1. Create a GitHub App.
  2. Create a Kubernetes secret from its private key:
  3. Configure the chart:
agenticCodingGithubAppPrivateKeyPath takes the name of the Kubernetes secret, not a file path. The chart mounts the secret and points the app at the key file.

Sandbox sizing and lifecycle

All of these are under sandboxConfig. For per-value details and the Box resource settings, see the configuration reference.
Some App Builder feature toggles, such as AGENTIC_CODING_CUSTOM_TOOLS_ENABLED and AGENTIC_CODING_SECURITY_SCAN_ENABLED, aren’t exposed as chart values yet. They default to on.

Private image registry

To pull images from a private registry, create a docker-registry secret in the platform namespace and set:
Set each component’s image under <component>.<component>.image, for example server.server.image.repository and server.server.image.tag.

Upgrading

The in-cluster PostgreSQL volume is annotated with helm.sh/resource-policy: keep, so Helm never deletes it on upgrade or uninstall.
helm uninstall deletes the platform namespace, because the chart creates it. That includes anything you created in it by hand, such as the temporal-cloud secret, image pull secrets, and TLS secrets. The PostgreSQL PersistentVolumeClaim is kept. Delete it manually if you want to remove the data.

Upgrading from the multiwoven chart

The chart was renamed from multiwoven to aisquared in 0.117.0, and its values keys were renamed. Version 0.118.0 also changed several defaults. To upgrade an existing installation in place:
1

Keep your resource names

Set nameOverride: multiwoven. Without it, every resource is recreated under a new name.
2

Rename your values keys

The chart fails with a message naming the new key if an old one is used, including with --reuse-values.
3

Pin the old defaults you relied on

If your install used any of these defaults, set the old value explicitly:
4

Upgrade

Keep your existing release name:

Configuration reference

Every chart value, the environment variable it sets, its default, and the secret group it belongs to are listed in the Helm configuration reference. The chart’s values.yaml is the source of truth for the version you’re installing.