ChatUI
Scope: namespaced · Workload: LibreChat via the official chart
The LibreChat web UI, wired to a Gateway. It requires MongoDB and optionally uses Meilisearch for search; both are first-class datastore resources that ChatUI only references.
Spec
| Field | Type | Description |
|---|---|---|
secretsRef | LocalRef (optional) | Same-namespace SecretsManagement to wait for. Leave it out to use plain Kubernetes Secrets you manage yourself — see secretsRef |
gatewayRef | ObjectRef | A Gateway (auto-wired if licensed) |
gateway | object | Manual endpoint fallback: { url, apiKeySecretRef: { name, key } }. key may be any entry of the Secret (default LITELLM_API_KEY); only that value reaches LibreChat, not the rest of the Secret |
models[] | list | Client-facing model list. The first is the default and titles new chats. Empty = every model the gateway offers (chats are then titled with the model in use): the referenced gateway's model names are listed, and models added later still appear. Required when the gateway is given by gateway.url — its models cannot be discovered |
agents | bool | LibreChat's Agents endpoint. Disabled by default (interface.agents: false); set true to enable |
host | string | UI hostname |
ingress | object | className, basic-auth, TLS |
mongo | DatastoreRef (required) | LibreChat's MongoDB store |
meilisearch | MeilisearchRef | Search backend (optional) |
subcharts | object | LibreChat subchart toggles (redis/ragApi only) |
values | object | Free-form Helm-values overlay for the librechat chart (see Custom chart values) |
imageVolume | object | PVC for uploaded images |
sso | object | OIDC/SSO login for LibreChat (see SSO) |
mcpRefs[] | list of ObjectRef | MCPServer CRs to wire in (cross-namespace allowed). Referencing any auto-enables Agents (see MCP servers) |
mongo (required)
| Mode | Description |
|---|---|
ref | A MongoCluster + databaseName (default LibreChat, which must be declared in the cluster's databases[]) |
external | A connectionSecretRef holding MONGO_URI |
MongoDB is required infrastructure, so it is not license-gated.
meilisearch (optional)
| Mode | Description |
|---|---|
ref (default) | A MeilisearchInstance |
external | host + masterKeySecretRef |
disabled | Search off |
The bundled LibreChat MongoDB and Meilisearch subcharts are always disabled — those datastores are managed by their own resources.
What it installs
The controller installs the librechat chart as a standalone release in the ChatUI namespace, plus the Forge Gateway config ConfigMap. It translates the resource into chart values (gateway base URL, model list, ingress host + basic-auth, ESO secret names, resolved MONGO_URI / MEILI_HOST, subchart toggles).
For Meilisearch, the controller copies the resolved master key into a same-namespace owned Secret <ui>-meili-key and injects MEILI_MASTER_KEY via global.librechat.env — so a MeilisearchInstance in another namespace still works.
Agents endpoint
LibreChat ships its Agents endpoint enabled. The operator turns it off by default — it renders interface.agents: false into librechat.yaml — so a fresh ChatUI does not expose agent building. Opt back in with:
spec:
agents: trueReferencing any MCP server also switches Agents on, because LibreChat surfaces MCP tools through them. In that case the operator grants only what the tools need:
| How Agents were enabled | use (run agents) | create (in-UI agent builder) |
|---|---|---|
spec.agents: true (explicit opt-in) | ✅ | ✅ |
| implicitly, by wiring an MCP server | ✅ | ❌ |
This matters because agent creation is not admin-gated in LibreChat: the permissions are emitted as an object rather than a bare true, which would inherit LibreChat's create: true default and show the agent builder to every user. share/public stay off in both cases.
Custom chart values
Not every librechat chart option is modelled as a CRD field. spec.values is a free-form object merged into the chart values, so you can set anything the chart supports (replica count, pod resources, extra annotations, …) without waiting for a new CRD field:
spec:
values:
replicaCount: 2
librechat:
resources:
limits: { cpu: "2", memory: 2Gi }Operator-managed keys win. Your values are the base; the operator's computed values (datastore wiring, secret references, the bundled-subchart enabled toggles, and the tracing/SSO env it injects) are layered on top, so spec.values cannot break the wiring the operator depends on. Use the dedicated fields (mongo, meilisearch, subcharts, agents, sso, …) for anything the operator models; reserve spec.values for the long tail.
Gateway wiring
- With the
auto-wiringfeature and agatewayRef, the controller mints aLiteLLMVirtualKeyon the referenced Gateway, stores it in an owned Secret, and injectsbaseURL = http://<gw-svc>.<gw-ns>.svc.cluster.local:4000/v1plus the key. - Without it, supply
gateway.{ url, apiKeySecretRef }manually. See Auto-Wiring.
SSO / OIDC login
spec.sso enables LibreChat's OpenID Connect provider — it turns on ALLOW_SOCIAL_LOGIN and injects the OPENID_* env. The OAuth client credentials come from a same-namespace Secret (via SecretsManagement); the operator mints the OPENID_SESSION_SECRET itself and wires DOMAIN_SERVER/DOMAIN_CLIENT to the UI's public URL so callbacks resolve.
| Field | Description |
|---|---|
issuerURL | OIDC issuer / discovery base URL |
clientSecretRef.name | Secret holding the OAuth client (keys default to client-id / client-secret) |
scopes | Requested scopes (default openid, profile, email) |
providerName | Login-button label |
The provider, tenantID, and explicit-endpoint fields of the shared SSO type are Gateway-only and ignored here (LibreChat derives endpoints from issuerURL).
spec:
sso:
issuerURL: https://idp.example.com
providerName: "Acme SSO"
clientSecretRef: { name: chatui-oidc }MCP servers
spec.mcpRefs wires MCPServer CRs (bundled catalog or external) into LibreChat's Agents endpoint. Referencing any server auto-enables Agents; the operator renders the mcpServers config and, for in-cluster targets, the mcpSettings SSRF allowlist — automatically.
spec:
mcpRefs:
- { name: websearch } # an MCPServer in this namespace
- { name: docs, namespace: team } # cross-namespace allowedHardened defaults & admin model
The operator always renders a hardened LibreChat interface, regardless of MCP usage:
- Native Web Search and Code Interpreter are OFF (
interface.webSearch: false,interface.runCode: false). MCPweb_searchis the supported web-search path. - Users cannot add or disable MCP servers from the UI — admins included (
interface.mcpServerspermission is locked touseonly). Only operator config (yourMCPServerCRs) defines them. - No real admin: on a fresh ChatUI the operator creates a reserved, never-used phantom admin (random in-Job password, never persisted) to claim LibreChat's "first registered user becomes ADMIN" slot, so all real users (Identity CRs, SSO) land as USER. Pre-existing admins are left untouched.
Example
apiVersion: core.navique.com/v1alpha1
kind: ChatUI
metadata:
name: forge-ui
namespace: forge-ui
spec:
secretsRef: { name: chatui-secrets }
gatewayRef: { name: gateway, namespace: forge-gateway }
models: [ azure_ai/gpt-5.4 ]
agents: false # default — LibreChat Agents endpoint off
host: chat.forge.example.com
mongo:
mode: ref
ref: { name: forge-mongo, namespace: forge-data }
databaseName: LibreChat
meilisearch:
mode: ref
ref: { name: forge-ui-search }
ingress:
enabled: true
className: nginx
basicAuthSecret: forge-ui-basic-auth
values: # free-form chart overlay (operator keys still win)
replicaCount: 2Status
Deployment availability and the ingress host, plus the standard conditions and observedGeneration.