Autonomize · Genesis Downloads

Genesis Downloads · Platform values

Platform values configuration

A production genesis-platform values file runs to several hundred lines, but roughly fifty values are actually environment-specific. Define those once as YAML anchors at the top; everything below references them. This page separates the values you must change from the ones you should leave alone.

Values, not secrets Nothing on this page is a credential. Every password, key and token reaches the platform through ai-studio-secrets — see Secrets management. What lives in the values file is where things are: hostnames, registry, vault URL, deployment names. If you find yourself typing a secret into this file, it belongs in your vault instead.

How the file is shaped

Three parts, in this order. Understanding the split is what keeps the file maintainable.

BlockContainsHow often you touch it
x-common Anchor definitions only — every environment-specific fact, declared once Every new environment. This is the block you edit
global Cross-service settings: routing, database, redis, secrets, identity. Mostly aliases into x-common Rarely — only to change a platform-wide behaviour
genesis-* One block per service: waves, databases, env vars, probes, tolerations Rarely — only to enable a feature or diverge one service
Nothing reads x-common The x-common key is not a chart value — Helm ignores it. It exists purely to hold anchors, so a fact is stated once and aliased everywhere it applies. That gives you a useful escape hatch: to diverge a single service, replace its alias with a literal and leave every other reference on the anchor.

The pattern looks like this:

x-common:
  routingHost: &routingHost "genesis.<env>.<your-domain>"

global:
  routing:
    mode: gateway-api
    host: *routingHost          # alias — follows the anchor

genesis-idp:
  extraEnv:
    - name: KC_HOSTNAME
      value: *keycloakExternalUrl

Tier 1 — must change for every environment

If you copy a values file and change nothing else, change these. Every one is a fact about your infrastructure, and a stale value here fails the install or silently points the platform at someone else's environment.

Environment identity — 7 values

AnchorShapeWhat it drives
routingHostgenesis.<env>.<your-domain>The single ingress host. Keycloak's issuer is derived from it, so getting this wrong breaks auth everywhere
baseUrlhttps://<routingHost>The https:// form. YAML cannot build it from routingHost, so it is stated separately — change both together
keycloakExternalUrlhttps://<routingHost>/authBrowser-facing Keycloak base
ccFePublicUrlhttps://<routingHost>/command-centerCommand Center frontend
tenantMgmtPublicUrlhttps://<routingHost>/tenant-mgmtTenant-management UI
temporalCodecUrlhttps://<routingHost>/studio/temporal/codecPayload codec for the Temporal UI
feRedirectUrislist: https://<routingHost>/*Keycloak client redirect allow-list. A stale entry here is an auth loop with no useful error
Six of these are just routingHost with a suffix YAML cannot concatenate strings, so each public URL restates the host in full. When the environment moves, all seven change together — and a search-and-replace on the old hostname is the reliable way to do it. One missed entry usually surfaces as a redirect failure rather than a startup error.

Routing, ingress and environment — 5 values

These sit in global rather than x-common, and every chart default here is a local-development placeholder.

ValueChart defaultSet it to
global.environment"development"One of development, sprint, dev, integration, production. Easy to leave on development in a UAT or production environment, because nothing enforces it
global.routing.mode"single-host"gateway-api if you route with Gateway API, otherwise single-host
global.routing.host"ai-studio.local.dev"*routingHost — alias it, don't restate it
global.ingress.classNamenginxYour controller: alb for Application Gateway for Containers, gce for GKE Gateway, nginx for ingress-nginx
global.ingress.tlsSecretNameunsetThe Secret holding your TLS certificate
global.ingress.enabled defaults to false The chart ships enabled: false with className: nginx and an empty host. If you route through Gateway API you leave ingress off deliberately; if you expect an Ingress and never set enabled: true, the platform comes up with no external route and nothing reports it as an error.

Container registry — 3 values

AnchorShapeNotes
imageRegistry<your-registry>The registry holding every service image
initImage<your-registry>/curl:8.5.0Wait-for and Keycloak-setup init container. Needs curl and a shell
dbInitImage<your-registry>/postgres:16Schema-creation init container. Pin a real tag — :latest works but makes the init step irreproducible across syncs
The registry appears inside three longer strings initImage and dbInitImage embed the registry host in a full image reference, and YAML cannot interpolate one anchor into another. Changing imageRegistry alone leaves both init images pointing at the previous registry, which fails as an ImagePullBackOff on an init container — so the pod never starts and the real service logs nothing. Change all three in one edit. Some charts embed it a fourth time in an image repository field; grep for the old host before you sync.

PostgreSQL — 8 values

AnchorShapeNotes
dbHost<your-server>.postgres.database.azure.comYour managed Postgres endpoint
dbPort5432 (integer)Used by global.database.port
dbPortStr"5432" (string)Used by env vars. Not interchangeable with dbPort
dbUsername<admin-login>Server admin login
dbAuthMethodpassword or managed identityFlip here to move the whole platform between auth modes
dbMigrateUser<migrate-role>The role Alembic runs migrations as
dbAiStudioai_studioShared database for backend, runtime, workers, connectors
dbAuthzgenesis_authzDatabase for authz and the OpenFGA store

The last two are database names. They only need changing if your naming convention differs — but they must match the databases preflight created.

Redis — 7 values, and the tier decides them

Two are anchors; the rest sit in global.redis. They are all Tier 1 because the Redis tier you provisioned as a prerequisite determines every one of them, and the chart's defaults match only the simplest case.

ValueChart defaultSet it from
redisHost (anchor) → global.redis.host""Your instance's endpoint
redisAuthMethod (anchor)passwordAccess-key auth. A separate fact from dbAuthMethod — they need not agree
global.redis.port6379Your endpoint. See the table below — the default is correct on AWS and in-cluster, wrong on Azure and GCP
global.redis.tlsfalsetrue for any managed instance. Prerequisites require TLS in transit
global.redis.sslVerify"false"Whether to verify the server certificate. A string, not a boolean
global.redis.modeunsetstandalone or cluster. Not in the chart defaults at all, so a clustered instance needs it added explicitly
global.redis.db—Logical database index. Clustered Redis supports only 0
The chart default contradicts the prerequisite The chart ships tls: false and sslVerify: "false", while prerequisites ask for auth plus TLS in transit. Those two are wrong for every managed product — leave them and the platform talks plaintext to a TLS-only endpoint.
The port default is subtler: 6379 is correct for AWS ElastiCache and for in-cluster Redis, and wrong for both Azure products and GCP. So do not reason from “TLS means not 6379” — take the port from the table below.

Values by product, each taken from a working deployment. The endpoint tells you which row you are on — the two Azure Redis products in particular are different services with different ports, and picking the wrong row is the most common Redis misconfiguration.

ProductHost suffixPorttlsmode
In-cluster Redis — dev only (the chart default) service DNS 6379 false unset
AWS ElastiCache, transit encryption on .cache.amazonaws.com 6379 true standalone
Azure Cache for Redis (classic) .redis.cache.windows.net 6380 true standalone
Azure Managed Redis (Microsoft.Cache/redisEnterprise) .redis.azure.net 10000 true cluster
GCP Memorystore, TLS enabled private IP 6378 true standalone
The two Azure products are not interchangeable .redis.cache.windows.net:6380 is classic Azure Cache for Redis. .redis.azure.net:10000 is Azure Managed Redis, a different resource type. If you provisioned the enterprise tier and copied the classic port — or the reverse — the connection fails at startup. Match the port to the host suffix your endpoint actually has. Clustered instances also require db: 0; no other index is supported.
And note the reverse trap: AWS ElastiCache serves TLS on 6379, the same port as plaintext Redis. On AWS the port stays at the default and only tls changes, so a “the port looks like the default, TLS must be off” reading is wrong there.

The reference customer values file starts at port: 6380, tls: true, auth: true — one managed shape, not the only one. Change the port to match your own endpoint. Leave enabled: true: the platform degrades badly without Redis, which handles sessions, rate limiting and SSE streaming.

These chart values take Redis as host plus port. If you are also setting the CLI's own config, that takes a rediss:// URL instead and has its own formatting trap — see the Redis notes in the install guide.

A privately-issued Redis CA needs one more value If your Redis presents a certificate from a private CA, supplying it via global.redis.caCert while sslVerify is on is caught at render time and fails the sync — deliberately. The gateway's rate-limit config is rendered by a subchart that derives verification from sslVerify alone, so it would verify against its image's system trust store, fail, and silently stop counting daily API quotas. The guard exists because that failure is invisible. Resolve it as the error message directs — either let the umbrella render that config so global.redis.gatewaySslVerify takes effect, or turn sslVerify off.

Secrets and workload identity — 4 values

AnchorShapeNotes
keyVaultUrlhttps://<your-vault>.vault.azure.net/The vault the ExternalSecret pulls from
secretNameai-studio-secretsThe Secret the ExternalSecret writes and every service reads. Rarely changed — but if you do, it must change everywhere
serviceAccountName<your-sa>A pre-existing ServiceAccount, created outside the chart (create: false), carrying the workload-identity annotations
azureClientId / azureTenantIdGUIDsWorkload-identity federation. Annotation-only, and inert while the ServiceAccount is create: false

Cloud service endpoints — 5 values

AnchorShapeNeeded when
azOpenAiEndpointhttps://<your-openai>.openai.azure.com/Azure OpenAI is your LLM backend
azSearchEndpointhttps://<your-search>.search.windows.netAzure AI Search is your vector store
azDocIntelEndpointhttps://<your-cognitive>.cognitiveservices.azure.com/Document Intelligence handles OCR
storageAccount<your-storage-account>Object storage. Not the same fact as imageRegistry, even when the names look alike
storageContainer<container>The container inside that account
Also change your OTLP endpoint otelHttpEndpoint points at your trace collector. It is easy to leave pointing at a shared or previous environment's collector, which is not an error — traces simply land somewhere you are not looking.

Tier 2 — must be internally consistent

These are not environment identity, so a copied file often "works". But they encode a contract between values, and a mismatch fails at runtime rather than at install.

AnchorShapeThe constraint
llmProviderazure_openaiSets the default and primary provider, and the retrieval provider. One value, several consumers
azOpenAiApiVersione.g. 2025-01-01-previewMust be an API version your Azure OpenAI resource actually serves
azEmbeddingDeploymenttext-embedding-3-smallA deployment name in your resource, not a model name
vectorSize"1536" for text-embedding-3-smallMust equal the embedding model's dimension. A mismatch is accepted at install and then fails on every write to the vector store
genesisEmbeddingsModele.g. BAAI/bge-large-en-v1.5Served by the embeddings service. The service's MODEL_ID and every client must name the same model
modelGpt41, modelGpt41Mini, …deployment namesEach names one deployment that must exist in your resource. Anchored per model, not per role, so every reference moves together
builderModel<provider>:<model>A compound value. YAML cannot build it from the provider and model anchors, so it must be updated by hand when either changes

The Postgres capacity gate

global.capacityGate is the one Tier 2 value that fails the render rather than failing later. It declares how many pods will consume the database, and the chart asserts your declaration against the footprint it actually renders.

ValueChart defaultChange it when
expectedApiPods4Your API replica counts differ from the subchart defaults (genesis-be 2 + genesis-be-runtime 2)
expectedWorkerPods2You enable or disable worker variants — the per-profile io / mixed / cpu splits are off by default and each one you enable joins the sum
externalDbConsumers55You share the database with services beyond the platform. The default covers Temporal (~40 connections) and Keycloak's pool (~15)

The floor it enforces at pod startup:

floor = (expectedApiPods    × api_ceiling)
      + (expectedWorkerPods × worker_ceiling)
      + externalDbConsumers
      + 23 reserved
It runs on every sync, and it is strict The assertion runs at every helm template, helm install and ArgoCD sync, and refuses to render when your declared numbers diverge from the rendered footprint. That is deliberate: it catches drift inside your cluster rather than in our CI, which matters when you overlay your own values onto the shipped chart. If you enable autoscaling you must raise these to the maxReplicas peak summed across enabled subcharts — not the steady-state count. And if you add your own subchart that consumes either pool, add it to apiShapeCharts or workerShapeCharts, or the gate will not count it.
Deployment names are the most common silent failure A deployment name that does not exist in your Azure OpenAI resource does not fail the install — nothing validates it. The platform comes up healthy and every model call returns a 404 from the provider. Confirm each distinct deployment name exists before the first sync, including any that only one service uses.

Tier 3 — leave these alone

Values that look environment-specific but are not. Editing them is how a working file starts drifting.

ValueWhy it stays
In-cluster service URLs — http://genesis-authz:8000, http://genesis-kc:8000/kc/api/v1, http://genesis-embeddings:7997Kubernetes service DNS, fixed by the charts. They are not environment identity, and rewriting them to public URLs routes internal traffic out through your gateway and back
Gateway upstreamsSame reasoning — they name in-cluster services
deploymentOrder.waveEncodes the real startup dependency order. Services init-wait on Keycloak and on each other; reordering causes timeouts that look like unrelated failures
Probe paths and thresholdsTuned to each service's real startup time. A long startupProbe.failureThreshold is deliberate, not a leftover
Feature flags — KAFKA_ENABLED, OTEL_EVENTHUB_ENABLED, APIM_ENABLEDOff by default. Turning one on requires its own configuration and its vault keys; flipping the flag alone gets you a service that fails to reach a backend that was never set up
enabled: false on unused servicesDeliberately off. Enabling one pulls in its dependencies and its required secret keys
Rate limits, replica counts, resource requestsSized for a working deployment. Change them for capacity reasons, not as part of environment setup

YAML behaviours that cost real time

Each of these has produced a failure that looked like something else.

Dotted keys are not paths Writing a.b.c: value does not set the nested key a → b → c. Helm reads it as a single key literally named a.b.c, finds nothing expecting it, and ignores it silently. There is no warning and no error — your setting simply never applies. Always write the nesting out.
Anchors cannot be composed YAML has no string interpolation. You cannot build https://<host>/path from a host anchor, and you cannot build <registry>/curl:8.5.0 from a registry anchor. Every compound value restates its parts in full, which is why the public URLs, the init images and builderModel all have to be changed alongside the anchor they appear to derive from.
Integer and string forms are distinct A port used as a chart value is an integer; the same port used in an environment variable must be a string. That is why two anchors exist for one number. Passing the integer where the string is expected fails schema validation at render; passing the string where the integer is expected can render and then fail at connect time.
Merge keys keep the worker family in sync Where several services differ in only a few keys, a shared block is anchored and pulled in with <<:, and each variant states only its differences. Add a shared setting to the base block, not to each variant — and remember an explicit key in a variant overrides the merged one.
x-common:
  devWorkerBase: &devWorkerBase
    enabled: true
    replicaCount: 2
  devWorkerEnv: &devWorkerEnv
    REDIS_ENABLED: "true"
    DEFAULT_PROVIDER: *llmProvider

genesis-dev-worker-io:
  <<: *devWorkerBase          # everything shared
  env:
    <<: *devWorkerEnv         # shared env
    WORKER_PROFILES: "io"     # ...then only what differs
An explicit env var beats the shared Secret A service's own env entry overrides the same name arriving via envFrom on the platform Secret. That is occasionally intended — but it also means a leftover literal in a service block can quietly shadow the value your vault is supplying.

Decisions to record, not copy

Some values are neither environment identity nor a safe default — they are open questions that a copied file carries forward invisibly. Mark them in your own file (a consistent # ACTION: comment works well) so they can be searched for and closed.

PatternWhy it needs a decision
A URL pointing at another environmentPerfectly valid YAML, and it resolves. Shared or upstream services are sometimes deliberately cross-environment — but a copied file is the usual reason, and it is worth confirming which
Placeholder tokensA dummy bearer token renders and deploys. The dependent feature then fails on first use, well after the install is declared green. Either supply the real value through your vault or disable the feature
Object-storage settings left unsetAccount and container are set, but the storage-type selector is not, so the service falls back to a local path. Nothing errors; files just do not land where you expect
Hard-coded identifiers inside a URLA client or copilot id embedded in a base URL is environment-specific in a place nobody looks. Pull it into an anchor so it is visible
A secret mapping pinned to a subsetTrimming secrets.data to the keys your vault holds is a legitimate way to avoid an all-or-nothing sync failure — but every reference you drop must stay optional: true on the consuming service. See Secrets management
A localhost origin in a CORS allow-listUseful in development, and it should not reach production
Never a credential API keys, client secrets and connection strings do not belong in a values file at any tier. A values file is normally committed to git, where a secret survives in history even after it is deleted — so the only real remedy is to rotate it. Keep credentials in your vault and reference them by name.

Before the first sync

CheckWhat it catches
Grep the file for the previous environment's hostname, registry and resource names — expect zero hitsThe single highest-yield check. Compound values that restate an anchor are exactly what a partial rename leaves behind
All three registry-bearing values name the same registryImagePullBackOff on an init container, where the service itself logs nothing
Every Azure OpenAI deployment name exists in the resourceA healthy platform whose model calls all 404
vectorSize matches the embedding model's dimensionVector writes failing after a clean install
The redirect allow-list contains the new hostAn auth redirect loop with no useful error
Vault URL, ServiceAccount name and workload-identity ids are yoursAn ExternalSecret that never syncs, so every pod sits in CreateContainerConfigError
Redis port matches your endpoint, and tls is ontls: false is wrong for every managed product. The port varies: 6379 on AWS, 6380 or 10000 on the two Azure products, 6378 on GCP
global.environment is not still developmentNothing enforces it, so it silently ships
global.ingress.className matches your controller, or ingress is off on purposeA platform with no external route and no error
capacityGate numbers match your replica counts and autoscaling peaksA render that refuses to sync — the one failure here that is loud
No dotted keys — search for . in key positionSettings that are silently ignored
No credentials anywhere in the fileA secret committed to git history
Every open decision is marked and triagedCross-environment URLs and placeholder tokens shipping to production

helm template with your values catches schema errors and renders the manifests, but none of the checks above — each one is valid YAML that renders cleanly and fails later.


See also

Secrets management

Every key ai-studio-secrets needs, the vault mapping, and per-cloud SecretStore configuration.

Deployment models

How this values file is delivered — ArgoCD multi-source, with values held in your own git repo.

Prerequisites

The Postgres, Redis, DNS, TLS and registry facts this file names must exist first.