Local Kubernetes and development operations
Build images for a disposable Kubernetes cluster, stop the development stack without deleting its data, or check local Agent access. Run commands from the repository root. If you are installing the platform for the first time, start with Local Setup. For Namespace and Agent setup on an existing installation, use the production deployment sequence.
Build images for local Kubernetes
Build the controller from this checkout and one combined OpenClaw/Codex image for both Installation image slots. The local Kubernetes tests use the same build and import commands. Local digests vary by build and platform; read them from the imported images instead of copying a sample digest.
Prerequisites: Docker, k3d, and yq v4. Create a disposable single-server cluster without changing your kubeconfig:
export CLUSTER="occ-images-$(date +%s)"export OCC_EXAMPLE_DIRECTORY="$(mktemp -d)"k3d cluster create "$CLUSTER" --image +v1.35 --servers 1 --agents 0 \ --api-port 127.0.0.1:0 \ --kubeconfig-update-default=false --kubeconfig-switch-context=falsek3d kubeconfig get "$CLUSTER" > "$OCC_EXAMPLE_DIRECTORY/kubeconfig"chmod 600 "$OCC_EXAMPLE_DIRECTORY/kubeconfig"export KUBECONFIG_FILE="$OCC_EXAMPLE_DIRECTORY/kubeconfig"export CONTEXT="k3d-$CLUSTER"Build and import the images:
docker build --target runtime \ --build-arg NODE_BASE_IMAGE=docker.io/library/node:24-bookworm@sha256:934240a162082fd8b8a2f90cd5114446443f1eba1c5378f6687167ca405e6584 \ -t "localhost/$CLUSTER/controller:local" .docker build -f deploy/runtime/Dockerfile \ -t "localhost/$CLUSTER/runtime:local" .k3d image import "localhost/$CLUSTER/controller:local" \ "localhost/$CLUSTER/runtime:local" -c "$CLUSTER"Register each imported manifest digest in k3s:
for role in controller runtime; do tag="localhost/$CLUSTER/$role:local" digest="$(docker exec "k3d-$CLUSTER-server-0" ctr -n k8s.io images list | awk -v image="$tag" '$1 == image { print $3 }')" printf '%s\n' "$digest" | grep -Eq '^sha256:[a-f0-9]{64}$' || exit 1 reference="localhost/$CLUSTER/$role@$digest" docker exec "k3d-$CLUSTER-server-0" ctr -n k8s.io images tag "$tag" "$reference" if [ "$role" = controller ]; then export CONTROLLER_IMAGE="$reference" else export RUNTIME_IMAGE="$reference" fidonePopulate private YAML copies with those references:
umask 077cp deploy/examples/production/{values,installation,bootstrap-pvc}.yaml "$OCC_EXAMPLE_DIRECTORY/"yq -i '.images.controller = strenv(CONTROLLER_IMAGE)' "$OCC_EXAMPLE_DIRECTORY/values.yaml"yq -i '.drivers.compute.configuration.images.gateway = strenv(RUNTIME_IMAGE) | .drivers.compute.configuration.images.agent = strenv(RUNTIME_IMAGE)' "$OCC_EXAMPLE_DIRECTORY/installation.yaml"printf 'Image-configured examples: %s\n' "$OCC_EXAMPLE_DIRECTORY"These references work in this cluster and retain requireImmutableDigest: true.
Use the generated directory in place of /secure/occ in the production commands;
keep its image values and kubeconfig instead of copying the templates again.
Set the remaining database, HTTPS, network, and storage inputs for your trial
(k3d's default StorageClass is local-path). The images alone do not configure
those dependencies or prove an Agent model turn. When finished with the trial,
run KUBECONFIG="$KUBECONFIG_FILE" k3d cluster delete "$CLUSTER".
For an already installed, persistent Helm release on k3d, follow local k3d image upgrades to preserve its state. The disposable cluster cleanup above is not an upgrade procedure.
For missing DNS, denied connections, or unready Kubernetes Agents after a
checkout update, inspect the ordinary network profile
on the affected Pod and its workload template, plus all matching NetworkPolicies.
The upgrade restarts nothing: running Pods keep their templates and grants until
Compute next prepares a revision of their Agent. To move an Agent onto the
profile, rebuild the controller and deploy a new revision. Preparing it
re-renders that Agent's grants with the profile, and its new templates carry the
label. A Gateway from an earlier template, embedded or dedicated, keeps serving
until activation replaces it. Re-preparing an active revision, for
example during repository-credential maintenance, rolls its Pods once onto
profiled templates. Namespace-wide allow-dns,
allow-gateway-ingress and allow-node-gateway are narrowed only in namespaces
provisioned after the upgrade; an earlier namespace keeps its previous policies
until it is recreated. OpenShell Sandboxes need a redeployed revision.
Restarting a Pod from an old template retains the missing label; assigning the
profile to arbitrary Pods grants access and is not a repair.
Stop development safely
Run the exact command under Cleanup in the dev-up output. For Podman, it
uses occ dev down with compose.podman.yaml and the Compose options passed at
startup. Keep any CONTAINER_CONNECTION or CONTAINER_HOST selection used for
startup, including macOS machine connections. See the
cleanup flow
for how the host connection and worker socket are handled.
This preserves PostgreSQL, Configuration, and bootstrap-key volumes. Use
--volumes only to delete the local Installation. First account for any Agent
containers and tenant networks owned by Docker Compute.
Development end-to-end TUI
Docker and Podman Compose support control-plane startup and Namespace
operations. Their Compute Driver rejects the harness authentication binding
required for Agent deployment. You cannot deploy an Agent or use its TUI through
Compose; exporting OPENAI_API_KEY to the worker does not change this.
For a local authenticated Agent and TUI trial, build the Kubernetes images above, then follow production Agent deployment and production TUI verification against that disposable cluster. Complete the same Secret binding, exact IAM grants, and tenant RoleBindings as for a production installation. Both the TUI and the HTTP model response check use an optional loopback password alongside the gateway's trusted-proxy authentication.
