OpenClaw EnterpriseDOCSGitHub

Installation Driver Package Loading Flow

Overview

The API and worker independently load trusted Installation YAML and construct their selected IAM, Compute, Configuration, Secret, and optional Sandbox capabilities. Only the API constructs the optional Backend client and ServiceAccount Driver. This trace follows package resolution through process composition and stops at request serving or worker reconciliation. Development without startup YAML uses the defaults traced in platform startup.

Entry Points

Flow

graph TD
  subgraph Startup["Independent API or worker startup"]
    A["Read trusted Installation selections"] --> B{"Bundled or packaged"}
    B -->|bundled| C["Resolve built-in implementation"]
    B -->|packaged| D["Resolve package identity and import code"]
    C --> E["Validate Driver configuration and capability"]
    D --> E
    E --> F["Construct Configuration, optional Sandbox, Compute, Secret, and IAM factory"]
  end

  subgraph OCC["Control-plane ownership"]
    F --> P{"API with ServiceAccount selection?"}
    P -->|yes| Q["Build Backend client and ServiceAccount Driver factory"]
    P -->|no| G["Construct IAM with platform state"]
    Q --> G
    G --> H["Select exact Drivers and attach lifecycle owners"]
    H --> V["Freeze Driver-projected<br/>startup values"]
    V --> I["Authorize requests and reconcile Namespace lifecycle"]
    I -->|Installation administer| R["Return projected values<br/>or values unavailable"]
  end

Execution Trace

1. Resolve and validate selected Driver implementations

apps/controller/src/composition/installation-config.ts:loadInstallationConfiguration, apps/controller/src/composition/driver-packages.ts:loadDriverPackage

The API, worker, and Helm Installation check load the bundled OpenShell implementation when validating its Credential Proxy or constructing its Sandbox. An Installation with Kubernetes Compute and neither OpenShell selection skips those imports.

Each process reads the same trusted startup YAML. Configuration, IAM, Compute, and optional Sandbox selections may name an operator-installed package; implementation identity comes from its installed metadata. The installed root package.json accepts one leading UTF-8 byte order mark, as Node does; remaining text must still be a JSON object with the selected name and exact version. Secret selection is required in this YAML path and accepts only bundled Kubernetes Secrets. Optional service_account selection identifies the bundled Backend member; it has no package-loading path. The operator installation guide defines the package, pinning, registry, and configuration contract. TypeBox checks each selected Driver's closed schema once per admission call before implementation-owned semantic validation. requireConfiguration gives the callback an isolated frozen copy, checks its field-error list, and returns the original input. Driver callbacks cannot supply replacement data; malformed results and throws fail closed. Composition retains each definition with its selection, registers startup and named contributions in packages/occ/src/configuration-registry.ts, and rejects missing owner bindings, duplicate identities, or unsupported schemas before construction. Invalid package exports, identity, capability, or lifecycle wiring reject startup without fallback.

apps/controller/src/composition/installation-config.ts:selected captures inspection values immediately after validation, before any constructor or package factory. packages/contracts/src/configuration-definition.ts:serializeStartupConfiguration copies actual input values and masks schema writeOnly fields or blocks. It combines branch annotations conservatively through the existing resolver. The separate immutable result cannot change when a factory mutates its own input. Unsupported inspection reports unavailable without raw values or exception text.

The package root export resolver follows Node's import() resolution: "." selects a subpath only at the top level (nested, it is an unmatched condition name), conditions are Node's defaults (node, import, module-sync, node-addons, default) in key order, and mixed subpath and condition keys or numeric keys are invalid. Invalid targets and unmatched conditions can select a later array entry; a matched null condition ends that condition branch. The selected target is resolved as a URL inside the package and percent-decoded; it must name an existing file exactly, with no extension, directory index or main lookup, and an encoded separator or directory is refused. Package containment, the compiled ESM check, and import must then succeed before Driver construction. Import uses the checked realpath with the selected URL's query and fragment preserved, so URL-qualified package profiles retain Node's module identity. Containment rejects only a parent directory path; an in-package filename that begins with two dots remains valid, matching Node's export resolution. The entry must be .mjs, or .js whose nearest package.json (searched from the entry's directory up to the package root, stopping at a node_modules directory, as Node's import does) declares "type": "module". The refusal names that package.json, or says the entry is neither .mjs nor .js. Unlike Node, the check never detects ESM syntax in a .js file outside a module scope. Missing files and import failures do not select another target.

For packageless Compute, the exact id compute-ssh selects SshComputeDriver with implementation occ/ssh. Every other packageless id retains Kubernetes selection. The SSH reference owns the host contract. Its helper is read at module import and sent through SSH operations with a 180-second timeout; bindAgent supplies authoritative Namespace and ServicePrincipal identity before version operations.

Installed packages run arbitrary, unsandboxed code with controller database, credential, Kubernetes, tenant, and authorization authority. An untrusted or malicious package can violate authorization and tenant isolation; package validation and lockfile integrity do not establish publisher trust.

Local Setup also calls the shared admission path before provisioning: internal/occdev/sandbox_network_policy.go:loadSandboxNetworkPolicies invokes scripts/validate-sandbox-network-policy.ts, which uses requireConfiguration for platform structural validation and Driver semantic checks. A failure stops before creating development state or invoking a container engine. API and worker startup log DRIVER_CONFIGURATION_INVALID with field diagnostics that identify the setting without echoing submitted values.

2. Construct the single authoritative runtime bundle

apps/controller/src/composition/installation-config.ts:loadInstallationConfiguration, apps/controller/src/composition/driver-packages.ts:createExternalDriver

The loader constructs Configuration, optional Sandbox, Compute, and Secret Drivers and returns them with the validated Installation and required createIAMDriver(state) function. A selected Sandbox Driver is passed to bundled Kubernetes Compute; selecting it with SSH or packaged Compute rejects startup. Bundled and packaged IAM receive the same controller-owned platform state. The bundled IAM Driver loads current policy for each identity lookup and authorization decision; packaged Drivers must do the same, which operator review verifies because the runtime cannot enforce package internals. Packaged factories must return their exact server-owned capability and identity. The Helm upgrade hook's installation-check also runs this loader with only NODE_ENV, OCC_CONFIG_PATH, the API's optional OCC_CONSOLE_THEME_DIR and the Installation, theme and repository mounts, so factories must defer other environment and file reads past construction.

Kubernetes-specific image and projected-credential requirements apply only to bundled Kubernetes Compute. SSH preflight verifies local SSH files and probes each configured host. Startup enforces the production version-stage contract before returning any production runtime. Development requires the five core operations: ensureNamespace, deleteNamespace, prepareRevision, stopRevision, and retireRevision. It permits Drivers without activateRevision and deactivateRevision. The worker still fails closed if a required stage becomes unavailable.

3. Construct the API-only Backend branch

api-startup.ts:startApi handles a selected ServiceAccount Driver after loading the common bundle. It requires PostgreSQL, Compute credential-storage methods, and an owning Backend definition. It reads that Backend's apiKeyPath, constructs ChatGPTClient, and supplies the ServiceAccount Driver factory to controller composition. The worker keeps only nonsecret Backend metadata; it constructs neither the client nor this Driver. The managed credential flow continues through account creation, issuance, and deployment checks.

4. Load current policy and hand off lifecycle ownership

apps/controller/src/worker.ts:ControllerWorker.start

API and worker construct separate process-local Driver instances. Production composition validates persisted policy, creates the selected IAM Driver with platform state, and selects the exact common Driver identities with OCC. The API also registers its selected ServiceAccount Driver after composition. Worker startup checks persisted identities, including Secret and optional Sandbox, and attaches selected lifecycle owners once. Both processes pass the retained definitions into OCC; the worker also resolves the current policy contribution before live application.

apps/controller/src/composition/installation-config.ts:installationDriverConfigurations forwards each selected identity and its retained redacted snapshot to the registry. The registry keeps no raw startup input. Later startup-file edits do not change these values; there are no Driver projection callbacks.

packages/occ/src/index.ts:OpenClawController.discoverConfigurations checks Installation administer before returning these projections as startupConfiguration. The Console renders them in expandable Driver sections. Agent discovery retains its resource-owned actions and does not return startup values. Neither path exposes executable validators. The bundled IAM Driver loads current policy for identity lookup and authorization; installed IAM Drivers must honor the same contract. Neither is rebuilt or replaced after account or policy changes.

OCC owns exact-resource authorization and invokes Compute only during Namespace or Agent revision reconciliation. Embedded OpenClaw and dedicated Codex retain their existing Harness-owned runtime topology.

Debugging and Verification

Search documentation