The controller worker advances Namespaces from provisioning to ready,
finishes deleting empty Namespaces, stops or deletes Agents, and prepares and
activates admitted Agent revisions. It runs separately from the OpenClaw Control Plane
(OCC) HTTP API, polls durable PostgreSQL work, and calls its selected Compute
Driver. The default development Docker Compute Driver creates one Docker
network per Namespace. It rejects the Harness authentication required by the
public deployment API and cannot deploy Agents. Select Kubernetes to deploy
Agents locally; it supports embedded OpenClaw, dedicated Codex, and dedicated
native OpenClaw when a full-facet provisioning SandboxDriver is selected. Reviewed
bundled or installed Drivers can reconcile their supported operations in both
development and production. See the deployment guide.
This reference owns durable reconciliation, queue states, and recovery guarantees. The worker flow explains their execution through the source; the quickstart and deployment guide own process startup procedures.
- Node.js 24 or newer and the repository's existing workspace dependencies.
- For default Compose development, Docker Engine and
docker compose. To deploy Agents locally, follow Local Setup. - A migrated local PostgreSQL database and an API using the same application connection; the full Compose stack starts both. See the configuration reference.
- For default PostgreSQL-backed development, the API must also use the
filesystem Configuration Driver root. Compose mounts
occ_configuration_dataonly into the controller at/app/.development/configurations. - A bootstrapped Installation. Compose's
bootstrapservice and the Helm initialization Job runscripts/bootstrap-installation.mjsafter migration and before the API or worker. Direct-process setups run that initializer first. NODE_ENV=developmentorNODE_ENV=productionand the application-roleOCC_DATABASE_URL.- In production, the shared absolute
OCC_CONFIG_PATHto trusted Installation startup YAML selecting approved IAM, Compute, and Configuration Drivers and the bundled Kubernetes Secret Driver.
The worker does not support process-local state. Never start it with migration or PostgreSQL administrator credentials.
The worker requires its own NODE_ENV and OCC_DATABASE_URL. Production also
requires the same absolute OCC_CONFIG_PATH startup YAML as the API.
Development omits OCC_CONFIG_PATH to select the bundled Docker Compute
Driver; the default filesystem Configuration Driver is API-only and uses the
controller's OCC_DEVELOPMENT_CONFIGURATION_ROOT. Set OCC_CONFIG_PATH only to
choose another trusted Driver set explicitly. The worker resolves the singleton
Installation internally. Driver IDs,
implementations, and closed-schema settings come from the YAML; worker
environment variables can tune the poll interval, claim lease, maximum
attempts, and optional readiness-marker path. Defaults and validation are
defined in the worker configuration reference.
The API's listener and Better Auth settings are not worker inputs. Both processes must use the same migrated PostgreSQL database.
Both processes resolve the persisted singleton Installation internally. Their YAML selects approved IAM, Compute, and Configuration Drivers and the bundled Kubernetes Secret Driver. Reviewed bundled and installed implementations are available according to the Driver selection reference. Driver-owned closed schemas are validated before construction; missing files, unknown fields, unavailable implementations, or plaintext credentials fail closed. See the Configuration guide.
The API additionally requires OCC_AUTH_SECRET and OCC_AUTH_BASE_URL.
User sessions authenticate controller API callers; ordinary
exact-resource IAM permissions and Restrictions still authorize every
operation. Operators must expose the API only through an internal ClusterIP
Service and enforce default-deny ingress with explicitly approved namespace and
Pod selectors.
Before serving requests or claiming work, both processes verify the existing
Installation and persisted IAM state. When the bundled Kubernetes Compute
Driver is selected, they also verify explicit Kubernetes credentials, TLS
trust, and exact Kubernetes Namespace access. The bundled Kubernetes
Configuration Driver validates its authentication settings at startup but
checks tenant ConfigMap access only when its first CRUD request runs; a
driver-managed provisioning Namespace can return 503 until its tenant
namespace and API RoleBinding exist. Explicitly selected external Namespaces
instead reject Configuration creation with 409 until ready. AgentRevisions
retain their selected Compute identity and immutable
Configuration snapshot and explicit Harness execution mode. Production worker
claim, stale-claim recovery, and backlog queries include Namespace and both
approved AgentRevision pairs: dedicated Codex and embedded OpenClaw. Each
Agent-owned gateway serves only its own selected version; unsupported
Harness/mode combinations and external ingress remain unavailable.
Namespace creation and deletion queue infrastructure work. Agent stop and
deletion queue exact-Agent lifecycle work. Agent deployment queues an immutable
version; the worker prepares it, activates its route, and retires its
predecessor. Kubernetes uses a single-replica gateway with Recreate, so
replacement can interrupt serving. For embedded OpenClaw, the predecessor can
stop before the replacement passes authentication and readiness. Read
Namespace and Agent reconciliation for lifecycle,
queue states, authorization, and recovery.
Optional OCC metrics expose request, reconciliation, Agent inventory, and process measurements through separate private API/worker listeners. Metrics remain active independently of log level.
Use the observability guide to set log levels,
configure export, and verify delivery. The API and worker share the OCC Pino
logger. The API disables Fastify's default request logging and emits one
sanitized http.completed record per response with the generated
request ID, method, route template, status, and duration. Unexpected internal
failures add http.unexpected_error with an error code that passes the log filter.
The worker emits fixed operational event classes through the same logger:
worker.started: confirms the selected Compute Driver and optional SandboxDriver.worker.health: reports readiness and pending work count at debug level.worker.completed: includesnamespaceId, work identity, attempt, outcome and a stable result code; for an Agent stop, deletion or credential-source withdrawal, an exhausted retry isoutcome: permanentwhileresultstays the Driver's classification; AgentRevision operations also includeagentIdandrevisionId. A failed or deferred version pass addscause: the error class, or for a transient dependency its closed failure code, withdependencynaming the dependency. An HTTP failure addsstatus, and the Kubernetes Statusreasonwhen its cause keeps one, such as403andForbiddenfor a refused Secret write. A version pass that loses the race for the Agent's selected version logs outcomeretrywith codeACTIVE_REVISION_CHANGED; the work fails once its attempts are exhausted. A pass that could not stop a refused candidate stays pending with codeREFUSED_CANDIDATE_STOP_PENDINGand addsrefusal, the refusal's code (CONVERGENCE_DEADLINE_EXCEEDEDonce a lifted refusal outlived the deadline), until the stop succeeds. A stopped Agent's stop or version pass whose Gateway drain yielded to other work stays pending withAGENT_STOP_YIELDEDand runs again after it; a deployment whose dedicated predecessor's drain yielded stays pending withPREDECESSOR_STOP_YIELDED. Such a deployment that then fails (with the full wait), is superseded or ends stopped first finishes that stop. A failed or superseded one addspredecessorStop, the stop'scause, if it still fails; a stopped one retries it. Only the work's first yield, then at most one a minute, is logged; these lines and the work's next other line addstopYields, the yields this worker counted for it. A provisioning plan that the Compute Driver refuses for a reason the caller cannot fix adds thatreason. A failed Namespace pass adds the Compute Driver'sreasonwhen it gives one: at most 256 printable characters that never carry another tenant's values. These fields stay in the local log; the Collector exports only the result code. Each deployment pass adds worker wall-clock milliseconds:durationMsfor the pass,deployPassesand summed ComputeprepareMsso far,readinessWaitMsfrom the first unready observation to the first ready one (or to now while pending),activationMsfrom the ready observation to completion, andelapsedMssince admission. Totals cover the passes this worker process ran; a restart starts them again. Maintenance, cleanup, and stop work carry no deployment timing.worker.error: reportsCLAIM_LOSTorWORKER_UNAVAILABLEwithout exposing credentials. A deployment pass that cannot read its stored refusal adds the work identity andcause, then leaves its claim to lease recovery. A claim lost around an external effect adds the work identity andcause:CLAIM_RENEWAL_REFUSED,CLAIM_RENEWAL_LATE,CLAIM_RENEWAL_FAILED, orCLAIM_LEASE_LAPSED(no renewal was confirmed within the lease).worker.claim-renewal-warning: a lease renewal that succeeded but answered after the lease could have run out, at warn level with the work identity, codeCLAIM_RENEWAL_LATEand the renewal'sdurationMs. The worker stops that work, because another worker may already own it.worker.pass-interrupted: a graceful shutdown aborted the pass in flight, at info level withcauseWorkerStopping; another worker resumes the work once its lease expires, unless that was its last attempt (LEASE_EXPIRED).worker.repository-cleanup-warning: a repository cleanup that another pass cannot settle, at warn level, once per work item andcause.causeisREPOSITORY_ATTEMPT_INVALIDATEDor the cleanup error code (for exampleCOMPUTE_DRIVER_MISMATCH).worker.stopped: confirms graceful shutdown.
Bootstrap and migration scripts use the same level and write machine-protocol
success records to stdout. Their structured failure diagnostics go to stderr.
Startup failures write startup-error, worker.startup-error,
installation.bootstrap-failed, or migration.failed and exit before serving
or processing work. Log sanitization keeps only reviewed fields and up to 32 configuration diagnostics, and drops
credentials, provider payloads, request objects, and unbounded error values. The
worker does not expose an HTTP health endpoint. Driver startup schema or semantic
refusals emit DRIVER_CONFIGURATION_INVALID with details: schema-owned
JSON Pointer paths, codes, and safe messages. This includes invalid StorageClass
names and runtime image settings. Submitted values and exception text are omitted.
- Namespace stays
provisioning: Start the separate worker, verify both processes use the same database, and inspectworker.healthandworker.completedoutput. - Docker Namespace does not become ready: Confirm Docker Engine access from the worker and inspect the per-Namespace Docker network labels. Docker Agent container tooling is for contributor verification; it cannot deploy through the public API. Use Docker Compute Driver troubleshooting.
- Configuration creation returns
503: Confirm the API, not the worker, hasOCC_DEVELOPMENT_CONFIGURATION_ROOTset and can write the/app/.development/configurationsmount backed byocc_configuration_data. - AgentRevision does not activate: Confirm its Namespace is
ready, the original actor retains exact-Agentdeploypermission andreadon any account in its immutable version, and its pinned Harness descriptor and Compute implementation match the worker. - Kubernetes Namespace or Agent workload does not become ready: Confirm the API and worker selected the same configured driver and the worker uses the bootstrapped singleton Installation; check explicit cluster authentication, externally provisioned tenant-local RBAC, enforced NetworkPolicies, image availability, and gateway EndpointSlices. See the Kubernetes Compute Driver guide.
- Installation is not bootstrapped: Confirm the Compose
bootstrapservice or Helm initialization Job succeeded against the API/worker database. For direct-process setup, runscripts/bootstrap-installation.mjswith the selected environment's protected output settings before starting either process. Resolve failed initialization manually before another attempt; bootstrap does not clean up or retry. - Startup YAML is missing or rejected: Set production
OCC_CONFIG_PATHto the same absolute, readable file for API and worker. Remove unknown Driver fields and plaintext credentials; verify all selected Driver implementations and exact Kubernetes access. KUBERNETES_API_UNAVAILABLEat startup: The Compute preflight got no answer from the Kubernetes API server in the event'shostandport. Confirm the API and worker egress policy still allows that address (Helmcluster.cidrs) and that the server is running.AUTH_SECRET_INVALIDorAUTH_BASE_URL_INVALIDat startup: The API and the initialization Job refuse a missingOCC_AUTH_SECRETor one under 32 characters (AUTH_SECRET_INVALID), and anOCC_AUTH_BASE_URLthat is not an absolute HTTP(S) origin (AUTH_BASE_URL_INVALID). In production the Job also requires HTTPS unless the host is loopback; in development the base URL host must be loopback. With native admin enabled, the API also reportsAUTH_BASE_URL_INVALIDfor anOCC_AUTH_COOKIE_DOMAINthat is malformed, a public suffix, does not contain the base URL host, or is used without HTTPS session cookies.GATEWAY_API_KEY_UNAVAILABLEat startup: The API refuses anOCC_GATEWAY_API_KEY_PATHthat is blank or not absolute, and a key file that is missing, not a regular file, over 4 KiB, or not printable ASCII without spaces (a trailing newline counts). Native admin without the path reports this code too. Helm mounts the file fromgatewayRouting.apiKeySecretName; see gateway routing.EXTERNAL_SIGN_IN_NATIVE_ADMIN_UNSUPPORTEDat startup: GitHub, Google and OIDC sign-in support host-only cookies only, so the API refuses any of them with native admin enabled, before it connects to the database. Turn off native admin; the chart refuses it with these providers.- Configuration operations fail: Verify exact Namespace or Configuration authorization, tenant-local ConfigMap CRUD, and a native JSON configuration document; see Configuration troubleshooting.
A valid PostgreSQL connection URL must be explicitly configured.: SetOCC_DATABASE_URLto the migrated application'spostgresql:connection.- Worker mode is rejected: Set
NODE_ENV=developmentorNODE_ENV=productionexplicitly. Production additionally requires valid trusted startup YAML selecting approved Drivers, including the bundled Kubernetes Secret Driver. AUTHORIZATION_DENIEDorACTOR_REVOKED: Inspect the initiating actor's current role, binding, exact-Namespace Restrictions, andreadpermission on any service account captured in the immutable version; see IAM.CLAIM_LOST: Another valid claim recovered the operation. The stale attempt cannot publish lifecycle state; inspect subsequent worker events.
- API operations, authentication, and permission reference
- Namespace lifecycle and deletion
- Agent Configuration, versions, and deployment
- Native service accounts and account authorization
- Controller and PostgreSQL configuration
- Docker Compute Driver and Compose development
- Namespace Configuration and Kubernetes ConfigMaps
- Kubernetes Compute Driver and local-cluster verification
- Identity and access management
- Platform architecture