API Reference

OpenClawInstance (v1alpha1)

Group: openclaw.rocks Version: v1alpha1 Kind: OpenClawInstance Scope: Namespaced

An OpenClawInstance represents a single deployment of the OpenClaw AI assistant in a Kubernetes cluster. The operator watches these resources and reconciles a full stack of dependent objects (StatefulSet, Service, RBAC, NetworkPolicy, storage, and more).

When listing resources with kubectl get openclawinstances, the following columns are displayed:

ColumnJSON Path
Phase.status.phase
Ready.status.conditions[?(@.type=='Ready')].status
Gateway.status.gatewayEndpoint
Age.metadata.creationTimestamp

Spec Fields

spec.image

Container image configuration for the main OpenClaw workload.

FieldTypeDefaultDescription
repositorystringghcr.io/openclaw/openclawContainer image repository.
tagstringlatestContainer image tag.
digeststringImage digest (overrides tag if set). Format: sha256:abc....
pullPolicystringIfNotPresentImage pull policy. One of: Always, IfNotPresent, Never.
pullSecrets[]LocalObjectReferenceList of Secrets for pulling from private registries.

spec.config

Configuration for the OpenClaw application (openclaw.json).

FieldTypeDefaultDescription
configMapRefConfigMapKeySelectorReference to an external ConfigMap. If set, raw is ignored.
rawRawConfigInline JSON configuration. The operator creates a managed ConfigMap.
mergeModestringoverwriteHow config is applied to the PVC. overwrite replaces on every restart. merge deep-merges with existing PVC config, preserving runtime changes.
formatstringjsonConfig file format. json (standard JSON) or json5 (JSON5 with comments/trailing commas). JSON5 requires configMapRef - inline raw must be valid JSON. JSON5 is converted to standard JSON by the init container using npx json5.

ConfigMapKeySelector:

FieldTypeDefaultDescription
namestring(required)Name of the ConfigMap.
keystringopenclaw.jsonKey within the ConfigMap to mount.

spec.workspace

Configures initial workspace files seeded into the instance. Files are copied once on first boot and never overwritten, so agent modifications survive pod restarts.

FieldTypeDefaultDescription
initialFilesmap[string]stringMaps filenames to their content. Each file is written to the workspace directory only if it does not already exist. Max 50 entries.
initialDirectories[]stringDirectories to create (mkdir -p) inside the workspace directory. Nested paths like tools/scripts are allowed. Max 20 items.
spec:
  workspace:
    initialDirectories:
      - tools/scripts
      - data
    initialFiles:
      README.md: |
        # My Workspace
        This workspace is managed by OpenClaw.
      tools/scripts/setup.sh: |
        #!/bin/bash
        echo "Hello from setup"

spec.skills

FieldTypeDefaultDescription
skills[]stringSkills to install. Three formats supported: ClawHub identifiers (e.g., @anthropic/mcp-server-fetch), npm packages with npm: prefix (e.g., npm:@openclaw/matrix), and GitHub-hosted skill packs with pack: prefix (e.g., pack:openclaw-rocks/skills/image-gen). npm lifecycle scripts are disabled for security. Max 20 items.
spec:
  skills:
    - "@anthropic/mcp-server-fetch"                         # ClawHub
    - "npm:@openclaw/matrix"                                # npm package
    - "pack:openclaw-rocks/skills/image-gen"                # skill pack (latest)
    - "pack:openclaw-rocks/skills/image-gen@v1.0.0"         # skill pack (pinned)

Skill packs (pack:owner/repo/path[@ref]) are resolved from GitHub repos containing a skillpack.json manifest. The manifest declares files to seed into the workspace, directories to create, and config entries to inject into config.raw.skills.entries. User-defined config entries take precedence over pack defaults. The operator caches resolved packs for 5 minutes. Set GITHUB_TOKEN on the operator for private repo access.

spec.envFrom

FieldTypeDefaultDescription
envFrom[]EnvFromSourceSources to populate environment variables (e.g., Secrets for ANTHROPIC_API_KEY).

Standard Kubernetes EnvFromSource. Commonly used to inject API keys from a Secret:

spec:
  envFrom:
    - secretRef:
        name: openclaw-api-keys

spec.env

FieldTypeDefaultDescription
env[]EnvVarIndividual environment variables to set.

Standard Kubernetes EnvVar. Example:

spec:
  env:
    - name: LOG_LEVEL
      value: "debug"

spec.resources

Compute resource requirements for the main OpenClaw container.

FieldTypeDefaultDescription
requests.cpustring500mMinimum CPU (e.g., 500m, 2).
requests.memorystring1GiMinimum memory (e.g., 512Mi).
limits.cpustring2000mMaximum CPU.
limits.memorystring4GiMaximum memory.

spec.security

Security-related configuration for the instance.

spec.security.podSecurityContext

FieldTypeDefaultDescription
runAsUser*int641000UID to run as. Setting to 0 is rejected by webhook.
runAsGroup*int641000GID to run as.
fsGroup*int641000Supplemental group for volume ownership.
fsGroupChangePolicy*PodFSGroupChangePolicyBehavior for changing volume ownership. OnRootMismatch skips recursive chown when ownership already matches, improving startup time for large PVCs. Always recursively chowns on every mount (Kubernetes default).
runAsNonRoot*booltrueRequire non-root execution. Warns if set to false.

spec.security.containerSecurityContext

FieldTypeDefaultDescription
allowPrivilegeEscalation*boolfalseAllow privilege escalation. Warns if set to true.
readOnlyRootFilesystem*booltrueMount root filesystem as read-only. The PVC at ~/.openclaw/ and /tmp emptyDir provide writable paths.
capabilities*CapabilitiesDrop ALLLinux capabilities to add or drop.

spec.security.networkPolicy

FieldTypeDefaultDescription
enabled*booltrueCreate a NetworkPolicy. Warns if disabled.
allowedIngressCIDRs[]stringCIDRs allowed to reach the instance.
allowedIngressNamespaces[]stringNamespaces allowed to reach the instance.
allowedEgressCIDRs[]stringCIDRs the instance can reach (in addition to HTTPS/DNS).
allowDNS*booltrueAllow DNS resolution (UDP/TCP port 53).
additionalEgress[]NetworkPolicyEgressRuleCustom egress rules appended to the default DNS + HTTPS rules. Use this to allow traffic to cluster-internal services on non-standard ports.

spec.security.rbac

FieldTypeDefaultDescription
createServiceAccount*booltrueCreate a dedicated ServiceAccount for this instance.
serviceAccountNamestringUse an existing ServiceAccount (only when createServiceAccount is false).
serviceAccountAnnotationsmap[string]stringAnnotations to add to the managed ServiceAccount. Use for cloud provider integrations like AWS IRSA or GCP Workload Identity.
additionalRules[]RBACRuleCustom RBAC rules appended to the generated Role.

RBACRule:

FieldTypeDescription
apiGroups[]stringAPI groups (e.g., [""] for core, ["apps"]).
resources[]stringResources (e.g., ["pods"]).
verbs[]stringVerbs (e.g., ["get", "list"]).

spec.security.caBundle

Injects a custom CA certificate bundle into all containers. Use this in environments with TLS-intercepting proxies or private CAs.

FieldTypeDefaultDescription
configMapNamestringName of a ConfigMap containing the CA bundle. The ConfigMap should have a key matching key.
secretNamestringName of a Secret containing the CA bundle. Only one of configMapName or secretName should be set.
keystringca-bundle.crtKey in the ConfigMap or Secret containing the CA bundle PEM file.
spec:
  security:
    caBundle:
      configMapName: corporate-ca
      key: ca-bundle.crt

spec.storage

Persistent storage configuration.

spec.storage.persistence

FieldTypeDefaultDescription
enabled*booltrueEnable persistent storage via PVC.
storageClass*string(cluster default)StorageClass name. Immutable after creation.
sizestring10GiPVC size.
accessModes[]PersistentVolumeAccessMode[ReadWriteOnce]PVC access modes.
existingClaimstringName of an existing PVC to use instead of creating one.
orphan*booltrueWhen true (the default), the operator removes the owner reference from the managed PVC before deleting the CR so the PVC is retained after deletion. Set to false to have the PVC garbage-collected with the CR. Has no effect when existingClaim is set (user-managed PVCs are never touched).

spec.chromium

Optional Chromium sidecar for browser automation.

FieldTypeDefaultDescription
enabledboolfalseEnable the Chromium sidecar container.
image.repositorystringghcr.io/browserless/chromiumChromium container image repository.
image.tagstringlatestChromium image tag.
image.digeststringChromium image digest for supply chain security.
resources.requests.cpustring250mChromium minimum CPU.
resources.requests.memorystring512MiChromium minimum memory.
resources.limits.cpustring1000mChromium maximum CPU.
resources.limits.memorystring2GiChromium maximum memory.
extraArgs[]stringAdditional command-line arguments passed to the Chromium process (appended to defaults). Browserless forwards unrecognised flags to the underlying Chromium binary.
extraEnv[]EnvVarAdditional environment variables for the Chromium sidecar container, merged with operator-managed variables.

When enabled, the sidecar:

  • Exposes Chrome DevTools Protocol on port 3000.
  • Runs as UID 999 (blessuser).
  • Mounts a memory-backed emptyDir at /dev/shm (1Gi) for shared memory.
  • Mounts an emptyDir at /tmp for scratch space.

When Chromium is enabled, the operator also auto-configures browser profiles in the OpenClaw config. Both "default" and "chrome" profiles are set to point at the sidecar’s CDP endpoint (http://localhost:3000). This ensures browser tool calls work regardless of which profile name the LLM passes.

spec.tailscale

Optional Tailscale integration for secure tailnet access without Ingress or LoadBalancer. Runs a Tailscale sidecar (tailscaled) that handles serve/funnel declaratively.

FieldTypeDefaultDescription
enabledboolfalseEnable Tailscale integration (adds sidecar + init container).
modestringserveTailscale mode. serve exposes to tailnet members only. funnel exposes to the public internet via Tailscale Funnel.
image.repositorystringghcr.io/tailscale/tailscaleTailscale sidecar container image repository.
image.tagstringlatestTailscale sidecar container image tag.
image.digeststringContainer image digest for supply chain security (overrides tag).
authKeySecretRef*LocalObjectReferenceReference to a Secret containing the Tailscale auth key. Use ephemeral+reusable keys from the Tailscale admin console.
authKeySecretKeystringauthkeyKey in the referenced Secret containing the auth key.
hostnamestring(instance name)Tailscale device name. Defaults to the OpenClawInstance name.
authSSOboolfalseEnable passwordless login for tailnet members. Sets gateway.auth.allowTailscale=true in the OpenClaw config.
resources.requests.cpustring50mCPU request for the Tailscale sidecar.
resources.requests.memorystring64MiMemory request for the Tailscale sidecar.
resources.limits.cpustring200mCPU limit for the Tailscale sidecar.
resources.limits.memorystring256MiMemory limit for the Tailscale sidecar.

When enabled, the operator:

  • Adds a Tailscale sidecar running tailscaled in userspace mode (TS_USERSPACE=true). The sidecar handles serve/funnel declaratively via TS_SERVE_CONFIG.
  • Adds an init container (init-tailscale-bin) that copies the tailscale CLI binary to a shared volume (/tailscale-bin), making it available to the main container for tailscale whois (SSO auth).
  • Sets TS_SOCKET on the main container pointing to the sidecar’s Unix socket.
  • Prepends /tailscale-bin to the main container’s PATH.
  • Adds tailscale-serve.json to the ConfigMap with the serve/funnel configuration.
  • When authSSO is true, sets gateway.auth.allowTailscale=true so tailnet members can authenticate without a gateway token.
  • Adds STUN (UDP 3478) and WireGuard (UDP 41641) egress rules to the NetworkPolicy.

spec.ollama

Optional Ollama sidecar for local LLM inference.

FieldTypeDefaultDescription
enabledboolfalseEnable the Ollama sidecar container.
image.repositorystringollama/ollamaOllama container image repository.
image.tagstringlatestOllama image tag.
image.digeststringOllama image digest for supply chain security.
models[]stringModels to pre-pull during pod init (e.g., ["llama3.2", "nomic-embed-text"]). Max 10 items.
resources.requests.cpustringOllama minimum CPU.
resources.requests.memorystringOllama minimum memory.
resources.limits.cpustringOllama maximum CPU.
resources.limits.memorystringOllama maximum memory.
storage.sizeLimitstring20GiSize limit for the emptyDir model cache volume.
storage.existingClaimstringName of an existing PVC for persistent model storage (overrides emptyDir).
gpu*int32Number of NVIDIA GPUs to allocate (sets nvidia.com/gpu resource limit). Minimum: 0.

When enabled, the operator:

  • Adds an Ollama sidecar container to the pod.
  • If models are specified, adds an init container (init-ollama) that pre-pulls the listed models so they are ready when the pod starts.
  • The model cache uses an emptyDir by default (bounded by storage.sizeLimit). Set storage.existingClaim to use a PVC for persistent model storage across pod restarts.
  • GPU allocation requires the NVIDIA device plugin to be installed on the cluster.
spec:
  ollama:
    enabled: true
    models:
      - llama3.2
      - nomic-embed-text
    resources:
      requests:
        cpu: "2"
        memory: 4Gi
      limits:
        cpu: "8"
        memory: 16Gi
    storage:
      sizeLimit: 40Gi
    gpu: 1

spec.webTerminal

Optional ttyd web terminal sidecar for browser-based shell access and debugging.

FieldTypeDefaultDescription
enabledboolfalseEnable the ttyd web terminal sidecar container.
image.repositorystringtsl0922/ttydWeb terminal container image repository.
image.tagstringlatestWeb terminal image tag.
image.digeststringWeb terminal image digest for supply chain security.
resources.requests.cpustring50mWeb terminal minimum CPU.
resources.requests.memorystring64MiWeb terminal minimum memory.
resources.limits.cpustring200mWeb terminal maximum CPU.
resources.limits.memorystring128MiWeb terminal maximum memory.
readOnlyboolfalseStart ttyd in read-only mode (view-only, no input). Data volume mount is also set to read-only.
credential.secretRef.namestringName of a Secret with username and password keys for basic auth.

When enabled, the operator:

  • Adds a ttyd sidecar container on port 7681 to the pod.
  • Mounts the instance data volume at /home/openclaw/.openclaw for inspection.
  • Adds a /tmp emptyDir volume for the web terminal container.
  • Adds the web terminal port to the Service and NetworkPolicy.
  • Runs as UID 1000 (same as the main container) for shared file permissions on the data volume.
spec:
  webTerminal:
    enabled: true
    readOnly: true
    credential:
      secretRef:
        name: terminal-credentials
    resources:
      requests:
        cpu: "100m"
        memory: "128Mi"

spec.initContainers

FieldTypeDefaultDescription
initContainers[]ContainerAdditional init containers to run before the main container. They run after the operator-managed init containers. Max 10 items.

Standard Kubernetes Container spec. The following names are reserved by the operator and rejected by the webhook: init-config, init-pnpm, init-python, init-skills, init-ollama.

spec:
  initContainers:
    - name: wait-for-db
      image: busybox:1.37
      command: ["sh", "-c", "until nc -z postgres.db.svc 5432; do sleep 2; done"]
    - name: seed-data
      image: my-seeder:latest
      volumeMounts:
        - name: data
          mountPath: /data

spec.sidecars

FieldTypeDefaultDescription
sidecars[]ContainerAdditional sidecar containers to inject into the pod. Use for custom sidecars like database proxies, log forwarders, or service meshes.

Standard Kubernetes Container spec. Sidecar containers run alongside the main OpenClaw container.

spec:
  sidecars:
    - name: cloud-sql-proxy
      image: gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0
      args: ["--structured-logs", "my-project:us-central1:my-db"]
      resources:
        requests:
          cpu: 100m
          memory: 128Mi

spec.sidecarVolumes

FieldTypeDefaultDescription
sidecarVolumes[]VolumeAdditional volumes to make available to sidecar containers.

Standard Kubernetes Volume spec. Use this to mount ConfigMaps, Secrets, or other volumes that your custom sidecars need.

spec:
  sidecarVolumes:
    - name: proxy-config
      configMap:
        name: cloud-sql-proxy-config

spec.extraVolumes

FieldTypeDefaultDescription
extraVolumes[]VolumeAdditional volumes to add to the pod. These volumes are available to the main container via extraVolumeMounts. Max 10 items.

Standard Kubernetes Volume spec.

spec.extraVolumeMounts

FieldTypeDefaultDescription
extraVolumeMounts[]VolumeMountAdditional volume mounts to add to the main container. Use with extraVolumes to mount ConfigMaps, Secrets, NFS shares, or CSI volumes. Max 10 items.

Standard Kubernetes VolumeMount spec.

spec:
  extraVolumes:
    - name: shared-data
      nfs:
        server: nfs.example.com
        path: /exports/data
    - name: custom-certs
      secret:
        secretName: my-tls-certs
  extraVolumeMounts:
    - name: shared-data
      mountPath: /mnt/shared
      readOnly: true
    - name: custom-certs
      mountPath: /etc/custom-certs
      readOnly: true

spec.networking

Network-related configuration for the instance.

spec.networking.service

FieldTypeDefaultDescription
typestringClusterIPService type. One of: ClusterIP, LoadBalancer, NodePort.
annotationsmap[string]stringAnnotations to add to the Service.
ports[]ServicePortSpecCustom ports exposed on the Service. When set, replaces the default gateway and canvas ports.

ServicePortSpec:

FieldTypeDefaultDescription
namestringName of the port (required).
portint32Port number exposed on the Service (required, 1-65535).
targetPort*int32portPort on the container to route to (defaults to port).
protocolstringTCPProtocol for the port. One of: TCP, UDP, SCTP.

When ports is not set, the Service exposes these default ports:

Port NamePortTarget PortDescription
gateway1878918790OpenClaw WebSocket gateway (via nginx proxy sidecar).
canvas1879318794OpenClaw Canvas HTTP server (via nginx proxy sidecar).
chromium92229222Chrome DevTools Protocol (only if Chromium sidecar is enabled).

The gateway and canvas ports route through an nginx reverse proxy sidecar because the gateway process binds to loopback (127.0.0.1). The proxy listens on dedicated ports (0.0.0.0) and forwards traffic to loopback. This avoids CWE-319 plaintext WebSocket security errors on non-loopback addresses.

Note: Custom ports fully replace the defaults, including the Chromium port. If you use custom ports and have the Chromium sidecar enabled, include the Chromium port (9222) explicitly.

Custom ports example:

networking:
  service:
    type: ClusterIP
    ports:
      - name: http
        port: 3978
        targetPort: 3978

spec.networking.ingress

FieldTypeDefaultDescription
enabledboolfalseCreate an Ingress resource.
className*stringIngressClass to use (e.g., nginx, traefik).
annotationsmap[string]stringCustom annotations added to the Ingress.
hosts[]IngressHostList of hosts to route traffic for.
tls[]IngressTLSTLS termination configuration. Warns if empty.
securityIngressSecuritySpecIngress security settings (HTTPS redirect, HSTS, rate limiting).

IngressHost:

FieldTypeDescription
hoststringFully qualified domain name.
paths[]IngressPathPaths to route. Defaults to [{path: "/"}].

IngressPath:

FieldTypeDefaultDescription
pathstring/URL path.
pathTypestringPrefixPath matching. One of: Prefix, Exact, ImplementationSpecific.
port*int3218789Backend service port number. Defaults to the gateway port when not set.

Custom backend port example:

networking:
  ingress:
    enabled: true
    className: nginx
    hosts:
      - host: aibot.example.com
        paths:
          - path: /api/messages
            pathType: Prefix
            port: 3978
    tls:
      - hosts:
          - aibot.example.com
        secretName: certificate-aibot-tls

IngressTLS:

FieldTypeDescription
hosts[]stringHostnames covered by the TLS certificate.
secretNamestringSecret containing the TLS key pair.

IngressSecuritySpec:

FieldTypeDefaultDescription
forceHTTPS*booltrueRedirect HTTP to HTTPS.
enableHSTS*booltrueAdd HSTS headers.
rateLimiting.enabled*booltrueEnable rate limiting.
rateLimiting.requestsPerSecond*int3210Maximum requests per second.
basicAuth*IngressBasicAuthSpecOptional HTTP Basic Authentication. See below.

IngressBasicAuthSpec:

FieldTypeDefaultDescription
enabled*boolfalseEnable HTTP Basic Authentication on the Ingress.
existingSecretstringName of an existing Secret containing htpasswd content in a key named auth. When set, no new Secret is generated.
usernamestringopenclawUsername for the auto-generated htpasswd Secret. Ignored when existingSecret is set.
realmstringOpenClawAuthentication realm shown in browser prompts.

When enabled: true and no existingSecret is provided, the operator:

  • Generates a random 40-hex-character password
  • Creates a <name>-basic-auth Secret with three keys:
    • auth - htpasswd-formatted line (used by ingress controllers)
    • username - plaintext username
    • password - plaintext password
  • Tracks the secret name in status.managedResources.basicAuthSecret

nginx-ingress: The auth-type, auth-secret, and auth-realm annotations are set automatically.

Traefik: A traefik.io/v1alpha1/Middleware resource named <name>-basic-auth is created in the same namespace (requires Traefik CRDs to be installed), and the traefik.ingress.kubernetes.io/router.middlewares annotation is set to reference it.

Retrieve the auto-generated credentials:

kubectl get secret my-agent-basic-auth -o jsonpath='{.data.username}' | base64 -d
kubectl get secret my-agent-basic-auth -o jsonpath='{.data.password}' | base64 -d

To rotate credentials, delete the Secret and the operator will generate a new one on next reconcile.

The operator automatically adds WebSocket-related annotations for nginx-ingress (proxy timeouts, HTTP/1.1 upgrade).

spec.probes

Health probe configuration for the main OpenClaw container. All probes use TCP socket checks against the gateway port (18789).

spec.probes.liveness

FieldTypeDefaultDescription
enabled*booltrueEnable the liveness probe.
initialDelaySeconds*int3230Seconds to wait before the first check.
periodSeconds*int3210Seconds between checks.
timeoutSeconds*int325Seconds before the check times out.
failureThreshold*int323Consecutive failures before restarting the container.

spec.probes.readiness

FieldTypeDefaultDescription
enabled*booltrueEnable the readiness probe.
initialDelaySeconds*int325Seconds to wait before the first check.
periodSeconds*int325Seconds between checks.
timeoutSeconds*int323Seconds before the check times out.
failureThreshold*int323Consecutive failures before removing from endpoints.

spec.probes.startup

FieldTypeDefaultDescription
enabled*booltrueEnable the startup probe.
initialDelaySeconds*int320Seconds to wait before the first check.
periodSeconds*int325Seconds between checks.
timeoutSeconds*int323Seconds before the check times out.
failureThreshold*int3230Consecutive failures before killing the container. Allows up to 150s startup.

spec.observability

Metrics and logging configuration.

spec.observability.metrics

FieldTypeDefaultDescription
enabled*booltrueEnable the metrics endpoint on the managed instance.
port*int329090Metrics port.
serviceMonitor.enabled*boolfalseCreate a Prometheus ServiceMonitor.
serviceMonitor.intervalstring30sPrometheus scrape interval.
serviceMonitor.labelsmap[string]stringLabels to add to the ServiceMonitor (for Prometheus selector matching).
prometheusRule.enabled*boolfalseCreate a PrometheusRule with operator alerts.
prometheusRule.labelsmap[string]stringLabels to add to the PrometheusRule (for Prometheus rule selector matching).
prometheusRule.runbookBaseURLstringhttps://openclaw.rocks/docs/runbooksBase URL for alert runbook links.
grafanaDashboard.enabled*boolfalseCreate Grafana dashboard ConfigMaps (operator overview + instance detail).
grafanaDashboard.labelsmap[string]stringExtra labels to add to dashboard ConfigMaps.
grafanaDashboard.folderstringOpenClawGrafana folder for the dashboards.

spec.observability.logging

FieldTypeDefaultDescription
levelstringinfoLog level. One of: debug, info, warn, error.
formatstringjsonLog format. One of: json, text.

spec.selfConfigure

Agent self-modification configuration. When enabled, the agent can create OpenClawSelfConfig resources to modify its own instance spec via the K8s API.

FieldTypeDefaultDescription
enabledboolfalseEnable self-configuration for this instance.
allowedActions[]SelfConfigActionAction categories the agent is allowed to perform. If empty, no actions pass validation (fail-safe). Max 4 items.

SelfConfigAction values:

ValueDescription
skillsAdd or remove skills (spec.skills).
configDeep-merge patches into the OpenClaw config (spec.config.raw).
workspaceFilesAdd or remove initial workspace files (spec.workspace.initialFiles).
envVarsAdd or remove plain environment variables (spec.env).

When enabled, the operator:

  • Grants the SA read access to its own OpenClawInstance and referenced Secrets (scoped by resourceNames)
  • Grants create, get, list on openclawselfconfigs
  • Sets automountServiceAccountToken: true on the SA and pod spec
  • Injects OPENCLAW_INSTANCE_NAME and OPENCLAW_NAMESPACE environment variables
  • Adds port 6443 egress to the NetworkPolicy for K8s API access
  • Injects SELFCONFIG.md (skill documentation) and selfconfig.sh (helper script) into the workspace

spec.availability

High availability and scheduling configuration.

FieldTypeDefaultDescription
podDisruptionBudget.enabled*booltrueCreate a PodDisruptionBudget.
podDisruptionBudget.maxUnavailable*int321Maximum pods that can be unavailable during disruption.
nodeSelectormap[string]stringNode labels for pod scheduling.
tolerations[]TolerationTolerations for pod scheduling.
affinity*AffinityAffinity and anti-affinity rules.
topologySpreadConstraints[]TopologySpreadConstraintTopology spread constraints for pod scheduling.
autoScaling.enabled*boolfalseCreate a HorizontalPodAutoscaler.
autoScaling.minReplicas*int321Minimum number of replicas.
autoScaling.maxReplicas*int325Maximum number of replicas.
autoScaling.targetCPUUtilization*int3280Target average CPU utilization (percentage).
autoScaling.targetMemoryUtilization*int32Target average memory utilization (percentage).

spec.backup

Configures periodic scheduled backups to S3-compatible storage. Requires the s3-backup-credentials Secret in the operator namespace and persistence to be enabled.

FieldTypeDefaultDescription
schedulestringCron expression for periodic backups (e.g., "0 2 * * *" for daily at 2 AM). When set, the operator creates a CronJob that runs rclone to sync PVC data to S3.
historyLimit*int323Number of successful CronJob runs to retain.
failedHistoryLimit*int321Number of failed CronJob runs to retain.

The CronJob mounts the PVC read-only (hot backup - no downtime) and uses pod affinity to schedule on the same node as the StatefulSet pod (required for RWO PVCs). Each run stores data under a unique timestamped path: backups/<tenantId>/<instanceName>/periodic/<timestamp>.

spec:
  backup:
    schedule: "0 2 * * *"   # Daily at 2 AM UTC
    historyLimit: 5          # Keep last 5 successful runs
    failedHistoryLimit: 2    # Keep last 2 failed runs

spec.restoreFrom

FieldTypeDefaultDescription
restoreFromstringS3 path to restore data from (e.g., backups/{tenantId}/{instanceId}/{timestamp}). When set, the operator restores PVC data from this path before creating the StatefulSet. Cleared automatically after successful restore. Requires the s3-backup-credentials Secret to be present in the operator namespace.

See Backup and Restore for full setup instructions.

spec.runtimeDeps

Configures built-in init containers that install runtime dependencies to the data PVC for use by MCP servers and skills.

FieldTypeDefaultDescription
pnpmboolfalseInstall pnpm via corepack for npm-based MCP servers and skills. Adds the init-pnpm init container.
pythonboolfalseInstall Python 3.12 and uv for Python-based MCP servers and skills. Adds the init-python init container.
spec:
  runtimeDeps:
    pnpm: true
    python: true

spec.gateway

Configures the gateway authentication token.

FieldTypeDefaultDescription
existingSecretstringName of a user-managed Secret containing the gateway token. The Secret must have a key named token. When set, the operator skips auto-generating a gateway token Secret and uses this Secret instead.

When existingSecret is not set, the operator automatically generates a random gateway token Secret, which is tracked in status.managedResources.gatewayTokenSecret.

spec:
  gateway:
    existingSecret: my-gateway-token

spec.autoUpdate

Configures automatic version updates from the OCI registry.

FieldTypeDefaultDescription
enabled*boolfalseEnable automatic version updates.
checkIntervalstring24hHow often to check for new versions (Go duration). Minimum: 1h, Maximum: 168h (7 days).
backupBeforeUpdate*booltrueCreate a backup before applying updates.
rollbackOnFailure*booltrueAutomatically revert to the previous version if the updated pod fails to become ready within healthCheckTimeout.
healthCheckTimeoutstring10mHow long to wait for the updated pod to become ready before triggering a rollback (Go duration). Minimum: 2m, Maximum: 30m.

When enabled, the operator periodically checks the OCI registry for newer image tags. If a new version is found, it optionally creates a backup, updates the StatefulSet image tag, and monitors the rollout. If the pod fails to become ready within the health check timeout, the operator automatically rolls back to the previous version (if rollbackOnFailure is enabled).

Auto-update pauses after 3 consecutive rollbacks. It resumes when a newer version becomes available.

spec:
  autoUpdate:
    enabled: true
    checkInterval: 12h
    backupBeforeUpdate: true
    rollbackOnFailure: true
    healthCheckTimeout: 15m

Status Fields

status.phase

FieldTypeDescription
phasestringCurrent lifecycle phase: Pending, Provisioning, Running, Degraded, Failed, Terminating, BackingUp, Restoring, Updating.

status.conditions

Standard metav1.Condition array. Condition types:

TypeDescription
ReadyOverall readiness of the instance.
ConfigValidConfiguration is valid and loaded.
StatefulSetReadyStatefulSet has ready replicas.
DeploymentReady(Deprecated) Legacy Deployment has ready replicas. Used during migration from Deployment to StatefulSet.
ServiceReadyService has been created.
NetworkPolicyReadyNetworkPolicy has been applied.
RBACReadyRBAC resources are in place.
StorageReadyPVC has been provisioned and is bound.
BackupCompleteThe backup job completed successfully.
RestoreCompleteThe restore job completed successfully.
ScheduledBackupReadyThe periodic backup CronJob is configured and ready.
AutoUpdateAvailableA newer version is available in the OCI registry.
SecretsReadyAll referenced Secrets exist and are accessible.

status.endpoints

FieldTypeDescription
gatewayEndpointstringIn-cluster endpoint for the gateway: <name>.<ns>.svc:18789.
canvasEndpointstringIn-cluster endpoint for canvas: <name>.<ns>.svc:18793.

status.observedGeneration

FieldTypeDescription
observedGenerationint64The .metadata.generation last processed by the controller.

status.lastReconcileTime

FieldTypeDescription
lastReconcileTime*metav1.TimeTimestamp of the last successful reconciliation.

status.managedResources

FieldTypeDescription
statefulSetstringName of the managed StatefulSet.
deploymentstringName of the legacy Deployment (deprecated, used during migration).
servicestringName of the managed Service.
configMapstringName of the managed ConfigMap.
pvcstringName of the managed PVC.
networkPolicystringName of the managed NetworkPolicy.
podDisruptionBudgetstringName of the managed PDB.
serviceAccountstringName of the managed ServiceAccount.
rolestringName of the managed Role.
roleBindingstringName of the managed RoleBinding.
gatewayTokenSecretstringName of the auto-generated gateway token Secret.
prometheusRulestringName of the managed PrometheusRule.
grafanaDashboardOperatorstringName of the operator overview dashboard ConfigMap.
grafanaDashboardInstancestringName of the instance detail dashboard ConfigMap.
horizontalPodAutoscalerstringName of the managed HorizontalPodAutoscaler.
backupCronJobstringName of the managed periodic backup CronJob.

status.backup and restore

FieldTypeDescription
backupJobNamestringName of the active backup Job.
restoreJobNamestringName of the active restore Job.
lastBackupPathstringS3 path of the last successful backup.
lastBackupTime*metav1.TimeTimestamp of the last successful backup.
restoredFromstringS3 path this instance was restored from.

status.autoUpdate

Tracks the state of automatic version updates.

FieldTypeDescription
lastCheckTime*metav1.TimeWhen the registry was last checked for new versions.
latestVersionstringLatest version available in the registry.
currentVersionstringVersion currently running.
pendingVersionstringSet during an in-flight update to the version being applied.
updatePhasestringProgress of an in-flight update. One of: "", BackingUp, ApplyingUpdate, HealthCheck, RollingBack.
lastUpdateTime*metav1.TimeWhen the last successful update was applied.
lastUpdateErrorstringError message from the last failed update attempt.
previousVersionstringVersion before the last update (used for rollback).
preUpdateBackupPathstringS3 path of the pre-update backup (used for rollback restore).
failedVersionstringVersion that failed health checks and will be skipped in future checks. Cleared when a newer version becomes available.
rollbackCountint32Consecutive rollback count. Auto-update pauses after 3. Reset to 0 on any successful update.

Backup and Restore

The operator uses rclone to sync PVC data to and from an S3-compatible backend. All backup operations are driven by a single Secret named s3-backup-credentials in the operator namespace (the namespace where the operator pod runs, typically openclaw-operator-system).

S3 Credentials Secret

Create the Secret before enabling any backup or restore feature:

apiVersion: v1
kind: Secret
metadata:
  name: s3-backup-credentials
  namespace: openclaw-operator-system  # must match the operator namespace
stringData:
  S3_ENDPOINT: "https://s3.us-east-1.amazonaws.com"   # or any S3-compatible URL
  S3_BUCKET: "my-openclaw-backups"
  S3_ACCESS_KEY_ID: "<key-id>"
  S3_SECRET_ACCESS_KEY: "<secret-key>"
  # S3_REGION: "us-east-1"  # optional - see below

The first four keys are required. The operator uses rclone’s S3 backend (--s3-provider=Other), which is compatible with AWS S3, Backblaze B2, MinIO, Cloudflare R2, Wasabi, and any other S3-compatible service.

KeyRequiredDescription
S3_ENDPOINTYesS3-compatible endpoint URL (e.g., https://s3.us-east-1.amazonaws.com)
S3_BUCKETYesBucket name for backups
S3_ACCESS_KEY_IDYesAccess key ID
S3_SECRET_ACCESS_KEYYesSecret access key
S3_REGIONNoS3 region (e.g., us-east-1). Required for MinIO instances configured with a custom region. Without this, rclone defaults to us-east-1, which causes authentication failures on providers using a different region.

When backups run automatically

TriggerCondition
Pre-delete backupAlways runs when a CR is deleted, unless openclaw.rocks/skip-backup: "true" annotation is set or persistence is disabled.
Pre-update backupRuns before each auto-update when spec.autoUpdate.backupBeforeUpdate: true (the default).
Periodic (scheduled)Runs on a cron schedule when spec.backup.schedule is set. See Periodic scheduled backups below.

If the s3-backup-credentials Secret does not exist, pre-delete and pre-update backups are silently skipped (deletion and updates proceed normally), and the periodic backup CronJob is not created (a ScheduledBackupReady=False condition is set with reason S3CredentialsMissing).

Backup path format

Backups are stored at:

s3://<bucket>/backups/<tenantId>/<instanceName>/<timestamp>

Where:

  • <tenantId> is the value of the openclaw.rocks/tenant label on the instance, or derived from the namespace (e.g., namespace oc-tenant-abc yields abc), or the namespace name itself.
  • <instanceName> is metadata.name of the OpenClawInstance.
  • <timestamp> is an RFC3339 timestamp at the time the backup job runs.

The path of the last successful backup is recorded in status.lastBackupPath.

Skip backup on delete

To delete an instance without waiting for a backup (e.g., the S3 backend is unavailable):

kubectl annotate openclawinstance my-agent openclaw.rocks/skip-backup=true
kubectl delete openclawinstance my-agent

Restoring an instance

Set spec.restoreFrom to an existing backup path. The operator runs an rclone restore job to populate the PVC before starting the StatefulSet, then clears the field automatically:

spec:
  restoreFrom: "backups/my-tenant/my-agent/2026-01-15T10:30:00Z"

To find available backups, list the S3 bucket directly (e.g., aws s3 ls s3://my-openclaw-backups/backups/). The status.lastBackupPath field on any existing instance shows its last backup path.

Periodic / scheduled backups

Set spec.backup.schedule to a cron expression to enable periodic backups:

spec:
  backup:
    schedule: "0 2 * * *"     # Daily at 2 AM UTC
    historyLimit: 3            # Successful job runs to retain (default: 3)
    failedHistoryLimit: 1      # Failed job runs to retain (default: 1)

The operator creates a Kubernetes CronJob (<instance>-backup-periodic) that:

  • Mounts the PVC read-only (hot backup - no downtime or StatefulSet scale-down)
  • Uses pod affinity to co-locate on the same node as the StatefulSet pod (required for RWO PVCs)
  • Stores each run under a unique timestamped path: backups/<tenantId>/<instanceName>/periodic/<YYYYMMDDTHHMMSSz>
  • Uses ConcurrencyPolicy: Forbid to prevent overlapping backup runs
  • Runs with the same rclone image and security context (UID/GID 1000) as on-delete backups

Requirements: persistence must be enabled and the s3-backup-credentials Secret must exist. If either is missing, the CronJob is not created and a ScheduledBackupReady=False condition is set.

Removing the schedule: set spec.backup.schedule to an empty string (or remove the backup section entirely) and the CronJob is automatically deleted.


OpenClawSelfConfig (v1alpha1)

Group: openclaw.rocks Version: v1alpha1 Kind: OpenClawSelfConfig Scope: Namespaced Short name: ocsc

An OpenClawSelfConfig represents a request from an agent to modify its own OpenClawInstance spec. The operator validates the request against the parent instance’s selfConfigure.allowedActions policy and applies approved changes.

ColumnJSON Path
Instance.spec.instanceRef
Phase.status.phase
Age.metadata.creationTimestamp

Spec Fields

FieldTypeDefaultDescription
instanceRefstring(required)Name of the parent OpenClawInstance in the same namespace.
addSkills[]stringSkills to add. Max 10 items.
removeSkills[]stringSkills to remove. Max 10 items.
configPatchRawConfigPartial JSON to deep-merge into spec.config.raw. Protected keys under gateway are rejected.
addWorkspaceFilesmap[string]stringFilenames to content to add to workspace. Max 10 entries.
removeWorkspaceFiles[]stringWorkspace filenames to remove. Max 10 items.
addEnvVars[]SelfConfigEnvVarEnvironment variables to add (plain values only, no secret refs). Max 10 items.
removeEnvVars[]stringEnvironment variable names to remove. Max 10 items.

SelfConfigEnvVar:

FieldTypeDescription
namestringEnvironment variable name.
valuestringEnvironment variable value.

Status Fields

FieldTypeDescription
phasestringProcessing state: Pending, Applied, Failed, Denied.
messagestringHuman-readable details about the current phase.
completionTime*metav1.TimeTimestamp when the request reached a terminal phase.

Lifecycle

  1. Agent creates an OpenClawSelfConfig resource — status starts as Pending
  2. Operator fetches the parent OpenClawInstance and validates:
    • selfConfigure.enabled must be true (otherwise: Denied)
    • All requested action categories must be in allowedActions (otherwise: Denied)
    • Protected config keys (gateway.*) and env var names are rejected (otherwise: Failed)
  3. Operator applies changes to the parent instance spec
  4. Status transitions to Applied (success) or Failed (error)
  5. An owner reference is set to the parent instance for garbage collection
  6. Terminal requests are auto-deleted after 1 hour

Protected Resources

The following are protected and cannot be modified via self-configure:

  • Config keys: gateway (entire subtree) — prevents breaking gateway auth
  • Environment variables: HOME, PATH, OPENCLAW_GATEWAY_TOKEN, OPENCLAW_INSTANCE_NAME, OPENCLAW_NAMESPACE, OPENCLAW_DISABLE_BONJOUR, CHROMIUM_URL, OLLAMA_HOST, TS_AUTHKEY, TS_HOSTNAME, NODE_EXTRA_CA_CERTS, NPM_CONFIG_CACHE, NPM_CONFIG_IGNORE_SCRIPTS

Example

apiVersion: openclaw.rocks/v1alpha1
kind: OpenClawSelfConfig
metadata:
  name: add-fetch-skill
spec:
  instanceRef: my-agent
  addSkills:
    - "@anthropic/mcp-server-fetch"
  addEnvVars:
    - name: MY_CUSTOM_VAR
      value: "hello"

Full Example

apiVersion: openclaw.rocks/v1alpha1
kind: OpenClawInstance
metadata:
  name: my-assistant
  namespace: openclaw
spec:
  image:
    repository: ghcr.io/openclaw/openclaw
    tag: "0.5.0"
    pullPolicy: IfNotPresent
    pullSecrets:
      - name: ghcr-secret

  config:
    mergeMode: merge
    raw:
      mcpServers:
        filesystem:
          command: npx
          args: ["-y", "@modelcontextprotocol/server-filesystem", "/data"]

  workspace:
    initialDirectories:
      - tools/scripts
    initialFiles:
      CLAUDE.md: |
        # Project Instructions
        Use the filesystem MCP server for file operations.

  skills:
    - "@anthropic/mcp-server-fetch"
    - "npm:@openclaw/matrix"

  envFrom:
    - secretRef:
        name: openclaw-api-keys

  selfConfigure:
    enabled: true
    allowedActions:
      - skills
      - config

  resources:
    requests:
      cpu: "1"
      memory: 2Gi
    limits:
      cpu: "4"
      memory: 8Gi

  security:
    podSecurityContext:
      runAsUser: 1000
      runAsGroup: 1000
      fsGroup: 1000
      fsGroupChangePolicy: OnRootMismatch
      runAsNonRoot: true
    containerSecurityContext:
      allowPrivilegeEscalation: false
    networkPolicy:
      enabled: true
      allowedIngressNamespaces:
        - monitoring
      allowDNS: true
      additionalEgress:
        - to:
            - namespaceSelector:
                matchLabels:
                  app: postgres
          ports:
            - protocol: TCP
              port: 5432
    rbac:
      createServiceAccount: true
      serviceAccountAnnotations:
        eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/openclaw-role
    caBundle:
      configMapName: corporate-ca
      key: ca-bundle.crt

  storage:
    persistence:
      enabled: true
      storageClass: gp3
      size: 50Gi
      accessModes:
        - ReadWriteOnce

  chromium:
    enabled: true
    image:
      repository: ghcr.io/browserless/chromium
      tag: "v2.0.0"
    resources:
      requests:
        cpu: 500m
        memory: 1Gi
      limits:
        cpu: "2"
        memory: 4Gi

  ollama:
    enabled: true
    models:
      - llama3.2
      - nomic-embed-text
    resources:
      requests:
        cpu: "2"
        memory: 4Gi
      limits:
        cpu: "8"
        memory: 16Gi
    storage:
      sizeLimit: 40Gi
    gpu: 1

  networking:
    service:
      type: ClusterIP
    ingress:
      enabled: true
      className: nginx
      hosts:
        - host: openclaw.example.com
          paths:
            - path: /
              pathType: Prefix
      tls:
        - hosts:
            - openclaw.example.com
          secretName: openclaw-tls
      security:
        forceHTTPS: true
        enableHSTS: true
        rateLimiting:
          enabled: true
          requestsPerSecond: 20

  probes:
    liveness:
      enabled: true
      initialDelaySeconds: 60
      periodSeconds: 15
    readiness:
      enabled: true
      initialDelaySeconds: 10
    startup:
      enabled: true
      failureThreshold: 60

  observability:
    metrics:
      enabled: true
      serviceMonitor:
        enabled: true
        interval: 15s
        labels:
          release: prometheus
    logging:
      level: info
      format: json

  availability:
    podDisruptionBudget:
      enabled: true
      maxUnavailable: 1
    nodeSelector:
      node-type: compute
    tolerations:
      - key: dedicated
        operator: Equal
        value: openclaw
        effect: NoSchedule
    affinity:
      podAntiAffinity:
        preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              topologyKey: kubernetes.io/hostname
              labelSelector:
                matchLabels:
                  app.kubernetes.io/name: openclaw

  runtimeDeps:
    pnpm: true
    python: true

  gateway:
    existingSecret: my-gateway-token

  autoUpdate:
    enabled: true
    checkInterval: 12h
    backupBeforeUpdate: true
    rollbackOnFailure: true
    healthCheckTimeout: 15m