Backends (experimental)
Experimental / work in progress. Backends are an unfinished Installation integration abstraction. The contracts and workflows below describe the current implemented subset; they are not a general model-provider catalog.
A Backend is Installation-owned configuration that gives related Drivers an
authenticated client. The bundled ChatGPT client manages upstream service
accounts. Its nullable Agent backendId association neither grants permissions
nor changes model or Harness selection. The GitHub Backend owns repository
credential configuration for the built-in GitHub policy and uses the separate
Agent repositoryBindings selection. The OpenShell Backend owns the gateway
connection shared by the OpenShell Sandbox and Credential Gateway Drivers.
Backends have no OCC resource or write API. Installation administrators can
discover nonsecret configured IDs and types through GET /backends.
Configure the ChatGPT Backend for the operator workflow. The bundled Backend types are ChatGPT, GitHub, and OpenShell.
A model provider identifies the service used by a model (for example, OpenAI). The Provider → Model choice in Agent setup selects model configuration; a Backend supplies clients to Installation Drivers. These are independent choices. An Agent using an existing OpenAI API key does not need a Backend.
Read configured Backends
GET /backends returns {data:[{id,type}],meta:{requestId}} after the selected
IAM Driver authorizes administer on the singleton Installation. Namespace
access alone does not grant discovery. The console route
/console/backends uses this Installation-wide inventory regardless of the
selected Namespace. Its sidebar tab is hidden while the concept is experimental;
the Create Agent model-provider selector does not query this inventory.
The API projects the validated definitions loaded at startup. It returns no
credentials, paths, workspace identifiers, Driver settings, or full configuration,
and makes no upstream request. A configured Backend is not a health or activation
claim. Authorized empty configuration returns 200 with data:[]; unavailable
discovery wiring or IAM is an error, never an empty inventory. Changes take effect
through the existing startup configuration lifecycle below.
Installation configuration
Add this fragment to the required occ and ordinary Driver settings:
backend: - id: openai type: chatgpt configuration: workspaceId: "11111111-1111-4111-8111-111111111111" apiKeyPath: /etc/openclaw/chatgpt/admin-key credentialTtlSeconds: 2592000 drivers: service_account: chatgpt-service-accountsdrivers: service_account: id: chatgpt-service-accounts configuration: {}The singular backend key is an array; omission or [] means none. IDs are
unique strings of 1–200 characters, counted as Unicode code points, with no
leading or trailing whitespace and no control characters (C0, DEL or C1) or
line (U+2028) or paragraph (U+2029) separators. An Agent's backendId follows
the same rule, so any configured ChatGPT Backend ID can be selected. A GitHub
Backend ID must also fit in 200 UTF-16 code units (for example, 100 characters
outside the Basic Multilingual Plane), because repository bindings store it
under that bound. openai is an operator-chosen ID. The bundled types are
chatgpt, github, and openshell; each has its own closed configuration and
required member Drivers. A ChatGPT workspace UUID identifies the upstream workspace, not a Namespace.
apiKeyPath must be an absolute mounted file path. The key needs
chatgpt.enterprise.service_account.write and authority for that workspace.
Inline keys and configurable upstream URLs are unsupported. Credential TTL
accepts 1–2,592,000 seconds and defaults to 2,592,000 (30 days); changing it does
not renew issued credentials. Retired integrations and adminKeyPath keys fail.
The production chart's backend.chatgpt.secretName must be a lowercase
DNS-subdomain Kubernetes resource name of at most 253 characters. Its
backend.chatgpt.key accepts letters, digits, -, _ and ., up to 253
characters, but cannot be . or start with ..; the unchanged default is
admin-key.
backend[].drivers declares required membership. The ChatGPT Backend and its
selected service_account Driver must be configured together with matching IDs.
OCC selects one Driver per capability, so only one ChatGPT Backend is supported.
Missing, conflicting, or unselected members reject configuration.
GitHub repository credentials
The GitHub Backend selects one canonical nonsecret JSON registry:
backend: - id: github-primary type: github configuration: registryPath: /etc/openclaw/repository-registry/registry.json drivers: repo: repository-credentialsrepository: id: repository-credentials configuration: sessionDurationSeconds: 86400 nativeSender: controlSocket: /run/openclaw/repository-control/private/control.sock publicCaPath: /etc/openclaw/repository-ca/ca.crt preparedGitHub: custodyKeyPath: /etc/openclaw/prepared-repository/custody.key privateKeyPath: /etc/openclaw/prepared-repository/private-key.pemKeep the ordinary required Driver settings alongside this fragment. One GitHub
Backend is supported and may coexist with one ChatGPT Backend. Its member ID
must match repository.id. With this configuration, the API and worker use the
built-in GitHub registry policy. They require no public Repo Driver registration.
Omit both the GitHub Backend and repository to leave Git unconfigured.
Existing configurations may keep or omit repository.policyMode: built-in with
the same policy and protected sender identity. Startup rejects other values and
the retired drivers.repo selection. Drain admitted work on its original owner
before changing senders. The registry's Backend ID must match the definition,
and the session duration must fit the registry's maximum.
See prepared native Git
for delivery settings.
The API, worker, and credential service consume the same immutable, versioned registry ConfigMap. Its exact Namespace, repository, and profile policies own admission; no repository list is stored in Helm values. Follow the repository credential reference for registry fields and the operator guide for service setup. The capability requires the bundled Kubernetes Compute Driver without a Sandbox Driver; admitted Agents must use a supported runtime and authentication combination.
OpenShell gateway
The OpenShell Backend holds the connection to one OpenShell gateway deployment.
These paths are the files Helm backend.openshell.clientSecretName projects
(ca.crt, tls.crt, tls.key under /etc/openclaw/openshell). The chart
mounts no bearer token file or separate operatorTls pair, so chart installs
cannot retrieve Codex OAuth access tokens; other packaging must mount those files
itself.
backend: - id: openshell type: openshell configuration: endpoint: https://openshell-gateway.openshell-system.svc:8080 auth: mode: mtls certificatePath: /etc/openclaw/openshell/tls.crt privateKeyPath: /etc/openclaw/openshell/tls.key rootCertificatePath: /etc/openclaw/openshell/ca.crt drivers: sandbox: openshell-sandbox credential_gateway: openshell-credentials credential_refresh: openshell-refreshIts closed configuration accepts:
endpoint:host:port(bracket IPv6 literals, such as[2001:db8::1]:8080), or anhttporhttpsorigin (scheme letters are case-insensitive) without credentials, path, query, or fragment. HTTP origins use port 80 when omitted; an explicit:80also remains 80 in the gRPC target. HTTPS retains its default 443. Either form refuses an IPv6 zone ID ([fe80::1%eth0]), which URL parsing cannot carry. An IPv4 host must be four decimal octets from 0 to 255 with no leading zeros; shorthand, a single integer, hex, and leading zeros dial a different address and are refused. The port, explicit or the scheme default, must be 1 to 65535, and a bare value must also parse ashttp://<value>, as both gateway clients read it.serviceName,scheme, andport: used whenendpointis omitted. A dotted name is used as-is; a bare name resolves in each tenant namespace.portdefaults to8080, andschemedefaults tohttpsonly whenrootCertificatePathis set. OAuth2 credential sources refusetoken_urlhosts in the gateway's namespace only when OCE knows it: from a bare or<service>.<namespace>serviceName, or aserviceNameorendpointhost<service>.<namespace>.svc[.<cluster domain>].auth:{ mode: unauthenticated },{ mode: bearerTokenFile, path }, or{ mode: mtls, certificatePath, privateKeyPath }. File paths must be absolute. mTLS requires HTTPS and supplies the client certificate and key to gRPC only. Service HTTP/WebSocket requests retain their separate scoped bearer identity.requestTimeoutMs: the per-call deadline, from 1000 to 30000 ms. The bound limits how late a timed-out credential registration can land. Sandbox deletion has its own 120-second bound: OpenShell answers only after the Sandbox Pod terminates, and OCE waits until the Sandbox is gone.rootCertificatePath: an absolute path to the gateway CA. Anhttpsendpointat an IP address sends no TLS server name, so the gateway certificate must carry that IP address.operatorTls: optional{ certificatePath, privateKeyPath }, both absolute paths. Required for OAuth access-token retrieval; requires HTTPS. It opens a separate certificate-only channel to the same gateway, using the same server CA and no bearer header. Ordinary RPCs keep the configuredauthidentity.insecureTransport: network-policy: required when the connection lacks TLS or bearer/mTLS authentication, and rejected otherwise. It cannot enable plaintext mTLS. It declares that NetworkPolicy restricts the gateway to the OCE API, worker, and OpenShell supervisors. Credential registration sends resolved values over this connection, and OCC cannot verify the NetworkPolicy itself.
Either endpoint or serviceName is required. Both drivers.sandbox and
drivers.credential_gateway are required and must match the selected bundled
OpenShell SandboxDriver and
OpenShell Credential Gateway. The
optional drivers.credential_refresh member must match the selected
Credential Refresh Driver; OpenShell keeps
refresh state on the gateway's provider records, so the two roles share this
Backend. One
OpenShell Backend is supported. Composition builds one gateway client object
and injects it into all members. It caches ordinary and credential-export
clients separately per resolved endpoint. The API and worker each construct it,
so mount their required credential files there, never in the Harness or Agent
Gateway. Restart these processes after rotating an operator certificate to replace
cached TLS channels. See the operator trust requirements.
Optional drivers.credential_proxy selects the paired
protected egress adapter. It requires an
authenticated HTTPS gateway and the credential-access protocol. Released OpenShell
v0.1.4 supports OAuth refresh and operator GetProviderCredentials, but lacks
the protected credential-access and loaded-enforcement contract. The protected
counterpart has that contract, not the OAuth export RPC. Select and verify the
deployed capability; the combined client schema is not a supplier capability claim.
Protected revision admission refuses legacy credential attachments.
For native OpenShell mTLS, a verified client certificate's CN becomes the User subject and OU values become roles. Without an OIDC administrator role configured, an authenticated User has platform administrator authority. Treat the dedicated client CA and every certificate it signs as administrator credentials. Keep the client key in the trusted control plane, never an Agent or Sandbox. With OIDC configured, its administrator-role check still applies; mTLS does not bypass it.
Driver and client contract
The Backend contract groups an ID,
concrete client, and declared member IDs. Composition constructs
Backend<ChatGPTClient> and injects it into ChatGPTServiceAccountDriver.
Membership is established there; the ordinary Driver registry retains its
(capability, id) identities and has no generic Backend ownership field.
Only the API reads the ChatGPT admin key and constructs its client and ServiceAccount Driver. The worker receives nonsecret ChatGPT definitions for reconciliation. Existing Driver lifecycle, controller/state injection, Compute credential storage, installed factory signatures, and package trust rules remain unchanged.
For GitHub, the API and worker bind GitHubRepositoryPolicy to the configured
Backend, validated registry and selected duration. API resolution uses local
policy. For native delivery, the worker invokes session operations through the
selected native sender and its private control socket.
Only the separate service owns the App key, private TLS material, token
acquisition, and forwarding engine.
Agent association and immutable deployment
Agent create and PATCH use these rules:
| Input | Create | PATCH |
|---|---|---|
| Omitted | Save null. |
Preserve current value. |
null |
Save null. |
Clear the draft reference. |
| Known ChatGPT ID | Save the ID. | Replace the draft reference. |
| Malformed or unknown ID | Reject. | Reject. |
PATCH still requires configurationId. Malformed/empty IDs return
400 INVALID_REQUEST; unknown nonempty IDs return 404 NOT_FOUND.
No Backend is inferred from model configuration or an account, and saving an
Agent makes no upstream call. At deployment, OCC writes the chosen Backend ID to the Agent revision.
PostgreSQL stores it in the backend_id column. Later draft edits leave that value unchanged.
A GitHub Backend ID is invalid in this field; the general /backends inventory
includes both types. Configure this association through the Agent API or a Preset.
The Create Agent model-provider selector does not configure it. Repository access
uses the separate admitted binding policy.
Secret-backed API-key harness bindings support Agents without a Backend. Managed access_token deployment requires dedicated Codex
execution and an exact same-Namespace binding matching the Backend, member
Driver, workspace, and recorded issuance. A mismatch returns
409 RESOURCE_CONFLICT; credential kind alone does not prove ownership.
The worker repeats ownership checks after IAM reauthorization and before Compute effects. It reads only binding metadata, never external IDs or admin credentials. Mismatches prevent candidate activation; database read failures use normal retries. The account-owned token Secret is delivered only to its compatible dedicated Codex workload.
The ChatGPT client cancels unused HTTP error bodies and responses declared larger than its 4 MiB allowance before reporting a sanitized failure. Cancelling releases occupied transport capacity without reading the discarded body. This cleanup adds no automatic retries or provider-effect guarantees.
Startup identity and safe Backend changes
Startup validates configuration and required dependencies, without scanning saved Agent references or managed bindings. A stale reference therefore does not prevent the API from starting so an authorized operator can repair it. Create/PATCH/deploy and reconciliation still require configured Backend IDs; issuance, deletion, admission, and reconciliation reject mismatched bindings.
Removing or retargeting a Backend does not reassign its existing accounts or
revoke their credentials. Affected operations fail closed until the original
configuration is restored or their references are repaired. Retain the original
configuration for exact upstream cleanup. To replace a managed deployment,
detach its account, clear/change backendId, supply valid independent
credentials, deploy, and wait for predecessor retirement before deleting the
unused account. Failed cleanup retains state for retry. Key/TTL changes preserve
ownership and do not rewrite existing credentials.
Unsupported state predating Backend composition requires explicit cleanup and recreation of the selected disposable state, as recorded in the implementation specification. Ownership is never inferred or backfilled. Draft edits and API shutdown do not stop workloads; exact upstream cleanup still needs the original configuration.
Production packaging and verification
Helm uses this packaging object separately from the Installation array:
backend: chatgpt: enabled: true secretName: occ-chatgpt-admin key: admin-key providerCidr: "203.0.113.10/32" # Example only; replace with the approved destination.Enable it with the Installation Backend. The dedicated Secret mounts only in
the API Pod at /etc/openclaw/chatgpt/admin-key; apiKeyPath must match.
providerCidr is required when enabled is true: the chart refuses to render
without exactly one IPv4 /32. It adds that destination on TCP/443 to the API
Pod's NetworkPolicy. It configures no DNS, routing, or application proxy. The bundled
client sends HTTPS directly to api.chatgpt.com; the upstream URL is fixed,
and the chart configures no HTTP CONNECT or HTTPS_PROXY transport. Entering
an ordinary forward proxy's IP will not cause the client to use it.
Before enabling the Backend, have your network operator confirm that the
address the NetworkPolicy sees for api.chatgpt.com:443 is the configured
destination. You can use a reviewed direct route where the hostname resolves
to that address, or transparent egress already provided by your cluster that
works with the client's direct HTTPS request and preserves the hostname and
certificate validation. The chart provisions neither. It supports only one
IPv4 address; if the direct hostname resolves to multiple or changing addresses,
do not rely on a single DNS lookup. Arrange suitable egress before enabling the
Backend. Disabled defaults keep occ-chatgpt-admin, admin-key, and an empty
CIDR. See the deployment guide and
security boundary.
To verify the admin key and route, issue a service-account credential.
GET /backends only reads Installation configuration and makes no upstream
request. Successful issuance does not prove that an Agent can reach its model.
The lifecycle flow names code and proof boundaries. Local API, PostgreSQL, Driver, and packaging tests do not prove live provider calls or model execution. See service-account testing for the remaining coverage and its limits.
Deferred behavior
Optional member Drivers, per-Agent Driver selection, automatic account creation, clientless Backends, installed Backend loading/injection, Backend detail, creation, and management UI, OAuth/refresh, renewal, and a common inference API remain out of scope.
