diff --git a/rfcs/0023-standard-hosting-profiles.md b/rfcs/0023-standard-hosting-profiles.md new file mode 100644 index 00000000..bd697b2f --- /dev/null +++ b/rfcs/0023-standard-hosting-profiles.md @@ -0,0 +1,500 @@ +--- +title: Standard Hosting Profiles +authors: + - Gio +created: 2026-07-14 +last_updated: 2026-07-25 +status: draft +issue: +rfc_pr: https://github.com/openclaw/rfcs/pull/37 +--- + +# Proposal: Standard Hosting Profiles + +## Summary + +Define a small catalog of named, release-tested OpenClaw runtime postures: +`local`, `container`, `reverse-proxy`, and `node-mode`. A selected profile +composes canonical readiness conditions into a support contract, identifies the +profile and runtime subjects being evaluated, and has a matching packaged release +scenario. + +This RFC depends on the separate Readiness Conditions and Providers RFC. That +RFC is directly usable: operators may explicitly select additional required or +advisory criteria without any profile. This RFC adds named, release-tested +presets over the same mechanism; it does not redefine readiness evaluation or +provider lifecycle. + +## Motivation + +OpenClaw can be deployed in many shapes, but "OpenClaw supports containers" or +"OpenClaw supports hosted deployments" is too broad to test or support. The +same package may run: + +- as a local foreground Gateway; +- directly reachable through a container listener; +- behind a trusted identity proxy; or +- as a controller for one or more paired execution targets. + +Each posture has different facts that must be true before it can serve its +supported role. Today hosts encode those facts in startup flags, environment +variables, Docker health checks, adapter code, and private support checklists. +OpenClaw cannot report which posture was intended, and release tests cannot +make a durable support claim about it. + +Standard profiles turn that open-ended claim into a small product contract: + +```text +OpenClaw supports these named runtime postures. +Each posture composes stable readiness conditions. +Each release executes the matching conformance scenarios. +The running process reports which posture and observed subjects it represents. +``` + +This helps maintainers reproduce issues against a supported subset without +preventing operators from configuring OpenClaw directly or running outside the +standard catalog. + +## Goals + +- Define `local`, `container`, `reverse-proxy`, and `node-mode` as standard + OpenClaw support profiles. +- Make selection opt-in so an upgrade preserves the existing unprofiled + readiness baseline. +- Select profiles through config, environment, or Gateway startup arguments + with explicit precedence. +- Compose profiles from reusable canonical readiness conditions. +- Define exact predicates and stable reasons for profile-specific conditions. +- Report the selected profile through readiness, health, and status. +- Attribute profile and topology conditions to the shared readiness subjects + defined by RFC 0018. +- Exercise every standard profile through a packaged release scenario lane. +- Keep host orchestration and OpenClaw runtime ownership separate. + +## Non-Goals + +- Define the canonical readiness-condition schema or plugin provider API. +- Generate, merge, repair, or replace OpenClaw configuration. +- Encode Docker, Kubernetes, systemd, Nomad, or ECS retry/interval settings. +- Define OCC resources, placement, tenant identity, quotas, or admission. +- Define the AgentHarness event protocol or put agent traffic in a control + plane. +- Standardize host storage, telemetry sinks, routing, worker pools, or admin + UX. +- Make the optional Policy or Doctor subsystems dependencies of startup. +- Guarantee checkpoint durability, restore compatibility, or safe destruction. +- Claim that every possible OpenClaw configuration belongs to a standard + profile. +- Define a second runtime-activation identity envelope, named operator + profiles, inheritance, host assertions, immutable + conformance records, or signed artifact attestations in V1. + +## Proposal + +The implementer-facing v1 contract is captured in +[`0023/hosting-profile-v1-spec.md`](0023/hosting-profile-v1-spec.md). This RFC +remains the design rationale, support argument, and rollout plan; the sidecar is +the concise profile catalog, selection, subject attribution, projection, and packaged +scenario reference for OpenClaw runtime and release implementations. + +### Dependency on canonical readiness + +This RFC assumes the contract proposed by Readiness Conditions and Providers: + +```text +condition type + status + requirement + reason + message +``` + +Profiles do not create a second evaluator. A profile is declarative data that +supplies a named preset of reusable conditions and requirement classes. The +canonical readiness engine evaluates those conditions exactly as if the +operator had selected them explicitly through `gateway.readiness`. + +Universal Gateway startup, drain, and selected-channel readiness remains in +force for every profile. No profile may remove, replace, or weaken it. + +```text +RFC 0018 direct use: + universal conditions + operator-selected criteria -> readiness + +RFC 0023 profile use: + universal conditions + standard profile preset + optional RFC 0018 additions + -> readiness + an OpenClaw-tested support posture +``` + +### Standard profile catalog + +| Profile | Runtime posture | Additional required condition types | +| --- | --- | --- | +| `local` | Explicit local or foreground Gateway posture | `ProfileSelected`, `WorkspaceWritable` | +| `container` | Gateway directly reachable through a container listener | `local` plus `ContainerStateReady` | +| `reverse-proxy` | Gateway behind a trusted identity proxy | `local` plus `TrustedProxyReady`; loopback requires the explicit trusted-proxy loopback allowance | +| `node-mode` | Gateway controlling one or more execution targets | `local` plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady` | + +A profile names runtime posture, not packaging. Docker behind an identity proxy +selects `reverse-proxy`; Docker with a directly reachable listener selects +`container`. + +New standard profiles require an independently useful support posture, stable +condition predicates, packaged conformance scenarios, and an owner willing to +maintain the support promise. A new diagnostic condition alone does not justify +a new profile. + +### Catalog inspection + +The standard catalog is a machine-readable support contract, not only a set of +internal constants. OpenClaw exposes it through local, read-only commands: + +```console +openclaw hosting profiles list +openclaw hosting profiles inspect +``` + +Both commands support human output and `--json`. The JSON contract identifies +its version and returns immutable descriptor copies containing the profile ID, +runtime-posture description, profile-owned conditions, required RFC 0018 +criteria, and advisory RFC 0018 criteria. Stable catalog order follows the +documented `local`, `container`, `reverse-proxy`, and `node-mode` order. + +Inspection does not load configuration or plugins, contact a Gateway, evaluate +readiness, infer active selection, or mutate state. The running Gateway remains +the authority for the selected profile and reports it through canonical +readiness. Catalog/runtime alignment is tested by deriving profile conditions +from the same shipped definitions used to build readiness. + +Operators validate a running profile through: + +```console +openclaw hosting profiles validate [profile] +``` + +The optional argument requires an exact active profile. Validation calls the +canonical `ready` RPC once, verifies the readiness schema, profile identity and +contract version, and required profile-condition coverage, then reports +`conformant` separately from `ready`. Both false states exit nonzero. A +conformant profile may still be non-ready because a required condition is +currently false. Validation embeds the canonical result as evidence and does +not load local configuration or plugins, reproduce predicates, or invoke a +second evaluator. + +### Profile conditions + +The standard catalog composes conditions owned by the canonical readiness +contract and existing OpenClaw runtime owners. + +| Condition | Profile | True when | Stable non-ready reasons | +| --- | --- | --- | --- | +| `ProfileSelected` | All | Selection precedence resolves to a valid standard profile. | Invalid explicit values fail startup validation. | +| `ContainerStateReady` | `container` | The resolved listener host is not loopback. | `ContainerGatewayLoopback` | +| `TrustedProxyReady` | `reverse-proxy` | Auth mode is `trusted-proxy`, a user header and trusted source are configured, and loopback sources are explicitly allowed. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing`, `TrustedProxyIngressUnsafe` | +| `NodePairingReady` | `node-mode` | Pairing state is readable and contains an approved pairing. | `NodePairingUnavailable`, `NodePairingTimedOut`, `NodePairingPending`, `NodePairingMissing` | +| `ControlledTargetsReady` | `node-mode` | At least one connected target is correlated to an approved pairing. | `ControlledTargetsDisconnected` | +| `CommandApprovalReady` | `node-mode` | A connected paired target advertises a command permitted by effective grants. | `CommandApprovalMissing` | +| `ControlChannelReady` | `node-mode` | At least one live target session is correlated to an approved pairing. | `ControlChannelUnavailable` | + +`node-mode` stays product-neutral. A target may be a desktop, sandbox, VM, pod, +browser, or another execution surface. OpenClaw does not assume one node maps to +exactly one product or tenant. One correlated approved pairing, connected +target, effective command grant, and live session must satisfy all four +conditions; independent targets cannot satisfy different rows. + +`TrustedProxyReady` validates the effective auth configuration. Existing +Gateway request handling remains responsible for rejecting forged or untrusted +identity ingress; readiness does not issue a synthetic request on every poll. + +Common runtime conditions remain owned by readiness and their source +subsystems. Every selected profile requires current config, usable model +routing/auth, successful plugin activation, resolved secrets, writable +workspace, session storage, context engine, tool catalog, and configured +MCP/sandbox/harness capability. Event-loop health, state, delivery-runtime, and +scheduler conditions are selected as advisory diagnostics. Profiles select the +ordinary RFC 0018 IDs `openclaw.plugins-loaded` and +`openclaw.event-loop-healthy`; they do not implement special profile-only +versions of those observations. + +### Selection and precedence + +Profile selection is optional and opt-in. When no value is supplied, OpenClaw +does not select a profile. Existing installations retain the universal +readiness baseline from RFC 0018 and do not silently acquire profile-specific +required conditions during an upgrade. + +Selection precedence is: + +```text +gateway startup argument +> OPENCLAW_HOSTING_PROFILE +> openclaw.json +``` + +Example: + +```json5 +{ + hosting: { + profile: "container", + }, +} +``` + +Equivalent startup selection: + +```bash +OPENCLAW_HOSTING_PROFILE=container openclaw gateway run +openclaw gateway run --hosting-profile container +``` + +When selected, the effective profile, selection source, and condition result +are reported by readiness, health, and status. An unprofiled runtime omits +`ProfileSelected`, profile identity, top-level profile fields, and +profile-only requirements. + +Profiles validate effective runtime state. They do not generate or repair the +underlying Gateway, proxy, plugin, model, node, or storage config. + +### Readiness subject attribution + +Profiles use RFC 0018's identity package instead of defining another runtime +identity. A profiled result declares `openclaw/hosting-profile/selected` with +the selected profile as its opaque ID. The profile contract version is result +metadata, not a generation of that subject. `ProfileSelected` targets the +profile subject. Topology-specific conditions target the Gateway or +node-controller subject and relate back to the selected profile. + +Node mode additionally declares `openclaw/nodes/managed` and bounded child +subjects for the paired nodes observed during that evaluation. Its aggregate +conditions use the controller as their primary subject and list observed nodes +as related subjects. Repeated results can therefore distinguish a changed +condition from a replaced Gateway, changed profile, or changed node set. + +Gateway, process, and optional host-workload identities remain RFC 0018's +concern. OpenClaw generates the Gateway serving-lifecycle ID and process ID. +When supplied, `OPENCLAW_INSTANCE_ID` identifies only the fingerprinted +host-workload parent; it never overrides either generated child identity. +Profiles do not add `runtimeId`, `incarnationId`, or an activation envelope. + +### Operator extensions + +V1 supports only the four OpenClaw-owned standard profile names. Operators may +select additional required or advisory criteria through RFC 0018's +`gateway.readiness` config, including while a profile is selected. Named +operator profiles and inheritance are possible follow-up work, not an implied +V1 contract. + +### Host-visible result + +The selected profile appears in the canonical readiness result. For example, a +container selected with a loopback-only listener returns: + +```http +HTTP/1.1 503 Service Unavailable +``` + +```json +{ + "profileContractVersion": 1, + "profile": "container", + "profileSource": "config", + "ready": false, + "identity": { + "producerRef": "openclaw/gateway/current", + "subjects": [ + { + "ref": "openclaw/hosting-profile/selected", + "kind": "openclaw.hosting-profile", + "id": "container", + "generation": "1", + "parentRef": "openclaw/gateway/current" + } + ] + }, + "conditions": [ + { + "type": "ContainerStateReady", + "subjectRef": "openclaw/gateway/current", + "relatedSubjectRefs": ["openclaw/hosting-profile/selected"], + "status": "False", + "requirement": "required", + "reason": "ContainerGatewayLoopback", + "message": "The effective Gateway listener is loopback-only." + } + ], + "failures": ["ContainerGatewayLoopback"] +} +``` + +After the listener becomes reachable, the same endpoint returns `200`. Docker, +Kubernetes, systemd, or OCC can consume the ordinary readiness endpoint without +interpreting a profile-specific API. + +### Packaged profile scenarios + +A standard profile is a support promise only if the release process tests it. +V1 adds one Docker E2E lane to the release-check matrix. It starts the packaged +OpenClaw entrypoint, validates the ordinary canonical `/readyz` result, and +invokes the packaged `hosting profiles validate --json` command. Runtime +readiness does not rerun release tests or claim artifact attestation. + +The initial profile matrix must execute package-installed scenarios for: + +- unchanged unprofiled readiness and explicit local-profile readiness; +- container success and loopback failure; +- reverse-proxy success and missing-auth failure; +- node-mode unpaired failure and paired/approved recovery; and +- workspace-full failure and recovery without restart. + +The implementation wires this lane into package acceptance and emits one +versioned `hosting-profile-conformance.json` artifact. The artifact identifies +the package and immutable Docker image, retains expected and observed +validation plus canonical readiness evidence for every scenario, and is marked +passed only after the exact matrix is complete. Expected non-ready states pass +the release gate only when they remain structurally conformant and report +`ready: false`. + +Upgrade survival, cross-surface parity, direct-ingress security scenarios, +immutable records, and signed attestations can strengthen the support program +later without expanding the V1 runtime contract. + +### Support ownership and compatibility + +OpenClaw owns: + +- standard profile names and definitions; +- profile-specific condition predicates and reasons; +- selection precedence and result projection; +- profile subject attribution semantics; and +- the packaged scenario lane for the standard catalog. + +Hosts own: + +- which profile to select; +- container and scheduler manifests; +- probe timing, retries, and restart policy; +- placement, routing, tenants, and rollout; +- telemetry sinks and fleet alerts; and +- any additional operator-selected RFC 0018 criteria. + +Adding a required condition, changing a stable reason, or changing an advisory +condition to required can alter host behavior and needs compatibility review, +release notes, and conformance coverage. + +### OCC and AgentHarness alignment + +OCC may compile desired state into OpenClaw config, profile selection, Gateway +instance identity, and host policy. The runtime plane still evaluates +readiness and reports the live subjects. + +AgentHarness owns harness execution events. Hosting profiles do not carry +assistant deltas, tool frames, approvals, patches, compaction events, or +harness protocol frames. + +```text +OCC/control plane + -> desired Gateway identity and profile + +OpenClaw/runtime plane + -> live Gateway, profile, and topology subjects + -> canonical readiness conditions + -> selected profile result + +AgentHarness/data plane + -> harness execution events +``` + +### Relationship to continuity + +Readiness says whether the current runtime can serve work under its selected +profile. It does not say whether mutable state has been durably published or +whether the runtime is safe to destroy. + +A runtime may be ready but dirty, or not ready while its durable state is +complete. Checkpoint publication, restore compatibility, hibernate, and +generation-fenced safe destruction remain Runtime State Continuity concerns. + +### Implementation plan + +After the readiness-only stack is established, the profile implementation is a +single dependent series in +[openclaw/openclaw#113422](https://github.com/openclaw/openclaw/pull/113422). +It depends on the readiness framework in +[openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018) +at exact head `2f131c6e220` +and the core-owner criteria in +[openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421) +at exact head `c1d7f394f86`. The exact profile head is `18c42a7f26a`. + +| Slice | Intended scope | +| --- | --- | +| Standard selection and predicates | Add opt-in selection, precedence, machine-readable projection, and `local`, `container`, and `reverse-proxy` conditions. | +| Node mode | Add product-neutral pairing, connected-target, canonical command-policy, and control-channel conditions. | +| Compatibility and safety | Keep unprofiled startup unchanged, validate profile-only identity only when selected, preserve attribution on failed evaluation, and bound pairing recovery work. | +| Packaged scenarios | Exercise all four profiles, primary failures, node approval, workspace-full recovery, unprofiled compatibility, repeated-poll identity, and container-restart renewal boundaries; retain one fail-closed release artifact. | + +PR 113422 is stacked on PRs 104018 and 113421. Until those dependencies land, +its aggregate GitHub diff includes the readiness implementation followed by the +profile commits. After both land, the same PR reduces to the profile-only diff. + +The refreshed stack passes 120 focused profile, readiness, selection, and +Gateway assertions; type-aware lint, formatting, shell syntax, and diff checks +are clean. The +[exact-head package-installed Docker matrix](https://github.com/giodl73-repo/openclaw/actions/runs/30289122192) +passes on GitHub-hosted Actions over profile head `18c42a7f26a` using an +immutable no-push package/image artifact. It proves unprofiled compatibility, +all four profiles, expected failures, node approval, workspace recovery, stable +repeated polls, and host-stable/process-and-Gateway-rotating container restart +identity. + +#### Operator and conformance facilities + +The standard catalog becomes easier to support when operators and release +automation can inspect and validate it without reproducing profile predicates: + +The three facilities below form one ordered upstream review unit in +[openclaw/openclaw#114636](https://github.com/openclaw/openclaw/pull/114636) at +exact head `123bae7b876`: + +1. Read-only `hosting profiles list` and `hosting profiles inspect` surfaces + expose the built-in definitions and selected criteria. +2. `hosting profiles validate` checks active identity, version, condition + coverage, and readiness over one live RFC 0018 canonical result. The + [package-installed proof](https://github.com/giodl73-repo/openclaw/actions/runs/30289122192) + exercises that exact validator ancestor. It does not mutate configuration or + run a second evaluator. +3. Package-installed release conformance invokes the canonical validator for + all 13 scenario states and retains one machine-readable artifact suitable + for Docker, Kubernetes, OCC, Lobster, CI, support bundles, and release + qualification. Its + [exact-head package-installed Docker proof](https://github.com/giodl73-repo/openclaw/actions/runs/30289122192) + passes all 13 scenarios, independently verifies the artifact, and uploads it + as release evidence. + +Transition watching, generic condition/provider inspection, and startup wait +remain RFC 0018 facilities. Doctor remediation, fleet telemetry, support +bundles, and upgrade orchestration remain with their existing owners and may +consume the same readiness and conformance evidence. + +## Rationale + +Named profiles are useful because OpenClaw's configuration space is much larger +than any support matrix. A small standard catalog provides reproducible bug +reports, executable release evidence, and clear responsibility without taking +configuration freedom away from operators. + +Profiles belong in OpenClaw because only the runtime can define the predicates +that mean its Gateway, proxy, node, plugin, and observed state satisfy a +supported posture. Hosts should select and operationalize the posture, not +reverse-engineer its internal readiness semantics. + +Separating this proposal from readiness keeps both decisions honest. OpenClaw +can accept the condition/provider facility without accepting profile product +semantics, and profile review can focus on names, predicates, support ownership, +and release cost rather than debating the underlying readiness API again. + +## Unresolved questions + +- Is `hosting.profile` the preferred config home for the opt-in standard + catalog? +- Should the packaged scenario lane be release-blocking immediately or begin as + an advisory release check? +- After the standard catalog proves stable, is there enough demand for named + operator profiles beyond direct RFC 0018 criterion selection? diff --git a/rfcs/0023/hosting-profile-v1-spec.md b/rfcs/0023/hosting-profile-v1-spec.md new file mode 100644 index 00000000..8f999296 --- /dev/null +++ b/rfcs/0023/hosting-profile-v1-spec.md @@ -0,0 +1,468 @@ +# Standard Hosting Profile v1 Specification + +This is the implementer-facing specification for RFC 0023. It defines the v1 +standard profile catalog, selection precedence, readiness composition, subject +attribution, host-visible projection, and packaged release scenarios. + +Status: draft, tied to RFC 0023 and dependent on RFC 0018. + +## Scope + +This specification defines: + +- the `local`, `container`, `reverse-proxy`, and `node-mode` profiles; +- composition over RFC 0018 readiness criteria; +- opt-in selection through config, environment, or startup argument; +- exact profile predicates and stable non-ready reasons; +- attribution through the RFC 0018 readiness identity package; +- readiness, health, and status projection; and +- packaged release scenarios for the standard catalog. + +It does not define a second readiness evaluator, runtime-activation envelope, +config repair system, scheduler policy, OCC resource, AgentHarness protocol, +continuity contract, operator-defined profile, or arbitrary OpenClaw support +promise. + +## Dependencies + +RFC 0018 owns condition shape, subjects, aggregation, deadlines, provider +bounds, fail-closed behavior, and host-visible projection. Profiles are data +that select reusable criteria and add a small set of runtime-owned predicates. + +An unprofiled RFC 0018 runtime remains conformant. Selecting a profile opts into +this specification. + +## Compatibility + +- Selection is optional and opt-in. +- Upgrade must not select a profile for an unprofiled deployment. +- Profile IDs, predicates, required criteria, and stable reasons are contracts. +- Strengthening a required criterion requires compatibility review, release + notes, and conformance coverage. +- An invalid explicit profile fails startup validation. +- A new standard profile requires a distinct support posture and packaged + conformance scenario. + +## Standard Catalog + +| Profile ID | Runtime posture | Required profile conditions | +| --- | --- | --- | +| `local` | Local or foreground Gateway | `ProfileSelected` | +| `container` | Directly reachable container listener | `local` plus `ContainerStateReady` | +| `reverse-proxy` | Gateway behind a trusted identity proxy | `local` plus `TrustedProxyReady` | +| `node-mode` | Gateway controlling paired execution targets | `local` plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady` | + +A profile describes runtime posture, not packaging. A container behind an +identity proxy selects `reverse-proxy`; a directly reachable container selects +`container`. + +Every profile selects these RFC 0018 criteria as required: + +- `openclaw.config-current`; +- `openclaw.model-route-ready`; +- `openclaw.plugins-loaded`; +- `openclaw.secrets-ready`; +- `openclaw.workspace-writable`; +- `openclaw.session-storage-ready`; +- `openclaw.context-engine-ready`; +- `openclaw.tool-catalog-ready`; +- `openclaw.mcp-runtime-ready`; +- `openclaw.sandbox-ready`; and +- `openclaw.harness-ready`. + +Every profile selects these as advisory: + +- `openclaw.event-loop-healthy`; +- `openclaw.state-ready`; +- `openclaw.delivery-runtime-ready`; and +- `openclaw.scheduler-ready`. + +The RFC 0018 universal Gateway lifecycle baseline remains in force and cannot +be removed or weakened by a profile. + +## Selection + +Selection precedence is: + +```text +gateway startup argument +> OPENCLAW_HOSTING_PROFILE +> openclaw.json hosting.profile +``` + +Examples: + +```json5 +{ + hosting: { + profile: "container", + }, +} +``` + +```bash +OPENCLAW_HOSTING_PROFILE=container openclaw gateway run +openclaw gateway run --hosting-profile container +``` + +An absent value means unprofiled operation, not `local`. The winning value is +validated before destructive lifecycle actions. The effective result records +the profile and selection source. + +## Profile Predicates + +### Profile Selection + +`ProfileSelected` is `True` when precedence resolves to a valid standard +profile. Invalid explicit values fail startup rather than becoming a running +false condition. + +### Container + +`ContainerStateReady` is `True` when the effective listener is not loopback. +Its stable false reason is `ContainerGatewayLoopback`. It inspects OpenClaw's +listener state, not a container scheduler API. + +### Reverse Proxy + +`TrustedProxyReady` is `True` when: + +- auth mode is `trusted-proxy`; +- a user identity header is configured; +- at least one valid trusted source is configured; +- a loopback listener has a loopback trusted source; and +- use of a loopback source is explicitly allowed. + +Stable false reasons are `TrustedProxyAuthMissing`, +`TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing`, and +`TrustedProxyIngressUnsafe`. + +This validates effective static auth configuration. Request-time Gateway auth +continues to reject untrusted sources and forged identity headers. + +### Node Mode + +One correlated approved pairing, connected target, effective command grant, +and live session must satisfy all four predicates. Separate targets cannot +satisfy different rows. + +| Condition | True when | Stable non-ready reasons | +| --- | --- | --- | +| `NodePairingReady` | Pairing state is readable and contains an approved pairing. | `NodePairingUnavailable`, `NodePairingTimedOut`, `NodePairingPending`, `NodePairingMissing` | +| `ControlledTargetsReady` | A connected target correlates to an approved pairing generation. | `ControlledTargetsDisconnected` | +| `CommandApprovalReady` | A connected paired target advertises a command allowed by effective grants. | `CommandApprovalMissing` | +| `ControlChannelReady` | A live target session correlates to an approved pairing. | `ControlChannelUnavailable` | + +Evaluation uses current cached runtime and pairing state. It does not perform +network discovery or wait for a target. Pairing reads are bounded, +single-flight, and limited to two unresolved generations after timeout. + +## Subject Attribution + +Profiles reuse the RFC 0018 identity package. They do not define `runtimeId`, +`incarnationId`, or another activation object. + +Every selected profile declares: + +```ts +{ + ref: "openclaw/hosting-profile/selected"; + kind: "openclaw.hosting-profile"; + id: "local" | "container" | "reverse-proxy" | "node-mode"; + parentRef: "openclaw/gateway/current"; +} +``` + +`ProfileSelected` targets this subject. Container and proxy conditions target +the Gateway and include the profile subject in `relatedSubjectRefs`. The +profile contract version is result metadata, not a generation of the selected +profile object. + +Node mode also declares: + +- `openclaw/nodes/managed`, kind `openclaw.node-controller`, parented by the + Gateway; and +- a deterministic subset of at most 16 paired node subjects observed during + evaluation, with a one-way fingerprint of pairing generation when available. + +Node-mode aggregate conditions target `openclaw/nodes/managed` and list the +observed node subjects as related subjects. Aggregate counts cover the complete +paired-node set even when related subjects are truncated. Node IDs must not be +copied into a subject ref; implementations use a deterministic bounded opaque +key and prioritize actionable disconnected subjects. + +Gateway, process, and optional host-workload identities are owned by RFC 0018. +OpenClaw generates a Gateway ID at every serving-lifecycle start and a process +ID at process start. `OPENCLAW_INSTANCE_ID`, when supplied, becomes only a +fingerprinted host-workload subject; it never overrides either generated child +identity. + +## Host-Visible Result + +A profiled canonical result adds: + +```ts +type ProfiledReadinessResult = ReadinessResult & { + profileContractVersion: 1; + profile: "local" | "container" | "reverse-proxy" | "node-mode"; + profileSource: "argument" | "environment" | "config"; +}; +``` + +The identity package carries runtime attribution. For example, a container +profile with a loopback listener returns `503`: + +```json +{ + "contractVersion": 1, + "profileContractVersion": 1, + "profile": "container", + "profileSource": "config", + "ready": false, + "identity": { + "producerRef": "openclaw/gateway/current", + "subjects": [ + { + "ref": "openclaw/process/current", + "kind": "openclaw.process", + "id": "process-opaque-id" + }, + { + "ref": "openclaw/gateway/current", + "kind": "openclaw.gateway", + "id": "gateway-opaque-id", + "parentRef": "openclaw/process/current" + }, + { + "ref": "openclaw/hosting-profile/selected", + "kind": "openclaw.hosting-profile", + "id": "container", + "parentRef": "openclaw/gateway/current" + } + ] + }, + "conditions": [ + { + "type": "ContainerStateReady", + "subjectRef": "openclaw/gateway/current", + "relatedSubjectRefs": ["openclaw/hosting-profile/selected"], + "status": "False", + "requirement": "required", + "reason": "ContainerGatewayLoopback", + "message": "The effective Gateway listener is loopback-only." + } + ], + "failures": ["ContainerGatewayLoopback"], + "advisories": [] +} +``` + +After the listener satisfies the predicate, the same endpoint returns `200`. +Hosts use canonical readiness and do not need a profile-specific probe API. +If evaluation times out or throws, the result remains `503` and retains the +selected profile metadata and profile subject. + +## Operator Extensions + +V1 supports only the four standard names. Operators may add required or +advisory RFC 0018 criteria directly through `gateway.readiness`, including +while a profile is selected. Named operator profiles and inheritance are not +part of V1. + +## Catalog Inspection + +OpenClaw exposes the shipped standard catalog through these local, read-only +commands: + +```console +openclaw hosting profiles list [--json] +openclaw hosting profiles inspect [--json] +``` + +`list --json` returns: + +```ts +{ + contractVersion: 1; + profiles: HostingProfileDescriptor[]; +} +``` + +`inspect --json` returns: + +```ts +{ + contractVersion: 1; + profile: HostingProfileDescriptor; +} +``` + +Each descriptor contains: + +```ts +type HostingProfileDescriptor = { + id: "local" | "container" | "reverse-proxy" | "node-mode"; + description: string; + profileConditions: string[]; + requiredCriteria: string[]; + advisoryCriteria: string[]; +}; +``` + +Catalog order is `local`, `container`, `reverse-proxy`, then `node-mode`. +Callers receive copies and cannot mutate the shipped definitions. Every +descriptor's `profileConditions` exactly matches the conditions constructed by +the runtime for that profile. + +Inspection is observationally inert: it does not load configuration or plugins, +contact a Gateway, evaluate readiness, infer active selection, or mutate state. +The selected profile and its runtime result remain canonical readiness data. + +## Live Profile Validation + +OpenClaw validates a running Gateway through: + +```console +openclaw hosting profiles validate [profile] [--json] [--timeout ] +``` + +With no profile argument, the exact profile ID in canonical readiness is used. +With an argument, that profile must be active. Input parsing may normalize CLI +text, but Gateway-produced profile identity must exactly match a standard +catalog ID. + +Validation calls the canonical `ready` RPC once. It does not load local +configuration or plugins, reproduce profile predicates, or invoke another +evaluator. It verifies: + +- canonical readiness schema version and structure; +- exact standard profile identity and profile contract version; and +- one required condition row for every `profileConditions` entry in the + descriptor. + +`--json` returns: + +```ts +type LiveProfileValidationResult = { + contractVersion: 1; + conformant: boolean; + ready: boolean; + expectedProfile?: string; + activeProfile?: string; + findings: Array<{ reason: string; message: string }>; + readiness?: unknown; +}; +``` + +`conformant` is false for unavailable or malformed readiness, no active +profile, unknown or mismatched profile identity, contract mismatch, or missing, +duplicate, or non-required profile conditions. `ready` is true only when the +canonical evidence is structurally valid and its serving decision is true. +Both false states exit nonzero. A structurally conformant profile whose current +required condition is false reports `conformant: true`, `ready: false`. + +## Packaged Scenario Gate + +The package-installed Docker lane probes the same canonical `/readyz` result +used by hosts and invokes `openclaw hosting profiles validate --json` against +each stable scenario state. It must prove: + +- unchanged unprofiled behavior; +- explicit `local` success and workspace failure/recovery; +- `container` success and loopback failure; +- `reverse-proxy` success and missing-auth failure; +- `node-mode` unpaired/unapproved failure and paired/approved recovery; +- stable profile metadata and subject attribution; and +- stable host/profile identity plus renewed process and Gateway identity when + the same host workload restarts; and +- exact condition status and profile contract version. + +The lane writes one `hosting-profile-conformance.json` artifact: + +```ts +{ + contractVersion: 1; + suite: "openclaw-standard-hosting-profiles"; + profileContractVersion: 1; + package: { + name: "openclaw"; + version: string; + sha256?: string; + }; + image: { + reference: string; + id: `sha256:${string}`; + }; + scenarios: Array<{ + id: string; + expected: { + profile?: string; + conformant: boolean; + ready: boolean; + exitCode: number; + }; + observed: { + exitCode: number; + validation: LiveProfileValidationResult; + }; + passed: boolean; + mismatches?: string[]; + }>; + summary: { + total: number; + passed: number; + failed: number; + }; + passed: boolean; +} +``` + +The candidate package SHA-256 is present when package provenance is available; +the immutable Docker image ID is always present. When a candidate package path +is supplied, the lane MUST verify that its SHA-256 matches the package digest +bound into the tested image and fail before recording scenarios on a missing or +mismatched binding. The writer independently validates the canonical readiness +fields, validation findings, profile identity, conformance state, readiness +state, and command exit before accepting a scenario. It writes mismatch +evidence before failing and sets top-level `passed: true` only after the exact +required scenario set is complete. + +Expected non-ready scenarios are successful conformance evidence only when the +profile is structurally conformant, `ready` is false, and the validator exits +nonzero. The artifact is portable release evidence, not an immutable or signed +attestation. + +Upgrade survival, direct-ingress security, immutable records, and signed +attestations are follow-up gates, not V1 runtime semantics. + +## Ownership + +OpenClaw owns profile IDs, predicates, reasons, precedence, subject attribution, +projection, and packaged scenarios. Hosts own selection, manifests, probe +timing, restart policy, placement, tenants, rollout, telemetry, and additional +operator-selected RFC 0018 criteria. + +## Conformance Checklist + +- No profile is selected by default or upgrade. +- Every selection source works with deterministic precedence. +- Invalid explicit profiles fail startup validation. +- Every profile composes the documented criteria. +- Catalog list and inspect output is versioned, stably ordered, and immutable to + callers. +- Catalog profile conditions exactly match the runtime conditions constructed + for the same profile. +- Live validation consumes one canonical readiness result and never invokes a + second evaluator. +- Validation fails closed on unavailable, malformed, mismatched, or incomplete + evidence and never reports malformed evidence as ready. +- Every profiled result identifies its profile through metadata and subjects. +- Node conditions identify the observed controller and related node set. +- Profile failures use stable reasons and canonical aggregation. +- Timeout and exception results remain bounded, fail closed, and retain profile + attribution. +- Readiness, health, and status project the same profile result. +- Packaged scenarios exercise each profile's primary success and recovery path. +- The packaged gate retains one complete, versioned, fail-closed conformance + artifact with package and image provenance. +- Unprofiled deployments retain RFC 0018 behavior.