Develop a Driver
Use this guide to add an implementation of an existing OpenClaw Control Plane (OCC) Driver contract. The Installation selects Drivers; an individual Agent or tenant cannot install or switch them. Start with the contract for the capability you are changing.
1. Choose the contract
The shared TypeScript contracts define the methods and data each Driver exchanges
with OCC. The base Driver types are
separate from each capability's drivers/<capability>/index.ts. Each reference links its
interface file, explains who calls those methods, what each implementation must
enforce, and which failures must stop the operation:
- Compute, Configuration, and IAM
- Sandbox, Credential Proxy, and Secret
- Plugin and ServiceAccount
Installed npm packages can implement Compute, Configuration, IAM, or Sandbox.
A Sandbox package can also provide Credential Proxy through one registration;
follow the Credential Proxy walkthrough for that
paired capability and its profile limits. Secret, Plugin, and ServiceAccount
have bundled selections only. If you need one of those capabilities, change the
existing platform implementation; adding an npm package alone will not make it
selectable. Use the supported selections
and repository layout to find its owner. Bundled
infrastructure implementations live under apps/controller/src/drivers/; native
IAM lives in packages/iam/. Composition lives in apps/controller/src/composition/.
Use the contracts in a separate Driver project
From the OpenClaw Enterprise repository root, with dependencies installed via
pnpm install --frozen-lockfile, pack both packages from the same revision.
Set archives to the absolute path of the vendor directory in your Driver
project.
archives=/absolute/path/to/driver-project/vendormkdir -p "$archives"pnpm --dir packages/utils pack --out "$archives/utils.tgz"pnpm --dir packages/contracts pack --out "$archives/contracts.tgz"In the Driver project's root pnpm-workspace.yaml, add this entry to the
top-level overrides mapping. The path is relative to the workspace root.
overrides: "@openclaw-enterprise/utils": "file:./vendor/utils.tgz"From that same root, run pnpm add ./vendor/contracts.tgz. The override resolves
the contracts package's dependency on @openclaw-enterprise/utils to the local
archive. Your TypeScript code can then import from @openclaw-enterprise/contracts.
2. Implement and register it
For an installed implementation, export a closed configurationSchema,
validateConfiguration, and createDriver from a precompiled JavaScript ESM
entry point. The platform validates structure before calling the semantic validator,
which returns a readonly field-error list (empty on success), as described in
configuration definitions;
factories consume the original validated input. Callbacks receive an isolated,
frozen copy and cannot replace configuration values. Declare runtime contributions only when a
resource-owner binding supplies their authorization and lifecycle. A Sandbox
advertising networkPolicy must contribute (agent, sandbox-network-policy).
Return the selected id and implementation, the expected
capability, and its required methods on each capability object. For paired
capabilities, return one DriverRegistration with shared lifecycle hooks
instead of independent instances. The controller must declare the package
as a direct production dependency at an exact version; update the lockfile with
it. For a bundled implementation, follow the existing capability directory and
wire it into controller composition. Consult the package and factory contract
for the complete loader rules.
Implement the failure paths as carefully as the successful ones. OCC owns platform authorization and resources; an execution Driver acts on the admitted scope it receives. Check backend ownership before changing a resource, make retried operations safe where the contract requires it, and fail rather than silently switching backends or broadening access. An installed package runs with control-plane authority, so its publisher and code need review. Startup validation can reject the wrong shape; it cannot establish that the code protects tenant boundaries.
3. Verify and document the change
Run the following from the repository root with dependencies installed:
pnpm typecheckpnpm test:files -- tests/integration/driver-plugin-installation.test.tsThe second command exercises package installation and controller admission for fixture Drivers. It does not verify your backend. Extend the relevant conformance and integration coverage and exercise your implementation through its normal API or worker caller, with the real backend needed to prove the behavior. Cover consequential failures such as an unavailable backend, access outside the admitted scope, or cancellation where supported.
Update the capability reference or implementation guide and the owning runtime flow when behavior changes. Use the contributor documentation guide for placement and writing conventions.
Check protected static Secret reads
Copy the test-only helper into your Node.js 24 test project with packed contracts types. Call
await assertProtectedStaticSecretRead(t, driver, identity, isIdentityRefusal, 1_000)
inside test("protected read", { timeout: 5_000 }, async (t) => { /* call here */ });
run it with node --test your-adapter.test.ts. Supply a disposable Driver, valid
SecretIdentity, and exact adapter error matcher. All reads share the supplied
millisecond budget; Node's finite enclosing timeout fails hung reads and runs cleanup.
The helper creates, rotates, and deletes one synthetic Secret. A create without a
returned reference cannot be cleaned up. Cancellation does not prove I/O drained.
This local check does not certify a backend or enable external Secret installation.
