Compute admission checks
A ComputeDriver can implement side-effect-free checks that let OCC refuse a request before it stores a Configuration or Agent, creates an Agent revision, or stops a running one. The checks read only their arguments and the Driver's trusted Installation settings, never the backend.
When OCC calls each check
| Method | Called at | Refusal |
|---|---|---|
validateConfiguration(configuration, options?) |
Configuration create and update, Agent provisioning, and Preset create and update (rendered with defaults; options.unresolved marks unfilled variables) |
ConfigurationHarnessError answers 400 with its message. Use it for rules every topology applies; validateHarnessAuth applies them again at deployment. |
validateHarnessAuth(harness, auth, configuration, secretBindings?, sourceType?) |
Deployment and provisioning, which require it; Agent create and update, with null bindings, when the binding is runtime or a Secret and the Configuration selects a model |
ConfigurationHarnessError answers 400 with its message; any other error becomes a fixed 409. A missing method at deployment is a dependency-unavailable error. |
validateGatewaySettings(configuration) |
Deployment, after validateHarnessAuth |
ComputeGatewaySettingError answers 409 with its message. Leave other refusals to preparation. |
validateWorkspaceSetup(harness, configuration, sandboxDriverId?) |
Agent create with initial workspace files, Agent update while that setup is pending (or completed, when the update names another Configuration or execution mode), deployment of an Agent with a pending or completed setup, and provisioning with initial workspace files | ConfigurationHarnessError answers 400; any other error becomes a fixed 409. Preparation applies the same rule. |
validateRepositoryCredentials(harness, sandboxDriverId?) |
Deployment with repository bindings, which requires it, Agent create and update, and the provisioning request, with repository bindings | Any error becomes a fixed 409. |
A message names the setting and what the Driver accepts, never a submitted
value, in at most 256 characters. Agent provisioning also calls
validateAgentProvisioning; see
initial runtime credential provisioning.
Agent save
Agent create and update read the named Configuration and check the Agent as it will be stored, with the messages deployment uses:
- With a Sandbox Driver selected, the execution mode must be
dedicated. An omittedexecutionModeisembedded. - The Harness the Configuration selects must be approved for the execution mode; a Harness approved only for the other mode is refused.
- The Compute checks above run on the values deployment would admit, after
the Sandbox Driver's
configureAgentand the logging policy.validateHarnessAuthreceivesnullSecret bindings and applies only rules that depend on the Agent.
Save leaves to deployment what depends on live state or not on the Agent: a Harness the Installation approves for neither mode, a Configuration that selects no model or no supported Harness, ServiceAccount and credential-source Harness authentication, a Secret binding whose Secret is gone, and whether the Installation provides dedicated OpenClaw or a channel runtime. On the bundled Kubernetes Compute, Configuration save already checked the channel Secret bindings (below). A stored Agent that fails a check still reads; its next update must fix the pair.
Kubernetes Compute
Kubernetes Compute keeps these rules in
its rule module.
validateConfiguration refuses:
- an enabled
channels.<provider>other thanslackormsteams; - a non-empty
auth; - an
envorenv.varsname startingOPENAI_orANTHROPIC_in any case, orCODEX_ACCESS_TOKEN,CODEX_CHATGPT_WORKSPACE_IDorCODEX_LOGIN_MODE; - on any
models.providers.<provider>, whether or not a model setting selects it: a credential header inheaders(on the provider or one of its models) orrequest.headers, a header name that is not a valid HTTP field name, and arequest.authother than exactly{mode: "provider-default"}. A credential header's last hyphen-, underscore- or dot-separated word isauth,authorization,token,secret,password,cookie,credential(s),signature,jwtor a like word, or its name ends inkey(not an idempotency, cache, dedup, partition, shard or sort key), before any trailing algorithm or version word such as-sha256,-ed25519or-v2; the rule lists them. The refusal quotes the header's name, never its value. On a Preset save, a header name that waits on a variable without a default is matched as the text around the variable (Authorization{{ vars.suffix }}is refused) and checked again once filled. Amodelsthat is not a list is refused too: it would hide its rows. - once the Configuration's model policy selects a Harness and its primary
model a supported provider: a model selection (including a
modelskey ormodelPolicy.allowentry) ormodels.providers.<name>.apiKeyoff that provider, and anapiKeythat Harness refuses. OpenClaw'sopenrouter:autoandopenrouter:freename theopenrouterprovider. Dedicated Codex also refuses a policy entry without a provider,mediaModels.*andvoiceModel: OpenClaw calls media and voice models directly, and Codex serves only chat models. Dedicated Codex takes noapiKey; OpenClaw takes${NAME}or an env SecretRef to the binding's variable, through an env provider that allows it or OpenClaw's default env alias. An inline key is left to the Configuration Driver. A Preset save runs this rule too, except on a reference or provider key whose provider waits on a variable, or anapiKeywhose value orsecretssource does: the launch checks them once filled. A draft whose model policy selects no Harness is left to deployment. - a reference OpenClaw cannot read in an active plugin's
secret input, with the
deployment refusal's text. A Preset save leaves it to the launch when
pluginsorsecretswaits on a variable. - once the model policy selects Codex, which runs only as Dedicated Codex, a
plugin policy that turns off the
codexplugin every Dedicated Codex Gateway enables, which would stop that Gateway at every start:plugins.enabled: false, aplugins.denythat listscodex, or a non-emptyplugins.allowwithout it (IDs compared trimmed and lowercased, blank items ignored). Except at provisioning, an item that is not text gets the save rule first.plugins.entries.codex.enabled: falsepasses: startup turns that entry back on. A Preset save leaves an item that waits on a variable to the launch.validateHarnessAuthapplies this rule to every Dedicated Codex Agent, after the rule that keeps file-transfer on for a Gateway that hosts the Agent's workspace node. Configuration save and deployment run this save rule first, so when both apply they namecodexfirst; Agent save and provisioning runvalidateHarnessAuthfirst and name file-transfer. - a
gateway.auth.trustedProxy.allowUserswithoutocc-workspace-files, or with an identity Gateway authentication refuses, and atrustedProxy.deviceAutoApprovethe Gateway's schema refuses. Deployment runs this save rule first (400) andvalidateGatewaySettingsafter it (409); provisioning applies the rule throughvalidateAgentProvisioning(409). Either way a dedicated Agent's running revision keeps serving. A Preset save leaves a setting that waits on a variable to the launch. - once the model policy selects Codex, a missing
gateway.auth.passwordwhen the Installation setsruntime,gatewayRoutingandnetwork.pluginStatusProxySourceCidrs. The Gateway then applies the Agent's workspace node at runtime and confirms it through its own Gateway client, which signs in with the generated password; without it every activation failed withAGENT_GATEWAY_UNAUTHORIZEDafter the running revision stopped. Deployment refuses a stored one with the same400before any revision, and the Console Agent page holds Deploy with that text. OpenClaw Agents, and Installations without private status (the node is then in the pod spec), need no password.
This Compute delivers channel credentials only from Configuration Secret
bindings. OCC, not a Driver member, refuses at Configuration create and update,
provisioning, and /agents/validate with configuration.secretBindings a
${NAME} reference (also inside other text, and in a credential field also
with a fallback), $NAME secret-input value or environment SecretRef in an
enabled channel without a binding of that name, and a secret-input ${ the
runtime does not substitute,
under the bundled implementations (occ/kubernetes, kubernetes-local). The
Secrets reference lists the forms. It shares
requireChannelSecretBindings with deployment admission; the message names
the setting and the binding or text.
These close the credential slots in a provider's headers and request.
The provider apiKey stays, checked against the Harness binding. The
Configuration Driver accepts the apiKey, the credential headers,
request.auth.token and .value and the TLS client keys only as references,
and refuses a request.proxy.url or model baseUrl with a user name or
password.
On Kubernetes a reference does not admit a credential header or a non-default
request.auth: model credentials come only from the Agent's Harness
authentication binding. Deployment runs OCC's model provider settings rules
(baseUrl, api, the models list, header names), then validateConfiguration,
on the stored values before the Configuration Driver validates them, so a stored Configuration that predates a
rule gets its save message.
A credential under a header name the rule does not match, in
localService.env, or as a literal in another env name that a reference
reads, still passes: the binding cannot see what a name means.
validateHarnessAuth applies the other rules above first, then names the
Agent's harnessAuth.method when its topology cannot use it (embedded OpenClaw
takes api_key, dedicated OpenClaw also credential_source, and dedicated
Codex also codex_pat and oauth), then the model provider rule above, a
channel credential reference without a Configuration Secret binding (for a
row stored before Configuration save checked it), and the dedicated
OpenClaw model catalog settings. On OpenClaw it also names a ${ or SecretRef in
the selected provider's settings (other than apiKey) or the primary model's
agents.defaults.models entry: the startup model check gets only the binding's
credential. Configuration save accepts these, since another Compute may resolve
them. Whether the Installation supplies
what a method needs (OAuth needs no Sandbox Driver; a credential source needs
its paired Sandbox) stays a fixed 409.
The channel runtime rule stays at deployment: it depends on the execution mode
and the Installation's runtime.channels.
With runtime set, validateHarnessAuth refuses dedicated without
gatewayRouting (and node enrollment) or runtime.gatewayNodeSelector,
naming the setting, at Agent save too: the execution mode is the Agent's.
Create Agent's preflight (POST .../agents/validate) runs the same check when
it names the planned harnessAuth, before the caller saves a Secret or
Configuration. Agent provisioning runs it for a Secret binding before its plan
check (validateAgentProvisioning), so it answers the same 400. A save that skips validateHarnessAuth (no model selected, or
another binding, such as a credential source) leaves it to deployment.
SSH Compute runs only embedded OpenClaw (other topologies get
a fixed 409) and names harnessAuth.method for any method but runtime,
through the same
shared rule.
validateWorkspaceSetup needs an agents.entries roster of main alone, in
any letter case (or none), and the managed workspace path (or
/home/node/workspace on a dedicated Harness); preparation also needs runtime
storage, an Installation setting. For a provisioning Sandbox, Compute approves only the managed workspace path
returned by its selected configureAgent transform. It initializes the approved
Harness PVC in a restricted private bootstrap Deployment, verifies completion,
and removes all writer Pods before Sandbox handoff. The Harness checks the
completion marker at its effective path, including OpenShell relocation. Other
workspace paths fail; Sandbox repository bindings remain unsupported.
Docker Compute
applies the same
shared rule,
with the same messages, at Agent save and in preparation. It accepts both paths on
either topology, since one volume backs both, and also refuses skipBootstrap
and skipOptionalBootstrapFiles on agents.defaults or main.
SSH Compute applies the shared roster rule, with its message, at Agent save and
when deploying an Agent with a setup, pending or completed. With initial
workspace files it also refuses any workspace on agents.defaults or main
there: the host always uses a workspace it derives under the Agent's own
directory, and checks that path again at deployment.
