Files
copilotkit__copilotkit/docs/snippets/shared/premium/self-hosting.mdx
Maxim 96bfdf4fc9 docs: fix broken links in self-hosting guide
The shared self-hosting snippet renders under every framework section
(built-in-agent, langgraph, ...), and the NavigationLink rewriter makes
absolute links section-relative.

- "Intelligence Platform Works" linked /learn/intelligence-platform,
  which became /<framework>/learn/intelligence-platform (404). The page
  is served at /premium/intelligence-platform in every section.
- The GHCR chart-releases link used the repo-scoped URL for the private
  Intelligence repo (404 for public readers); switched to the public
  org-scoped package URL.
2026-06-03 21:17:12 +02:00

606 lines
32 KiB
Plaintext

import { Tabs, Tab } from "fumadocs-ui/components/tabs";
## What is this?
CopilotKit Intelligence — the platform that powers threads, shared state, the inspector, and observability — can be self-hosted on your own Kubernetes cluster using the `copilot-intelligence` Helm chart. You run the control plane and data plane inside your own network boundary; the chart leaves you in charge of identity, storage, and secrets.
**What you bring:**
- Postgres and Redis — your own, or the bundled Bitnami subcharts
- An OIDC provider for identity
- Secrets via External Secrets Operator, direct Kubernetes Secrets, or chart-managed credentials
**What the chart deploys:**
| Component | Role | Port |
|---|---|---|
| `app-api` | Backend service | 4201 |
| `app-frontend` | Web UI | 8080 |
| `realtime-gateway` *(optional)* | WebSocket service for realtime sync | 4401 |
Plus a `database-migrations` Job, a `thread-culler` CronJob, and the usual supporting resources (Services, Ingress, HPAs, PodDisruptionBudgets, ConfigMaps, and — when ESO is enabled — ExternalSecret resources).
<Callout type="info" title="User memory (closed beta)">
The Intelligence Platform image also includes an opt-in user memory
capability: agents can recall information from prior conversations in the
same project (e.g. *"what did we discuss earlier?"*, *"remind me about X"*).
Currently supported with the Built-in Agent runtime. Reach out to your
CopilotKit contact for access; see [Configuration reference → User memory](#user-memory-closed-beta) below for the enablement variables.
</Callout>
## When should I use this?
- Your organization requires CopilotKit Intelligence to run inside your own VPC or data center for compliance, data residency, or security reasons
- You want to connect Intelligence to internal databases, identity providers, or secret stores that are not reachable from Copilot Cloud
- You need to operate the platform under your existing Kubernetes tooling, CI/CD, and observability stack
- You have a CopilotKit Intelligence Platform license and the platform-engineering capacity to run a production Kubernetes workload
<Callout type="info" title="Validate locally before committing to a real cluster">
The chart installs the same way against a local Docker Desktop or k3d cluster as against a production one, so walk this guide end-to-end on your laptop first. Two local paths are supported:
- **Bundled overlay** — install with the `values-quickstart-local.yaml` overlay shipped in the chart. It enables in-cluster Postgres, Redis, and (optionally) Keycloak; you drive the install yourself, following this guide.
- **One-shot script** — `scripts/local-demo.sh` spins up a disposable k3d cluster, installs the released chart from GHCR, and brings up bundled Keycloak in one command:
```bash title="Terminal"
./scripts/local-demo.sh --version <chart-version>
```
Both paths use the same install commands described below — pick whichever fits.
</Callout>
## Prerequisites
Before starting, make sure the following are in place. The [How the Intelligence Platform Works](/premium/intelligence-platform) page explains the layering in more depth.
**License and registry access:**
- A valid CopilotKit Intelligence Platform license key (contact your CopilotKit account team if you do not have one)
- Read access to the chart OCI registry at `oci://ghcr.io/copilotkit/charts/intelligence` (anonymous pulls are allowed for the released chart)
- The latest released chart version. Check the [chart releases](https://github.com/orgs/CopilotKit/packages/container/package/charts%2Fintelligence) on GHCR; substitute the value into the `<chart-version>` placeholder used throughout this guide (e.g. `0.1.0-rc.16`).
**Cluster and tooling:**
- Kubernetes ≥ 1.28
- Helm ≥ 3.12
- `kubectl` configured against the target cluster with an admin-equivalent context
**Platform prerequisites (cluster-wide, installed once):**
- An ingress controller — either `nginx-ingress` or the AWS Load Balancer Controller
- `cert-manager` (or a cloud-managed certificate alternative such as AWS ACM) for TLS on the public hostnames
- `External Secrets Operator` if you plan to sync secrets from AWS Secrets Manager, HashiCorp Vault, or GCP Secret Manager (recommended for production, but not required — see [Secrets](#create-secrets))
**External dependencies (reachable from the cluster):**
- PostgreSQL ≥ 14 — managed (Amazon RDS, Aurora, Cloud SQL) or operator-deployed in-cluster
- Redis ≥ 7 (or a Valkey-compatible service such as Amazon ElastiCache)
- An OIDC identity provider — Keycloak, Okta, Azure AD, Auth0, Google Workspace, or equivalent
**Optional:**
- Amazon OpenSearch (only when analytics features are in use)
- An S3-compatible object store (only when the realtime gateway is configured to persist AG-UI events)
## Implementation
<Steps>
<Step>
### Prepare your Kubernetes cluster
Ensure `kubectl` points to the cluster that will run Intelligence.
```bash title="Terminal"
kubectl config current-context
kubectl auth can-i create namespace --all-namespaces
```
Confirm the context names your target cluster and that the permission check returns `yes`. If not, fix your kubeconfig before proceeding.
</Step>
<Step>
### Install platform prerequisites
These components are cluster-wide and installed once per cluster, independently of the application chart.
<Tabs items={["AWS (EKS)", "On-prem / generic", "Local (Docker Desktop / k3d)"]}>
<Tab value="AWS (EKS)">
```bash title="Terminal"
# AWS Load Balancer Controller (kube-system)
helm repo add eks https://aws.github.io/eks-charts
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<YOUR_CLUSTER_NAME>
# cert-manager
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
-n cert-manager --create-namespace \
--set installCRDs=true
# External Secrets Operator (optional — see Secrets step)
helm repo add external-secrets https://charts.external-secrets.io
helm install external-secrets external-secrets/external-secrets \
-n external-secrets --create-namespace
```
</Tab>
<Tab value="On-prem / generic">
```bash title="Terminal"
# NGINX Ingress Controller
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx \
-n ingress-nginx --create-namespace
# cert-manager
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
-n cert-manager --create-namespace \
--set installCRDs=true
```
</Tab>
<Tab value="Local (Docker Desktop / k3d)">
```bash title="Terminal"
# NGINX Ingress Controller as ClusterIP — you will reach it via
# `kubectl port-forward` later, so no LoadBalancer service is needed.
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace \
--set controller.service.type=ClusterIP \
--wait
```
cert-manager and External Secrets Operator are not required for a local validation pass — TLS is terminated outside the cluster and secrets are managed by the chart (Path C below) or pre-created by hand (Path B).
</Tab>
</Tabs>
After each controller is running, its pods should be `Ready` in their respective namespaces.
</Step>
<Step>
### Provision external dependencies
Intelligence needs Postgres, Redis, and an OIDC issuer. You can either point the chart at managed services you already run, or enable the bundled Bitnami subcharts for in-cluster Postgres and Redis (appropriate for evaluation and small self-hosted installs).
**Using managed services (recommended for production):**
- Create a Postgres database and user. Record the host, port (default `5432`), database name, username, and password.
- Create a Redis instance with TLS enabled. Record the host, port (default `6379`), and password.
- Configure an OIDC client in your identity provider. Record the issuer URL, client ID, and client secret.
**Using the bundled in-cluster subcharts:**
Set `postgresql.enabled: true` and `redis-subchart.enabled: true` in your values file (covered in the next step). A matching `StorageClass` must exist in the cluster. The bundled Keycloak subchart is available via `keycloak.enabled: true` if you also need a quick OIDC provider for evaluation; do not use the bundled Keycloak for production workloads. See [Bundled Keycloak (eval only)](#bundled-keycloak-eval-only) for the realm and credentials it creates.
The chart already ships a tested overlay for this shape — `values-quickstart-local.yaml` — which enables bundled Postgres + Redis, sets `migrations.enabled: true`, sizes resources for a laptop, and creates disposable secrets so the install runs end-to-end with no manual prep. Layer your own overlay on top of it (see the next step) to plug in your IdP and ingress.
</Step>
<Step>
### Create a values file
The released chart ships several example values files for the common deployment shapes. Pick the one closest to your environment and copy it into a working overlay you can edit. Pull and untar the chart so you have local copies to diff against:
```bash title="Terminal"
helm pull oci://ghcr.io/copilotkit/charts/intelligence --version <chart-version> --untar
# AWS-flavored (ALB, IRSA, External Secrets from AWS Secrets Manager)
cp intelligence/values-aws-example.yaml my-values.yaml
# Or on-prem-flavored (nginx, manual Kubernetes Secrets)
cp intelligence/values-onprem-example.yaml my-values.yaml
# Or self-hosted eval (bundled Keycloak + in-cluster Postgres/Redis)
cp intelligence/values-self-hosted-eval.yaml.example my-values.yaml
```
The chart untars into a directory named `intelligence/` (the published chart name on GHCR; the chart's `nameOverride` keeps release-prefixed resources named `cpki-*`).
Edit `my-values.yaml` to set at minimum:
- `database.host`, `database.port`, `database.name` — your Postgres connection (`name` defaults to `intelligence`)
- `redis.host`, `redis.port`, `redis.tls` — your Redis connection (TLS is on by default; managed Redis requires it)
- `auth.issuer` — your OIDC provider's issuer URL
- `auth.existingSecret` — name of the Kubernetes Secret containing `auth-secret`, `auth-client-id`, `auth-client-secret` (or use one of the alternate paths in [Secrets](#create-secrets))
- `ingress.ui.host` — the hostname users will load the Intelligence UI on (for example `intelligence.example.com`)
- `ingress.api.host` — optional dedicated API hostname. When omitted, the `ui.host` rule routes `/api` and `/auth` paths to `app-api`, so a single hostname is fine for most installs.
- `ingress.tls` — TLS configuration for the hosts above
- `migrations.enabled: true` — **required for first install**; defaults to `false`. Without it the database schema is never applied and `app-api` will crashloop. (The eval overlay `values-quickstart-local.yaml` sets this for you when you layer on top of it.)
<Callout type="warn" title="OIDC issuer URL — trailing slash matters">
Some providers (Auth0 in particular) only accept the issuer URL with a trailing slash (e.g. `https://your-tenant.auth0.com/`). A missing or extra slash produces an opaque "issuer mismatch" failure at login time. Match the value exactly to what your provider's discovery endpoint advertises.
</Callout>
See the [Configuration reference](#configuration-reference) section for the full set of values.
</Step>
<Step id="create-secrets">
### Create secrets
The chart supports three paths for secrets management. Pick exactly one.
**Path A — External Secrets Operator (recommended for production):**
1. Ensure your secret backend (AWS Secrets Manager, Vault, etc.) has entries for the database URL, Redis URL, and auth credentials.
2. Create a `ClusterSecretStore` (or `SecretStore`) that references that backend.
3. In `my-values.yaml`, set `externalSecrets.enabled: true`, `externalSecrets.store.kind`, and `externalSecrets.store.name` to match. The chart then generates `ExternalSecret` resources that sync those entries into Kubernetes Secrets at the names `app-api` expects.
**Path B — Direct Kubernetes Secrets (you manage the rotations):**
Leave `externalSecrets.enabled: false` (the default) and create the Secrets manually before installing:
```bash title="Terminal"
kubectl create namespace copilot-intelligence
kubectl create secret generic cpki-db \
--from-literal=database-url='postgresql://user:pass@host:5432/intelligence' \
-n copilot-intelligence
kubectl create secret generic cpki-redis \
--from-literal=redis-url='rediss://:password@host:6379' \
-n copilot-intelligence
kubectl create secret generic cpki-auth \
--from-literal=auth-secret="$(openssl rand -hex 32)" \
--from-literal=auth-client-id='<OIDC client id>' \
--from-literal=auth-client-secret='<OIDC client secret>' \
-n copilot-intelligence
```
Reference these names in your values file via `database.existingSecret`, `redis.existingSecret`, and `auth.existingSecret`. The Secret keys are lowercase-hyphenated (`auth-secret`, `database-url`, `runner-auth-secret`); the workloads consume them as the corresponding uppercase env vars (`AUTH_SECRET`, `DATABASE_URL`, `RUNNER_AUTH_SECRET`).
**Path C — Chart-managed self-hosted secrets (simplest BYOC):**
Useful when you do not run a secret manager and prefer Helm to create the Kubernetes Secrets directly from values you provide at install time. Set `selfHostedSecrets.enabled: true` and supply the credentials inline:
```yaml title="my-values.yaml"
selfHostedSecrets:
enabled: true
db:
url: "postgresql://user:pass@host:5432/intelligence"
redis:
url: "rediss://:password@host:6379"
auth:
# Auto-generated when left empty.
secret: ""
clientId: "<OIDC client id>"
clientSecret: "<OIDC client secret>"
realtimeGateway:
# Auto-generated when left empty.
runnerAuthSecret: ""
secretKeyBase: ""
beam:
# Auto-generated when left empty.
releaseCookie: ""
```
The chart auto-generates `auth.secret`, the realtime-gateway runner/key-base, and the BEAM cookie when those fields are empty, so you only need to provide what you actually have.
</Step>
<Step>
### Install the chart
The release can be installed directly from the GHCR OCI registry — no local untar is required for the install itself. Use `helm upgrade --install` so the same command works for first-time installs and upgrades.
```bash title="Terminal"
helm upgrade --install copilot-intelligence \
oci://ghcr.io/copilotkit/charts/intelligence \
--version <chart-version> \
-f my-values.yaml \
-n copilot-intelligence \
--create-namespace \
--wait \
--timeout 10m
```
Layering multiple values files is supported and is the recommended pattern for evaluation: combine the chart's bundled `values-quickstart-local.yaml` (in-cluster Postgres/Redis, eval-sized resources, `migrations.enabled: true`, disposable secrets) with your own overlay (IdP, ingress, anything cluster-specific). Pull the chart first so you have a local copy of `values-quickstart-local.yaml` to reference:
```bash title="Terminal"
helm upgrade --install copilot-intelligence \
oci://ghcr.io/copilotkit/charts/intelligence \
--version <chart-version> \
-f intelligence/values-quickstart-local.yaml \
-f my-values.yaml \
-n copilot-intelligence --create-namespace \
--wait --timeout 10m
```
`--wait` blocks until the `Deployments` report healthy replicas; `--timeout 10m` allows enough time for image pulls and the initial database migration job. Right-most `-f` files win on conflicts, so put your overlay last.
<Callout type="info" title="When the migrations Job runs">
The migrations Job runs as a **pre-install/pre-upgrade** hook (weight `-5`) when secrets are pre-created (Path A or Path B above), so the schema is ready before app pods start. It runs as a **post-install/post-upgrade** hook (weight `5`) when secrets are managed by Helm (Path C, or when using `postgresql.enabled: true`), because the Secret resources don't exist until Helm has created them.
</Callout>
</Step>
<Step>
### Verify the install
Check that every pod is `Running` and the ingress is ready:
```bash title="Terminal"
kubectl get pods -n copilot-intelligence
kubectl get ingress -n copilot-intelligence
```
You should see `app-api`, `app-frontend`, and — if enabled — `realtime-gateway` pods running. The migrations `Job` will appear as `Completed`.
Confirm the API health check reports `ok`:
```bash title="Terminal"
curl https://<ingress.api.host>/api/health
```
The endpoint returns `200 OK` only when the database is reachable — a failed health check is almost always a database connectivity problem.
Service-specific health endpoints, useful when port-forwarding to an individual pod:
| Service | Path |
|---|---|
| `app-api` | `/api/health` |
| `app-frontend` | `/healthz` |
| `realtime-gateway` | `/health` |
Finally, browse to `https://<ingress.ui.host>` and log in via your OIDC provider. A successful login confirms end-to-end wiring.
<Callout type="info" title="Local validation — port-forward the ingress controller">
On a local cluster (Docker Desktop, k3d) without a public DNS name, port-forward the **ingress controller** rather than the frontend service so the UI host rule still routes `/api` and `/auth` to `app-api`. Set `ingress.ui.host: "localhost"` in your overlay, then leave this terminal open for as long as you're using the app:
```bash title="Terminal"
kubectl -n ingress-nginx port-forward svc/ingress-nginx-controller 8080:80
```
Browse to `http://localhost:8080`. Port-forwarding the `app-frontend` service directly bypasses the ingress and breaks `/api` and `/auth` routing.
</Callout>
</Step>
<Step>
### Upgrade and uninstall
**Upgrade** — bump the version in your install command and re-run it. Because the install command already uses `helm upgrade --install`, the same invocation works for both fresh installs and upgrades:
```bash title="Terminal"
helm upgrade --install copilot-intelligence \
oci://ghcr.io/copilotkit/charts/intelligence \
--version <new-chart-version> \
-f my-values.yaml \
-n copilot-intelligence \
--wait
```
Before upgrading, regenerate the example values for the target version (`helm pull ... --version <new-chart-version> --untar`) and diff against your overlay to catch new keys.
**Uninstall** — releases leave PersistentVolumes in place by default if you enabled bundled subcharts; delete them manually if you intend to tear down state.
```bash title="Terminal"
helm uninstall copilot-intelligence -n copilot-intelligence
```
</Step>
</Steps>
## Bundled Keycloak (eval only)
When `keycloak.enabled: true`, the chart deploys the Bitnami Keycloak subchart with a pre-seeded realm and demo user. This is for evaluation and demos — not production. The realm import creates:
- **Realm:** `cpk-dev`
- **OIDC client:** `cpk-self-hosted` with secret `cpk-self-hosted-secret` (override via `auth.keycloakClient.clientId` / `auth.keycloakClient.clientSecret`)
- **Demo user:** `engineer` / `engineer` (override via `auth.keycloakDemoUser`)
- **Redirect URIs / web origins:** default `["*"]` for eval flexibility (override via `auth.keycloakClient.redirectUris` / `webOrigins`)
The chart auto-wires `auth.issuer` to the in-cluster Keycloak service, so leaving `auth.issuer` empty when `keycloak.enabled: true` is intentional.
For production self-hosted deployments, leave `keycloak.enabled: false` and point `auth.issuer` at your own IdP.
## Configuration reference
The tables below summarize the most common values. For every option, see `values.yaml` in the pulled chart.
### Global
| Key | Description | Default |
|---|---|---|
| `global.imageRegistry` | Registry prefix for unqualified image names | `""` |
| `global.intelligenceImageRegistry` | Registry prefix specifically for the five Intelligence service images | `""` |
| `global.imagePullSecrets` | Image pull secrets for private registries | `[]` |
| `global.storageClass` | StorageClass override for bundled subcharts | `""` |
### Database
| Key | Description | Default |
|---|---|---|
| `database.host` | Postgres host | `""` (required) |
| `database.port` | Postgres port | `5432` |
| `database.name` | Database name | `intelligence` |
| `database.existingSecret` | Pre-existing Secret with `database-url` | `""` |
| `database.secretKeys.url` | Key inside the Secret holding the connection string | `database-url` |
### Redis
| Key | Description | Default |
|---|---|---|
| `redis.host` | Redis host | `""` (required) |
| `redis.port` | Redis port | `6379` |
| `redis.tls` | Require TLS (ElastiCache defaults to on) | `true` |
| `redis.existingSecret` | Pre-existing Secret with `redis-url` | `""` |
| `redis.secretKeys.url` | Key inside the Secret holding the connection URL | `redis-url` |
### OpenSearch (optional)
| Key | Description | Default |
|---|---|---|
| `openSearch.host` | OpenSearch domain endpoint | `""` |
| `openSearch.port` | Port | `443` |
| `openSearch.tls` | Require TLS | `true` |
| `openSearch.existingSecret` | Pre-existing Secret with `opensearch-url` | `""` |
### Authentication
| Key | Description | Default |
|---|---|---|
| `auth.deploymentMode` | `self-hosted` (single org) or `hosted` (multi-org) | `self-hosted` |
| `auth.issuer` | OIDC issuer URL (auto-set when `keycloak.enabled: true`) | `""` |
| `auth.existingSecret` | Secret with `auth-secret`, `auth-client-id`, `auth-client-secret` | `""` |
| `auth.defaultOrganizationId` | Default organization ID in self-hosted mode | `default` |
| `auth.providerId` | Stable identifier for the OIDC provider | `enterprise-sso` |
| `auth.providerName` | Display name shown in the UI | `Enterprise SSO` |
| `auth.trustHost` | Trust the `X-Forwarded-Host` header (set behind a reverse proxy) | `"true"` |
### Ingress
| Key | Description | Default |
|---|---|---|
| `ingress.enabled` | Create Ingress resources | `true` |
| `ingress.className` | `nginx` or `alb` | `nginx` |
| `ingress.ui.host` | UI hostname; the rule for this host routes `/api` and `/auth` to `app-api` and `/` to `app-frontend` | `""` (required) |
| `ingress.api.host` | Optional dedicated API hostname. When set, this hostname routes `/` to `app-api`. When empty, no separate API rule is created — the UI host already serves the API. | `""` |
| `ingress.realtimePlane.host` | Optional dedicated realtime hostname (only used when `realtimeGateway.enabled: true`) | `""` |
| `ingress.tls` | TLS configuration | `[]` |
| `ingress.websocket.enabled` | Add WebSocket-friendly annotations (auto-enabled when realtime-gateway is enabled with nginx) | `false` |
| `ingress.annotations` | Additional ingress annotations | `{}` |
### Services (`appApi`, `appFrontend`, `realtimeGateway`)
| Key | Description | Default (`appApi`) | Default (`appFrontend`) | Default (`realtimeGateway`) |
|---|---|---|---|---|
| `<svc>.enabled` | Enable the service | `true` | `true` | `false` |
| `<svc>.replicaCount` | Replicas | `2` | `2` | `2` |
| `<svc>.image.repository` | Image repository (published chart fully-qualifies these to `ghcr.io/copilotkit/intelligence/<svc>`) | `intelligence/app-api` | `intelligence/app-frontend` | `intelligence/realtime-gateway` |
| `<svc>.image.tag` | Image tag (defaults to chart `appVersion`) | `""` | `""` | `""` |
| `<svc>.resources` | CPU/memory requests | `250m` / `512Mi` | `100m` / `128Mi` | `500m` / `512Mi` |
| `<svc>.autoscaling.enabled` | Enable HPA | `true` | `false` | `true` |
| `<svc>.autoscaling.minReplicas` | HPA minimum | `2` | `2` | `2` |
| `<svc>.autoscaling.maxReplicas` | HPA maximum | `10` | `4` | `10` |
| `<svc>.serviceAccount.annotations` | Annotations on the ServiceAccount (IRSA, workload identity) | `{}` | `{}` | `{}` |
| `<svc>.podAnnotations` | Pod template annotations (e.g. for Stakater Reloader on ESO secret rotation) | `{}` | n/a | `{}` |
### Realtime gateway (additional keys)
| Key | Description | Default |
|---|---|---|
| `realtimeGateway.enabled` | Enable the gateway | `false` |
| `realtimeGateway.host` | `PHX_HOST` override | `""` |
| `realtimeGateway.existingSecret` | Secret containing keys `runner-auth-secret` and `secret-key-base` (mapped to env vars `RUNNER_AUTH_SECRET` / `SECRET_KEY_BASE`) | `""` |
| `realtimeGateway.beam.clustering.enabled` | BEAM clustering across replicas | `true` |
| `realtimeGateway.beam.cookieSecret.name` | Secret containing the BEAM cookie | `cpki-beam-cookie` |
Enabling the realtime gateway requires that either `realtimeGateway.existingSecret` is set, or that `externalSecrets.secrets.realtimeGateway.enabled` or `selfHostedSecrets.enabled` is `true` — the chart fails validation otherwise.
### User memory (closed beta)
<InsecurePasswordProtected password="cpki-mem-beta">
User memory lets agents recall information from prior conversations in the same project. Built-in Agent runtime only today; LangGraph, Mastra, and other frameworks are in development.
**What it does.** The chat agent can recall the user's prior conversations and use that recall to answer questions like:
- *"What did we discuss last week?"*
- *"Remind me what I decided about X"*
- *"Have we covered Y before?"*
**Scope.** Only the current user's conversations in the current `(organization, project)`. The agent never sees another user's conversations or another project's data, and it cannot modify what was said.
**Discovery.** The agent will use the capability on its own when asked recall-style questions; for best results, add one line to your agent's `prompt` nudging it to consult its memory when relevant.
**Enabling it.** Two flips, one on each side:
| Where | How |
|---|---|
| `app-api` (platform) | Set `SL_ENABLED=true` via `appApi.env: [{ name: SL_ENABLED, value: "true" }]` in your `values.yaml`. This mounts the platform's `/mcp` endpoint on `app-api`. |
| Your runtime / BFF | Pass `mcpServer: true` when constructing `CopilotKitIntelligence` from `@copilotkit/runtime/v2`. The runtime then auto-attaches the platform's `/mcp` endpoint to every `BuiltInAgent` run. |
```typescript title="runtime.ts"
import { CopilotKitIntelligence } from "@copilotkit/runtime/v2";
const intelligence = new CopilotKitIntelligence({
apiKey: process.env.INTELLIGENCE_API_KEY!,
apiUrl: process.env.INTELLIGENCE_API_URL!,
wsUrl: process.env.INTELLIGENCE_GATEWAY_WS_URL!,
mcpServer: true, // [!code highlight]
});
```
Once both flips are in place the agent gains recall on its next turn — no further application changes needed.
</InsecurePasswordProtected>
### External Secrets Operator integration
| Key | Description | Default |
|---|---|---|
| `externalSecrets.enabled` | Generate `ExternalSecret` resources | `false` |
| `externalSecrets.store.kind` | `ClusterSecretStore` or `SecretStore` | `ClusterSecretStore` |
| `externalSecrets.store.name` | SecretStore name | `""` (required when enabled) |
| `externalSecrets.refreshInterval` | How often ESO syncs | `1h` |
| `externalSecrets.secrets.*` | Per-secret mappings — see `values.yaml` | — |
### Self-hosted (chart-managed) secrets
| Key | Description | Default |
|---|---|---|
| `selfHostedSecrets.enabled` | Create Kubernetes Secrets from inline values; auto-generates blank fields | `false` |
| `selfHostedSecrets.db.url` | Postgres connection URL | `""` (required when enabled) |
| `selfHostedSecrets.redis.url` | Redis connection URL | `""` (required when enabled) |
| `selfHostedSecrets.auth.clientId` / `clientSecret` | OIDC client credentials | `""` (required when enabled) |
| `selfHostedSecrets.auth.secret` | Internal auth signing secret | auto-generated when empty |
| `selfHostedSecrets.realtimeGateway.runnerAuthSecret` / `secretKeyBase` | Runtime gateway secrets | auto-generated when empty |
| `selfHostedSecrets.beam.releaseCookie` | BEAM clustering cookie | auto-generated when empty |
### Bundled subcharts (evaluation only)
| Key | Description | Default |
|---|---|---|
| `postgresql.enabled` | Deploy in-cluster Postgres | `false` |
| `postgresql.auth.password` | Postgres password (set at deploy time) | `""` |
| `redis-subchart.enabled` | Deploy in-cluster Redis (aliased to avoid collision with `redis.*`) | `false` |
| `redis-subchart.auth.password` | Redis password | `""` |
| `keycloak.enabled` | Deploy bundled Keycloak for quick eval | `false` |
### Object storage (realtime gateway event persistence)
| Key | Description | Default |
|---|---|---|
| `objectStorage.enabled` | Persist AG-UI events from the realtime gateway to S3-compatible storage | `false` |
| `objectStorage.bucket` | Bucket name | `""` |
| `objectStorage.region` | Bucket region | `us-east-1` |
| `objectStorage.endpoint` | S3-compatible endpoint override (e.g. for MinIO) | `""` |
| `objectStorage.forcePathStyle` | Force path-style addressing (required for MinIO) | `false` |
| `objectStorage.existingSecret` | Secret with static access keys (optional if using IRSA) | `""` |
### Database migrations
| Key | Description | Default |
|---|---|---|
| `migrations.enabled` | Run the migrations Job. **Required for first install** — defaults to `false`. | `false` |
| `migrations.image.repository` | Migrations image repository | `intelligence/db-migrations` |
| `migrations.activeDeadlineSeconds` | Job deadline | `1800` |
| `migrations.backoffLimit` | Retry count before failing | `3` |
The migrations Job runs as a **pre-install/pre-upgrade** Helm hook (weight `-5`) when secrets are pre-created (External Secrets path or manual `existingSecret`) and as a **post-install/post-upgrade** hook (weight `5`) when secrets are managed by Helm itself (`selfHostedSecrets.enabled` or `postgresql.enabled`).
### Thread culler (CronJob)
| Key | Description | Default |
|---|---|---|
| `threadCuller.enabled` | Run a CronJob that soft-deletes stale threads in unlicensed deployments | `false` |
| `threadCuller.schedule` | Cron expression | `0 * * * *` |
| `threadCuller.staleHours` | Threads older than this many hours (since last update) are culled | `"3"` |
| `threadCuller.batchSize` | Maximum threads to cull per run | `"1000"` |
| `threadCuller.licenseSecret.existingSecret` | Secret containing `COPILOTKIT_LICENSE_TOKEN`. When set, the CronJob skips culling (licensed install). When empty, it culls. | `""` |
### Shared config (CORS, logging)
| Key | Description | Default |
|---|---|---|
| `config.logLevel` | Log level for all services (`trace`/`debug`/`info`/`warn`/`error`/`fatal`) | `info` |
| `config.nodeEnv` | Node environment; affects cookie security and runtime defaults | `production` |
| `config.appFrontendOrigin` | Browser origin allowed to perform authenticated bootstrap writes | `""` |
| `config.publicAppOrigin` | Public UI origin used by server-side callbacks when distinct from `appFrontendOrigin` | `""` |
| `config.allowedOrigins` | Additional CORS allowlist (comma-separated). Entries are exact origins (`https://app.example.com`) or Phoenix-style `//host` patterns | `""` |
### Pod-level controls
Per-service keys `podDisruptionBudget`, `podAntiAffinity`, and `networkPolicy` are available for high-availability and traffic-isolation requirements. See `values.yaml` for full shapes.
## Next steps
- **Understand how it works:** [How the Intelligence Platform Works](/premium/intelligence-platform) — architecture, multi-tenancy model, platform layering, and the decision between hosted and self-hosted
- **Premium features overview:** [CopilotKit Premium](/premium/overview) — all premium capabilities that require an Intelligence license
- **Use threads in your app:** [Threads](/threads) — the persistent-conversation surface powered by the Intelligence Platform you just deployed