helm

Multica Helm Chart

Deploy Multica, the open-source managed agents platform, on Kubernetes.

Features

Important Runtime Note

The upstream multica-web image currently bakes its Next.js rewrites to http://backend:8080 at build time. This chart creates a compatibility Service named backend by default so the official image works in Kubernetes.

If you build a custom frontend image with a different REMOTE_API_URL, disable it:

frontend:
  backendServiceAlias:
    enabled: false

Prerequisites

Install

helm repo add icoretech https://icoretech.github.io/helm
helm repo update
helm upgrade --install multica icoretech/multica \
  -n multica --create-namespace \
  --set backend.config.jwtSecret="replace-with-a-strong-secret-at-least-32-characters"

OCI:

helm upgrade --install multica oci://ghcr.io/icoretech/charts/multica \
  -n multica --create-namespace \
  --set backend.config.jwtSecret="replace-with-a-strong-secret-at-least-32-characters"

Production Shape

For production, prefer external PostgreSQL and S3-compatible uploads:

postgres:
  enabled: false

database:
  external:
    enabled: true
    urlFrom:
      secretKeyRef:
        name: multica-db
        key: DATABASE_URL

backend:
  config:
    frontendOrigin: https://multica.example.com
    jwtSecretRef:
      name: multica-auth
      key: JWT_SECRET
  email:
    resendApiKeyRef:
      name: multica-email
      key: RESEND_API_KEY
    resendFromEmail: noreply@example.com

storage:
  local:
    persistence:
      enabled: false
  s3:
    bucket: multica-uploads
    region: eu-west-1

Agent Execution Model

This chart deploys the Multica server layer only: backend, frontend, database wiring, and upload storage. Agent execution still happens through Multica daemons running on separate machines where Codex, Claude Code, OpenCode, or another supported coding tool is installed.

Do not run arbitrary coding-agent daemons inside this chart by default. Treat runners as separately managed compute with their own filesystem, credentials, and security boundary.

Configuration Reference

Values

Key Type Default Description
backend.affinity object {} Backend affinity.
backend.autoscaling.enabled bool false Enable backend HPA.
backend.autoscaling.maxReplicas int 5 Maximum backend replicas.
backend.autoscaling.minReplicas int 1 Minimum backend replicas.
backend.autoscaling.targetCPUUtilizationPercentage int 80 Target CPU utilization percentage.
backend.autoscaling.targetMemoryUtilizationPercentage string nil Target memory utilization percentage.
backend.config.allowSignup bool true Signup master switch.
backend.config.allowedEmailDomains string "" Signup domain allowlist, comma-separated.
backend.config.allowedEmails string "" Explicit signup email allowlist, comma-separated.
backend.config.allowedOrigins string "" Additional WebSocket origins, comma-separated.
backend.config.analyticsDisabled bool true Disable backend/frontend analytics. Defaults to true for self-host privacy.
backend.config.appEnv string "production" Runtime environment. Keep production on public deployments.
backend.config.cookieDomain string "" Optional cookie Domain attribute. Leave empty for single-host deployments.
backend.config.corsAllowedOrigins string "" Additional CORS origins, comma-separated.
backend.config.devVerificationCode string "" Fixed local test verification code. Keep empty in production.
backend.config.frontendOrigin string "http://localhost:3000" Public frontend origin. Required for production links, cookies, CORS, and WebSocket origin checks.
backend.config.jwtSecret string "change-me-in-production" JWT signing secret. Replace in production or use jwtSecretRef.
backend.config.jwtSecretRef.key string "" Secret key for JWT_SECRET.
backend.config.jwtSecretRef.name string "" Existing secret containing JWT_SECRET.
backend.config.metricsAddr string "" Prometheus metrics listener, e.g. 127.0.0.1:9090. Empty disables it.
backend.config.port int 8080 Backend bind port.
backend.config.posthogApiKey string "" PostHog API key when analytics are enabled.
backend.config.posthogHost string "https://us.i.posthog.com"  
backend.config.realtimeMetricsToken string "" Token required to expose /health/realtime through a proxy.
backend.config.realtimeMetricsTokenRef.key string "" Secret key for REALTIME_METRICS_TOKEN.
backend.config.realtimeMetricsTokenRef.name string "" Existing secret containing REALTIME_METRICS_TOKEN.
backend.deployment.progressDeadlineSeconds int 600 Time in seconds for the Deployment controller to wait before marking a rollout failed.
backend.deployment.strategy.type string "Recreate" Deployment strategy. Recreate avoids RWO upload PVC multi-attach deadlocks.
backend.email.resendApiKey string "" Resend API key. When empty, Multica prints verification codes to stdout.
backend.email.resendApiKeyRef.key string "" Secret key for RESEND_API_KEY.
backend.email.resendApiKeyRef.name string "" Existing secret containing RESEND_API_KEY.
backend.email.resendFromEmail string "noreply@multica.ai" Sender address for verification emails.
backend.envFrom list [] Extra backend envFrom refs.
backend.extraEnv list [] Extra backend env vars. Managed env names are rejected to avoid silent overrides.
backend.google.clientId string "" Google OAuth client ID.
backend.google.clientIdRef.key string "" Secret key for GOOGLE_CLIENT_ID.
backend.google.clientIdRef.name string "" Existing secret containing GOOGLE_CLIENT_ID.
backend.google.clientSecret string "" Google OAuth client secret.
backend.google.clientSecretRef.key string "" Secret key for GOOGLE_CLIENT_SECRET.
backend.google.clientSecretRef.name string "" Existing secret containing GOOGLE_CLIENT_SECRET.
backend.google.redirectUri string "http://localhost:3000/auth/callback" Google OAuth redirect URI.
backend.image.pullPolicy string "IfNotPresent" Backend image pull policy.
backend.image.repository string "ghcr.io/multica-ai/multica-backend" Backend image repository.
backend.image.tag string "" Backend image tag override. Defaults to chart appVersion.
backend.nodeSelector object {} Backend node selector.
backend.podAnnotations object {} Pod annotations for backend pods.
backend.podLabels object {} Pod labels for backend pods.
backend.podSecurityContext object {} Pod security context for backend pods.
backend.replicaCount int 1 Number of backend replicas.
backend.resources object {} Backend resources.
backend.securityContext object {} Container security context for the backend container.
backend.service.annotations object {} Backend Service annotations.
backend.service.nodePort string nil Optional nodePort when service.type is NodePort/LoadBalancer.
backend.service.port int 8080 Backend Service port.
backend.service.targetPort int 8080 Backend container port.
backend.service.type string "ClusterIP" Backend Service type.
backend.tolerations list [] Backend tolerations.
backend.volumeMounts list [] Additional backend volume mounts.
backend.volumes list [] Additional backend volumes.
database.external.enabled bool false Enable external PostgreSQL mode. When enabled, set postgres.enabled=false.
database.external.host string "" External PostgreSQL host. Required for waitForReady when using urlFrom; optional with url because the chart can derive the host from the URL.
database.external.name string "multica" External PostgreSQL database name.
database.external.password string "" External PostgreSQL password.
database.external.port int 5432 External PostgreSQL port.
database.external.sslMode string "disable" SSL mode appended to generated DATABASE_URL.
database.external.url string "" Full PostgreSQL connection URL.
database.external.urlFrom.secretKeyRef object {"key":"","name":""} Existing secret containing DATABASE_URL.
database.external.username string "" External PostgreSQL username.
database.internal.port int 5432 Internal PostgreSQL service port.
database.internal.serviceName string "" Override internal PostgreSQL service name. Defaults to <release>-postgres.
database.waitForReady.enabled bool true Wait for PostgreSQL TCP readiness before starting the backend.
database.waitForReady.image string "busybox:1.37" Init container image used for DB readiness checks.
database.waitForReady.imagePullPolicy string "IfNotPresent" Init container image pull policy.
database.waitForReady.periodSeconds int 2 Poll interval in seconds.
database.waitForReady.timeoutSeconds int 180 Max seconds to wait for DB readiness.
frontend.affinity object {} Frontend affinity.
frontend.autoscaling.enabled bool false Enable frontend HPA.
frontend.autoscaling.maxReplicas int 5 Maximum frontend replicas.
frontend.autoscaling.minReplicas int 1 Minimum frontend replicas.
frontend.autoscaling.targetCPUUtilizationPercentage int 80 Target CPU utilization percentage.
frontend.autoscaling.targetMemoryUtilizationPercentage string nil Target memory utilization percentage.
frontend.backendServiceAlias.annotations object {} Compatibility Service annotations.
frontend.backendServiceAlias.enabled bool true Create a Service named backend because upstream multica-web images bake Next.js rewrites to http://backend:8080.
frontend.backendServiceAlias.name string "backend" Compatibility Service name.
frontend.envFrom list [] Extra frontend envFrom refs.
frontend.extraEnv list [] Extra frontend env vars. The official image bakes API rewrites at build time; use these only for custom images or generic runtime config.
frontend.image.pullPolicy string "IfNotPresent" Frontend image pull policy.
frontend.image.repository string "ghcr.io/multica-ai/multica-web" Frontend image repository.
frontend.image.tag string "" Frontend image tag override. Defaults to chart appVersion.
frontend.nodeSelector object {} Frontend node selector.
frontend.podAnnotations object {} Pod annotations for frontend pods.
frontend.podLabels object {} Pod labels for frontend pods.
frontend.podSecurityContext object {} Pod security context for frontend pods.
frontend.replicaCount int 1 Number of frontend replicas.
frontend.resources object {} Frontend resources.
frontend.securityContext object {} Container security context for the frontend container.
frontend.service.annotations object {} Frontend Service annotations.
frontend.service.externalTrafficPolicy string nil External traffic policy.
frontend.service.loadBalancerIP string nil Optional LoadBalancer IP.
frontend.service.loadBalancerSourceRanges list [] Optional CIDRs allowed via LoadBalancer.
frontend.service.nodePort string nil Optional nodePort when service.type is NodePort/LoadBalancer.
frontend.service.port int 80 Frontend Service port.
frontend.service.targetPort int 3000 Frontend container port.
frontend.service.type string "ClusterIP" Frontend Service type.
frontend.tolerations list [] Frontend tolerations.
fullnameOverride string "" Override fully-qualified release name.
httpRoute.annotations object {} HTTPRoute annotations.
httpRoute.enabled bool false Enable Gateway API HTTPRoute for the frontend.
httpRoute.hostnames list [] Optional HTTPRoute hostnames.
httpRoute.matches list [{"path":{"type":"PathPrefix","value":"/"}}] Match rules for HTTPRoute.
httpRoute.parentRefs list [] ParentRefs for HTTPRoute. Required when enabled.
imagePullSecrets list [] Shared image pull secrets.
ingress.annotations object {} Ingress annotations.
ingress.className string "" IngressClass name.
ingress.enabled bool false Enable Ingress for the frontend.
ingress.hosts list [] Ingress hosts and paths.
ingress.tls list [] Ingress TLS entries.
livenessProbe.backend.failureThreshold int 6  
livenessProbe.backend.httpGet.path string "/health"  
livenessProbe.backend.httpGet.port string "http"  
livenessProbe.backend.initialDelaySeconds int 10  
livenessProbe.backend.periodSeconds int 10  
livenessProbe.backend.successThreshold int 1  
livenessProbe.backend.timeoutSeconds int 3  
livenessProbe.frontend.failureThreshold int 6  
livenessProbe.frontend.httpGet.path string "/"  
livenessProbe.frontend.httpGet.port string "http"  
livenessProbe.frontend.initialDelaySeconds int 10  
livenessProbe.frontend.periodSeconds int 10  
livenessProbe.frontend.successThreshold int 1  
livenessProbe.frontend.timeoutSeconds int 3  
nameOverride string "" Override chart name.
postgres.auth.database string "multica"  
postgres.auth.password string "multica"  
postgres.auth.username string "multica"  
postgres.enabled bool true  
postgres.image.imagePullPolicy string "IfNotPresent"  
postgres.image.repository string "pgvector/pgvector"  
postgres.image.tag string "pg17"  
postgres.persistence.enabled bool true  
postgres.persistence.size string "8Gi"  
readinessProbe.backend.failureThreshold int 6  
readinessProbe.backend.httpGet.path string "/readyz"  
readinessProbe.backend.httpGet.port string "http"  
readinessProbe.backend.initialDelaySeconds int 10  
readinessProbe.backend.periodSeconds int 10  
readinessProbe.backend.successThreshold int 1  
readinessProbe.backend.timeoutSeconds int 3  
readinessProbe.frontend.failureThreshold int 6  
readinessProbe.frontend.httpGet.path string "/"  
readinessProbe.frontend.httpGet.port string "http"  
readinessProbe.frontend.initialDelaySeconds int 5  
readinessProbe.frontend.periodSeconds int 10  
readinessProbe.frontend.successThreshold int 1  
readinessProbe.frontend.timeoutSeconds int 3  
serviceAccount.annotations object {} Service account annotations.
serviceAccount.create bool true Create a service account for Multica pods.
serviceAccount.name string "" Service account name.
storage.local.baseUrl string "" Public base URL for local uploads. Empty returns relative /uploads/... paths.
storage.local.persistence.accessModes list ["ReadWriteOnce"] PVC access modes.
storage.local.persistence.annotations object {} PVC annotations.
storage.local.persistence.enabled bool true Persist local uploads with a PVC. Use S3 for multi-replica production deployments.
storage.local.persistence.existingClaim string "" Existing PVC name.
storage.local.persistence.size string "10Gi" PVC size.
storage.local.persistence.storageClass string "" PVC storage class.
storage.local.uploadDir string "/app/data/uploads" Local upload directory inside the backend container.
storage.s3.accessKeyId string "" AWS access key ID.
storage.s3.accessKeyIdRef.key string "" Secret key for AWS_ACCESS_KEY_ID.
storage.s3.accessKeyIdRef.name string "" Existing secret containing AWS_ACCESS_KEY_ID.
storage.s3.bucket string "" S3 bucket. When set, Multica uses S3-compatible storage instead of local disk for uploads.
storage.s3.cloudfrontDomain string "" CloudFront domain for signed/download URLs.
storage.s3.cloudfrontKeyPairId string "" CloudFront key pair ID.
storage.s3.cloudfrontPrivateKey string "" CloudFront private key.
storage.s3.cloudfrontPrivateKeyRef.key string "" Secret key for CLOUDFRONT_PRIVATE_KEY.
storage.s3.cloudfrontPrivateKeyRef.name string "" Existing secret containing CLOUDFRONT_PRIVATE_KEY.
storage.s3.cloudfrontPrivateKeySecret string "" AWS Secrets Manager secret name for CLOUDFRONT_PRIVATE_KEY.
storage.s3.endpointUrl string "" S3-compatible endpoint URL, e.g. MinIO/R2/Wasabi.
storage.s3.region string "us-west-2" S3 region.
storage.s3.secretAccessKey string "" AWS secret access key.
storage.s3.secretAccessKeyRef.key string "" Secret key for AWS_SECRET_ACCESS_KEY.
storage.s3.secretAccessKeyRef.name string "" Existing secret containing AWS_SECRET_ACCESS_KEY.
tests.enabled bool true Enable Helm test pod.
tests.image.pullPolicy string "IfNotPresent" Test image pull policy.
tests.image.repository string "busybox" Test image repository.
tests.image.tag string "1.37" Test image tag.