Genesis publishes Helm charts to Docker Hub (
oci://registry-1.docker.io/genesiscomputingai/genesis), ECR (oci://<account>.dkr.ecr.<region>.amazonaws.com/charts/genesis), and GHCR (oci://ghcr.io/genesis-computing-ai/charts/genesis). Docker Hub and ECR credentials are provided during onboarding; GHCR access uses a GitHub PAT with read:packages.Operator bundle (local-k8s/): The bundled deploy-local.sh flow is ECR-only — both the container image and the Helm chart come from your private Amazon ECR registry. There is no public image and no local unpacked Chart.yaml; set GENESIS_HELM_CHART_OCI in local-config.env to the helm.chart_url value from your Genesis credential bundle. See Operator bundle (ECR + OCI) below.Unpacked chart directory: You can still pull and unpack an OCI chart (or use a chart archive) and run helm install from a directory that contains Chart.yaml. That path supports GHCR or Docker Hub when ecr.enabled is disabled.Table of Contents
- Prerequisites
- Operator bundle (ECR + OCI)
- Initial Setup
- Quick Start
- Step-by-Step Deployment
- Accessing Genesis
- Port Forwarding
- PVC data backups (local)
- Troubleshooting
- Appendix
Prerequisites
Required Software
-
Docker Desktop (with Kubernetes enabled)
- Download: https://www.docker.com/products/docker-desktop/
- Enable Kubernetes: Docker Desktop → Settings → Kubernetes → Enable Kubernetes
- Verify:
kubectl cluster-info
-
kubectl (Kubernetes command-line tool)
- Usually included with Docker Desktop
- Verify:
kubectl version --client - Install separately: https://kubernetes.io/docs/tasks/tools/
-
Helm 3.8+ (Kubernetes package manager)
- macOS:
brew install helm - Linux:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash - Windows:
choco install kubernetes-helm - Verify:
helm version
- macOS:
-
Network Access
- Operator bundle (
deploy-local.sh): Requires Helm. Its default ECR mode also requires AWS CLI v2, IAM keys that can pull from the privategenesisECR repository, outbound HTTPS to ECR, and Helm 3.8+ for OCI chart install. SetIMAGE_SOURCE=ghcrto use an image from GHCR instead; that mode requires a GitHub token withread:packagesaccess,curl, and Python 3 for registry preflight. IfGENESIS_HELM_CHART_PATHis not set, it also uses Git to fetch the chart ref. - Unpacked chart: Ability to pull images from the registry configured for your bundle. Raw Helm installs can use the GHCR fallback only if
ecr.enabledis disabled.
- Operator bundle (
Operator bundle (ECR or GHCR)
Thelocal-k8s/ operator bundle deploys Genesis with OIDC/Auth0 only (you sign in before using Genesis). By default, the container image and Helm chart come from your private ECR registry. To deploy a release candidate image published to GitHub’s Container Registry (GHCR), opt in with IMAGE_SOURCE=ghcr; that mode gets the image from ghcr.io/genesis-computing-ai/genesis and uses a chart directory from this repository or a path you provide.
For the default ECR mode, you need a credential bundle (YAML) from Genesis Computing with ECR registry URL, IAM pull keys, a license key, and Helm hints (helm.image_repository, helm.chart_url). Field names match credentials-bundle.example.yaml in the bundle folder.
For ECR mode, set
image.tag in local-values.yaml to a tag that exists in the ECR repository genesis (or override once with IMAGE_TAG in the shell).
For GHCR mode, set IMAGE_SOURCE=ghcr and select the image tag with IMAGE_TAG or image.tag in local-values.yaml. Authenticate either by setting both GHCR_TOKEN and GHCR_USERNAME (the GitHub user the token belongs to), or by using a GitHub CLI login with read:packages access (gh auth refresh -h github.com -s read:packages). Without the explicit GHCR_TOKEN, the script uses the GitHub CLI login; it can determine the username from that login. Set GENESIS_HELM_CHART_GIT_REF to choose the repository ref for the chart (defaults to the resolved image tag), or set GENESIS_HELM_CHART_PATH to use a chart directory instead. For example:
ghcr-pull-secret in the genesis namespace so Kubernetes can pull the image. It keeps the secret while deploying from GHCR; after a successful ECR deployment, it deletes that secret.
What deploy-local.sh does:
- Registry preflight — ECR mode uses
aws ecr describe-imagesto verify the tag in${ECR_REPO_NAME:-genesis}; GHCR mode verifies the tag is readable from GHCR. - Chart and registry access — ECR mode logs Helm in to
ECR_REGISTRYfor the OCI chart atGENESIS_HELM_CHART_OCI. GHCR mode uses its selected chart directory and creates theghcr-pull-secretfor Kubernetes image pulls. helm upgrade --install— Installs/upgrades with--reset-values; ECR mode also supplies a freshecr.tokenand optionalGENESIS_HELM_CHART_VERSION.- PVC backups — When
genesis-0is Running, runs./backup-genesis.shto stream PVC data to./backups/*.tgzbefore and after deploy (see PVC data backups (local)). - Post-upgrade pod delete — Deletes
genesis-0once after upgrade (PVC unchanged) unlessGENESIS_SKIP_POST_UPGRADE_POD_DELETE=1.
service.type: LoadBalancer on port 9090 (avoids conflict with local genesis start on 8080). Access at http://localhost:9090 after deploy.
System Requirements
- CPU: 4+ cores recommended
- Memory: 8GB+ RAM (Docker Desktop should allocate at least 4GB)
- Disk: 20GB+ free space
- OS: macOS, Windows, or Linux
Initial Setup
Working from the Chart Package or OCI Registry
If you are starting from the OCI chart instead of a bundle, authenticate with your registry first, then pull and unpack the chart so the rest of this guide can use a local chart directory:Chart releases are published from
main. On each GA release, Genesis updates appVersion in Chart.yaml to the promoted container version and patch-bumps the chart version automatically. To find the chart version for a specific GA release, query the GA_HELM_MAP repo variable: gh variable get GA_HELM_MAP -R genesis-computing-ai/genesis-agents | jq -r '.["vX.Y.Z"]'.Verify Chart Structure
Quick Start
For experienced users, here’s the minimal setup (run all commands from the helm chart directory):Step-by-Step Deployment
Step 1: Verify You’re in the Correct Directory
Important: All subsequent commands assume you’re working from the helm chart directory.Chart.yaml (the folder you extracted or were given).
Step 2: Verify Kubernetes Cluster
Check Current Context
If you have multiple Kubernetes clusters configured (e.g., AKS, EKS, GKE, or multiple local clusters), you need to ensure you’re using the correct context for your local Docker Desktop cluster.* indicates your current context. If it’s not pointing to your local Docker Desktop cluster, switch contexts:
Switch to Docker Desktop Context
docker-desktopdocker-for-desktopdocker-for-desktop-clusterdesktop-docker
docker in the name from the kubectl config get-contexts output.
Verify Cluster is Running
If you see errors: Ensure Kubernetes is enabled in Docker Desktop (Settings → Kubernetes → Enable Kubernetes). Wait a few minutes after enabling Kubernetes for it to fully start. Try restarting Docker Desktop if the cluster won’t start.
Step 3: Install NGINX Ingress Controller
Docker Desktop doesn’t include an ingress controller by default. Install NGINX Ingress:Step 4: Verify Storage Class
Check available storage classes:hostpath storage class. The Helm chart will use it automatically.
Step 5: Create Local Values File
Important: Use or createlocal/local-values.yaml in the local/ directory (under the helm chart directory).
You can either:
- Copy and modify the existing
local/local-values.yamlif it exists - Create a new
local/local-values.yamlfile
local/local-values.yaml:
PriorityClass by default. The default
priorityClass settings are:
The generated class name includes the release namespace and release name, so multiple Genesis
releases can coexist on one cluster. To enable the chart-managed class, set
priorityClass.create: true. This is best suited to a cluster dedicated to Genesis; on a
shared cluster, the resulting priority can make Genesis the preferred survivor over other
teams’ workloads. To reference a class that the cluster already defines, leave
priorityClass.create: false and set priorityClass.name to that class’s name.
With priorityClass.create: true, priorityClass.preemptionPolicy: Never remains the
conservative default: the backend can schedule ahead of lower-priority Pods, but it cannot
evict them to make room. Set priorityClass.preemptionPolicy: PreemptLowerPriority only when
that eviction behavior is intentional.
When a provider credential is supplied through the chart, the chart seeds the
corresponding unset AppConfig fields: Databricks credentials select
ACTIVE_LLM_PROVIDER=databricks; OpenAI
credentials select ACTIVE_LLM_PROVIDER=openai, or azureopenai when
azureOpenaiEndpoint is set. config.modelName seeds
the provider-specific main and premier model, while config.fastModelName
defaults to config.modelName when supplied and config.harvesterModel seeds
the provider-specific harvester model. Saved configuration and
genesisConfig values take precedence; use config.extraEnv.ACTIVE_LLM_PROVIDER
or the provider-specific GENESIS__* overrides when a deployment must seed or
pin an identity explicitly.
For a provider detected from the chart credentials or API-key settings, Helm
also sets the matching DATABRICKS_ENABLED, OPENAI_ENABLED, or
AZURE_OPENAI_ENABLED variable to true unless that key is set in
config.extraEnv. This keeps the provider recognized as configured by images
through v1.19.95; newer images ignore the switch and log a warning. For
images v1.19.92 through v1.19.95, chart versions 0.3.100–0.3.103 do
not set this switch, so providers configured only through Helm values may be
reported as unconfigured; use chart 0.3.104 or newer. For a Bedrock provider
on images through v1.19.95, set config.extraEnv.BEDROCK_ENABLED: "true"
when no configured marker is stored; the chart does not add this switch for
Bedrock automatically.
For local Helm installs, the chart also supports a separate
genesis-config.yaml for providers,
llm, embedding, auth, oauth_providers, features (gated Launchpad
journeys such as Onboard client files), and related app settings
(including LiteLLM Proxy OAuth). Copy the chart’s
genesis-config-example.yaml, then deploy with
--set-file genesisConfig.content=genesis-config.yaml, or use
genesisConfig.existingConfigMap when the file already exists as a
ConfigMap. This is the better fit when you want local Kubernetes to mirror a
production IaC configuration.For LiteLLM Proxy, set
providers.litellm_proxy.connection.transport in that file; it defaults to
auto. To pin the value through Helm environment configuration, set
config.extraEnv.GENESIS__PROVIDERS__LITELLM_PROXY__CONNECTION__TRANSPORT.
That GENESIS__ override takes precedence over the config file and a UI-saved
value. See AI model setup
for transport selection guidance.For Helm-driven RBAC on OIDC deployments, you can also pass
--set-file groupRoleMapping.content=group-role-mapping.yaml and
--set-file rbacSeedPolicy.content=rbac-policies.csv. See
Deploying Genesis - Azure AKS with OIDC Authentication.Configuring the LLM provider
Genesis starts without a provider and reports No suitable LLM found until one is configured. Configure it against the running pod, either from Config -> AI Providers in the UI or through the config API. Keep credentials in a request-body file — process arguments are visible to every process on the host and land in shell history.200 with
success: false (for example when the provider already exists — repeat that call as
a PUT).
Embeddings are configured separately, on the Embeddings tab or with
PUT /api/config/models/embeddings/config. LITELLM_EMBEDDING_MODEL is no longer
read as an input. For the full endpoint reference, the other providers and the
identity resolution rules, see
Configuring a provider through the config API
and AI model setup.
Some schema fields carry a
default_env_var binding that seeds them from the pod
environment while nothing is stored, so an image can come up pre-seeded. That is
bootstrap only — it is not the way to configure a provider, and anything saved
through the UI or the config API outranks it.Documentation links: internal (offline) vs public hosted Mintlify
Genesis images can bundle an offline documentation export served locally at/client-docs (no external network dependency). The docs.use_internal_docs app-config setting controls where in-app docs links (the header Help button, changelog links, and similar) point:
true(default) — links open the locally served offline export (/client-docs), useful for intranet or air-gapped clusters.false— links open the hosted docs atdocs.genesiscomputing.comdirectly.
genesis-config.yaml (mounted via genesisConfig.content):
secretName is configured, the chart automatically injects MINTLIFY_JWT_PRIVATE_KEY with secretKeyRef and injects GENESIS__DOCS__MINTLIFY_JWT_PRIVATE_KEY=env_MINTLIFY_JWT_PRIVATE_KEY. This keeps APP_CONFIG on a live environment reference and prevents startup from capturing the key into managed configuration storage. Operators do not need to hand-author that override. Never copy the key into Helm values, genesisConfig.content, config.extraEnv, or a ConfigMap.
To rotate the key, update the Kubernetes Secret and then roll out the workload so the container receives the new environment value:
https://<your-genesis-origin>/docs-login, confirm the Enterprise JWT entitlement and public-key setup, assign a fleet key owner, and pass real authenticated-human in-app, direct-bookmark, and expired-session smoke tests.
To override or lock the value at deploy time, add the derived environment variable through Helm config.extraEnv (takes precedence over the config file and the database value):
docs.use_internal_docs at runtime in Admin → Advanced Settings → docs (no pod rebuild required). When GENESIS__DOCS__USE_INTERNAL_DOCS is set, the field is shown locked with the env var name. Switching it back to true immediately refuses new hosted sessions; Mintlify sessions already issued can remain valid for up to one hour. The packaged offline docs remain served at /client-docs regardless of this flag, and the /docs-login page falls back to them if a hosted session request fails.
Current Genesis container images also bundle the in-repo
genesis_sdk package under /app/genesis_sdk (for execute_python_code local execution — not installable from PyPI) and the llm_wiki package under /app/llm_wiki, so the SDK, wiki APIs, and tools shipped with Genesis are available without extra image customization.If you use the bundled
local-k8s/deploy-local.sh helper, copy local-k8s/local-config-example.env to local-k8s/local-config.env, set ECR_REGISTRY, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and GENESIS_HELM_CHART_OCI (from bundle helm.chart_url), and optionally GENESIS_HELM_CHART_VERSION. Set AWS_DEFAULT_REGION if it cannot be inferred from the registry hostname. Optionally set ECR_REPO_NAME (defaults to genesis) and IMAGE_TAG for a one-off override. If IMAGE_TAG is unset, the script resolves the tag from local-k8s/local-values.yaml and exits if neither source provides a tag. Before running Helm, it verifies that ECR_REGISTRY/ECR_REPO_NAME:<resolved-tag> is accessible in ECR, runs helm registry login, then passes ecr.enabled, ecr.registry, and ecr.token to helm upgrade --install against GENESIS_HELM_CHART_OCI. It only forces image.pullPolicy=Always when the resolved tag is latest or edge.Important: No LLM provider is configured in this file. Install first, then connect a provider from Config -> AI Providers or through the config API — see Configuring the LLM provider. Save this file as
local/local-values.yaml for the raw Helm flow, or as local-k8s/local-values.yaml when using the bundled local-k8s/deploy-local.sh helper.Step 6: Deploy Genesis with Helm
Important: Run all helm commands from the helm chart directory (whereChart.yaml is located).
Option A: Install from Local Chart (Recommended)
Option B: Upgrade Existing Installation
If Genesis is already installed:Step 7: Verify Deployment
Check the deployment status:READY shows 1/1.
Accessing Genesis
Option 1: Port Forwarding (Recommended for Local)
Port forwarding is the simplest way to access Genesis on a local cluster:- React UI: http://localhost:8080
- API: http://localhost:8080/api
- Health Check: http://localhost:8080/api/health
Multiple Ports (if needed)
If you need to access other services:Background Port Forwarding
To run port forwarding in the background:Option 2: Ingress with /etc/hosts
If you prefer using ingress (requires/etc/hosts modification):
Step 1: Add to /etc/hosts
macOS/Linux:- Open Notepad as Administrator
- Open
C:\Windows\System32\drivers\etc\hosts - Add:
127.0.0.1 genesis.localhost - Save
Step 2: Port Forward Ingress Controller
The NGINX ingress controller needs to be accessible:Step 3: Access Genesis
- React UI: http://genesis.localhost
- API: http://genesis.localhost/api
Port Forwarding
Basic Port Forwarding
Port Forwarding to Pod Directly
Multiple Ports
Port Forwarding with Specific Address
Troubleshooting Port Forwarding
PVC data backups (local)
Docker Desktop Kubernetes resets and some upgrades recreate the cluster disk — the PVC inside the cluster is then empty. Thelocal-k8s/backup-genesis.sh script streams PVC data to ./backups/*.tgz on the host; deploy-local.sh runs it automatically before and after each deploy when the pod is Running, and you can run it standalone against any kubectl context (Docker Desktop, EKS, AKS, etc.). This does not replace cloud volume snapshots, but it protects against Docker Desktop / Kubernetes resets that wipe the cluster disk.
What deploy-local.sh backs up
When genesis-0 is Running and GENESIS_SKIP_BACKUP is unset:
- Before
helm upgrade— writes./backups/genesis-local-backup-<context>-<timestamp>-pre-helm.tgz(best-effort; skipped if no Running pod, for example first install orErrImagePull). - After the new pod reaches Running and Ready — writes
…-post-deploy.tgz.
tar czf of /app/.genesis/db, bot_storage, bot_git, and tmp (same paths as the chart PVC subpaths). This is a filesystem-consistent copy while the app is live; for SQLite, treat it like a snapshot for disaster recovery (restore to a stopped pod / empty PVC and start once).
Environment variables
Manual backup without upgrading
From thelocal-k8s directory, same context you use for deploy:
manual):
Restore (outline)
- Scale down or delete the StatefulSet pod so nothing writes the volume (or use a new namespace / release for a dry run).
- Use
kubectl cpor mount an initContainer / one-off pod with the same PVC andtar xzfthe tarball into/app(or replace onlybot_storage/.genesis/dbas needed).
genesis release name and namespace to preserve PVC identity; avoid deleting the PVC unless you intend to wipe data.
Troubleshooting
Pod Not Starting
-
ImagePullBackOff: Cannot pull container image
The helper script now performs this ECR preflight before Helm, so a missing or inaccessible tag should fail fast before the rollout starts. If
kubectl describe podshows an image reference containing%!s(float64=...), the numericimage.tagwas not coerced to a string. Upgrade to chart 0.3.55 or later, or quote the tag in your values file / use--set-string image.tag=.... -
Pending: Pod waiting for resources
-
CrashLoopBackOff: Container crashing
Upgrade / same PVC: The deploy script deletes
genesis-0once afterhelm upgradeso the StatefulSet recreates the pod on the existing claim (clears CrashLoop/probe backoff on some local clusters). To do it manually:kubectl delete pod -n genesis genesis-0 --wait=false. SetGENESIS_SKIP_POST_UPGRADE_POD_DELETE=1to skip the delete and use rollout restart only. For backup discipline before risky changes, see PVC data backups (local).
Persistent Volume Issues
Service Not Accessible
Ingress Not Working
Network Connectivity Issues
Viewing Logs
Resetting Deployment
If you need to start fresh:helm uninstall or changing
sandbox.namespace can leave per-instance bindings outside the Genesis
namespace. Revoke them with cluster/scripts/cleanup-retained-rbac.sh genesis
before reinstalling or re-applying. For the full retention behavior, including
ServiceAccounts, shared sandbox resources, and rollback handling, see Helm
resource retention.
Reference: Example values file
The following is an examplelocal/local-values.yaml for Genesis on a local Kubernetes cluster (Docker Desktop, minikube, kind). If you are using the bundled helper script, save the same content as local-k8s/local-values.yaml instead. It carries no LLM provider: connect one after install, from Config -> AI Providers or the config API.
Appendix
A. Command Reference
kubectl Commands
Once you’re inside the Genesis pod with
kubectl exec, current container images include ripgrep (rg) for file-content searches in mounted directories such as /app/bot_storage and /app/bot_git.Helm Commands
Useful kubectl Aliases
Add to your~/.bashrc or ~/.zshrc:
B. YAML Configuration Reference
Complete local/local-values.yaml Template
C. Online Documentation Links
Kubernetes
Helm
Docker Desktop
NGINX Ingress
D. Tutorials and Learning Resources
Kubernetes Basics
Helm Tutorials
Docker Desktop Kubernetes
Port Forwarding
E. Common kubectl Commands for Local Development
F. Common Helm Commands for Local Development
G. Troubleshooting Commands
H. Quick Reference: Use the Provided Deployment Script
If your Genesis bundle includeslocal-k8s/deploy-local.sh, run it from the helm chart directory after copying the example config and values files:
local-k8s/deploy-local.sh defaults to ECR: it verifies the resolved tag exists in ECR_REGISTRY/${ECR_REPO_NAME:-genesis}, logs Helm in, and installs the OCI chart with ECR values. With Helm 4, it adds --force-conflicts to the upgrade so server-side apply can update the ECR pull secret if another manager, such as a scheduled refresh job, has taken ownership of its .data; Helm 3 does not use this flag. For GHCR images, use IMAGE_SOURCE=ghcr; the script checks the resolved tag in GHCR, uses the chart directory selected by GENESIS_HELM_CHART_GIT_REF or GENESIS_HELM_CHART_PATH, and configures the namespace pull secret. When the resolved tag is latest or edge, it also sets image.pullPolicy=Always. After upgrade, it deletes genesis-0 once (PVC unchanged) unless GENESIS_SKIP_POST_UPGRADE_POD_DELETE=1, then polls pod status every GENESIS_ROLLOUT_POLL seconds (default 15) until the pod reports STATUS=Running and READY=1/1, or GENESIS_ROLLOUT_TIMEOUT (default 1200) expires. When the pod is Running, it writes PVC tarballs to ./backups/ before and after deploy unless GENESIS_SKIP_BACKUP=1. The script exits early on failing states such as ImagePullBackOff or CrashLoopBackOff.I. Additional Learning Resources
Kubernetes Learning Path
Troubleshooting Guides
Community Resources
- Kubernetes Slack
- Stack Overflow: Tag
kubernetes,helm - Reddit: r/kubernetes, r/helm
Summary
This guide provides everything needed to deploy Genesis on a local Kubernetes cluster:- Initial Setup: Extract the provided zip (or use the chart folder you were given) so you have the helm chart directory
- Prerequisites: Docker Desktop, kubectl, Helm
- Deployment: Helm chart with
local/local-values.yaml(all commands from chart directory) - Access: Port forwarding to
localhost:8080 - Troubleshooting: Common issues and solutions
- Reference: Complete command and YAML reference
helm install, helm upgrade, etc.) must be run from the helm chart directory where Chart.yaml is located.
For questions or issues, refer to the troubleshooting section or the online documentation links in the appendix. For the full container-based local experience without Kubernetes, see Genesis on Docker.
