From 32fa7827d0c9edbd6aba6ccd440a8e5e57b7b7bc Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 16:59:12 -0700 Subject: [PATCH 01/98] Add standard hosting profiles RFC --- ...andard-hosting-profiles-and-ready-check.md | 246 ++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 rfcs/0010-standard-hosting-profiles-and-ready-check.md diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md new file mode 100644 index 00000000..68bd9d98 --- /dev/null +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -0,0 +1,246 @@ +--- +title: Standard Hosting Profiles and Ready Check +authors: + - Gio +created: 2026-07-09 +last_updated: 2026-07-09 +status: draft +issue: +rfc_pr: +--- + +# Proposal: Standard Hosting Profiles and Ready Check + +## Summary + +Define standard hosting profiles for running OpenClaw as a workload, plus a +canonical ready check that evaluates the selected profile against runtime +evidence and reports stable readiness conditions through host-facing surfaces +such as `openclaw ready`, `status --json`, and Gateway health. + +## Motivation + +OpenClaw can be hosted today, but it does not yet expose the small workload +contract that container hosts and orchestrators expect. Hosts need to answer one +question before routing traffic: + +```text +Is this OpenClaw instance ready under the hosting profile it was started with? +``` + +Without that contract, downstream hosts compensate with private startup checks, +baked config, environment restore lists, persistence wrappers, and adapter-only +readiness logic. That makes hosted OpenClaw harder to test upstream and harder +to upgrade downstream. + +Profiles turn the broad claim "OpenClaw supports hosted deployments" into a +reviewable support matrix: + +```text +OpenClaw supports these profiles. +Each profile has stable readiness conditions. +Each release can test those conditions. +Hosts can prove which profile they are running. +``` + +## Goals + +- Define built-in hosting profiles for `local`, `container`, `reverse-proxy`, + `managed`, and `node-mode`. +- Make `local` the default profile when no profile is selected. +- Add a canonical readiness result with stable condition `type`, `status`, + `reason`, and human-readable `message`. +- Add a focused `openclaw ready --json` command for host readiness probes. +- Expose the same readiness result through existing status and health surfaces. +- Add explicit profile selection through config, environment, and Gateway + startup. +- Keep OpenClaw generic: no Lobster, Scout, Microsoft, tenant, Teams, Kusto, or + product-specific host concepts. +- Keep the first implementation in core so readiness works without optional + plugins. +- Leave room for later namespaced plugin or driver readiness conditions without + letting operators redefine built-in profile semantics. + +## Non-Goals + +- Replace `openclaw.json`. +- Define OCC resources or require OCC before hosted readiness works. +- Define the remote AgentHarness event protocol. +- Standardize a host's storage backend, auth provider, telemetry sink, tenant + routing, UI, deployment system, or worker-pool model. +- Put assistant deltas, tool frames, approvals, patches, compaction events, or + harness protocol frames into the hosting contract. +- Make arbitrary operator-defined conditions part of the first core contract. + +## Proposal + +OpenClaw should expose a standard hostee contract: + +```text +profile selection ++ runtime evidence ++ readiness condition evaluation +-> ready/not-ready result +``` + +The contract is not a parallel hosted config tree. Existing OpenClaw config +continues to own Gateway, proxy, plugin, model, session, node, and state +behavior. A hosting profile decides which runtime evidence must be true before +the instance is considered ready. + +### Built-in profiles + +OpenClaw should ship profile definitions rather than ask every host to invent +one. Operators can still configure the underlying OpenClaw settings; the profile +names the support contract. + +| Profile | Purpose | +| --- | --- | +| `local` | Developer/local foreground process readiness. | +| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | +| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | +| `managed` | Platform-hosted OpenClaw with managed lifecycle expectations. | +| `node-mode` | Platform-controlled execution node or cell readiness. | + +The initial `local` readiness condition set should include: + +- `ProfileSelected` +- `ConfigLoaded` +- `GatewayResponding` +- `WorkspaceUsable` +- `PluginsLoaded` + +The initial `node-mode` condition set should add: + +- `NodePairingReady` +- `ControlledTargetsReady` +- `CommandApprovalReady` +- `ControlChannelReady` +- `StateReady` + +`node-mode` must stay product-neutral. A controlled target can be a desktop, +sandbox, VM, pod, browser, or another execution surface. OpenClaw should not +assume one node maps to exactly one target. + +### Profile selection + +OpenClaw should not require an explicit profile to run. If no profile is +selected, the effective profile is `local`. + +Profile selection should be visible in normal hosting mechanisms: + +- config: `hosting.profile` +- environment: `OPENCLAW_HOSTING_PROFILE` +- startup: `openclaw gateway run --hosting-profile ` + +`openclaw ready --expect-profile ` should be an assertion, not a +selection mechanism. If the running Gateway selected a different profile, the +ready result should be `ready=false` with a stable `ProfileMismatch` reason. + +### Ready result + +Readiness should use Kubernetes-style conditions: + +```jsonc +{ + "profile": "container", + "expectedProfile": "container", + "ready": false, + "conditions": [ + { + "type": "ProfileSelected", + "status": "True", + "reason": "ProfileSelected", + "message": "Runtime selected the container hosting profile." + }, + { + "type": "GatewayResponding", + "status": "False", + "reason": "GatewayUnavailable", + "message": "Gateway did not respond to the readiness request." + } + ], + "failures": ["GatewayUnavailable"] +} +``` + +Hosts and tests should key on `type`, `status`, and `reason`. `message` is for +operators and should remain non-normative. + +### Extensibility + +The first contract should keep built-in profile conditions stable and +OpenClaw-owned. Operators should not be able to redefine what `local`, +`container`, or `node-mode` means. + +Future work can add namespaced plugin or driver conditions, for example +`acme.backupReady` or `driver.egressReady`. Those conditions should append to +the readiness result and participate in readiness only through explicit profile +or host policy, rather than mutating the built-in profile definitions. + +### OCC and AgentHarness alignment + +This RFC does not conflict with OCC or the remote AgentHarness RFC. OCC can +compile declarative desired state into OpenClaw config, selected profile, and +host policy. The runtime plane still owns readiness evaluation, channel ingress, +session routing, cell supervision, and AgentHarness event streams. + +In that model: + +```text +OCC/control plane: desired state, tenant identity, admission, restrictions, +quotas, policy compilation, provisioning, audit indexing. + +OpenClaw/runtime plane: startup, Gateway, sessions, cells/nodes, harness +execution, readiness evidence, ready/not-ready result. +``` + +OCC should not be in the hot path for assistant deltas, tool events, approvals, +patches, compaction events, or harness protocol frames. + +### Implementation branches + +The initial implementation is being prepared as draft branches in the OpenClaw +fork before upstream OpenClaw PRs are opened: + +| Slice | Fork PR | Branch | +| --- | --- | --- | +| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` | +| Profile selection | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` | + +The remaining proof work should happen before upstream OpenClaw implementation +PRs are filed: + +- local Docker proof for default `local` readiness using `openclaw ready --json` +- local Docker proof for `container` using + `openclaw ready --expect-profile container --json` +- local Docker proof for `node-mode` readiness behavior +- Crabbox Linux/container proof when reviewer-grade platform evidence is needed + +## Rationale + +This follows the normal contract between a host and a hosted workload. The host +selects a runtime shape and supplies configuration. The workload starts, gathers +its own runtime evidence, evaluates readiness, and reports stable conditions. + +Putting the result into `ready`, `status`, and `health` is preferable to a +special "hosted OpenClaw" command tree. "Hosted" is a runtime posture and support +profile, not the primary CLI noun. + +Built-in profiles make the support promise concrete. Instead of one broad +hosted-deployment claim, OpenClaw can say which profiles are supported, which +conditions are stable, and which release tests prove them. + +## Unresolved questions + +- Should OpenClaw also add an HTTP `/ready` endpoint, or is `openclaw ready` plus + Gateway health enough for the first release? +- Which profile conditions should be release-blocking versus warning-only as + `container`, `reverse-proxy`, and `managed` mature? +- What is the right plugin or driver hook for namespaced custom readiness + conditions? +- Should future profile conformance live in QA Lab, maturity scorecards, Docker + E2E, or a dedicated profile conformance runner? +- Which stable telemetry event names should accompany readiness transitions in a + follow-up PR? From 214687d96d39ff066c811c583d60089bbf016550 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 16:59:36 -0700 Subject: [PATCH 02/98] Record RFC pull request URL --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 68bd9d98..b0eac55d 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -6,7 +6,7 @@ created: 2026-07-09 last_updated: 2026-07-09 status: draft issue: -rfc_pr: +rfc_pr: https://github.com/openclaw/rfcs/pull/33 --- # Proposal: Standard Hosting Profiles and Ready Check From fe0accc590ccdc66c861d0eaff596e1d26b31451 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 17:38:06 -0700 Subject: [PATCH 03/98] Add readiness criteria implementation reference --- ...0-standard-hosting-profiles-and-ready-check.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index b0eac55d..e6a0ff53 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -173,10 +173,15 @@ The first contract should keep built-in profile conditions stable and OpenClaw-owned. Operators should not be able to redefine what `local`, `container`, or `node-mode` means. -Future work can add namespaced plugin or driver conditions, for example -`acme.backupReady` or `driver.egressReady`. Those conditions should append to -the readiness result and participate in readiness only through explicit profile -or host policy, rather than mutating the built-in profile definitions. +Custom readiness should use a reusable criteria model, not ad hoc profile +redefinitions. Operators can declare namespaced criteria under a registry such +as `hosting.criteria`, then custom profiles or host policy can reference those +criteria as required or optional. For example, `acme.backup-ready` can be +defined once and reused by `acme.managed` and `acme.node-cell`. + +Built-in profile names and built-in condition names remain reserved. +Custom profiles extend built-in profiles and append criteria; they do not +mutate the built-in definitions. ### OCC and AgentHarness alignment @@ -208,6 +213,7 @@ fork before upstream OpenClaw PRs are opened: | Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` | | Profile selection | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` | | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` | +| Extensible readiness criteria | https://github.com/giodl73-repo/openclaw/pull/20 | `user/giodl/hosting-readiness-extensibility` | The remaining proof work should happen before upstream OpenClaw implementation PRs are filed: @@ -216,6 +222,7 @@ PRs are filed: - local Docker proof for `container` using `openclaw ready --expect-profile container --json` - local Docker proof for `node-mode` readiness behavior +- local Docker proof for custom criteria/profile readiness behavior - Crabbox Linux/container proof when reviewer-grade platform evidence is needed ## Rationale From 7894599543eb2f61f04512649550ab30aeb41aa5 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 17:58:02 -0700 Subject: [PATCH 04/98] Clarify readiness criteria scope --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index e6a0ff53..e8ea64b3 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -70,7 +70,8 @@ Hosts can prove which profile they are running. routing, UI, deployment system, or worker-pool model. - Put assistant deltas, tool frames, approvals, patches, compaction events, or harness protocol frames into the hosting contract. -- Make arbitrary operator-defined conditions part of the first core contract. +- Allow arbitrary operator-defined conditions to redefine built-in profile + semantics or built-in condition names. ## Proposal @@ -245,8 +246,8 @@ conditions are stable, and which release tests prove them. Gateway health enough for the first release? - Which profile conditions should be release-blocking versus warning-only as `container`, `reverse-proxy`, and `managed` mature? -- What is the right plugin or driver hook for namespaced custom readiness - conditions? +- Should later plugin or driver hooks be able to publish criteria evidence into + the same `hosting.criteria` model, and what trust boundary should that use? - Should future profile conformance live in QA Lab, maturity scorecards, Docker E2E, or a dedicated profile conformance runner? - Which stable telemetry event names should accompany readiness transitions in a From e68c5335bd6a911e30eec997629fddc9e5c8ef08 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 18:09:33 -0700 Subject: [PATCH 05/98] Fold readiness criteria into profile selection slice --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index e8ea64b3..fde5c15a 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -212,9 +212,8 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | | Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` | -| Profile selection | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` | +| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` | | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` | -| Extensible readiness criteria | https://github.com/giodl73-repo/openclaw/pull/20 | `user/giodl/hosting-readiness-extensibility` | The remaining proof work should happen before upstream OpenClaw implementation PRs are filed: From 0c1351033b2005dd38af4234b11e1226e0a48f19 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 18:18:50 -0700 Subject: [PATCH 06/98] Clarify hosting criteria spec status split --- ...010-standard-hosting-profiles-and-ready-check.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index fde5c15a..3254c498 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -180,10 +180,23 @@ as `hosting.criteria`, then custom profiles or host policy can reference those criteria as required or optional. For example, `acme.backup-ready` can be defined once and reused by `acme.managed` and `acme.node-cell`. +Criteria declarations are desired contract, not observed state. They should +carry stable identity and human-readable intent, while readiness output carries +observed `status`, `reason`, and `message`. This keeps `openclaw.json` aligned +with normal host systems: config/spec declares what must be true, runtime status +reports whether it is true. + Built-in profile names and built-in condition names remain reserved. Custom profiles extend built-in profiles and append criteria; they do not mutate the built-in definitions. +Built-in profiles also should not encode host-specific numeric probe values. +Intervals, retries, start periods, and timeouts belong in Docker, Compose, +Kubernetes, systemd, Nomad, ECS, or another host manifest. OpenClaw can document +recommended host manifests, and a later doctor/lint conformance pass can emit +findings and fix recommendations when config does not match the selected +profile, but `openclaw ready` should not depend on that optional repair path. + ### OCC and AgentHarness alignment This RFC does not conflict with OCC or the remote AgentHarness RFC. OCC can From 1be27a1fee7990805c97ce4b7125a9d1772a5fc1 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 18:21:15 -0700 Subject: [PATCH 07/98] Update hosting profiles RFC with current stack --- ...0010-standard-hosting-profiles-and-ready-check.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 3254c498..5ba73105 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -3,7 +3,7 @@ title: Standard Hosting Profiles and Ready Check authors: - Gio created: 2026-07-09 -last_updated: 2026-07-09 +last_updated: 2026-07-10 status: draft issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 @@ -60,6 +60,8 @@ Hosts can prove which profile they are running. plugins. - Leave room for later namespaced plugin or driver readiness conditions without letting operators redefine built-in profile semantics. +- Leave room for later doctor/lint conformance findings that recommend fixes + for config that does not match the selected built-in profile. ## Non-Goals @@ -72,6 +74,10 @@ Hosts can prove which profile they are running. harness protocol frames into the hosting contract. - Allow arbitrary operator-defined conditions to redefine built-in profile semantics or built-in condition names. +- Encode host-specific probe intervals, retries, start periods, or timeout + values into OpenClaw profile config. +- Make `openclaw ready` depend on doctor, lint, policy, or another optional + conformance layer. ## Proposal @@ -225,8 +231,8 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | | Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` | -| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` | +| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`17473adc33`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`d24dd5f241`) | The remaining proof work should happen before upstream OpenClaw implementation PRs are filed: From a841029aa8b5db04a8c8dcf2d2bfc3bcd05a315d Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 18:25:39 -0700 Subject: [PATCH 08/98] Clarify hosting profile motivation --- ...andard-hosting-profiles-and-ready-check.md | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 5ba73105..8e78a912 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -20,9 +20,10 @@ such as `openclaw ready`, `status --json`, and Gateway health. ## Motivation -OpenClaw can be hosted today, but it does not yet expose the small workload -contract that container hosts and orchestrators expect. Hosts need to answer one -question before routing traffic: +OpenClaw can be hosted today, but it is not obvious which hosting models are +turnkey, supportable, and release-validated. It also does not yet expose the +small workload contract that container hosts and orchestrators expect. Hosts +need to answer one question before routing traffic: ```text Is this OpenClaw instance ready under the hosting profile it was started with? @@ -34,7 +35,8 @@ readiness logic. That makes hosted OpenClaw harder to test upstream and harder to upgrade downstream. Profiles turn the broad claim "OpenClaw supports hosted deployments" into a -reviewable support matrix: +reviewable support matrix and a supportable subset that issues can be validated +against: ```text OpenClaw supports these profiles. @@ -81,6 +83,13 @@ Hosts can prove which profile they are running. ## Proposal +The RFC has two pieces that can be reviewed together or split if maintainers +prefer: + +1. Standard hosting profiles: named support contracts for the OpenClaw runtime. +2. A canonical ready check: a host-facing pass/fail surface for the selected + profile. + OpenClaw should expose a standard hostee contract: ```text @@ -258,6 +267,11 @@ Built-in profiles make the support promise concrete. Instead of one broad hosted-deployment claim, OpenClaw can say which profiles are supported, which conditions are stable, and which release tests prove them. +The ready check is intentionally smaller than the profile model. Container +hosters can use it directly as their readiness probe, while hosts that already +have their own probe plumbing can still benefit from standard profiles and +stable readiness conditions. + ## Unresolved questions - Should OpenClaw also add an HTTP `/ready` endpoint, or is `openclaw ready` plus From c0d74daf3a597fc96ae840781a03b09e40ead041 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 18:30:29 -0700 Subject: [PATCH 09/98] Add profile readiness signals to RFC --- ...andard-hosting-profiles-and-ready-check.md | 30 +++++-------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 8e78a912..8a01d418 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -110,29 +110,13 @@ OpenClaw should ship profile definitions rather than ask every host to invent one. Operators can still configure the underlying OpenClaw settings; the profile names the support contract. -| Profile | Purpose | -| --- | --- | -| `local` | Developer/local foreground process readiness. | -| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | -| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | -| `managed` | Platform-hosted OpenClaw with managed lifecycle expectations. | -| `node-mode` | Platform-controlled execution node or cell readiness. | - -The initial `local` readiness condition set should include: - -- `ProfileSelected` -- `ConfigLoaded` -- `GatewayResponding` -- `WorkspaceUsable` -- `PluginsLoaded` - -The initial `node-mode` condition set should add: - -- `NodePairingReady` -- `ControlledTargetsReady` -- `CommandApprovalReady` -- `ControlChannelReady` -- `StateReady` +| Profile | Purpose | Readiness signals | +| --- | --- | --- | +| `local` | Developer/local foreground process readiness. | `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`, `WorkspaceUsable`, `PluginsLoaded` | +| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | Core signals plus `ContainerStateReady`: writable state path, usable workspace mount, Gateway bind address/port resolved, plugin load failures surfaced. | +| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | Container signals plus `TrustedProxyReady`: advertised public URL/proxy origin configured, forwarded header trust mode explicit, Gateway reachable through the proxy path. | +| `managed` | Platform-hosted OpenClaw with managed lifecycle expectations. | Reverse-proxy signals plus `ManagedLifecycleReady`: selected managed profile, durable state location present, required host criteria declared, telemetry/audit hooks can report readiness without blocking core startup. | +| `node-mode` | Platform-controlled execution node or cell readiness. | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`, `StateReady`. | `node-mode` must stay product-neutral. A controlled target can be a desktop, sandbox, VM, pod, browser, or another execution surface. OpenClaw should not From b5b225d702d7e2c4d828f71eacfc1c58af00c774 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 18:31:54 -0700 Subject: [PATCH 10/98] Clarify implemented versus target profile signals --- ...andard-hosting-profiles-and-ready-check.md | 75 ++++++++++++------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 8a01d418..2a203f82 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -14,8 +14,8 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/33 ## Summary Define standard hosting profiles for running OpenClaw as a workload, plus a -canonical ready check that evaluates the selected profile against runtime -evidence and reports stable readiness conditions through host-facing surfaces +canonical ready check that evaluates the selected profile against existing +runtime status/config fields and reports stable readiness conditions through host-facing surfaces such as `openclaw ready`, `status --json`, and Gateway health. ## Motivation @@ -94,15 +94,17 @@ OpenClaw should expose a standard hostee contract: ```text profile selection -+ runtime evidence ++ runtime status/config facts + readiness condition evaluation -> ready/not-ready result ``` The contract is not a parallel hosted config tree. Existing OpenClaw config continues to own Gateway, proxy, plugin, model, session, node, and state -behavior. A hosting profile decides which runtime evidence must be true before -the instance is considered ready. +behavior. A hosting profile decides which existing runtime status/config facts +must be true before the instance is considered ready. If a criterion needs a +fact that status does not expose yet, the implementation should add that +missing status field rather than introduce a parallel readiness evidence path. ### Built-in profiles @@ -110,13 +112,20 @@ OpenClaw should ship profile definitions rather than ask every host to invent one. Operators can still configure the underlying OpenClaw settings; the profile names the support contract. -| Profile | Purpose | Readiness signals | -| --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`, `WorkspaceUsable`, `PluginsLoaded` | -| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | Core signals plus `ContainerStateReady`: writable state path, usable workspace mount, Gateway bind address/port resolved, plugin load failures surfaced. | -| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | Container signals plus `TrustedProxyReady`: advertised public URL/proxy origin configured, forwarded header trust mode explicit, Gateway reachable through the proxy path. | -| `managed` | Platform-hosted OpenClaw with managed lifecycle expectations. | Reverse-proxy signals plus `ManagedLifecycleReady`: selected managed profile, durable state location present, required host criteria declared, telemetry/audit hooks can report readiness without blocking core startup. | -| `node-mode` | Platform-controlled execution node or cell readiness. | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`, `StateReady`. | +Profiles should be declarative compositions of reusable readiness criteria. A +built-in profile references OpenClaw-owned `openclaw.*` criteria. Each criterion +is a named rule over OpenClaw runtime status/config fields and has one +OpenClaw-owned evaluator that emits the runtime readiness condition. +Custom profiles can extend built-in profiles and append their own namespaced +criteria without redefining the built-in support contract. + +| Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | +| --- | --- | --- | --- | --- | +| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.gateway-responding`, `openclaw.workspace-usable`, `openclaw.plugins-loaded` | config load, Gateway reachability, workspace usability, plugin load status | `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`, `WorkspaceUsable`, `PluginsLoaded` | +| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `openclaw.container-state-ready` | Gateway mode/bind/port, workspace usability | Core signals plus `ContainerStateReady`. | +| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `container` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Container signals plus `TrustedProxyReady`. | +| `managed` | Platform-hosted OpenClaw with managed lifecycle expectations. | `reverse-proxy` + `openclaw.managed-lifecycle-ready` | config load, workspace usability, host criteria declarations | Reverse-proxy signals plus `ManagedLifecycleReady`. | +| `node-mode` | Platform-controlled execution node or cell readiness. | `local` + node-mode `openclaw.*` criteria | node pairing, target inventory, command approval, control channel, state/workspace status | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`, `StateReady`. | `node-mode` must stay product-neutral. A controlled target can be a desktop, sandbox, VM, pod, browser, or another execution surface. OpenClaw should not @@ -173,21 +182,25 @@ The first contract should keep built-in profile conditions stable and OpenClaw-owned. Operators should not be able to redefine what `local`, `container`, or `node-mode` means. -Custom readiness should use a reusable criteria model, not ad hoc profile -redefinitions. Operators can declare namespaced criteria under a registry such -as `hosting.criteria`, then custom profiles or host policy can reference those -criteria as required or optional. For example, `acme.backup-ready` can be -defined once and reused by `acme.managed` and `acme.node-cell`. +Custom readiness should use the same reusable criteria model, not ad hoc +profile redefinitions. Operators can declare namespaced criteria under a +registry such as `hosting.criteria`, then custom profiles or host policy can +reference those criteria as required or optional. For example, +`acme.backup-ready` can be defined once and reused by `acme.managed` and +`acme.node-cell`. Criteria declarations are desired contract, not observed state. They should carry stable identity and human-readable intent, while readiness output carries -observed `status`, `reason`, and `message`. This keeps `openclaw.json` aligned -with normal host systems: config/spec declares what must be true, runtime status -reports whether it is true. +observed `status`, `reason`, and `message`. Built-in criteria evaluate the same +runtime status/config facts that `status --json` and Gateway health already +expose, plus any missing status fields added alongside the criterion. This keeps +`openclaw.json` aligned with normal host systems: config/spec declares what must +be true, runtime status reports whether it is true, and readiness is a +projection over that status. -Built-in profile names and built-in condition names remain reserved. -Custom profiles extend built-in profiles and append criteria; they do not -mutate the built-in definitions. +Built-in profile names, built-in `openclaw.*` criterion names, and built-in +condition names remain reserved. Custom profiles extend built-in profiles and +append criteria; they do not mutate the built-in definitions. Built-in profiles also should not encode host-specific numeric probe values. Intervals, retries, start periods, and timeouts belong in Docker, Compose, @@ -210,7 +223,7 @@ OCC/control plane: desired state, tenant identity, admission, restrictions, quotas, policy compilation, provisioning, audit indexing. OpenClaw/runtime plane: startup, Gateway, sessions, cells/nodes, harness -execution, readiness evidence, ready/not-ready result. +execution, runtime status fields, ready/not-ready projection. ``` OCC should not be in the hot path for assistant deltas, tool events, approvals, @@ -224,8 +237,8 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | | Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` | -| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`17473adc33`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`d24dd5f241`) | +| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`ed4823d67d`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`662a0034c3`) | The remaining proof work should happen before upstream OpenClaw implementation PRs are filed: @@ -237,11 +250,17 @@ PRs are filed: - local Docker proof for custom criteria/profile readiness behavior - Crabbox Linux/container proof when reviewer-grade platform evidence is needed +This first stack proves the core ready/result shape, explicit profile +selection, built-in profile composition from reusable criteria, built-in +container/reverse-proxy/managed criteria over status fields, custom criteria +declarations, and node-mode status-field rules. + ## Rationale This follows the normal contract between a host and a hosted workload. The host -selects a runtime shape and supplies configuration. The workload starts, gathers -its own runtime evidence, evaluates readiness, and reports stable conditions. +selects a runtime shape and supplies configuration. The workload starts, +publishes runtime status, evaluates readiness criteria over that status, and +reports stable conditions. Putting the result into `ready`, `status`, and `health` is preferable to a special "hosted OpenClaw" command tree. "Hosted" is a runtime posture and support From 40bfd82febd593e7655095d4bc65e709c250ae52 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 20:22:35 -0700 Subject: [PATCH 11/98] Align hosting readiness RFC with HTTP ready probes --- ...andard-hosting-profiles-and-ready-check.md | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 2a203f82..c5d90d97 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -15,8 +15,9 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/33 Define standard hosting profiles for running OpenClaw as a workload, plus a canonical ready check that evaluates the selected profile against existing -runtime status/config fields and reports stable readiness conditions through host-facing surfaces -such as `openclaw ready`, `status --json`, and Gateway health. +runtime status/config fields and reports stable readiness conditions through +host-facing surfaces such as Gateway `/ready` and `/readyz`, `status --json`, +and Gateway health. ## Motivation @@ -52,8 +53,8 @@ Hosts can prove which profile they are running. - Make `local` the default profile when no profile is selected. - Add a canonical readiness result with stable condition `type`, `status`, `reason`, and human-readable `message`. -- Add a focused `openclaw ready --json` command for host readiness probes. -- Expose the same readiness result through existing status and health surfaces. +- Expose the same readiness result through existing HTTP readiness, status, and + health surfaces. - Add explicit profile selection through config, environment, and Gateway startup. - Keep OpenClaw generic: no Lobster, Scout, Microsoft, tenant, Teams, Kusto, or @@ -78,7 +79,7 @@ Hosts can prove which profile they are running. semantics or built-in condition names. - Encode host-specific probe intervals, retries, start periods, or timeout values into OpenClaw profile config. -- Make `openclaw ready` depend on doctor, lint, policy, or another optional +- Make readiness depend on doctor, lint, policy, or another optional conformance layer. ## Proposal @@ -142,9 +143,11 @@ Profile selection should be visible in normal hosting mechanisms: - environment: `OPENCLAW_HOSTING_PROFILE` - startup: `openclaw gateway run --hosting-profile ` -`openclaw ready --expect-profile ` should be an assertion, not a -selection mechanism. If the running Gateway selected a different profile, the -ready result should be `ready=false` with a stable `ProfileMismatch` reason. +The selected profile should be reported in `/ready`, `/readyz`, `status --json`, +and Gateway health so hosts and release tests can assert that the running +process selected the intended profile. A later optional CLI wrapper can add an +`openclaw ready --expect-profile ` assertion if maintainers want that +ergonomic surface, but it is not required for the first contract. ### Ready result @@ -153,7 +156,6 @@ Readiness should use Kubernetes-style conditions: ```jsonc { "profile": "container", - "expectedProfile": "container", "ready": false, "conditions": [ { @@ -207,7 +209,7 @@ Intervals, retries, start periods, and timeouts belong in Docker, Compose, Kubernetes, systemd, Nomad, ECS, or another host manifest. OpenClaw can document recommended host manifests, and a later doctor/lint conformance pass can emit findings and fix recommendations when config does not match the selected -profile, but `openclaw ready` should not depend on that optional repair path. +profile, but core `/ready` should not depend on that optional repair path. ### OCC and AgentHarness alignment @@ -236,16 +238,17 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | -| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` | -| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`ed4823d67d`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`662a0034c3`) | +| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`0c5aaa2b88`) | +| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`068bc0ced0`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`7d51aee03a`) | The remaining proof work should happen before upstream OpenClaw implementation PRs are filed: -- local Docker proof for default `local` readiness using `openclaw ready --json` -- local Docker proof for `container` using - `openclaw ready --expect-profile container --json` +- local Docker proof for default `local` readiness using Gateway `/ready` +- local Docker proof for `container` using `OPENCLAW_HOSTING_PROFILE=container` + or `gateway run --hosting-profile container`, then asserting `/ready` reports + the selected `container` profile - local Docker proof for `node-mode` readiness behavior - local Docker proof for custom criteria/profile readiness behavior - Crabbox Linux/container proof when reviewer-grade platform evidence is needed @@ -277,8 +280,9 @@ stable readiness conditions. ## Unresolved questions -- Should OpenClaw also add an HTTP `/ready` endpoint, or is `openclaw ready` plus - Gateway health enough for the first release? +- Should OpenClaw later add an `openclaw ready` CLI wrapper over the same + readiness result, or are HTTP `/ready` plus status/health enough for the first + release? - Which profile conditions should be release-blocking versus warning-only as `container`, `reverse-proxy`, and `managed` mature? - Should later plugin or driver hooks be able to publish criteria evidence into From ddcaca7cadf2f1a8d752298921f70a65247a08ad Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 22:11:38 -0700 Subject: [PATCH 12/98] Refine hosting profile readiness contract --- ...andard-hosting-profiles-and-ready-check.md | 98 +++++++++++-------- 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index c5d90d97..df6689ca 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -21,10 +21,11 @@ and Gateway health. ## Motivation -OpenClaw can be hosted today, but it is not obvious which hosting models are -turnkey, supportable, and release-validated. It also does not yet expose the -small workload contract that container hosts and orchestrators expect. Hosts -need to answer one question before routing traffic: +OpenClaw can be hosted today and already exposes Gateway `/ready` and `/readyz`. +Those probes cover Gateway startup, channel runtime health, drain state, and +event-loop health. What they do not identify is the selected hosting model or +the config/runtime predicates that make that model supportable. Hosts therefore +cannot answer one higher-level question before routing traffic: ```text Is this OpenClaw instance ready under the hosting profile it was started with? @@ -61,8 +62,10 @@ Hosts can prove which profile they are running. product-specific host concepts. - Keep the first implementation in core so readiness works without optional plugins. -- Leave room for later namespaced plugin or driver readiness conditions without - letting operators redefine built-in profile semantics. +- Define the exact truth predicates and stable non-ready reasons for every + built-in profile condition. +- Reserve namespaced plugin or driver readiness conditions for a later contract + that defines trusted runtime evidence publication. - Leave room for later doctor/lint conformance findings that recommend fixes for config that does not match the selected built-in profile. @@ -117,21 +120,42 @@ Profiles should be declarative compositions of reusable readiness criteria. A built-in profile references OpenClaw-owned `openclaw.*` criteria. Each criterion is a named rule over OpenClaw runtime status/config fields and has one OpenClaw-owned evaluator that emits the runtime readiness condition. -Custom profiles can extend built-in profiles and append their own namespaced -criteria without redefining the built-in support contract. | Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | | --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.gateway-responding`, `openclaw.workspace-usable`, `openclaw.plugins-loaded` | config load, Gateway reachability, workspace usability, plugin load status | `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`, `WorkspaceUsable`, `PluginsLoaded` | -| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `openclaw.container-state-ready` | Gateway mode/bind/port, workspace usability | Core signals plus `ContainerStateReady`. | -| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `container` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Container signals plus `TrustedProxyReady`. | -| `managed` | Platform-hosted OpenClaw with managed lifecycle expectations. | `reverse-proxy` + `openclaw.managed-lifecycle-ready` | config load, workspace usability, host criteria declarations | Reverse-proxy signals plus `ManagedLifecycleReady`. | -| `node-mode` | Platform-controlled execution node or cell readiness. | `local` + node-mode `openclaw.*` criteria | node pairing, target inventory, command approval, control channel, state/workspace status | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`, `StateReady`. | +| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.gateway-responding`, `openclaw.plugins-loaded` | config load, Gateway reachability, selected plugin activation status | `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`, `PluginsLoaded` | +| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `openclaw.container-state-ready` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | +| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | +| `managed` | Platform-hosted OpenClaw behind managed ingress. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. Existing Gateway readiness remains the lifecycle source of truth. | +| `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + node-mode `openclaw.*` criteria | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`. | `node-mode` must stay product-neutral. A controlled target can be a desktop, sandbox, VM, pod, browser, or another execution surface. OpenClaw should not assume one node maps to exactly one target. +### Built-in truth predicates + +Profile readiness is composed with, and does not replace, the existing Gateway +readiness result. Final `/ready` and `/readyz` readiness is true only when the +existing startup/channel/drain/event-loop evaluation is ready and every +condition listed for the selected profile is `True`. Both `False` and `Unknown` +block profile readiness. A status surface that did not observe a required fact +reports `Unknown`; it must not turn missing evidence into a positive readiness +result. + +| Condition | True when | Stable non-ready reasons | +| --- | --- | --- | +| `ProfileSelected` | The runtime resolved and reports the selected built-in profile. The default is `local`. | None; invalid explicit values fail selection before startup. | +| `ConfigLoaded` | Runtime configuration loaded successfully. | `ConfigNotLoaded` | +| `GatewayResponding` | The running Gateway is evaluating its own readiness request. | `GatewayUnavailable`, `GatewayNotChecked` | +| `PluginsLoaded` | The active plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not block. | `PluginLoadFailures`, `PluginStatusUnavailable` | +| `ContainerStateReady` | The effective Gateway mode is `local` and the resolved listener host is not loopback. The port has already passed normal config validation. Config-only status reports `Unknown` when an `auto` bind has not been resolved. | `ContainerGatewayRemote`, `ContainerGatewayLoopback`, `ContainerBindNotResolved` | +| `TrustedProxyReady` | Auth mode is `trusted-proxy`, `trustedProxy.userHeader` is non-empty, and `gateway.trustedProxies` contains at least one address/CIDR. Loopback is valid for a same-host proxy. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing` | +| `NodePairingReady` | The pairing store is readable and contains at least one approved pairing. | `NodePairingUnavailable`, `NodePairingPending`, `NodePairingMissing` | +| `ControlledTargetsReady` | The live Gateway node registry contains at least one connected node whose id is approved in the pairing store. Persisted pairing alone is insufficient. | `ControlledTargetsDisconnected` | +| `CommandApprovalReady` | A connected paired node advertises at least one command that is granted by pairing or `gateway.nodes.allowCommands` and not removed by `gateway.nodes.denyCommands`. A deny-only list is not approval evidence. | `CommandApprovalMissing` | +| `ControlChannelReady` | At least one connected node session is correlated to an approved pairing. Gateway HTTP responsiveness alone is insufficient. | `ControlChannelUnavailable` | + ### Profile selection OpenClaw should not require an explicit profile to run. If no profile is @@ -178,31 +202,22 @@ Readiness should use Kubernetes-style conditions: Hosts and tests should key on `type`, `status`, and `reason`. `message` is for operators and should remain non-normative. -### Extensibility +### Future extensibility The first contract should keep built-in profile conditions stable and OpenClaw-owned. Operators should not be able to redefine what `local`, `container`, or `node-mode` means. -Custom readiness should use the same reusable criteria model, not ad hoc -profile redefinitions. Operators can declare namespaced criteria under a -registry such as `hosting.criteria`, then custom profiles or host policy can -reference those criteria as required or optional. For example, -`acme.backup-ready` can be defined once and reused by `acme.managed` and -`acme.node-cell`. - -Criteria declarations are desired contract, not observed state. They should -carry stable identity and human-readable intent, while readiness output carries -observed `status`, `reason`, and `message`. Built-in criteria evaluate the same -runtime status/config facts that `status --json` and Gateway health already -expose, plus any missing status fields added alongside the criterion. This keeps -`openclaw.json` aligned with normal host systems: config/spec declares what must -be true, runtime status reports whether it is true, and readiness is a -projection over that status. - -Built-in profile names, built-in `openclaw.*` criterion names, and built-in -condition names remain reserved. Custom profiles extend built-in profiles and -append criteria; they do not mutate the built-in definitions. +This first RFC does not add custom profile or criterion config. A declaration +without a trusted observed-state producer can never become ready and would be a +sticky but unusable public contract. A later RFC may add namespaced criteria +after it defines who may publish evidence, how evidence is scoped and expired, +how plugins or drivers are authenticated, and how status and readiness consume +the same fact without creating a parallel evidence model. + +Built-in profile names, `openclaw.*` criterion names, and built-in condition +names remain reserved. Operators configure the underlying OpenClaw settings; +they do not redefine built-in profile semantics. Built-in profiles also should not encode host-specific numeric probe values. Intervals, retries, start periods, and timeouts belong in Docker, Compose, @@ -238,9 +253,9 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | -| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`0c5aaa2b88`) | -| Profile selection and reusable criteria | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`068bc0ced0`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`7d51aee03a`) | +| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`63ad1aaa64`) | +| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`468b0f289d`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`464310eefa`) | The remaining proof work should happen before upstream OpenClaw implementation PRs are filed: @@ -250,13 +265,12 @@ PRs are filed: or `gateway run --hosting-profile container`, then asserting `/ready` reports the selected `container` profile - local Docker proof for `node-mode` readiness behavior -- local Docker proof for custom criteria/profile readiness behavior - Crabbox Linux/container proof when reviewer-grade platform evidence is needed This first stack proves the core ready/result shape, explicit profile -selection, built-in profile composition from reusable criteria, built-in -container/reverse-proxy/managed criteria over status fields, custom criteria -declarations, and node-mode status-field rules. +selection, built-in profile composition from reusable criteria, exact built-in +container/reverse-proxy/managed predicates, and node-mode rules backed by the +live node registry. ## Rationale @@ -285,8 +299,8 @@ stable readiness conditions. release? - Which profile conditions should be release-blocking versus warning-only as `container`, `reverse-proxy`, and `managed` mature? -- Should later plugin or driver hooks be able to publish criteria evidence into - the same `hosting.criteria` model, and what trust boundary should that use? +- Should later plugin or driver hooks publish namespaced criteria evidence, and + what identity, scoping, freshness, and trust boundary should that require? - Should future profile conformance live in QA Lab, maturity scorecards, Docker E2E, or a dedicated profile conformance runner? - Which stable telemetry event names should accompany readiness transitions in a From 866551341c993109a20020adcb21ad7c73423955 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 22:22:09 -0700 Subject: [PATCH 13/98] Clarify hosting profiles maintainer case --- ...andard-hosting-profiles-and-ready-check.md | 107 +++++++++++++++++- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index df6689ca..f6726848 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -13,11 +13,13 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/33 ## Summary -Define standard hosting profiles for running OpenClaw as a workload, plus a -canonical ready check that evaluates the selected profile against existing -runtime status/config fields and reports stable readiness conditions through -host-facing surfaces such as Gateway `/ready` and `/readyz`, `status --json`, -and Gateway health. +Add a small support contract for running OpenClaw as a workload. A +built-in hosting profile names a validated composition of existing OpenClaw +settings; readiness reports whether the running process satisfies that +composition. This extends the existing Gateway `/ready` and `/readyz` result +and projects the same conditions into `status --json` and Gateway health. It +does not add a second config system, generate config, or replace existing +Gateway readiness. ## Motivation @@ -36,6 +38,12 @@ baked config, environment restore lists, persistence wrappers, and adapter-only readiness logic. That makes hosted OpenClaw harder to test upstream and harder to upgrade downstream. +A concrete example is a container that starts successfully with a loopback-only +Gateway. Existing lifecycle readiness can correctly report that the process is +healthy while the selected container topology is unusable from outside the +container. The missing information is not another liveness probe; it is the +runtime assertion that this process satisfies the container support contract. + Profiles turn the broad claim "OpenClaw supports hosted deployments" into a reviewable support matrix and a supportable subset that issues can be validated against: @@ -47,6 +55,11 @@ Each release can test those conditions. Hosts can prove which profile they are running. ``` +This gives bug reports and release tests a reproducible starting point. Instead +of debugging an unbounded hosted configuration, maintainers can ask for the +selected profile and its stable condition result. Profiles complement maturity +work by turning a support claim into executable release evidence. + ## Goals - Define built-in hosting profiles for `local`, `container`, `reverse-proxy`, @@ -103,6 +116,15 @@ profile selection -> ready/not-ready result ``` +Four constraints keep this narrow: + +1. A profile does not write, merge, or repair configuration. +2. Operators may continue to configure every OpenClaw setting directly. +3. Profile readiness is an additional conjunction with existing Gateway + readiness, never a replacement for it. +4. The first contract evaluates only facts owned by OpenClaw core. Optional + plugins, policy, and doctor may consume the result but are not dependencies. + The contract is not a parallel hosted config tree. Existing OpenClaw config continues to own Gateway, proxy, plugin, model, session, node, and state behavior. A hosting profile decides which existing runtime status/config facts @@ -167,6 +189,17 @@ Profile selection should be visible in normal hosting mechanisms: - environment: `OPENCLAW_HOSTING_PROFILE` - startup: `openclaw gateway run --hosting-profile ` +Selection precedence is deterministic: + +```text +gateway startup flag > environment > openclaw.json > local default +``` + +An invalid value from any explicitly supplied source is a startup/config error; +it must not silently fall through to a lower-priority source or to `local`. +The effective value after precedence resolution is the profile reported by all +readiness and status surfaces. + The selected profile should be reported in `/ready`, `/readyz`, `status --json`, and Gateway health so hosts and release tests can assert that the running process selected the intended profile. A later optional CLI wrapper can add an @@ -202,6 +235,49 @@ Readiness should use Kubernetes-style conditions: Hosts and tests should key on `type`, `status`, and `reason`. `message` is for operators and should remain non-normative. +### Compatibility and operational cost + +No explicit selection is required. Existing installations resolve to `local`, +and their Gateway/session/plugin configuration remains unchanged. Selecting a +profile does not enable auth, change bind addresses, install plugins, move +state, or provision nodes. It only changes which runtime-owned facts must be +true for profile readiness. + +The readiness result is intentionally stricter than the old result in one +case: an activation error from a selected plugin makes the default `local` +profile not ready. Explicitly disabled plugins do not block. This treats +"configured but failed to activate" as incomplete startup rather than a +healthy process, and makes the failure visible through a stable reason instead +of host-specific log scraping. Because this can change an existing probe from +200 to 503, it requires release notes and upgrade coverage; it is not presented +as a behavior-neutral migration. + +This keeps the operational contract familiar to container hosts: + +```text +host supplies config and selects a supported runtime shape +OpenClaw starts using its normal config semantics +host waits for the existing readiness endpoint +readiness explains both lifecycle and profile conformance +``` + +Hosts that do not set a profile retain the existing endpoints and configuration +model, with `local` as the reported and evaluated support contract. + +### Why this belongs in core + +Doctor can explain or repair static misconfiguration, and policy can restrict +what configuration is allowed. Neither is the right owner for a workload's +live readiness contract: both are optional, while `/ready` is consumed during +startup and continuously by supervisors. Core already owns the authoritative +Gateway, plugin, proxy, pairing, and live-node facts used here. The smallest +reliable implementation is therefore a projection over those facts at the +existing core readiness boundary. + +Keeping the predicates in core also makes the support promise testable in the +OpenClaw release matrix. Downstream hosts remain responsible for tenant routing, +deployment, storage destinations, telemetry backends, and product policy. + ### Future extensibility The first contract should keep built-in profile conditions stable and @@ -272,6 +348,21 @@ selection, built-in profile composition from reusable criteria, exact built-in container/reverse-proxy/managed predicates, and node-mode rules backed by the live node registry. +### Incremental adoption + +The proposal does not require one all-or-nothing implementation landing: + +1. Land the condition shape and default `local` projection into existing + readiness, health, and status surfaces. +2. Add explicit selection plus `container`, `reverse-proxy`, and `managed` + predicates over effective runtime facts. +3. Add `node-mode` using pairing and live node-registry evidence. + +The first slice is independently useful because it creates one canonical, +explainable result without introducing non-local hosting behavior. If the +profile catalog needs further design, maintainers can accept that foundation +without committing to every proposed profile at once. + ## Rationale This follows the normal contract between a host and a hosted workload. The host @@ -287,6 +378,12 @@ Built-in profiles make the support promise concrete. Instead of one broad hosted-deployment claim, OpenClaw can say which profiles are supported, which conditions are stable, and which release tests prove them. +This is intentionally less powerful than a general profile or policy engine. +Its value comes from OpenClaw owning a small number of definitions and testing +them release after release. A host-specific profile language would move the +support boundary back downstream and recreate the ambiguity this RFC is meant +to remove. + The ready check is intentionally smaller than the profile model. Container hosters can use it directly as their readiness probe, while hosts that already have their own probe plumbing can still benefit from standard profiles and From 4507d82e491a167ebc09d92c2f33ef6faca853ad Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 9 Jul 2026 22:55:43 -0700 Subject: [PATCH 14/98] Add required and advisory readiness conditions --- ...andard-hosting-profiles-and-ready-check.md | 91 +++++++++++-------- 1 file changed, 55 insertions(+), 36 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index f6726848..e2d75a70 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -75,8 +75,8 @@ work by turning a support claim into executable release evidence. product-specific host concepts. - Keep the first implementation in core so readiness works without optional plugins. -- Define the exact truth predicates and stable non-ready reasons for every - built-in profile condition. +- Define the requirement class, exact truth predicates, and stable non-ready + reasons for every built-in profile condition. - Reserve namespaced plugin or driver readiness conditions for a later contract that defines trusted runtime evidence publication. - Leave room for later doctor/lint conformance findings that recommend fixes @@ -124,6 +124,8 @@ Four constraints keep this narrow: readiness, never a replacement for it. 4. The first contract evaluates only facts owned by OpenClaw core. Optional plugins, policy, and doctor may consume the result but are not dependencies. +5. Only required conditions affect the binary ready result. Advisory conditions + remain visible without turning a useful diagnostic into an outage. The contract is not a parallel hosted config tree. Existing OpenClaw config continues to own Gateway, proxy, plugin, model, session, node, and state @@ -145,7 +147,7 @@ OpenClaw-owned evaluator that emits the runtime readiness condition. | Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | | --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.gateway-responding`, `openclaw.plugins-loaded` | config load, Gateway reachability, selected plugin activation status | `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`, `PluginsLoaded` | +| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.gateway-responding`, `openclaw.plugins-loaded` | config load, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`. Advisory: `PluginsLoaded`. | | `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `openclaw.container-state-ready` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | | `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | | `managed` | Platform-hosted OpenClaw behind managed ingress. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. Existing Gateway readiness remains the lifecycle source of truth. | @@ -160,23 +162,29 @@ assume one node maps to exactly one target. Profile readiness is composed with, and does not replace, the existing Gateway readiness result. Final `/ready` and `/readyz` readiness is true only when the existing startup/channel/drain/event-loop evaluation is ready and every -condition listed for the selected profile is `True`. Both `False` and `Unknown` -block profile readiness. A status surface that did not observe a required fact -reports `Unknown`; it must not turn missing evidence into a positive readiness -result. - -| Condition | True when | Stable non-ready reasons | -| --- | --- | --- | -| `ProfileSelected` | The runtime resolved and reports the selected built-in profile. The default is `local`. | None; invalid explicit values fail selection before startup. | -| `ConfigLoaded` | Runtime configuration loaded successfully. | `ConfigNotLoaded` | -| `GatewayResponding` | The running Gateway is evaluating its own readiness request. | `GatewayUnavailable`, `GatewayNotChecked` | -| `PluginsLoaded` | The active plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not block. | `PluginLoadFailures`, `PluginStatusUnavailable` | -| `ContainerStateReady` | The effective Gateway mode is `local` and the resolved listener host is not loopback. The port has already passed normal config validation. Config-only status reports `Unknown` when an `auto` bind has not been resolved. | `ContainerGatewayRemote`, `ContainerGatewayLoopback`, `ContainerBindNotResolved` | -| `TrustedProxyReady` | Auth mode is `trusted-proxy`, `trustedProxy.userHeader` is non-empty, and `gateway.trustedProxies` contains at least one address/CIDR. Loopback is valid for a same-host proxy. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing` | -| `NodePairingReady` | The pairing store is readable and contains at least one approved pairing. | `NodePairingUnavailable`, `NodePairingPending`, `NodePairingMissing` | -| `ControlledTargetsReady` | The live Gateway node registry contains at least one connected node whose id is approved in the pairing store. Persisted pairing alone is insufficient. | `ControlledTargetsDisconnected` | -| `CommandApprovalReady` | A connected paired node advertises at least one command that is granted by pairing or `gateway.nodes.allowCommands` and not removed by `gateway.nodes.denyCommands`. A deny-only list is not approval evidence. | `CommandApprovalMissing` | -| `ControlChannelReady` | At least one connected node session is correlated to an approved pairing. Gateway HTTP responsiveness alone is insufficient. | `ControlChannelUnavailable` | +required condition listed for the selected profile is `True`. `False` and +`Unknown` required conditions block profile readiness. Non-`True` advisory +conditions are reported but do not change the binary result. + +The condition contract and aggregation rules are shared across surfaces; the +observed status may differ with probe depth and observation time. A status +surface that did not observe a required fact reports `Unknown` and cannot claim +ready. A status operation that successfully probes the Gateway may project that +observation as `True`. Missing required evidence must never become a positive +readiness result. + +| Condition | Requirement | True when | Stable non-ready reasons | +| --- | --- | --- | --- | +| `ProfileSelected` | Required | The runtime resolved and reports the selected built-in profile. The default is `local`. | None; invalid explicit values fail selection before startup. | +| `ConfigLoaded` | Required | Runtime configuration loaded successfully. | `ConfigNotLoaded` | +| `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | +| `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | +| `ContainerStateReady` | Required for `container` | The effective Gateway mode is `local` and the resolved listener host is not loopback. The port has already passed normal config validation. Config-only status reports `Unknown` when an `auto` bind has not been resolved. | `ContainerGatewayRemote`, `ContainerGatewayLoopback`, `ContainerBindNotResolved` | +| `TrustedProxyReady` | Required for `reverse-proxy` and `managed` | Auth mode is `trusted-proxy`, `trustedProxy.userHeader` is non-empty, and `gateway.trustedProxies` contains at least one address/CIDR. Loopback is valid for a same-host proxy. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing` | +| `NodePairingReady` | Required for `node-mode` | The pairing store is readable and contains at least one approved pairing. | `NodePairingUnavailable`, `NodePairingPending`, `NodePairingMissing` | +| `ControlledTargetsReady` | Required for `node-mode` | The live Gateway node registry contains at least one connected node whose id is approved in the pairing store. Persisted pairing alone is insufficient. | `ControlledTargetsDisconnected` | +| `CommandApprovalReady` | Required for `node-mode` | A connected paired node advertises at least one command that is granted by pairing or `gateway.nodes.allowCommands` and not removed by `gateway.nodes.denyCommands`. A deny-only list is not approval evidence. | `CommandApprovalMissing` | +| `ControlChannelReady` | Required for `node-mode` | At least one connected node session is correlated to an approved pairing. Gateway HTTP responsiveness alone is insufficient. | `ControlChannelUnavailable` | ### Profile selection @@ -218,22 +226,30 @@ Readiness should use Kubernetes-style conditions: { "type": "ProfileSelected", "status": "True", + "requirement": "required", "reason": "ProfileSelected", "message": "Runtime selected the container hosting profile." }, { "type": "GatewayResponding", "status": "False", + "requirement": "required", "reason": "GatewayUnavailable", "message": "Gateway did not respond to the readiness request." } ], - "failures": ["GatewayUnavailable"] + "failures": ["GatewayUnavailable"], + "advisories": [] } ``` -Hosts and tests should key on `type`, `status`, and `reason`. `message` is for -operators and should remain non-normative. +Hosts and tests should key on `type`, `status`, `requirement`, and `reason`. +`failures` is the deduplicated union of existing Gateway lifecycle failure +reasons and non-`True` required profile-condition reasons. This preserves +existing channel/startup/drain/event-loop explanations even though those legacy +checks are not duplicated as profile conditions. `advisories` is the set of +non-`True` advisory profile reasons. `message` is for operators and should +remain non-normative. ### Compatibility and operational cost @@ -243,14 +259,10 @@ profile does not enable auth, change bind addresses, install plugins, move state, or provision nodes. It only changes which runtime-owned facts must be true for profile readiness. -The readiness result is intentionally stricter than the old result in one -case: an activation error from a selected plugin makes the default `local` -profile not ready. Explicitly disabled plugins do not block. This treats -"configured but failed to activate" as incomplete startup rather than a -healthy process, and makes the failure visible through a stable reason instead -of host-specific log scraping. Because this can change an existing probe from -200 to 503, it requires release notes and upgrade coverage; it is not presented -as a behavior-neutral migration. +Plugin activation errors are advisory in the default profile. They remain +visible through stable conditions and the `advisories` list without changing an +existing healthy readiness response from 200 to 503. Explicitly disabled +plugins do not report an advisory. This keeps the operational contract familiar to container hosts: @@ -295,6 +307,13 @@ Built-in profile names, `openclaw.*` criterion names, and built-in condition names remain reserved. Operators configure the underlying OpenClaw settings; they do not redefine built-in profile semantics. +Condition identity and requirement class are part of the support contract. +Changing an advisory condition to required, adding a new required condition to +an existing profile, or changing a stable reason can alter host behavior and +must receive compatibility review, release notes, and profile conformance +coverage. New diagnostics should default to advisory unless failure means the +named runtime shape cannot perform its supported role. + Built-in profiles also should not encode host-specific numeric probe values. Intervals, retries, start periods, and timeouts belong in Docker, Compose, Kubernetes, systemd, Nomad, ECS, or another host manifest. OpenClaw can document @@ -329,9 +348,9 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | -| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`63ad1aaa64`) | -| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`468b0f289d`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`464310eefa`) | +| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`bf44ae3b45`) | +| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`cc43cc5a02`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`88d44534af`) | The remaining proof work should happen before upstream OpenClaw implementation PRs are filed: @@ -394,8 +413,8 @@ stable readiness conditions. - Should OpenClaw later add an `openclaw ready` CLI wrapper over the same readiness result, or are HTTP `/ready` plus status/health enough for the first release? -- Which profile conditions should be release-blocking versus warning-only as - `container`, `reverse-proxy`, and `managed` mature? +- Which additional advisory conditions would improve supportability without + weakening the meaning of required profile conformance? - Should later plugin or driver hooks publish namespaced criteria evidence, and what identity, scoping, freshness, and trust boundary should that require? - Should future profile conformance live in QA Lab, maturity scorecards, Docker From 6e6e4eacdd340f04610133ecd216c2f1989aebd0 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 06:31:19 -0700 Subject: [PATCH 15/98] Document hosting profile Docker conformance --- ...andard-hosting-profiles-and-ready-check.md | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index e2d75a70..c985e910 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -348,19 +348,26 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | -| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`bf44ae3b45`) | -| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`cc43cc5a02`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`88d44534af`) | - -The remaining proof work should happen before upstream OpenClaw implementation -PRs are filed: - -- local Docker proof for default `local` readiness using Gateway `/ready` -- local Docker proof for `container` using `OPENCLAW_HOSTING_PROFILE=container` - or `gateway run --hosting-profile container`, then asserting `/ready` reports - the selected `container` profile -- local Docker proof for `node-mode` readiness behavior -- Crabbox Linux/container proof when reviewer-grade platform evidence is needed +| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`f11b19d553`) | +| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`87cf11e944`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`22bdbbd3c8`) | + +The stack includes one package-installed Docker conformance lane, +`pnpm test:docker:hosting-profiles`, built incrementally across the three +branches: + +- PR 17 proves an unset profile defaults to `local`, `/readyz` returns 200, and + required/advisory aggregation is stable. +- PR 18 proves a LAN-bound `container` profile returns 200 and a loopback-bound + `container` profile returns 503 with `ContainerGatewayLoopback`. +- PR 19 starts a real node host and proves `node-mode` transitions from 503 to + 200 only after approved pairing, a correlated live target, an advertised + approved command, and a connected control channel are all observed. + +The lane is the reproducible behavior proof for upstream review. A brokered +Linux/Crabbox execution should be attached before the implementation PRs are +promoted upstream; the draft branches do not depend on Crabbox to define the +contract. This first stack proves the core ready/result shape, explicit profile selection, built-in profile composition from reusable criteria, exact built-in From ef1b84ee18aa7b761d82f8f99b1db0d0d6fd3061 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 07:24:37 -0700 Subject: [PATCH 16/98] Narrow hosting profile support contracts --- ...andard-hosting-profiles-and-ready-check.md | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index c985e910..48831469 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -63,7 +63,7 @@ work by turning a support claim into executable release evidence. ## Goals - Define built-in hosting profiles for `local`, `container`, `reverse-proxy`, - `managed`, and `node-mode`. + and `node-mode`. - Make `local` the default profile when no profile is selected. - Add a canonical readiness result with stable condition `type`, `status`, `reason`, and human-readable `message`. @@ -140,6 +140,12 @@ OpenClaw should ship profile definitions rather than ask every host to invent one. Operators can still configure the underlying OpenClaw settings; the profile names the support contract. +A profile names the expected ingress/runtime posture, not the packaging +technology. A Gateway directly reachable through its container listener uses +`container`. A Gateway in a container behind a trusted identity proxy uses +`reverse-proxy`. New profile names should be added only when they define a +distinct OpenClaw-owned invariant and conformance scenario. + Profiles should be declarative compositions of reusable readiness criteria. A built-in profile references OpenClaw-owned `openclaw.*` criteria. Each criterion is a named rule over OpenClaw runtime status/config fields and has one @@ -150,7 +156,6 @@ OpenClaw-owned evaluator that emits the runtime readiness condition. | `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.gateway-responding`, `openclaw.plugins-loaded` | config load, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`. Advisory: `PluginsLoaded`. | | `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `openclaw.container-state-ready` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | | `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | -| `managed` | Platform-hosted OpenClaw behind managed ingress. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. Existing Gateway readiness remains the lifecycle source of truth. | | `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + node-mode `openclaw.*` criteria | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`. | `node-mode` must stay product-neutral. A controlled target can be a desktop, @@ -180,7 +185,7 @@ readiness result. | `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | | `ContainerStateReady` | Required for `container` | The effective Gateway mode is `local` and the resolved listener host is not loopback. The port has already passed normal config validation. Config-only status reports `Unknown` when an `auto` bind has not been resolved. | `ContainerGatewayRemote`, `ContainerGatewayLoopback`, `ContainerBindNotResolved` | -| `TrustedProxyReady` | Required for `reverse-proxy` and `managed` | Auth mode is `trusted-proxy`, `trustedProxy.userHeader` is non-empty, and `gateway.trustedProxies` contains at least one address/CIDR. Loopback is valid for a same-host proxy. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing` | +| `TrustedProxyReady` | Required for `reverse-proxy` | Auth mode is `trusted-proxy`, `trustedProxy.userHeader` is non-empty, and `gateway.trustedProxies` contains at least one address/CIDR. Loopback is valid for a same-host proxy. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing` | | `NodePairingReady` | Required for `node-mode` | The pairing store is readable and contains at least one approved pairing. | `NodePairingUnavailable`, `NodePairingPending`, `NodePairingMissing` | | `ControlledTargetsReady` | Required for `node-mode` | The live Gateway node registry contains at least one connected node whose id is approved in the pairing store. Persisted pairing alone is insufficient. | `ControlledTargetsDisconnected` | | `CommandApprovalReady` | Required for `node-mode` | A connected paired node advertises at least one command that is granted by pairing or `gateway.nodes.allowCommands` and not removed by `gateway.nodes.denyCommands`. A deny-only list is not approval evidence. | `CommandApprovalMissing` | @@ -251,6 +256,11 @@ checks are not duplicated as profile conditions. `advisories` is the set of non-`True` advisory profile reasons. `message` is for operators and should remain non-normative. +The top-level fields above are the one canonical public result. Implementations +should not serialize a second nested copy of the profile readiness object; +health and status should project the same result rather than create another +consumer choice or source of drift. + ### Compatibility and operational cost No explicit selection is required. Existing installations resolve to `local`, @@ -307,6 +317,13 @@ Built-in profile names, `openclaw.*` criterion names, and built-in condition names remain reserved. Operators configure the underlying OpenClaw settings; they do not redefine built-in profile semantics. +`node-mode` requires at least one approved, connected, controllable target. It +does not prove that every target desired by OCC or a host platform is present; +desired fleet cardinality remains a control-plane concern. Pairing snapshots +used by frequent readiness probes should be briefly cached or event-driven, +while live node sessions and current command policy are evaluated on each +observation. + Condition identity and requirement class are part of the support contract. Changing an advisory condition to required, adding a new required condition to an existing profile, or changing a stable reason can alter host behavior and @@ -348,9 +365,9 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | -| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`f11b19d553`) | -| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`87cf11e944`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`22bdbbd3c8`) | +| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`cefbe89976`) | +| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`00fef7fde8`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`c034dc4311`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the three @@ -359,7 +376,9 @@ branches: - PR 17 proves an unset profile defaults to `local`, `/readyz` returns 200, and required/advisory aggregation is stable. - PR 18 proves a LAN-bound `container` profile returns 200 and a loopback-bound - `container` profile returns 503 with `ContainerGatewayLoopback`. + `container` profile returns 503 with `ContainerGatewayLoopback`. It also + proves a configured trusted-proxy posture returns 200 for `reverse-proxy` + while token auth returns 503 with `TrustedProxyAuthMissing`. - PR 19 starts a real node host and proves `node-mode` transitions from 503 to 200 only after approved pairing, a correlated live target, an advertised approved command, and a connected control channel are all observed. @@ -371,7 +390,7 @@ contract. This first stack proves the core ready/result shape, explicit profile selection, built-in profile composition from reusable criteria, exact built-in -container/reverse-proxy/managed predicates, and node-mode rules backed by the +container/reverse-proxy predicates, and node-mode rules backed by the live node registry. ### Incremental adoption @@ -380,8 +399,8 @@ The proposal does not require one all-or-nothing implementation landing: 1. Land the condition shape and default `local` projection into existing readiness, health, and status surfaces. -2. Add explicit selection plus `container`, `reverse-proxy`, and `managed` - predicates over effective runtime facts. +2. Add explicit selection plus `container` and `reverse-proxy` predicates over + effective runtime facts. 3. Add `node-mode` using pairing and live node-registry evidence. The first slice is independently useful because it creates one canonical, From 8651f8d1e23193921c78183a23c9cf3a50598921 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 08:02:16 -0700 Subject: [PATCH 17/98] Add release conformance implementation slice --- .../0010-standard-hosting-profiles-and-ready-check.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 48831469..74d749df 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -368,10 +368,12 @@ fork before upstream OpenClaw PRs are opened: | Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`cefbe89976`) | | Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`00fef7fde8`) | | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`c034dc4311`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`d2047d8f21`) | The stack includes one package-installed Docker conformance lane, -`pnpm test:docker:hosting-profiles`, built incrementally across the three -branches: +`pnpm test:docker:hosting-profiles`, built incrementally across the runtime +branches and promoted into blocking package-acceptance release checks by the +fourth branch: - PR 17 proves an unset profile defaults to `local`, `/readyz` returns 200, and required/advisory aggregation is stable. @@ -382,6 +384,8 @@ branches: - PR 19 starts a real node host and proves `node-mode` transitions from 503 to 200 only after approved pairing, a correlated live target, an advertised approved command, and a connected control channel are all observed. +- PR 21 selects that packaged profile matrix in the non-advisory release + workflow, preserving its targeted plan, log, timing, and summary artifacts. The lane is the reproducible behavior proof for upstream review. A brokered Linux/Crabbox execution should be attached before the implementation PRs are @@ -402,6 +406,7 @@ The proposal does not require one all-or-nothing implementation landing: 2. Add explicit selection plus `container` and `reverse-proxy` predicates over effective runtime facts. 3. Add `node-mode` using pairing and live node-registry evidence. +4. Make the packaged profile matrix a blocking package-acceptance release gate. The first slice is independently useful because it creates one canonical, explainable result without introducing non-local hosting behavior. If the @@ -443,7 +448,5 @@ stable readiness conditions. weakening the meaning of required profile conformance? - Should later plugin or driver hooks publish namespaced criteria evidence, and what identity, scoping, freshness, and trust boundary should that require? -- Should future profile conformance live in QA Lab, maturity scorecards, Docker - E2E, or a dedicated profile conformance runner? - Which stable telemetry event names should accompany readiness transitions in a follow-up PR? From 5a496d229b9e4c8e2806306b692a78d4b130c976 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 08:16:51 -0700 Subject: [PATCH 18/98] Record release conformance review --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 74d749df..00100426 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -387,6 +387,12 @@ fourth branch: - PR 21 selects that packaged profile matrix in the non-advisory release workflow, preserving its targeted plan, log, timing, and summary artifacts. +PR 21 validation confirms the release workflow selects `hosting-profiles`, the +Docker planner resolves the lane with both package and functional-image +requirements, and the existing 33 planner assertions remain green. Formatting, +diff checks, and a full branch Codex review against PR 19 also passed with no +actionable findings. + The lane is the reproducible behavior proof for upstream review. A brokered Linux/Crabbox execution should be attached before the implementation PRs are promoted upstream; the draft branches do not depend on Crabbox to define the From 58b279f1f589560d7bda819832b74419ef14f4f1 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 08:50:45 -0700 Subject: [PATCH 19/98] Define hosting readiness schemas --- ...andard-hosting-profiles-and-ready-check.md | 124 ++++++++++++++++-- 1 file changed, 116 insertions(+), 8 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 00100426..bb88d936 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -202,6 +202,26 @@ Profile selection should be visible in normal hosting mechanisms: - environment: `OPENCLAW_HOSTING_PROFILE` - startup: `openclaw gateway run --hosting-profile ` +The v1 config schema is intentionally closed: + +```ts +type HostingProfileId = "local" | "container" | "reverse-proxy" | "node-mode"; + +type HostingConfig = { + profile?: HostingProfileId; +}; + +type OpenClawConfig = { + hosting?: HostingConfig; + // Existing OpenClaw fields remain unchanged. +}; +``` + +`hosting` is a strict object and `profile` is its only v1 field. Unknown fields +and profile ids fail normal config validation. The environment variable and +startup flag accept the same closed profile-id set. The `local` default is +resolved at runtime and does not need to be persisted into `openclaw.json`. + Selection precedence is deterministic: ```text @@ -223,6 +243,41 @@ ergonomic surface, but it is not required for the first contract. Readiness should use Kubernetes-style conditions: +```ts +type HostingReadinessConditionType = + | "ProfileSelected" + | "ConfigLoaded" + | "GatewayResponding" + | "PluginsLoaded" + | "ContainerStateReady" + | "TrustedProxyReady" + | "NodePairingReady" + | "ControlledTargetsReady" + | "CommandApprovalReady" + | "ControlChannelReady"; + +type HostingReadinessCondition = { + type: HostingReadinessConditionType; + status: "True" | "False" | "Unknown"; + requirement: "required" | "advisory"; + reason: string; + message: string; +}; + +type HostingReadinessResult = { + profile: HostingProfileId; + ready: boolean; + conditions: HostingReadinessCondition[]; + failures: string[]; + advisories: string[]; +}; +``` + +Every field in `HostingReadinessResult` is required whenever the result is +present; empty `conditions`, `failures`, or `advisories` are serialized as empty +arrays rather than omitted. Built-in condition types and the stable reasons in +the truth-predicate table are reserved by OpenClaw. + ```jsonc { "profile": "container", @@ -256,10 +311,58 @@ checks are not duplicated as profile conditions. `advisories` is the set of non-`True` advisory profile reasons. `message` is for operators and should remain non-normative. -The top-level fields above are the one canonical public result. Implementations -should not serialize a second nested copy of the profile readiness object; -health and status should project the same result rather than create another -consumer choice or source of drift. +`conditions` has map semantics keyed by `type`; a built-in result contains at +most one condition of each type, and consumers must not depend on array order. +`failures` and `advisories` have deduplicated set semantics, and their order is +not contractual. Condition and reason identity is stable; `message` wording is +not. + +The object above is the one canonical public result. Transports may embed or +flatten that object exactly once, but implementations must not serialize a +second nested copy that gives consumers another contract or source of drift. + +### Transport projections + +The existing HTTP readiness envelope remains backward compatible: + +```ts +type DetailedGatewayReadyResponse = HostingReadinessResult & { + // Existing Gateway readiness fields. + ready: boolean; + failing: string[]; + suppressed?: string[]; + uptimeMs: number; + eventLoop?: GatewayEventLoopHealth; +}; +``` + +For local or authenticated detailed `GET /ready` and `GET /readyz` requests, +the canonical hosting fields are flattened once into this existing Gateway +envelope. `ready` is the conjunction of Gateway lifecycle readiness and all +required profile conditions. `failing` remains the legacy Gateway-oriented +list; `failures` is the canonical deduplicated union described above. HTTP is +`200` when `ready` is true and `503` otherwise. `HEAD` returns the same status +without a body. Unauthenticated remote probes retain the redacted shape +`{ "ready": boolean }` and do not disclose condition details. + +Gateway health and `status --json` embed the canonical object once: + +```ts +type HealthReadinessProjection = { + readiness?: HostingReadinessResult; +}; + +type StatusReadinessProjection = { + readiness: HostingReadinessResult; +}; +``` + +The optional health field preserves existing observation-depth and +compatibility behavior. A surface that cannot authoritatively observe required +runtime evidence must omit the result or report the affected condition as +`Unknown`; it must never invent a positive observation. When `readiness` is +present, all five canonical fields are required. Text status is a human summary +of this object and is not a separate machine-readable schema. ### Compatibility and operational cost @@ -366,9 +469,9 @@ fork before upstream OpenClaw PRs are opened: | Slice | Fork PR | Branch | | --- | --- | --- | | Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`cefbe89976`) | -| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`00fef7fde8`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`c034dc4311`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`d2047d8f21`) | +| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`c423b77720`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`0dc6c7184f`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`504310c0b9`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime @@ -380,7 +483,8 @@ fourth branch: - PR 18 proves a LAN-bound `container` profile returns 200 and a loopback-bound `container` profile returns 503 with `ContainerGatewayLoopback`. It also proves a configured trusted-proxy posture returns 200 for `reverse-proxy` - while token auth returns 503 with `TrustedProxyAuthMissing`. + while token auth returns 503 with `TrustedProxyAuthMissing`, and projects the + canonical result into Gateway health without a duplicate nested payload. - PR 19 starts a real node host and proves `node-mode` transitions from 503 to 200 only after approved pairing, a correlated live target, an advertised approved command, and a connected control channel are all observed. @@ -393,6 +497,10 @@ requirements, and the existing 33 planner assertions remain green. Formatting, diff checks, and a full branch Codex review against PR 19 also passed with no actionable findings. +After the schema/projection audit, the final composed branch passed 193 focused +profile, config-schema, Gateway-health, status, and node assertions, plus the +release-workflow assertion and all 33 Docker planner assertions. + The lane is the reproducible behavior proof for upstream review. A brokered Linux/Crabbox execution should be attached before the implementation PRs are promoted upstream; the draft branches do not depend on Crabbox to define the From 52df01a2db463e2c3309aeba002a763130ce38d4 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 08:56:56 -0700 Subject: [PATCH 20/98] Document readiness error envelope --- ...andard-hosting-profiles-and-ready-check.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index bb88d936..7ef041d3 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -334,6 +334,21 @@ type DetailedGatewayReadyResponse = HostingReadinessResult & { uptimeMs: number; eventLoop?: GatewayEventLoopHealth; }; + +type ReadinessEvaluationErrorResponse = { + ready: false; + failing: ["internal"]; + uptimeMs: 0; +}; + +type RedactedRemoteReadyResponse = { + ready: boolean; +}; + +type GatewayReadyHttpBody = + | DetailedGatewayReadyResponse + | ReadinessEvaluationErrorResponse + | RedactedRemoteReadyResponse; ``` For local or authenticated detailed `GET /ready` and `GET /readyz` requests, @@ -345,6 +360,12 @@ list; `failures` is the canonical deduplicated union described above. HTTP is without a body. Unauthenticated remote probes retain the redacted shape `{ "ready": boolean }` and do not disclose condition details. +If readiness evaluation itself throws before it can produce the canonical +object, the existing detailed fail-closed response is +`{ "ready": false, "failing": ["internal"], "uptimeMs": 0 }`; an +unauthenticated remote caller still receives only `{ "ready": false }`. This +exception envelope is not a second readiness model and must never report ready. + Gateway health and `status --json` embed the canonical object once: ```ts From a34f08f97bd293a46fa003fd1533fc0d23b407f6 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 09:22:14 -0700 Subject: [PATCH 21/98] Document existing readiness demand --- ...andard-hosting-profiles-and-ready-check.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 7ef041d3..f9611299 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -60,6 +60,28 @@ of debugging an unbounded hosted configuration, maintainers can ask for the selected profile and its stable condition result. Profiles complement maturity work by turning a support claim into executable release evidence. +### Evidence From Existing Issues + +The proposal generalizes recurring operator failures already reported against +OpenClaw. The issues ask for truthful readiness under additional runtime facts; +they do not require each fact to introduce a new hosting profile. + +| Issue | Observed gap | Contract implication | +| --- | --- | --- | +| [openclaw#96084](https://github.com/openclaw/openclaw/issues/96084) | `/readyz` remains healthy when a PVC-backed workspace is full and writes fail with `ENOSPC`. | Workspace writability should be an observable status fact with a stable readiness condition. | +| [openclaw#78136](https://github.com/openclaw/openclaw/issues/78136) | Docker health and readiness remain healthy while the command queue is draining and rejects model work. | Admission/drain state must participate in required readiness, not only process liveness. | +| [openclaw#73652](https://github.com/openclaw/openclaw/issues/73652) | The Gateway accepts connections before internal startup is ready. | Readiness must represent the actual startup admission boundary. | +| [openclaw#78954](https://github.com/openclaw/openclaw/issues/78954) | Channel/plugin sidecars can block reaching a usable core Gateway state. | Conditions need required versus advisory classification. | +| [openclaw#43886](https://github.com/openclaw/openclaw/issues/43886) | A Docker Gateway configured for LAN still listens on loopback. | Container readiness must evaluate effective bind state rather than configured intent alone. | + +Other reports show the same need at additional projections: systemd can declare +the service started before Gateway readiness +([openclaw#66512](https://github.com/openclaw/openclaw/issues/66512)), and a +channel can report healthy while retrying a fatal login error +([openclaw#101083](https://github.com/openclaw/openclaw/issues/101083)). One +canonical condition result lets HTTP probes, status, service managers, and +future telemetry consume the same runtime truth. + ## Goals - Define built-in hosting profiles for `local`, `container`, `reverse-proxy`, @@ -107,6 +129,18 @@ prefer: 2. A canonical ready check: a host-facing pass/fail surface for the selected profile. +These pieces compose but are separable. The canonical condition/result model +is useful without adding any non-default profile. A generally required runtime +invariant, such as accepting work rather than draining, can extend existing +Gateway readiness. A new OpenClaw-owned fact, such as workspace writability, +can add a criterion to the existing `local` contract inherited by the hosted +profiles. Neither change requires defining a new profile. + +A new profile is justified only when OpenClaw wants to name and release-test a +distinct support posture that selects a different composition or requirement +class for existing criteria. Profiles organize readiness criteria into support +contracts; they are not the extension mechanism for every readiness fix. + OpenClaw should expose a standard hostee contract: ```text From 93492107b3cd4ef18b3b82c8f7b135933139831f Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 10:15:57 -0700 Subject: [PATCH 22/98] Add workspace readiness criterion --- ...andard-hosting-profiles-and-ready-check.md | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index f9611299..4240b398 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -150,7 +150,7 @@ profile selection -> ready/not-ready result ``` -Four constraints keep this narrow: +Five constraints keep this narrow: 1. A profile does not write, merge, or repair configuration. 2. Operators may continue to configure every OpenClaw setting directly. @@ -187,7 +187,7 @@ OpenClaw-owned evaluator that emits the runtime readiness condition. | Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | | --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.gateway-responding`, `openclaw.plugins-loaded` | config load, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `GatewayResponding`. Advisory: `PluginsLoaded`. | +| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.workspace-writable`, `openclaw.gateway-responding`, `openclaw.plugins-loaded` | config load, effective default workspace write evidence, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `WorkspaceWritable`, `GatewayResponding`. Advisory: `PluginsLoaded`. | | `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `openclaw.container-state-ready` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | | `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | | `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + node-mode `openclaw.*` criteria | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`. | @@ -216,6 +216,7 @@ readiness result. | --- | --- | --- | --- | | `ProfileSelected` | Required | The runtime resolved and reports the selected built-in profile. The default is `local`. | None; invalid explicit values fail selection before startup. | | `ConfigLoaded` | Required | Runtime configuration loaded successfully. | `ConfigNotLoaded` | +| `WorkspaceWritable` | Required for all built-in profiles | The running Gateway resolves the effective default-agent workspace and completes a write, flush, and cleanup probe. The probe is cached and coalesced so readiness polling does not cause unbounded filesystem work. Non-probing command fallbacks do not invent positive evidence. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | | `ContainerStateReady` | Required for `container` | The effective Gateway mode is `local` and the resolved listener host is not loopback. The port has already passed normal config validation. Config-only status reports `Unknown` when an `auto` bind has not been resolved. | `ContainerGatewayRemote`, `ContainerGatewayLoopback`, `ContainerBindNotResolved` | @@ -281,6 +282,7 @@ Readiness should use Kubernetes-style conditions: type HostingReadinessConditionType = | "ProfileSelected" | "ConfigLoaded" + | "WorkspaceWritable" | "GatewayResponding" | "PluginsLoaded" | "ContainerStateReady" @@ -526,12 +528,13 @@ fork before upstream OpenClaw PRs are opened: | Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`cefbe89976`) | | Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`c423b77720`) | | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`0dc6c7184f`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`504310c0b9`) | +| Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5678370063`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`a9f29c0b94`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime branches and promoted into blocking package-acceptance release checks by the -fourth branch: +fifth branch: - PR 17 proves an unset profile defaults to `local`, `/readyz` returns 200, and required/advisory aggregation is stable. @@ -543,18 +546,30 @@ fourth branch: - PR 19 starts a real node host and proves `node-mode` transitions from 503 to 200 only after approved pairing, a correlated live target, an advertised approved command, and a connected control channel are all observed. +- PR 22 adds `WorkspaceWritable` to every built-in profile without defining a + new profile or changing the HTTP probe implementation. Its Docker scenario + fills a workspace `tmpfs` to `ENOSPC`, expects 503 with + `WorkspaceStorageFull`, removes the fill file, and expects recovery to 200 + without restarting OpenClaw. - PR 21 selects that packaged profile matrix in the non-advisory release workflow, preserving its targeted plan, log, timing, and summary artifacts. PR 21 validation confirms the release workflow selects `hosting-profiles`, the Docker planner resolves the lane with both package and functional-image requirements, and the existing 33 planner assertions remain green. Formatting, -diff checks, and a full branch Codex review against PR 19 also passed with no +diff checks, and a full branch Codex review against PR 22 also passed with no actionable findings. -After the schema/projection audit, the final composed branch passed 193 focused -profile, config-schema, Gateway-health, status, and node assertions, plus the -release-workflow assertion and all 33 Docker planner assertions. +The workspace-readiness composed branch passed 188 focused profile, +Gateway-probe, health-state, status, node, and workspace assertions. PR 21's +changed release-workflow assertion and all 33 Docker planner assertions also +pass. The full package-acceptance test file retains five unrelated Windows +executable-bit/shell fixture failures and 77 passing assertions. + +Actual execution of the new workspace `tmpfs` failure/recovery scenario remains +pending because Docker Desktop was unavailable on the authoring host. The +scenario, package-installed lane, and deterministic plan are implemented, but +the draft stack does not claim a local or brokered runtime pass yet. The lane is the reproducible behavior proof for upstream review. A brokered Linux/Crabbox execution should be attached before the implementation PRs are @@ -575,7 +590,10 @@ The proposal does not require one all-or-nothing implementation landing: 2. Add explicit selection plus `container` and `reverse-proxy` predicates over effective runtime facts. 3. Add `node-mode` using pairing and live node-registry evidence. -4. Make the packaged profile matrix a blocking package-acceptance release gate. +4. Add a generally applicable workspace-writability criterion to every + existing profile, proving that criteria can extend readiness without adding + a profile. +5. Make the packaged profile matrix a blocking package-acceptance release gate. The first slice is independently useful because it creates one canonical, explainable result without introducing non-local hosting behavior. If the From bb6d95dcb08e439769497cd5b64e6c552259df6e Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 12:38:35 -0700 Subject: [PATCH 23/98] Document extensible hosting readiness criteria --- ...andard-hosting-profiles-and-ready-check.md | 152 ++++++++++++------ 1 file changed, 105 insertions(+), 47 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 4240b398..aacf2112 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -99,8 +99,9 @@ future telemetry consume the same runtime truth. plugins. - Define the requirement class, exact truth predicates, and stable non-ready reasons for every built-in profile condition. -- Reserve namespaced plugin or driver readiness conditions for a later contract - that defines trusted runtime evidence publication. +- Let plugins register namespaced advisory criteria through the existing plugin + lifecycle, and let operators promote them only through additive custom + profiles. - Leave room for later doctor/lint conformance findings that recommend fixes for config that does not match the selected built-in profile. @@ -156,8 +157,9 @@ Five constraints keep this narrow: 2. Operators may continue to configure every OpenClaw setting directly. 3. Profile readiness is an additional conjunction with existing Gateway readiness, never a replacement for it. -4. The first contract evaluates only facts owned by OpenClaw core. Optional - plugins, policy, and doctor may consume the result but are not dependencies. +4. Built-in profiles evaluate facts owned by OpenClaw core. Plugins may publish + advisory namespaced criteria; only an operator-defined profile can make one + required. Policy and doctor may consume the result but are not dependencies. 5. Only required conditions affect the binary ready result. Advisory conditions remain visible without turning a useful diagnostic into an outage. @@ -166,7 +168,8 @@ continues to own Gateway, proxy, plugin, model, session, node, and state behavior. A hosting profile decides which existing runtime status/config facts must be true before the instance is considered ready. If a criterion needs a fact that status does not expose yet, the implementation should add that -missing status field rather than introduce a parallel readiness evidence path. +missing status field. Plugin-owned dependencies use the readiness registration +contract below rather than a host-specific endpoint or global evidence store. ### Built-in profiles @@ -181,16 +184,16 @@ technology. A Gateway directly reachable through its container listener uses distinct OpenClaw-owned invariant and conformance scenario. Profiles should be declarative compositions of reusable readiness criteria. A -built-in profile references OpenClaw-owned `openclaw.*` criteria. Each criterion +built-in profile references reserved OpenClaw condition ids. Each criterion is a named rule over OpenClaw runtime status/config fields and has one OpenClaw-owned evaluator that emits the runtime readiness condition. | Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | | --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `openclaw.config-loaded`, `openclaw.workspace-writable`, `openclaw.gateway-responding`, `openclaw.plugins-loaded` | config load, effective default workspace write evidence, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `WorkspaceWritable`, `GatewayResponding`. Advisory: `PluginsLoaded`. | -| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `openclaw.container-state-ready` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | -| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `openclaw.trusted-proxy-ready` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | -| `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + node-mode `openclaw.*` criteria | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady`. | +| `local` | Developer/local foreground process readiness. | `ConfigLoaded`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded` | config load, effective default workspace write evidence, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `WorkspaceWritable`, `GatewayResponding`. Advisory: `PluginsLoaded`. | +| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `ContainerStateReady` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | +| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `TrustedProxyReady` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | +| `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady` | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus the four node-mode conditions. | `node-mode` must stay product-neutral. A controlled target can be a desktop, sandbox, VM, pod, browser, or another execution surface. OpenClaw should not @@ -214,7 +217,7 @@ readiness result. | Condition | Requirement | True when | Stable non-ready reasons | | --- | --- | --- | --- | -| `ProfileSelected` | Required | The runtime resolved and reports the selected built-in profile. The default is `local`. | None; invalid explicit values fail selection before startup. | +| `ProfileSelected` | Required | The runtime resolved and reports the selected built-in or configured custom profile. The default is `local`. | None; invalid explicit values fail selection before startup. | | `ConfigLoaded` | Required | Runtime configuration loaded successfully. | `ConfigNotLoaded` | | `WorkspaceWritable` | Required for all built-in profiles | The running Gateway resolves the effective default-agent workspace and completes a write, flush, and cleanup probe. The probe is cached and coalesced so readiness polling does not cause unbounded filesystem work. Non-probing command fallbacks do not invent positive evidence. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | @@ -237,13 +240,24 @@ Profile selection should be visible in normal hosting mechanisms: - environment: `OPENCLAW_HOSTING_PROFILE` - startup: `openclaw gateway run --hosting-profile ` -The v1 config schema is intentionally closed: +Built-in ids are closed, while operator profiles are additive and namespaced: ```ts -type HostingProfileId = "local" | "container" | "reverse-proxy" | "node-mode"; +type BuiltInHostingProfileId = + | "local" + | "container" + | "reverse-proxy" + | "node-mode"; + +type OperatorHostingProfile = { + extends: BuiltInHostingProfileId; + requiredCriteria?: string[]; + advisoryCriteria?: string[]; +}; type HostingConfig = { - profile?: HostingProfileId; + profile?: string; + profiles?: Record; }; type OpenClawConfig = { @@ -252,10 +266,16 @@ type OpenClawConfig = { }; ``` -`hosting` is a strict object and `profile` is its only v1 field. Unknown fields -and profile ids fail normal config validation. The environment variable and -startup flag accept the same closed profile-id set. The `local` default is -resolved at runtime and does not need to be persisted into `openclaw.json`. +`hosting` and each profile definition are strict objects. Operator profile names +must match `/` using lowercase alphanumeric DNS-label-like +segments. A selected custom profile must exist in `hosting.profiles`. Each +custom profile extends exactly one built-in profile and can only add criteria; +it cannot remove or demote inherited requirements. A criterion cannot be both +required and advisory in the same profile. + +The environment variable and startup flag accept built-in ids or a namespaced +custom id. Runtime resolution validates a custom id against the loaded config. +The `local` default is resolved at runtime and does not need to be persisted. Selection precedence is deterministic: @@ -279,7 +299,7 @@ ergonomic surface, but it is not required for the first contract. Readiness should use Kubernetes-style conditions: ```ts -type HostingReadinessConditionType = +type BuiltInHostingReadinessCriterionId = | "ProfileSelected" | "ConfigLoaded" | "WorkspaceWritable" @@ -292,6 +312,10 @@ type HostingReadinessConditionType = | "CommandApprovalReady" | "ControlChannelReady"; +type HostingReadinessConditionType = + | BuiltInHostingReadinessCriterionId + | (string & {}); + type HostingReadinessCondition = { type: HostingReadinessConditionType; status: "True" | "False" | "Unknown"; @@ -301,7 +325,7 @@ type HostingReadinessCondition = { }; type HostingReadinessResult = { - profile: HostingProfileId; + profile: string; ready: boolean; conditions: HostingReadinessCondition[]; failures: string[]; @@ -312,7 +336,8 @@ type HostingReadinessResult = { Every field in `HostingReadinessResult` is required whenever the result is present; empty `conditions`, `failures`, or `advisories` are serialized as empty arrays rather than omitted. Built-in condition types and the stable reasons in -the truth-predicate table are reserved by OpenClaw. +the truth-predicate table are reserved by OpenClaw. Plugin criteria are +namespaced by core as `plugin..`. ```jsonc { @@ -460,22 +485,50 @@ Keeping the predicates in core also makes the support promise testable in the OpenClaw release matrix. Downstream hosts remain responsible for tenant routing, deployment, storage destinations, telemetry backends, and product policy. -### Future extensibility +### Extensible criteria and operator profiles + +Built-in profile conditions remain stable and OpenClaw-owned. Operators cannot +redefine what `local`, `container`, or `node-mode` means. They can define a +namespaced profile that extends one built-in profile and adds reusable built-in +or plugin criteria. + +Plugins register observed-state producers during normal activation: + +```ts +type PluginReadinessResult = { + status: "True" | "False" | "Unknown"; + reason: string; + message: string; +}; + +api.registerReadinessCriterion({ + id: "backend", + check: async ({ config, pluginConfig, signal }) => { + // Return PluginReadinessResult. + }, +}); +``` + +Core owns namespacing, lifecycle, timeout, caching, coalescing, invalid-result, +error, and missing-registration behavior. Registrations live in the existing +Gateway-pinned plugin registry, so plugin load rollback and reload replace the +criterion with the rest of that registry. There is no process-global hosting +registry and no downstream-specific publication path. -The first contract should keep built-in profile conditions stable and -OpenClaw-owned. Operators should not be able to redefine what `local`, -`container`, or `node-mode` means. +Every plugin criterion is advisory by default. A plugin cannot choose its +requirement class. An operator promotes a criterion by listing its full id in a +custom profile's `requiredCriteria`. A required criterion that is absent, +times out, throws, or reports `False` or `Unknown` blocks readiness. An absent +selected criterion emits `Unknown` with `CriterionUnavailable`. Plugin failures +use generic messages so readiness does not expose thrown error details. -This first RFC does not add custom profile or criterion config. A declaration -without a trusted observed-state producer can never become ready and would be a -sticky but unusable public contract. A later RFC may add namespaced criteria -after it defines who may publish evidence, how evidence is scoped and expired, -how plugins or drivers are authenticated, and how status and readiness consume -the same fact without creating a parallel evidence model. +The initial implementation evaluates registered checks concurrently, supplies +an `AbortSignal`, uses a one-second deadline, and caches/coalesces each result +for five seconds. These mechanics are core-owned rather than profile-authored +numeric values. -Built-in profile names, `openclaw.*` criterion names, and built-in condition -names remain reserved. Operators configure the underlying OpenClaw settings; -they do not redefine built-in profile semantics. +Built-in profile names and condition names remain reserved. Operators configure +the underlying OpenClaw settings; they do not redefine built-in semantics. `node-mode` requires at least one approved, connected, controllable target. It does not prove that every target desired by OCC or a host platform is present; @@ -529,12 +582,13 @@ fork before upstream OpenClaw PRs are opened: | Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`c423b77720`) | | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`0dc6c7184f`) | | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5678370063`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`a9f29c0b94`) | +| Extensible readiness criteria | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`ead9dc570e`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`f10436a3bc`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime branches and promoted into blocking package-acceptance release checks by the -fifth branch: +sixth branch: - PR 17 proves an unset profile defaults to `local`, `/readyz` returns 200, and required/advisory aggregation is stable. @@ -551,20 +605,23 @@ fifth branch: fills a workspace `tmpfs` to `ENOSPC`, expects 503 with `WorkspaceStorageFull`, removes the fill file, and expects recovery to 200 without restarting OpenClaw. +- PR 23 adds activation-scoped plugin criterion registration and additive + operator profiles while preserving built-in requirements and canonical + `/ready` projection. - PR 21 selects that packaged profile matrix in the non-advisory release workflow, preserving its targeted plan, log, timing, and summary artifacts. PR 21 validation confirms the release workflow selects `hosting-profiles`, the Docker planner resolves the lane with both package and functional-image -requirements, and the existing 33 planner assertions remain green. Formatting, -diff checks, and a full branch Codex review against PR 22 also passed with no -actionable findings. +requirements, and the existing 33 planner assertions remain green. PR 23 +passes 88 focused plugin, config, CLI, and readiness assertions; its final +exact-commit Codex review reports no actionable findings. The workspace-readiness composed branch passed 188 focused profile, Gateway-probe, health-state, status, node, and workspace assertions. PR 21's changed release-workflow assertion and all 33 Docker planner assertions also pass. The full package-acceptance test file retains five unrelated Windows -executable-bit/shell fixture failures and 77 passing assertions. +Telegram shell/executable-bit fixture failures and 44 passing assertions. Actual execution of the new workspace `tmpfs` failure/recovery scenario remains pending because Docker Desktop was unavailable on the authoring host. The @@ -593,7 +650,9 @@ The proposal does not require one all-or-nothing implementation landing: 4. Add a generally applicable workspace-writability criterion to every existing profile, proving that criteria can extend readiness without adding a profile. -5. Make the packaged profile matrix a blocking package-acceptance release gate. +5. Add plugin criterion registration and additive operator profiles over the + same canonical result. +6. Make the packaged profile matrix a blocking package-acceptance release gate. The first slice is independently useful because it creates one canonical, explainable result without introducing non-local hosting behavior. If the @@ -616,10 +675,9 @@ hosted-deployment claim, OpenClaw can say which profiles are supported, which conditions are stable, and which release tests prove them. This is intentionally less powerful than a general profile or policy engine. -Its value comes from OpenClaw owning a small number of definitions and testing -them release after release. A host-specific profile language would move the -support boundary back downstream and recreate the ambiguity this RFC is meant -to remove. +Its value comes from OpenClaw owning a small number of built-in definitions and +testing them release after release. Operator profiles are constrained to +additive composition; they cannot rewrite the support boundary downstream. The ready check is intentionally smaller than the profile model. Container hosters can use it directly as their readiness probe, while hosts that already @@ -633,7 +691,7 @@ stable readiness conditions. release? - Which additional advisory conditions would improve supportability without weakening the meaning of required profile conformance? -- Should later plugin or driver hooks publish namespaced criteria evidence, and - what identity, scoping, freshness, and trust boundary should that require? +- Should non-plugin runtime drivers need a separate criterion registration + surface, or is activation-scoped plugin registration sufficient? - Which stable telemetry event names should accompany readiness transitions in a follow-up PR? From 34181745803fd4365f545abf670d3df59d79f44d Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 13:00:13 -0700 Subject: [PATCH 24/98] Refresh hosting readiness stack evidence --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index aacf2112..37a76047 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -582,8 +582,8 @@ fork before upstream OpenClaw PRs are opened: | Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`c423b77720`) | | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`0dc6c7184f`) | | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5678370063`) | -| Extensible readiness criteria | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`ead9dc570e`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`f10436a3bc`) | +| Extensible readiness criteria | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`990ab4808c`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`8aa1abbcf9`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime @@ -614,8 +614,9 @@ sixth branch: PR 21 validation confirms the release workflow selects `hosting-profiles`, the Docker planner resolves the lane with both package and functional-image requirements, and the existing 33 planner assertions remain green. PR 23 -passes 88 focused plugin, config, CLI, and readiness assertions; its final -exact-commit Codex review reports no actionable findings. +passes 99 focused plugin, config, CLI, status-contract, and readiness +assertions. The full-facility exact-commit Codex review reports no actionable +findings; two review attempts for the small CI-closeout commit timed out. The workspace-readiness composed branch passed 188 focused profile, Gateway-probe, health-state, status, node, and workspace assertions. PR 21's From 29e88b66e5599d0f0bf968521f611d1291207640 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 13:23:43 -0700 Subject: [PATCH 25/98] Lead hosting RFC with readiness framework --- ...tandard-hosting-profiles-and-ready-check.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 37a76047..0b885398 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -1,5 +1,5 @@ --- -title: Standard Hosting Profiles and Ready Check +title: Readiness Framework and Hosting Profiles authors: - Gio created: 2026-07-09 @@ -9,17 +9,17 @@ issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 --- -# Proposal: Standard Hosting Profiles and Ready Check +# Proposal: Readiness Framework and Hosting Profiles ## Summary -Add a small support contract for running OpenClaw as a workload. A -built-in hosting profile names a validated composition of existing OpenClaw -settings; readiness reports whether the running process satisfies that -composition. This extends the existing Gateway `/ready` and `/readyz` result -and projects the same conditions into `status --json` and Gateway health. It -does not add a second config system, generate config, or replace existing -Gateway readiness. +Add a canonical readiness framework for evaluating reusable runtime criteria +and projecting one result through Gateway `/ready`, `/readyz`, health, and +status. Hosting profiles compose those criteria into named, release-tested +support contracts for running OpenClaw as a workload. The readiness framework +is independently useful without selecting a non-default profile, and profiles +do not add a second config system, generate config, or replace existing Gateway +readiness. ## Motivation From 9b218768199c472a5b4e04c5a714ae0e6d3393d3 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 13:34:19 -0700 Subject: [PATCH 26/98] Clarify readiness provider and profile support contracts --- ...andard-hosting-profiles-and-ready-check.md | 109 ++++++++++++++---- 1 file changed, 85 insertions(+), 24 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 0b885398..40dcca81 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -1,5 +1,5 @@ --- -title: Readiness Framework and Hosting Profiles +title: Readiness Providers and Hosting Profiles authors: - Gio created: 2026-07-09 @@ -9,17 +9,17 @@ issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 --- -# Proposal: Readiness Framework and Hosting Profiles +# Proposal: Readiness Providers and Hosting Profiles ## Summary -Add a canonical readiness framework for evaluating reusable runtime criteria -and projecting one result through Gateway `/ready`, `/readyz`, health, and -status. Hosting profiles compose those criteria into named, release-tested -support contracts for running OpenClaw as a workload. The readiness framework -is independently useful without selecting a non-default profile, and profiles -do not add a second config system, generate config, or replace existing Gateway -readiness. +Add a canonical readiness-provider contract for publishing reusable runtime +criteria and projecting one result through Gateway `/ready`, `/readyz`, health, +and status. Built-in hosting profiles compose those criteria into named, +OpenClaw-owned, release-tested support contracts for running OpenClaw as a +workload. The readiness-provider contract is independently useful without +selecting a non-default profile, and profiles do not add a second config system, +generate config, or replace existing Gateway readiness. ## Motivation @@ -102,6 +102,8 @@ future telemetry consume the same runtime truth. - Let plugins register namespaced advisory criteria through the existing plugin lifecycle, and let operators promote them only through additive custom profiles. +- Make readiness providers enumerable and self-describing so status, operators, + and future doctor tooling can discover the active criterion catalog. - Leave room for later doctor/lint conformance findings that recommend fixes for config that does not match the selected built-in profile. @@ -492,7 +494,8 @@ redefine what `local`, `container`, or `node-mode` means. They can define a namespaced profile that extends one built-in profile and adds reusable built-in or plugin criteria. -Plugins register observed-state producers during normal activation: +Plugins register self-describing observed-state providers during normal +activation: ```ts type PluginReadinessResult = { @@ -501,32 +504,88 @@ type PluginReadinessResult = { message: string; }; +type PluginReadinessProvider = { + id: string; + description: string; + check: (context: { + config: OpenClawConfig; + pluginConfig: unknown; + signal: AbortSignal; + }) => Promise | PluginReadinessResult; +}; + api.registerReadinessCriterion({ id: "backend", + description: "Reports whether the plugin backend can accept work.", check: async ({ config, pluginConfig, signal }) => { // Return PluginReadinessResult. }, }); ``` -Core owns namespacing, lifecycle, timeout, caching, coalescing, invalid-result, -error, and missing-registration behavior. Registrations live in the existing -Gateway-pinned plugin registry, so plugin load rollback and reload replace the -criterion with the rest of that registry. There is no process-global hosting -registry and no downstream-specific publication path. - -Every plugin criterion is advisory by default. A plugin cannot choose its -requirement class. An operator promotes a criterion by listing its full id in a -custom profile's `requiredCriteria`. A required criterion that is absent, -times out, throws, or reports `False` or `Unknown` blocks readiness. An absent -selected criterion emits `Unknown` with `CriterionUnavailable`. Plugin failures -use generic messages so readiness does not expose thrown error details. +The registration is a readiness provider: a lifecycle-owned producer with a +stable identity, owner, description, and bounded evaluator. Core owns +namespacing, lifecycle, enumeration, timeout, caching, coalescing, +invalid-result, error, and missing-registration behavior. Registrations live in +the existing Gateway-pinned plugin registry, so plugin load rollback and reload +replace the provider with the rest of that registry. There is no process-global +hosting registry and no downstream-specific publication path. + +The active provider catalog is enumerable from that pinned registry. Detailed +readiness and status expose each evaluated provider through its canonical +condition type; future doctor or administrative surfaces may list the same +descriptor catalog without inventing another registration mechanism. Provider +identity is the namespaced condition type. Plugin-owned reasons must be stable +within that identity, and messages are non-normative and must not contain +credentials, tokens, personal data, or thrown error details. + +Every active plugin provider is evaluated and reported as advisory by default, +even when the selected profile does not reference it. Installing a plugin may +therefore add advisory conditions, but cannot make an otherwise ready built-in +profile unready. A plugin cannot choose its requirement class. An operator +promotes a criterion by listing its full id in a custom profile's +`requiredCriteria`. A required criterion that is absent, times out, throws, or +reports `False` or `Unknown` blocks readiness. An absent selected criterion +emits `Unknown` with `CriterionUnavailable`. Plugin failures use generic +messages so readiness does not expose thrown error details. The initial implementation evaluates registered checks concurrently, supplies an `AbortSignal`, uses a one-second deadline, and caches/coalesces each result for five seconds. These mechanics are core-owned rather than profile-authored numeric values. +A provider check is an observational probe, not a lifecycle or repair hook. It +must be read-only, idempotent, safe under concurrent and repeated invocation, +avoid blocking synchronous I/O, and honor the supplied `AbortSignal`. It must +not start dependencies, rewrite config, repair state, or emit durable audit +claims. The cache duration bounds how stale a reported observation may be; a +cached result is not historical or audit-grade evidence. + +### Profile inheritance and support ownership + +Every operator profile extends exactly one built-in profile and inherits all of +its required and advisory criteria. It may add requirements, but cannot remove, +replace, or demote the inherited contract. This gives custom hosting models a +known OpenClaw support baseline instead of allowing each operator to redefine +what a healthy Gateway means. + +Support ownership follows the composition: + +- OpenClaw owns, documents, and release-tests each built-in profile and its + inherited criteria. +- An extended profile retains that OpenClaw-tested baseline. A failure in an + inherited criterion can be reproduced against and supported as the built-in + profile it extends. +- The plugin or operator owns added provider semantics and the additional + support promise made by the extended profile. OpenClaw does not certify an + arbitrary downstream composition merely because it inherits a built-in. + +A namespaced profile is therefore still an operator's own profile, but it is +never a from-scratch replacement for core readiness. In v1, requiring +`extends` is intentional: a completely independent profile with no built-in +baseline would weaken the support and compatibility promise this RFC is meant +to create. + Built-in profile names and condition names remain reserved. Operators configure the underlying OpenClaw settings; they do not redefine built-in semantics. @@ -672,8 +731,10 @@ special "hosted OpenClaw" command tree. "Hosted" is a runtime posture and suppor profile, not the primary CLI noun. Built-in profiles make the support promise concrete. Instead of one broad -hosted-deployment claim, OpenClaw can say which profiles are supported, which -conditions are stable, and which release tests prove them. +hosted-deployment claim, OpenClaw can say which built-in profiles it supports, +which conditions are stable, and which release tests prove them. An operator +profile preserves the tested baseline it inherits while clearly identifying +the additional criteria whose support belongs to the operator or plugin owner. This is intentionally less powerful than a general profile or policy engine. Its value comes from OpenClaw owning a small number of built-in definitions and From 033e267d74027a0ab589ea30aa7497356a6c5366 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 13:41:51 -0700 Subject: [PATCH 27/98] Clarify provider registration and standard profiles --- ...andard-hosting-profiles-and-ready-check.md | 52 +++++++++++++------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 40dcca81..75ad7ccc 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -15,7 +15,7 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/33 Add a canonical readiness-provider contract for publishing reusable runtime criteria and projecting one result through Gateway `/ready`, `/readyz`, health, -and status. Built-in hosting profiles compose those criteria into named, +and status. Standard hosting profiles compose those criteria into named, OpenClaw-owned, release-tested support contracts for running OpenClaw as a workload. The readiness-provider contract is independently useful without selecting a non-default profile, and profiles do not add a second config system, @@ -173,11 +173,14 @@ fact that status does not expose yet, the implementation should add that missing status field. Plugin-owned dependencies use the readiness registration contract below rather than a host-specific endpoint or global evidence store. -### Built-in profiles +### Standard profiles -OpenClaw should ship profile definitions rather than ask every host to invent -one. Operators can still configure the underlying OpenClaw settings; the profile -names the support contract. +OpenClaw should ship a small catalog of standard profile definitions rather +than ask every host to invent one. Operators can still configure the underlying +OpenClaw settings; the profile names the support contract. These profiles are +implemented in core, which is why the schema calls their ids "built-in," but +their product role is to be OpenClaw's documented and release-gated standard +profiles. A profile names the expected ingress/runtime posture, not the packaging technology. A Gateway directly reachable through its container listener uses @@ -514,6 +517,10 @@ type PluginReadinessProvider = { }) => Promise | PluginReadinessResult; }; +type RegisterReadinessCriterion = ( + provider: PluginReadinessProvider, +) => void; + api.registerReadinessCriterion({ id: "backend", description: "Reports whether the plugin backend can accept work.", @@ -523,6 +530,19 @@ api.registerReadinessCriterion({ }); ``` +`registerReadinessCriterion` is available to an activated OpenClaw plugin +through its normal `OpenClawPluginApi`. Registration installs the descriptor and +callback into the Gateway-pinned registry for that plugin activation. Core +criteria use internal core evaluators; operators, host config, and OCC do not +register executable callbacks. They only select profiles and reference full +provider ids. + +The `check` member is the provider callback. The Gateway readiness evaluator +invokes it asynchronously with the effective OpenClaw config, that plugin's +resolved config, and an `AbortSignal`. The callback returns one observed +condition result. Core validates and namespaces the result before adding it to +the canonical readiness projection. + The registration is a readiness provider: a lifecycle-owned producer with a stable identity, owner, description, and bounded evaluator. Core owns namespacing, lifecycle, enumeration, timeout, caching, coalescing, @@ -563,15 +583,15 @@ cached result is not historical or audit-grade evidence. ### Profile inheritance and support ownership -Every operator profile extends exactly one built-in profile and inherits all of -its required and advisory criteria. It may add requirements, but cannot remove, +In v1, every operator profile extends exactly one standard profile and inherits +all of its required and advisory criteria. It may add requirements, but cannot remove, replace, or demote the inherited contract. This gives custom hosting models a known OpenClaw support baseline instead of allowing each operator to redefine what a healthy Gateway means. Support ownership follows the composition: -- OpenClaw owns, documents, and release-tests each built-in profile and its +- OpenClaw owns, documents, and release-tests each standard profile and its inherited criteria. - An extended profile retains that OpenClaw-tested baseline. A failure in an inherited criterion can be reproduced against and supported as the built-in @@ -580,11 +600,13 @@ Support ownership follows the composition: support promise made by the extended profile. OpenClaw does not certify an arbitrary downstream composition merely because it inherits a built-in. -A namespaced profile is therefore still an operator's own profile, but it is -never a from-scratch replacement for core readiness. In v1, requiring -`extends` is intentional: a completely independent profile with no built-in -baseline would weaken the support and compatibility promise this RFC is meant -to create. +A namespaced profile is therefore still an operator's own profile. Requiring +`extends` in v1 gives the first implementation a known release-tested baseline. +A later revision may allow an operator profile to compose its own provider set +without extending a standard profile. Such a profile would be operator-owned +and would still be conjoined with universal Gateway lifecycle readiness; custom +composition must never replace or bypass core startup, drain, channel, or +event-loop readiness. Built-in profile names and condition names remain reserved. Operators configure the underlying OpenClaw settings; they do not redefine built-in semantics. @@ -730,8 +752,8 @@ Putting the result into `ready`, `status`, and `health` is preferable to a special "hosted OpenClaw" command tree. "Hosted" is a runtime posture and support profile, not the primary CLI noun. -Built-in profiles make the support promise concrete. Instead of one broad -hosted-deployment claim, OpenClaw can say which built-in profiles it supports, +Standard profiles make the support promise concrete. Instead of one broad +hosted-deployment claim, OpenClaw can say which standard profiles it supports, which conditions are stable, and which release tests prove them. An operator profile preserves the tested baseline it inherits while clearly identifying the additional criteria whose support belongs to the operator or plugin owner. From 8a4dd7257c1abfeaddbad1666d1d325a3f6ebede Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 14:26:16 -0700 Subject: [PATCH 28/98] Clarify existing Gateway readiness baseline --- ...standard-hosting-profiles-and-ready-check.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 75ad7ccc..f68413bf 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -33,6 +33,23 @@ cannot answer one higher-level question before routing traffic: Is this OpenClaw instance ready under the hosting profile it was started with? ``` +Today this readiness surface is a purpose-built, Gateway-owned evaluator over a +fixed set of lifecycle signals. It is not a general readiness framework: +plugins cannot register readiness callbacks, operators cannot enumerate or +compose reusable criteria, and releases do not validate named hosting profiles. +This RFC preserves the existing evaluator as an authoritative required input +and adds a provider and composition contract around it: + +```text +existing fixed Gateway readiness ++ standard-profile conditions ++ plugin-provider conditions +-> canonical /ready and /readyz result +``` + +The proposal does not move existing lifecycle checks into plugins or permit a +profile to weaken, replace, or bypass them. + Without that contract, downstream hosts compensate with private startup checks, baked config, environment restore lists, persistence wrappers, and adapter-only readiness logic. That makes hosted OpenClaw harder to test upstream and harder From 9c78d22a9305b9c32347885ac74d66073be8efd8 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 14:29:11 -0700 Subject: [PATCH 29/98] Normalize existing Gateway readiness as conditions --- ...andard-hosting-profiles-and-ready-check.md | 53 ++++++++++++------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index f68413bf..e73904d0 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -239,6 +239,10 @@ readiness result. | Condition | Requirement | True when | Stable non-ready reasons | | --- | --- | --- | --- | +| `GatewayStartupComplete` | Required | Gateway startup dependencies and startup sidecars are no longer pending. | `GatewayStartupPending` | +| `GatewayAcceptingWork` | Required | The Gateway is not draining and can admit new work. | `GatewayDraining` | +| `ChannelRuntimeReady` | Required | No selected channel has an unsuppressed runtime-health failure under the existing channel readiness policy. | `ChannelRuntimeUnavailable` | +| `EventLoopHealthy` | Advisory | The existing event-loop health observation is within its healthy threshold. It remains advisory unless a separate compatibility-reviewed change intentionally makes it gate readiness. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | | `ProfileSelected` | Required | The runtime resolved and reports the selected built-in or configured custom profile. The default is `local`. | None; invalid explicit values fail selection before startup. | | `ConfigLoaded` | Required | Runtime configuration loaded successfully. | `ConfigNotLoaded` | | `WorkspaceWritable` | Required for all built-in profiles | The running Gateway resolves the effective default-agent workspace and completes a write, flush, and cleanup probe. The probe is cached and coalesced so readiness polling does not cause unbounded filesystem work. Non-probing command fallbacks do not invent positive evidence. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | @@ -321,7 +325,11 @@ ergonomic surface, but it is not required for the first contract. Readiness should use Kubernetes-style conditions: ```ts -type BuiltInHostingReadinessCriterionId = +type CoreReadinessCriterionId = + | "GatewayStartupComplete" + | "GatewayAcceptingWork" + | "ChannelRuntimeReady" + | "EventLoopHealthy" | "ProfileSelected" | "ConfigLoaded" | "WorkspaceWritable" @@ -335,7 +343,7 @@ type BuiltInHostingReadinessCriterionId = | "ControlChannelReady"; type HostingReadinessConditionType = - | BuiltInHostingReadinessCriterionId + | CoreReadinessCriterionId | (string & {}); type HostingReadinessCondition = { @@ -387,12 +395,11 @@ namespaced by core as `plugin..`. ``` Hosts and tests should key on `type`, `status`, `requirement`, and `reason`. -`failures` is the deduplicated union of existing Gateway lifecycle failure -reasons and non-`True` required profile-condition reasons. This preserves -existing channel/startup/drain/event-loop explanations even though those legacy -checks are not duplicated as profile conditions. `advisories` is the set of -non-`True` advisory profile reasons. `message` is for operators and should -remain non-normative. +`failures` is the deduplicated set of non-`True` required-condition reasons. +`advisories` is the set of non-`True` advisory-condition reasons. Existing +Gateway startup, drain, channel, and event-loop observations are projected into +the same canonical condition model rather than remaining a permanent parallel +readiness system. `message` is for operators and should remain non-normative. `conditions` has map semantics keyed by `type`; a built-in result contains at most one condition of each type, and consumers must not depend on array order. @@ -435,13 +442,20 @@ type GatewayReadyHttpBody = ``` For local or authenticated detailed `GET /ready` and `GET /readyz` requests, -the canonical hosting fields are flattened once into this existing Gateway -envelope. `ready` is the conjunction of Gateway lifecycle readiness and all -required profile conditions. `failing` remains the legacy Gateway-oriented -list; `failures` is the canonical deduplicated union described above. HTTP is -`200` when `ready` is true and `503` otherwise. `HEAD` returns the same status -without a body. Unauthenticated remote probes retain the redacted shape -`{ "ready": boolean }` and do not disclose condition details. +the canonical fields are flattened once into this existing Gateway envelope. +`ready` is true only when every required core, profile, and selected provider +condition is `True`. `failing` and `suppressed` remain compatibility projections +of the normalized Gateway lifecycle/channel conditions; new consumers should +use `conditions`, `failures`, and `advisories`. HTTP is `200` when `ready` is +true and `503` otherwise. `HEAD` returns the same status without a body. +Unauthenticated remote probes retain the redacted shape `{ "ready": boolean }` +and do not disclose condition details. + +Normalization must preserve current behavior. Startup-pending, draining, and +unsuppressed channel failures remain required and continue to make readiness +false. Existing event-loop health is initially advisory because the current +evaluator reports it diagnostically without changing `ready`. Changing that +requirement class later requires compatibility review and release coverage. If readiness evaluation itself throws before it can produce the canonical object, the existing detailed fail-closed response is @@ -672,7 +686,9 @@ patches, compaction events, or harness protocol frames. ### Implementation branches The initial implementation is being prepared as draft branches in the OpenClaw -fork before upstream OpenClaw PRs are opened: +fork before upstream OpenClaw PRs are opened. The first slice must be amended to +normalize the existing Gateway startup, drain, channel, and event-loop outputs +into core conditions before it is promoted upstream: | Slice | Fork PR | Branch | | --- | --- | --- | @@ -741,8 +757,9 @@ live node registry. The proposal does not require one all-or-nothing implementation landing: -1. Land the condition shape and default `local` projection into existing - readiness, health, and status surfaces. +1. Land the condition shape, normalize existing Gateway startup, drain, + channel, and event-loop observations into core conditions, and add the + default `local` projection across readiness, health, and status surfaces. 2. Add explicit selection plus `container` and `reverse-proxy` predicates over effective runtime facts. 3. Add `node-mode` using pairing and live node-registry evidence. From ad72017eff365399d5ac03366bc1ee54eff0fd0a Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 14:56:19 -0700 Subject: [PATCH 30/98] Lead with readiness conditions and standard profiles --- ...andard-hosting-profiles-and-ready-check.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index e73904d0..d711e260 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -1,5 +1,5 @@ --- -title: Readiness Providers and Hosting Profiles +title: Readiness Conditions and Standard Hosting Profiles authors: - Gio created: 2026-07-09 @@ -9,17 +9,18 @@ issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 --- -# Proposal: Readiness Providers and Hosting Profiles +# Proposal: Readiness Conditions and Standard Hosting Profiles ## Summary -Add a canonical readiness-provider contract for publishing reusable runtime -criteria and projecting one result through Gateway `/ready`, `/readyz`, health, -and status. Standard hosting profiles compose those criteria into named, -OpenClaw-owned, release-tested support contracts for running OpenClaw as a -workload. The readiness-provider contract is independently useful without -selecting a non-default profile, and profiles do not add a second config system, -generate config, or replace existing Gateway readiness. +Add a canonical readiness-condition model and project one result through +Gateway `/ready`, `/readyz`, health, and status. Normalize existing fixed +Gateway signals into core conditions, let plugins publish additional conditions +through readiness providers, and let standard hosting profiles compose +conditions into named, OpenClaw-owned, release-tested support contracts. The +condition model is independently useful without selecting a non-default +profile, and profiles do not add a second config system, generate config, or +replace existing Gateway readiness. ## Motivation From de760a2a549390076e8f5ec33bff072356f21c46 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 15:08:34 -0700 Subject: [PATCH 31/98] Update readiness condition implementation stack --- ...andard-hosting-profiles-and-ready-check.md | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index d711e260..13c878ab 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -687,26 +687,27 @@ patches, compaction events, or harness protocol frames. ### Implementation branches The initial implementation is being prepared as draft branches in the OpenClaw -fork before upstream OpenClaw PRs are opened. The first slice must be amended to -normalize the existing Gateway startup, drain, channel, and event-loop outputs -into core conditions before it is promoted upstream: +fork before upstream OpenClaw PRs are opened. The first slice normalizes the +existing Gateway startup, drain, channel, and event-loop outputs into core +conditions before adding profile-specific conditions: | Slice | Fork PR | Branch | | --- | --- | --- | -| Ready surfaces | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`cefbe89976`) | -| Built-in profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`c423b77720`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`0dc6c7184f`) | -| Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5678370063`) | -| Extensible readiness criteria | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`990ab4808c`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`8aa1abbcf9`) | +| Core conditions and local profile | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`1bb6bfd5`) | +| Standard profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`a7cba836`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`ca8ab296`) | +| Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`781df835`) | +| Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`a073f69e`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`f7362189`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime branches and promoted into blocking package-acceptance release checks by the sixth branch: -- PR 17 proves an unset profile defaults to `local`, `/readyz` returns 200, and - required/advisory aggregation is stable. +- PR 17 normalizes startup, drain, channel, and event-loop observations into + core conditions, proves an unset profile defaults to `local`, and preserves + the legacy readiness fields while canonical aggregation drives HTTP status. - PR 18 proves a LAN-bound `container` profile returns 200 and a loopback-bound `container` profile returns 503 with `ContainerGatewayLoopback`. It also proves a configured trusted-proxy posture returns 200 for `reverse-proxy` @@ -720,18 +721,18 @@ sixth branch: fills a workspace `tmpfs` to `ENOSPC`, expects 503 with `WorkspaceStorageFull`, removes the fill file, and expects recovery to 200 without restarting OpenClaw. -- PR 23 adds activation-scoped plugin criterion registration and additive - operator profiles while preserving built-in requirements and canonical - `/ready` projection. +- PR 23 adds activation-scoped, self-describing, enumerable readiness providers + and additive operator profiles while preserving standard-profile requirements + and canonical `/ready` projection. - PR 21 selects that packaged profile matrix in the non-advisory release workflow, preserving its targeted plan, log, timing, and summary artifacts. PR 21 validation confirms the release workflow selects `hosting-profiles`, the Docker planner resolves the lane with both package and functional-image -requirements, and the existing 33 planner assertions remain green. PR 23 -passes 99 focused plugin, config, CLI, status-contract, and readiness -assertions. The full-facility exact-commit Codex review reports no actionable -findings; two review attempts for the small CI-closeout commit timed out. +requirements, and the existing 33 planner assertions remain green. After the +condition/provider amendments, the focused provider-registry, provider +evaluation, hosting config, Gateway readiness, and HTTP probe suites pass 121 +routed assertions. Earlier status-contract coverage remains part of the stack. The workspace-readiness composed branch passed 188 focused profile, Gateway-probe, health-state, status, node, and workspace assertions. PR 21's From 2ed226a42c22988280ed569dc4e2f3672072cbca Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 15:11:07 -0700 Subject: [PATCH 32/98] Refresh release conformance evidence --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 13c878ab..10af7b26 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -735,10 +735,9 @@ evaluation, hosting config, Gateway readiness, and HTTP probe suites pass 121 routed assertions. Earlier status-contract coverage remains part of the stack. The workspace-readiness composed branch passed 188 focused profile, -Gateway-probe, health-state, status, node, and workspace assertions. PR 21's -changed release-workflow assertion and all 33 Docker planner assertions also -pass. The full package-acceptance test file retains five unrelated Windows -Telegram shell/executable-bit fixture failures and 44 passing assertions. +Gateway-probe, health-state, status, node, and workspace assertions. After the +restack, PR 21's package-acceptance workflow file passes all 49 assertions and +the Docker planner passes all 33 assertions on Linux. Actual execution of the new workspace `tmpfs` failure/recovery scenario remains pending because Docker Desktop was unavailable on the authoring host. The From 915ff957ae1a0546df13059ccd4db5e520bdc5d8 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 15:16:54 -0700 Subject: [PATCH 33/98] Define readiness evaluation budgets --- ...andard-hosting-profiles-and-ready-check.md | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 10af7b26..795b9d57 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -613,6 +613,33 @@ not start dependencies, rewrite config, repair state, or emit durable audit claims. The cache duration bounds how stale a reported observation may be; a cached result is not historical or audit-grade evidence. +### Evaluation budgets and fail-closed behavior + +Every readiness condition must have a bounded evaluation strategy in code. A +condition may read an already-owned in-memory snapshot, perform a finite pass +over configured runtime state, or use a core-owned timeout and cache. It must +not introduce unbounded readiness-path I/O. + +| Condition family | Code-owned bound | +| --- | --- | +| Startup, drain, Gateway response, config, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config snapshots. | +| Channel runtime | One finite pass over the current in-memory channel snapshot, cached for one second. | +| Workspace writability | One-second hard timeout with five-second cache/coalescing. | +| Node mode | Pairing snapshot cached for one second; live sessions and command policy are finite in-memory passes. A later event-driven pairing snapshot may remove readiness-time storage reads entirely. | +| Plugin providers | All providers run concurrently; each has a core-enforced one-second `Promise.race` deadline and five-second cache/coalescing. The deadline does not depend on the callback honoring cancellation. | +| Complete readiness evaluation | Independent two-second outer watchdog around workspace, provider, and node evaluation, which run concurrently. | + +Timeout, throw, invalid result, or missing registration becomes `Unknown` with a +stable reason. It blocks readiness when required and remains visible without +blocking when advisory. If the complete evaluation exceeds its outer deadline, +the existing HTTP exception path returns `503` and never reports ready. + +An in-process timer cannot interrupt JavaScript that synchronously blocks the +Node.js event loop. Core evaluators therefore use bounded snapshot work, and the +plugin contract forbids blocking synchronous I/O or computation. Stronger +isolation against a malicious plugin would require worker/process execution and +is outside this RFC; it is not implied by `AbortSignal`. + ### Profile inheritance and support ownership In v1, every operator profile extends exactly one standard profile and inherits @@ -697,8 +724,8 @@ conditions before adding profile-specific conditions: | Standard profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`a7cba836`) | | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`ca8ab296`) | | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`781df835`) | -| Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`a073f69e`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`f7362189`) | +| Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`07c6aae3`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`b0974bb7`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime @@ -731,8 +758,9 @@ PR 21 validation confirms the release workflow selects `hosting-profiles`, the Docker planner resolves the lane with both package and functional-image requirements, and the existing 33 planner assertions remain green. After the condition/provider amendments, the focused provider-registry, provider -evaluation, hosting config, Gateway readiness, and HTTP probe suites pass 121 -routed assertions. Earlier status-contract coverage remains part of the stack. +evaluation, hosting config, Gateway readiness, timeout, and HTTP probe suites +pass 132 routed assertions. Earlier status-contract coverage remains part of +the stack. The workspace-readiness composed branch passed 188 focused profile, Gateway-probe, health-state, status, node, and workspace assertions. After the From ce8d2b67998e2abef10e9e4d7d62e8664776bf7b Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 15:58:49 -0700 Subject: [PATCH 34/98] Complete readiness condition audit --- ...andard-hosting-profiles-and-ready-check.md | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 795b9d57..f7da1231 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -243,6 +243,7 @@ readiness result. | `GatewayStartupComplete` | Required | Gateway startup dependencies and startup sidecars are no longer pending. | `GatewayStartupPending` | | `GatewayAcceptingWork` | Required | The Gateway is not draining and can admit new work. | `GatewayDraining` | | `ChannelRuntimeReady` | Required | No selected channel has an unsuppressed runtime-health failure under the existing channel readiness policy. | `ChannelRuntimeUnavailable` | +| `ChannelRuntimeSuppressed` | Advisory when present | One or more channel runtime failures are intentionally suppressed by the existing autostart/crash-loop policy. | `ChannelRuntimeSuppressed` | | `EventLoopHealthy` | Advisory | The existing event-loop health observation is within its healthy threshold. It remains advisory unless a separate compatibility-reviewed change intentionally makes it gate readiness. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | | `ProfileSelected` | Required | The runtime resolved and reports the selected built-in or configured custom profile. The default is `local`. | None; invalid explicit values fail selection before startup. | | `ConfigLoaded` | Required | Runtime configuration loaded successfully. | `ConfigNotLoaded` | @@ -251,7 +252,7 @@ readiness result. | `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | | `ContainerStateReady` | Required for `container` | The effective Gateway mode is `local` and the resolved listener host is not loopback. The port has already passed normal config validation. Config-only status reports `Unknown` when an `auto` bind has not been resolved. | `ContainerGatewayRemote`, `ContainerGatewayLoopback`, `ContainerBindNotResolved` | | `TrustedProxyReady` | Required for `reverse-proxy` | Auth mode is `trusted-proxy`, `trustedProxy.userHeader` is non-empty, and `gateway.trustedProxies` contains at least one address/CIDR. Loopback is valid for a same-host proxy. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing` | -| `NodePairingReady` | Required for `node-mode` | The pairing store is readable and contains at least one approved pairing. | `NodePairingUnavailable`, `NodePairingPending`, `NodePairingMissing` | +| `NodePairingReady` | Required for `node-mode` | The pairing store is readable and contains at least one approved pairing. | `NodePairingUnavailable`, `NodePairingTimedOut`, `NodePairingPending`, `NodePairingMissing` | | `ControlledTargetsReady` | Required for `node-mode` | The live Gateway node registry contains at least one connected node whose id is approved in the pairing store. Persisted pairing alone is insufficient. | `ControlledTargetsDisconnected` | | `CommandApprovalReady` | Required for `node-mode` | A connected paired node advertises at least one command that is granted by pairing or `gateway.nodes.allowCommands` and not removed by `gateway.nodes.denyCommands`. A deny-only list is not approval evidence. | `CommandApprovalMissing` | | `ControlChannelReady` | Required for `node-mode` | At least one connected node session is correlated to an approved pairing. Gateway HTTP responsiveness alone is insufficient. | `ControlChannelUnavailable` | @@ -330,6 +331,7 @@ type CoreReadinessCriterionId = | "GatewayStartupComplete" | "GatewayAcceptingWork" | "ChannelRuntimeReady" + | "ChannelRuntimeSuppressed" | "EventLoopHealthy" | "ProfileSelected" | "ConfigLoaded" @@ -625,7 +627,7 @@ not introduce unbounded readiness-path I/O. | Startup, drain, Gateway response, config, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config snapshots. | | Channel runtime | One finite pass over the current in-memory channel snapshot, cached for one second. | | Workspace writability | One-second hard timeout with five-second cache/coalescing. | -| Node mode | Pairing snapshot cached for one second; live sessions and command policy are finite in-memory passes. A later event-driven pairing snapshot may remove readiness-time storage reads entirely. | +| Node mode | Pairing reads have a one-second condition-level deadline and one-second cache; live sessions and command policy are finite in-memory passes. Timeout emits `NodePairingTimedOut` before the outer watchdog is needed. | | Plugin providers | All providers run concurrently; each has a core-enforced one-second `Promise.race` deadline and five-second cache/coalescing. The deadline does not depend on the callback honoring cancellation. | | Complete readiness evaluation | Independent two-second outer watchdog around workspace, provider, and node evaluation, which run concurrently. | @@ -720,12 +722,12 @@ conditions before adding profile-specific conditions: | Slice | Fork PR | Branch | | --- | --- | --- | -| Core conditions and local profile | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`1bb6bfd5`) | -| Standard profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`a7cba836`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`ca8ab296`) | -| Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`781df835`) | -| Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`07c6aae3`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`b0974bb7`) | +| Core conditions and local profile | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`cc9c4246`) | +| Standard profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`39a3b947`) | +| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`270f7a3d`) | +| Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5723f664`) | +| Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`399cf745`) | +| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`cd643a42`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime @@ -757,10 +759,10 @@ sixth branch: PR 21 validation confirms the release workflow selects `hosting-profiles`, the Docker planner resolves the lane with both package and functional-image requirements, and the existing 33 planner assertions remain green. After the -condition/provider amendments, the focused provider-registry, provider -evaluation, hosting config, Gateway readiness, timeout, and HTTP probe suites -pass 132 routed assertions. Earlier status-contract coverage remains part of -the stack. +condition/provider amendments, the latest focused provider-registry, provider +evaluation, hosting config, Gateway readiness, node/workspace timeout, and +status projection run passes 120 routed assertions. The corrected PR 17 health, +status, and legacy-condition run passes another 114 assertions. The workspace-readiness composed branch passed 188 focused profile, Gateway-probe, health-state, status, node, and workspace assertions. After the From 447eb0ed7d2718ed9aef473d97bacceca82c8285 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 16:55:01 -0700 Subject: [PATCH 35/98] Add canonical ready CLI slice --- ...0-standard-hosting-profiles-and-ready-check.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index f7da1231..9bf2e362 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -318,9 +318,9 @@ readiness and status surfaces. The selected profile should be reported in `/ready`, `/readyz`, `status --json`, and Gateway health so hosts and release tests can assert that the running -process selected the intended profile. A later optional CLI wrapper can add an -`openclaw ready --expect-profile ` assertion if maintainers want that -ergonomic surface, but it is not required for the first contract. +process selected the intended profile. The optional `openclaw ready` CLI +wrapper projects that same live result for operators and scripts; it does not +evaluate a second local readiness model. ### Ready result @@ -728,6 +728,7 @@ conditions before adding profile-specific conditions: | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5723f664`) | | Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`399cf745`) | | Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`cd643a42`) | +| Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`08d09d31`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime @@ -755,6 +756,11 @@ sixth branch: and canonical `/ready` projection. - PR 21 selects that packaged profile matrix in the non-advisory release workflow, preserving its targeted plan, log, timing, and summary artifacts. +- PR 27 adds `openclaw ready` as an optional operator convenience over the live + Gateway result. Human output lists every structured condition; `--json` + preserves the canonical successful result; and exit status fails closed for + required failures, unknowns, transport errors, or a missing readiness + contract. Advisory findings remain visible without changing exit success. PR 21 validation confirms the release workflow selects `hosting-profiles`, the Docker planner resolves the lane with both package and functional-image @@ -835,9 +841,6 @@ stable readiness conditions. ## Unresolved questions -- Should OpenClaw later add an `openclaw ready` CLI wrapper over the same - readiness result, or are HTTP `/ready` plus status/health enough for the first - release? - Which additional advisory conditions would improve supportability without weakening the meaning of required profile conformance? - Should non-plugin runtime drivers need a separate criterion registration From a4d32a50c2ad0fe46d04b883eeadd8b7e624507a Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 17:26:21 -0700 Subject: [PATCH 36/98] Refresh ready CLI implementation head --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 9bf2e362..a17fa62c 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -728,7 +728,7 @@ conditions before adding profile-specific conditions: | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5723f664`) | | Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`399cf745`) | | Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`cd643a42`) | -| Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`08d09d31`) | +| Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`1064104a`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime From 580faabd05960f2a7d58bd4fbd95c16bb6326bf5 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 17:39:10 -0700 Subject: [PATCH 37/98] Defer release gating from initial implementation --- ...andard-hosting-profiles-and-ready-check.md | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index a17fa62c..d5205e3f 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -727,13 +727,11 @@ conditions before adding profile-specific conditions: | Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`270f7a3d`) | | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5723f664`) | | Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`399cf745`) | -| Release conformance gate | https://github.com/giodl73-repo/openclaw/pull/21 | `user/giodl/hosting-profile-release-conformance` (`cd643a42`) | -| Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`1064104a`) | +| Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`fe4c51c1`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime -branches and promoted into blocking package-acceptance release checks by the -sixth branch: +branches but not yet promoted into blocking package-acceptance release checks: - PR 17 normalizes startup, drain, channel, and event-loop observations into core conditions, proves an unset profile defaults to `local`, and preserves @@ -754,17 +752,14 @@ sixth branch: - PR 23 adds activation-scoped, self-describing, enumerable readiness providers and additive operator profiles while preserving standard-profile requirements and canonical `/ready` projection. -- PR 21 selects that packaged profile matrix in the non-advisory release - workflow, preserving its targeted plan, log, timing, and summary artifacts. - PR 27 adds `openclaw ready` as an optional operator convenience over the live Gateway result. Human output lists every structured condition; `--json` preserves the canonical successful result; and exit status fails closed for required failures, unknowns, transport errors, or a missing readiness contract. Advisory findings remain visible without changing exit success. -PR 21 validation confirms the release workflow selects `hosting-profiles`, the -Docker planner resolves the lane with both package and functional-image -requirements, and the existing 33 planner assertions remain green. After the +The Docker planner resolves the lane with both package and functional-image +requirements, and its existing 33 planner assertions remain green. After the condition/provider amendments, the latest focused provider-registry, provider evaluation, hosting config, Gateway readiness, node/workspace timeout, and status projection run passes 120 routed assertions. The corrected PR 17 health, @@ -772,8 +767,13 @@ status, and legacy-condition run passes another 114 assertions. The workspace-readiness composed branch passed 188 focused profile, Gateway-probe, health-state, status, node, and workspace assertions. After the -restack, PR 21's package-acceptance workflow file passes all 49 assertions and -the Docker planner passes all 33 assertions on Linux. +restack, the Docker planner passes all 33 assertions on Linux. + +Making this lane a blocking package-acceptance release gate is intentionally a +follow-up after maintainers accept the contract and packaged Docker execution +is proven. Draft fork PR 21 demonstrates that separate six-line workflow/docs +change without coupling the initial implementation to a permanent release +obligation. Actual execution of the new workspace `tmpfs` failure/recovery scenario remains pending because Docker Desktop was unavailable on the authoring host. The @@ -805,7 +805,12 @@ The proposal does not require one all-or-nothing implementation landing: a profile. 5. Add plugin criterion registration and additive operator profiles over the same canonical result. -6. Make the packaged profile matrix a blocking package-acceptance release gate. +6. Add the optional `openclaw ready` CLI projection over the canonical live + Gateway result. + +After contract acceptance and successful packaged Docker proof, a separate +follow-up can make the profile matrix a blocking package-acceptance release +gate. The first slice is independently useful because it creates one canonical, explainable result without introducing non-local hosting behavior. If the From 365d9a50f0cd5346ee432a47b48a07b321ab7bd2 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 22:29:06 -0700 Subject: [PATCH 38/98] Document readiness completion roadmap --- ...andard-hosting-profiles-and-ready-check.md | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index d5205e3f..d04301fa 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -713,6 +713,71 @@ execution, runtime status fields, ready/not-ready projection. OCC should not be in the hot path for assistant deltas, tool events, approvals, patches, compaction events, or harness protocol frames. +### Completion roadmap + +The first implementation stack establishes the contract, but it does not make +the support promise complete by itself. The remaining work is grouped below so +that readiness does not become another collection of partially overlapping +surfaces. + +1. **Finish the canonical core conditions.** Existing Gateway startup, drain, + unsuppressed channel, and event-loop observations must be represented as + conditions rather than maintained as a second readiness model. Startup + validation that determines whether this process can serve belongs here as + readiness evidence; it does not require a separate ignition endpoint. + Config-loaded, Gateway-responsive, required-plugin, workspace, selected + topology, and node-mode evidence should use the same condition vocabulary. + Legacy `failing`, `suppressed`, and `eventLoop` fields remain compatibility + projections during migration. +2. **Unify every projection.** `/ready`, `/readyz`, Gateway health, status, and + the optional `openclaw ready` command must be projections of one canonical + evaluation, with the same effective profile, condition identities, + requirement classes, reasons, and overall result. `/health` and `/healthz` + remain shallow liveness checks. Detailed output remains available only to + appropriately authenticated or local callers; unauthenticated probes keep a + compact result. +3. **Complete the bounded provider facility.** Active providers must remain + activation-scoped, enumerable, self-describing, observational, and advisory + by default. Core owns concurrent evaluation, per-provider deadlines, + cancellation, invalid-result handling, cache/coalescing, and an independent + outer evaluation deadline so a plugin cannot stall `/ready` or `/readyz`. + Operators may promote a provider condition to required only through an + additive operator profile. +4. **Prove the standard profiles as packaged workloads.** Run the Docker lane + against the package-installed release candidate for `local`, `container`, + `reverse-proxy`, and `node-mode`, including deterministic failure and + recovery cases. The current workspace-full and node-pairing scenarios must + be executed on Linux/container infrastructure, not only planned or unit + tested. Publish the profile id, OpenClaw artifact/version, condition set, + result, and test evidence so a host can distinguish a supported release from + an untested configuration. +5. **Promote accepted profiles into release conformance.** Once maintainers + accept the condition and profile contracts and the packaged Docker proof is + reliable, make that matrix a blocking package-acceptance gate. A built-in + profile is a release-tested support promise, not merely a convenient bundle + of settings. Changes to required conditions or stable reasons require + compatibility review and release notes. +6. **Add stable readiness transition evidence.** Emit bounded, redacted events + when the effective profile or overall readiness changes, including the + previous and current result and changed condition identities. Event naming, + initial observation, deduplication, restart behavior, and operation when no + caller polls readiness must be specified before telemetry becomes a stable + contract. OpenClaw owns event semantics; hosts own fleet sinks, dashboards, + alerts, and retention. +7. **Add non-blocking operator guidance.** A later Doctor/lint pass may compare + the selected profile with effective config and host-facing recommendations, + report structured findings, and suggest safe fixes. Doctor, policy, and + optional plugins must never be dependencies of the core readiness path, and + built-in profiles must not absorb Docker-, Kubernetes-, or systemd-specific + retry counts and probe intervals. + +Readiness answers whether this runtime can accept and serve work now. It does +not prove that the latest mutable state has been durably published. Drain, +checkpoint publication, dirty/synced state, and a generation-fenced +safe-to-destroy result belong to the separate Runtime Continuity and Safe +Shutdown contract. A runtime may be ready but dirty, or not ready but already +synced; neither surface should be made an alias for the other. + ### Implementation branches The initial implementation is being prepared as draft branches in the OpenClaw From aa56959a61b404ec2b7b24c457b22f117b4b02ab Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 22:33:41 -0700 Subject: [PATCH 39/98] Reconcile activation readiness conditions --- ...andard-hosting-profiles-and-ready-check.md | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index d04301fa..06862361 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -213,7 +213,7 @@ OpenClaw-owned evaluator that emits the runtime readiness condition. | Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | | --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `ConfigLoaded`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded` | config load, effective default workspace write evidence, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `WorkspaceWritable`, `GatewayResponding`. Advisory: `PluginsLoaded`. | +| `local` | Developer/local foreground process readiness. | `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded`, plus `RequiredPluginsActivated` when required activation is declared | effective runtime config and secrets snapshots, model-route resolution, default workspace write evidence, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, and any declared `RequiredPluginsActivated`. Advisory: general `PluginsLoaded`. | | `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `ContainerStateReady` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | | `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `TrustedProxyReady` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | | `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady` | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus the four node-mode conditions. | @@ -246,7 +246,10 @@ readiness result. | `ChannelRuntimeSuppressed` | Advisory when present | One or more channel runtime failures are intentionally suppressed by the existing autostart/crash-loop policy. | `ChannelRuntimeSuppressed` | | `EventLoopHealthy` | Advisory | The existing event-loop health observation is within its healthy threshold. It remains advisory unless a separate compatibility-reviewed change intentionally makes it gate readiness. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | | `ProfileSelected` | Required | The runtime resolved and reports the selected built-in or configured custom profile. The default is `local`. | None; invalid explicit values fail selection before startup. | -| `ConfigLoaded` | Required | Runtime configuration loaded successfully. | `ConfigNotLoaded` | +| `ConfigLoaded` | Required | The validated effective runtime configuration snapshot is installed after normal precedence and activation processing; parsing a source file alone is insufficient. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | +| `RequiredPluginsActivated` | Required when a standard or operator profile declares required plugin/provider activation | Every declared required plugin/provider is present and activated without an activation error. General selected-plugin health remains advisory through `PluginsLoaded`. | `RequiredPluginMissing`, `RequiredPluginActivationFailed`, `RequiredPluginStatusUnavailable` | +| `RequiredSecretsAvailable` | Required | Every secret declared startup-required by the selected profile or effective runtime route is available in the installed redacted secrets snapshot. Optional and lazy credentials do not block readiness. | `RequiredSecretMissing`, `RequiredSecretActivationFailed`, `RequiredSecretStatusUnavailable` | +| `ModelRoutingResolved` | Required when the selected runtime role accepts agent work | The effective default or selected model route resolves to a configured provider after config and secret activation. Evaluation reads the startup snapshot and does not issue a model request. | `ModelRouteMissing`, `ModelProviderUnavailable`, `ModelRouteStatusUnavailable` | | `WorkspaceWritable` | Required for all built-in profiles | The running Gateway resolves the effective default-agent workspace and completes a write, flush, and cleanup probe. The probe is cached and coalesced so readiness polling does not cause unbounded filesystem work. Non-probing command fallbacks do not invent positive evidence. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | @@ -335,6 +338,9 @@ type CoreReadinessCriterionId = | "EventLoopHealthy" | "ProfileSelected" | "ConfigLoaded" + | "RequiredPluginsActivated" + | "RequiredSecretsAvailable" + | "ModelRoutingResolved" | "WorkspaceWritable" | "GatewayResponding" | "PluginsLoaded" @@ -624,7 +630,7 @@ not introduce unbounded readiness-path I/O. | Condition family | Code-owned bound | | --- | --- | -| Startup, drain, Gateway response, config, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config snapshots. | +| Startup, drain, Gateway response, effective config, required plugin activation, required secret availability, model-route resolution, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config/activation snapshots. Readiness does not reload plugins, resolve secrets, or call a model. | | Channel runtime | One finite pass over the current in-memory channel snapshot, cached for one second. | | Workspace writability | One-second hard timeout with five-second cache/coalescing. | | Node mode | Pairing reads have a one-second condition-level deadline and one-second cache; live sessions and command policy are finite in-memory passes. Timeout emits `NodePairingTimedOut` before the outer watchdog is needed. | @@ -729,6 +735,30 @@ surfaces. topology, and node-mode evidence should use the same condition vocabulary. Legacy `failing`, `suppressed`, and `eventLoop` fields remain compatibility projections during migration. + + The earlier Runtime Activation inventory is reconciled explicitly below. + These are startup facts needed to serve a normal request, not general policy + conformance checks: + + | Activation observation | Readiness disposition | + | --- | --- | + | Effective configuration resolved | Strengthen `ConfigLoaded` so `True` means the validated effective runtime snapshot is installed, not merely that a source file parsed. Use `ConfigNotLoaded`, `ConfigInvalid`, or `EffectiveConfigUnavailable` when that cannot be established. | + | Hosting profile applied | Covered by required `ProfileSelected`; the reported profile is the effective value after flag, environment, config, and default precedence. | + | Required plugins activated | Keep general `PluginsLoaded` advisory for compatibility, but add required `RequiredPluginsActivated` when a standard or operator profile names a plugin/provider as required. Missing, failed, or unavailable required activation must block readiness. | + | Required secrets available | Add required `RequiredSecretsAvailable` over the installed startup secrets snapshot. It reports only redacted availability and stable reasons; it never exposes secret values. Optional or lazy credentials do not block readiness until a selected profile declares them startup-required. | + | Model routing resolved | Add required `ModelRoutingResolved` when the selected runtime role is expected to accept agent work. It proves that the effective default/selected model route resolves to a configured provider after config and secret activation; it does not perform a billable model request on every readiness poll. | + + `RequiredPluginsActivated`, `RequiredSecretsAvailable`, and + `ModelRoutingResolved` must be implemented as bounded reads over activation + snapshots produced during normal startup. Readiness polling must not reload + plugins, resolve secrets again, contact a model, or mutate configuration. + + Other early hosted-start candidates do not become universal core + conditions. Brokered egress may be a required provider condition in a + derived managed profile. A no-runtime-secrets rule is conformance, not a + liveness probe. Workspace restoration, single-writer ownership, checkpoint + publication, and durable-state freshness belong to Runtime Continuity unless + a specific profile requires a bounded readiness observation before serving. 2. **Unify every projection.** `/ready`, `/readyz`, Gateway health, status, and the optional `openclaw ready` command must be projections of one canonical evaluation, with the same effective profile, condition identities, @@ -853,7 +883,10 @@ contract. This first stack proves the core ready/result shape, explicit profile selection, built-in profile composition from reusable criteria, exact built-in container/reverse-proxy predicates, and node-mode rules backed by the -live node registry. +live node registry. It does not yet implement the newly reconciled +`RequiredPluginsActivated`, `RequiredSecretsAvailable`, or +`ModelRoutingResolved` activation conditions; those remain completion work +before the standard-profile matrix can become a release support gate. ### Incremental adoption From 83bbaa063baef8f6466f2cb0ff407f52a5de984b Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 22:55:04 -0700 Subject: [PATCH 40/98] Add release evidence readiness conditions --- ...andard-hosting-profiles-and-ready-check.md | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 06862361..b966efd7 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -213,7 +213,7 @@ OpenClaw-owned evaluator that emits the runtime readiness condition. | Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | | --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded`, plus `RequiredPluginsActivated` when required activation is declared | effective runtime config and secrets snapshots, model-route resolution, default workspace write evidence, Gateway reachability, selected plugin activation status | Required: `ProfileSelected`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, and any declared `RequiredPluginsActivated`. Advisory: general `PluginsLoaded`. | +| `local` | Developer/local foreground process readiness. | `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded`, release-evidence conditions, plus `RequiredPluginsActivated` when required activation is declared | effective runtime config and secrets snapshots, model-route resolution, default workspace write evidence, Gateway reachability, selected plugin activation status, packaged artifact identity/conformance metadata | Required: `ProfileSelected`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, and any declared `RequiredPluginsActivated`. Advisory by default: general `PluginsLoaded`, `ArtifactIdentityAvailable`, and `SelectedProfileConformant`. `ExpectedArtifactMatched` is required when a host supplies an expectation. | | `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `ContainerStateReady` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | | `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `TrustedProxyReady` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | | `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady` | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus the four node-mode conditions. | @@ -250,6 +250,9 @@ readiness result. | `RequiredPluginsActivated` | Required when a standard or operator profile declares required plugin/provider activation | Every declared required plugin/provider is present and activated without an activation error. General selected-plugin health remains advisory through `PluginsLoaded`. | `RequiredPluginMissing`, `RequiredPluginActivationFailed`, `RequiredPluginStatusUnavailable` | | `RequiredSecretsAvailable` | Required | Every secret declared startup-required by the selected profile or effective runtime route is available in the installed redacted secrets snapshot. Optional and lazy credentials do not block readiness. | `RequiredSecretMissing`, `RequiredSecretActivationFailed`, `RequiredSecretStatusUnavailable` | | `ModelRoutingResolved` | Required when the selected runtime role accepts agent work | The effective default or selected model route resolves to a configured provider after config and secret activation. Evaluation reads the startup snapshot and does not issue a model request. | `ModelRouteMissing`, `ModelProviderUnavailable`, `ModelRouteStatusUnavailable` | +| `ArtifactIdentityAvailable` | Advisory by default | The runtime can report a stable packaged artifact identity containing at least OpenClaw version and build/package identity. Source and development runs may report `Unknown` without becoming unready. | `ArtifactIdentityUnavailable`, `DevelopmentArtifact` | +| `SelectedProfileConformant` | Advisory by default; operator profiles may promote it to required | Embedded release evidence is bound to the running artifact identity and records a passing packaged conformance result for the selected standard profile and condition-contract version. It does not rerun conformance at readiness time. | `ProfileConformanceMissing`, `ProfileConformanceFailed`, `ProfileConformanceStale`, `ProfileConformanceArtifactMismatch` | +| `ExpectedArtifactMatched` | Required when the host supplies an expected artifact identity | The running artifact identity matches the immutable identity selected by the host for this deployment. Absence of a host expectation omits the condition. | `ExpectedArtifactMismatch`, `ExpectedArtifactNotVerifiable` | | `WorkspaceWritable` | Required for all built-in profiles | The running Gateway resolves the effective default-agent workspace and completes a write, flush, and cleanup probe. The probe is cached and coalesced so readiness polling does not cause unbounded filesystem work. Non-probing command fallbacks do not invent positive evidence. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | @@ -341,6 +344,9 @@ type CoreReadinessCriterionId = | "RequiredPluginsActivated" | "RequiredSecretsAvailable" | "ModelRoutingResolved" + | "ArtifactIdentityAvailable" + | "SelectedProfileConformant" + | "ExpectedArtifactMatched" | "WorkspaceWritable" | "GatewayResponding" | "PluginsLoaded" @@ -630,7 +636,7 @@ not introduce unbounded readiness-path I/O. | Condition family | Code-owned bound | | --- | --- | -| Startup, drain, Gateway response, effective config, required plugin activation, required secret availability, model-route resolution, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config/activation snapshots. Readiness does not reload plugins, resolve secrets, or call a model. | +| Startup, drain, Gateway response, effective config, required plugin activation, required secret availability, model-route resolution, artifact identity, packaged profile conformance, expected-artifact match, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config/activation/build-metadata snapshots. Readiness does not reload plugins, resolve secrets, call a model, or rerun conformance tests. | | Channel runtime | One finite pass over the current in-memory channel snapshot, cached for one second. | | Workspace writability | One-second hard timeout with five-second cache/coalescing. | | Node mode | Pairing reads have a one-second condition-level deadline and one-second cache; live sessions and command policy are finite in-memory passes. Timeout emits `NodePairingTimedOut` before the outer watchdog is needed. | @@ -778,9 +784,15 @@ surfaces. `reverse-proxy`, and `node-mode`, including deterministic failure and recovery cases. The current workspace-full and node-pairing scenarios must be executed on Linux/container infrastructure, not only planned or unit - tested. Publish the profile id, OpenClaw artifact/version, condition set, + tested. Publish an artifact-bound conformance record containing the profile + id, OpenClaw artifact/version, condition-contract version, condition set, result, and test evidence so a host can distinguish a supported release from - an untested configuration. + an untested configuration. Package that bounded metadata with the release so + readiness can emit `ArtifactIdentityAvailable` and + `SelectedProfileConformant` without rerunning tests. A host may also supply + an immutable expected artifact identity; when present, + `ExpectedArtifactMatched` is required and prevents a different build from + becoming ready under the deployment's support claim. 5. **Promote accepted profiles into release conformance.** Once maintainers accept the condition and profile contracts and the packaged Docker proof is reliable, make that matrix a blocking package-acceptance gate. A built-in @@ -885,8 +897,9 @@ selection, built-in profile composition from reusable criteria, exact built-in container/reverse-proxy predicates, and node-mode rules backed by the live node registry. It does not yet implement the newly reconciled `RequiredPluginsActivated`, `RequiredSecretsAvailable`, or -`ModelRoutingResolved` activation conditions; those remain completion work -before the standard-profile matrix can become a release support gate. +`ModelRoutingResolved` activation conditions, nor the artifact identity and +profile-conformance conditions. Those remain completion work before the +standard-profile matrix can become a release support gate. ### Incremental adoption @@ -932,6 +945,13 @@ which conditions are stable, and which release tests prove them. An operator profile preserves the tested baseline it inherits while clearly identifying the additional criteria whose support belongs to the operator or plugin owner. +Artifact and profile-conformance conditions keep that support promise on the +same host-facing result. They are not a general compatibility, upgrade, or +migration framework. Release jobs produce immutable evidence; readiness only +checks that the running artifact, selected profile, and supplied host +expectation match that evidence. Restore-version compatibility remains part of +Runtime State Continuity. + This is intentionally less powerful than a general profile or policy engine. Its value comes from OpenClaw owning a small number of built-in definitions and testing them release after release. Operator profiles are constrained to From 0a42c2e44158277bd9a8bf74057c10cf959d211e Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 23:02:11 -0700 Subject: [PATCH 41/98] Specify packaged profile evidence --- ...andard-hosting-profiles-and-ready-check.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index b966efd7..78ef4381 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -263,6 +263,47 @@ readiness result. | `CommandApprovalReady` | Required for `node-mode` | A connected paired node advertises at least one command that is granted by pairing or `gateway.nodes.allowCommands` and not removed by `gateway.nodes.denyCommands`. A deny-only list is not approval evidence. | `CommandApprovalMissing` | | `ControlChannelReady` | Required for `node-mode` | At least one connected node session is correlated to an approved pairing. Gateway HTTP responsiveness alone is insufficient. | `ControlChannelUnavailable` | +### Packaged profile evidence + +Release conformance produces immutable metadata; readiness consumes it. The +minimum record is intentionally small: + +```ts +type HostingProfileConformanceRecord = { + schemaVersion: 1; + artifact: { + openclawVersion: string; + packageIdentity: string; + digest: string; + }; + profile: BuiltInHostingProfileId; + conditionContractVersion: number; + requiredConditionTypes: string[]; + result: "passed" | "failed"; + suiteIdentity: string; + completedAt: string; + provenance?: { + builder?: string; + sourceRevision?: string; + attestationRef?: string; + }; +}; +``` + +The release process binds the record to the same immutable package/image +identity reported by the runtime. OpenClaw validates the schema, digest, +selected profile, condition-contract version, and result before emitting +`SelectedProfileConformant=True`. Unknown fields are tolerated for forward +compatibility, but unknown schema or condition-contract versions report +`Unknown`, never success. + +The record contains no tenant, operator, secret, or runtime health data. Build +signing and attestation may protect provenance, but this RFC does not prescribe +one supply-chain system. A host that requires stronger provenance validates it +before deployment and supplies the expected immutable artifact identity; +readiness then proves only that the admitted artifact is the process now +running. + ### Profile selection OpenClaw should not require an explicit profile to run. If no profile is From d33e42a488a7f5ae1aa72774cb169d3222cf8c2c Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 10 Jul 2026 23:30:30 -0700 Subject: [PATCH 42/98] Add ClawBus readiness condition --- rfcs/0010-standard-hosting-profiles-and-ready-check.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0010-standard-hosting-profiles-and-ready-check.md index 78ef4381..726b0120 100644 --- a/rfcs/0010-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0010-standard-hosting-profiles-and-ready-check.md @@ -253,6 +253,7 @@ readiness result. | `ArtifactIdentityAvailable` | Advisory by default | The runtime can report a stable packaged artifact identity containing at least OpenClaw version and build/package identity. Source and development runs may report `Unknown` without becoming unready. | `ArtifactIdentityUnavailable`, `DevelopmentArtifact` | | `SelectedProfileConformant` | Advisory by default; operator profiles may promote it to required | Embedded release evidence is bound to the running artifact identity and records a passing packaged conformance result for the selected standard profile and condition-contract version. It does not rerun conformance at readiness time. | `ProfileConformanceMissing`, `ProfileConformanceFailed`, `ProfileConformanceStale`, `ProfileConformanceArtifactMismatch` | | `ExpectedArtifactMatched` | Required when the host supplies an expected artifact identity | The running artifact identity matches the immutable identity selected by the host for this deployment. Absence of a host expectation omits the condition. | `ExpectedArtifactMismatch`, `ExpectedArtifactNotVerifiable` | +| `RequiredClawBusCapabilitiesAvailable` | Required when the selected standard or operator profile declares hosted duplex capabilities | The active generation-bound ClawBus peer negotiated every required canonical OpenClaw family/provider ID and version. It reads the live negotiated session snapshot and does not probe the remote service on every readiness call. | `ClawBusUnavailable`, `ClawBusGenerationMismatch`, `ClawBusCapabilityMissing`, `ClawBusStatusUnavailable` | | `WorkspaceWritable` | Required for all built-in profiles | The running Gateway resolves the effective default-agent workspace and completes a write, flush, and cleanup probe. The probe is cached and coalesced so readiness polling does not cause unbounded filesystem work. Non-probing command fallbacks do not invent positive evidence. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | @@ -388,6 +389,7 @@ type CoreReadinessCriterionId = | "ArtifactIdentityAvailable" | "SelectedProfileConformant" | "ExpectedArtifactMatched" + | "RequiredClawBusCapabilitiesAvailable" | "WorkspaceWritable" | "GatewayResponding" | "PluginsLoaded" @@ -677,7 +679,7 @@ not introduce unbounded readiness-path I/O. | Condition family | Code-owned bound | | --- | --- | -| Startup, drain, Gateway response, effective config, required plugin activation, required secret availability, model-route resolution, artifact identity, packaged profile conformance, expected-artifact match, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config/activation/build-metadata snapshots. Readiness does not reload plugins, resolve secrets, call a model, or rerun conformance tests. | +| Startup, drain, Gateway response, effective config, required plugin activation, required secret availability, model-route resolution, artifact identity, packaged profile conformance, expected-artifact match, negotiated ClawBus capabilities, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config/activation/build-metadata/session snapshots. Readiness does not reload plugins, resolve secrets, call a model, probe host services, or rerun conformance tests. | | Channel runtime | One finite pass over the current in-memory channel snapshot, cached for one second. | | Workspace writability | One-second hard timeout with five-second cache/coalescing. | | Node mode | Pairing reads have a one-second condition-level deadline and one-second cache; live sessions and command policy are finite in-memory passes. Timeout emits `NodePairingTimedOut` before the outer watchdog is needed. | From 27a8687684b07a85839d29991e1587168c887238 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 11 Jul 2026 14:18:43 -0700 Subject: [PATCH 43/98] Renumber readiness hosting profiles RFC to 0018 --- ...check.md => 0018-standard-hosting-profiles-and-ready-check.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename rfcs/{0010-standard-hosting-profiles-and-ready-check.md => 0018-standard-hosting-profiles-and-ready-check.md} (100%) diff --git a/rfcs/0010-standard-hosting-profiles-and-ready-check.md b/rfcs/0018-standard-hosting-profiles-and-ready-check.md similarity index 100% rename from rfcs/0010-standard-hosting-profiles-and-ready-check.md rename to rfcs/0018-standard-hosting-profiles-and-ready-check.md From 37b5dc2754bab83ad61f7a873e8a7fe3213bf86f Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 11 Jul 2026 18:18:48 -0700 Subject: [PATCH 44/98] docs(rfc): add hosting activation identity --- ...andard-hosting-profiles-and-ready-check.md | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/rfcs/0018-standard-hosting-profiles-and-ready-check.md b/rfcs/0018-standard-hosting-profiles-and-ready-check.md index 726b0120..17de899f 100644 --- a/rfcs/0018-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0018-standard-hosting-profiles-and-ready-check.md @@ -111,6 +111,9 @@ future telemetry consume the same runtime truth. health surfaces. - Add explicit profile selection through config, environment, and Gateway startup. +- Let a hosting profile declare the minimal activation facts required for its + supported runtime shape, and report the resolved runtime activation identity + through readiness and status. - Keep OpenClaw generic: no Lobster, Scout, Microsoft, tenant, Teams, Kusto, or product-specific host concepts. - Keep the first implementation in core so readiness works without optional @@ -132,6 +135,8 @@ future telemetry consume the same runtime truth. - Define the remote AgentHarness event protocol. - Standardize a host's storage backend, auth provider, telemetry sink, tenant routing, UI, deployment system, or worker-pool model. +- Define an OCC-style instance resource, placement model, replica identity, or + tenant lifecycle API. - Put assistant deltas, tool frames, approvals, patches, compaction events, or harness protocol frames into the hosting contract. - Allow arbitrary operator-defined conditions to redefine built-in profile @@ -166,6 +171,7 @@ OpenClaw should expose a standard hostee contract: ```text profile selection ++ validated runtime activation context + runtime status/config facts + readiness condition evaluation -> ready/not-ready result @@ -183,6 +189,14 @@ Five constraints keep this narrow: 5. Only required conditions affect the binary ready result. Advisory conditions remain visible without turning a useful diagnostic into an outage. +The runtime activation context is the small entry point into this contract. It +identifies this activation and references the configuration, host integration, +and restore inputs selected by the launcher. It does not duplicate those +systems' data. Each referenced owner validates and activates its own input, +publishes its own status evidence, and contributes readiness conditions. The +profile only declares which activation facts and resulting conditions are +required for the named support posture. + The contract is not a parallel hosted config tree. Existing OpenClaw config continues to own Gateway, proxy, plugin, model, session, node, and state behavior. A hosting profile decides which existing runtime status/config facts @@ -213,7 +227,7 @@ OpenClaw-owned evaluator that emits the runtime readiness condition. | Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | | --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded`, release-evidence conditions, plus `RequiredPluginsActivated` when required activation is declared | effective runtime config and secrets snapshots, model-route resolution, default workspace write evidence, Gateway reachability, selected plugin activation status, packaged artifact identity/conformance metadata | Required: `ProfileSelected`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, and any declared `RequiredPluginsActivated`. Advisory by default: general `PluginsLoaded`, `ArtifactIdentityAvailable`, and `SelectedProfileConformant`. `ExpectedArtifactMatched` is required when a host supplies an expectation. | +| `local` | Developer/local foreground process readiness. | `RuntimeActivationIdentified`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded`, release-evidence conditions, plus `RequiredPluginsActivated` when required activation is declared | resolved runtime/incarnation identity, effective runtime config and secrets snapshots, model-route resolution, default workspace write evidence, Gateway reachability, selected plugin activation status, packaged artifact identity/conformance metadata | Required: `ProfileSelected`, `RuntimeActivationIdentified`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, and any declared `RequiredPluginsActivated`. Advisory by default: general `PluginsLoaded`, `ArtifactIdentityAvailable`, and `SelectedProfileConformant`. `ExpectedArtifactMatched` is required when a host supplies an expectation. | | `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `ContainerStateReady` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | | `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `TrustedProxyReady` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | | `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady` | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus the four node-mode conditions. | @@ -246,6 +260,7 @@ readiness result. | `ChannelRuntimeSuppressed` | Advisory when present | One or more channel runtime failures are intentionally suppressed by the existing autostart/crash-loop policy. | `ChannelRuntimeSuppressed` | | `EventLoopHealthy` | Advisory | The existing event-loop health observation is within its healthy threshold. It remains advisory unless a separate compatibility-reviewed change intentionally makes it gate readiness. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | | `ProfileSelected` | Required | The runtime resolved and reports the selected built-in or configured custom profile. The default is `local`. | None; invalid explicit values fail selection before startup. | +| `RuntimeActivationIdentified` | Required | The runtime has resolved non-empty logical-runtime and unique-incarnation identities. OpenClaw-generated local defaults satisfy this condition when the launcher supplies neither value. | `RuntimeIdentityInvalid`, `IncarnationIdentityInvalid`, `ActivationIdentityUnavailable` | | `ConfigLoaded` | Required | The validated effective runtime configuration snapshot is installed after normal precedence and activation processing; parsing a source file alone is insufficient. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | | `RequiredPluginsActivated` | Required when a standard or operator profile declares required plugin/provider activation | Every declared required plugin/provider is present and activated without an activation error. General selected-plugin health remains advisory through `PluginsLoaded`. | `RequiredPluginMissing`, `RequiredPluginActivationFailed`, `RequiredPluginStatusUnavailable` | | `RequiredSecretsAvailable` | Required | Every secret declared startup-required by the selected profile or effective runtime route is available in the installed redacted secrets snapshot. Optional and lazy credentials do not block readiness. | `RequiredSecretMissing`, `RequiredSecretActivationFailed`, `RequiredSecretStatusUnavailable` | @@ -331,6 +346,11 @@ type OperatorHostingProfile = { advisoryCriteria?: string[]; }; +type RuntimeActivationIdentity = { + runtimeId: string; + incarnationId: string; +}; + type HostingConfig = { profile?: string; profiles?: Record; @@ -349,6 +369,22 @@ custom profile extends exactly one built-in profile and can only add criteria; it cannot remove or demote inherited requirements. A criterion cannot be both required and advisory in the same profile. +The runtime activation identity is startup metadata, not another OpenClaw +config document. `runtimeId` identifies the logical runtime across restarts; +`incarnationId` identifies one process or container execution. A launcher may +supply stable values through startup arguments, environment, or a mounted +activation descriptor. OpenClaw generates local defaults when they are absent, +so existing installations and the `local` profile remain zero-configuration. + +Configuration sources, host-bundle selection, and restore selection stay in +their owning contracts rather than being copied into this identity. Those +owners publish the effective config generation, selected bundle identity and +version, and restored state generation after successful activation. Their +readiness providers contribute the corresponding conditions, and a profile may +promote those conditions to required. This avoids a circular config-source +reference and prevents Hosting Profiles from becoming a second configuration, +integration, or continuity system. + The environment variable and startup flag accept built-in ids or a namespaced custom id. Runtime resolution validates a custom id against the loaded config. The `local` default is resolved at runtime and does not need to be persisted. @@ -370,6 +406,12 @@ process selected the intended profile. The optional `openclaw ready` CLI wrapper projects that same live result for operators and scripts; it does not evaluate a second local readiness model. +Those surfaces should also report a redacted activation summary containing the +runtime id, incarnation id, effective config generation, selected host-bundle +identity/version, and restored state generation when available. They must not +echo source contents, credentials, or host-private metadata. This makes the +ready result attributable to the exact activation being supervised. + ### Ready result Readiness should use Kubernetes-style conditions: @@ -382,6 +424,7 @@ type CoreReadinessCriterionId = | "ChannelRuntimeSuppressed" | "EventLoopHealthy" | "ProfileSelected" + | "RuntimeActivationIdentified" | "ConfigLoaded" | "RequiredPluginsActivated" | "RequiredSecretsAvailable" @@ -414,6 +457,7 @@ type HostingReadinessCondition = { type HostingReadinessResult = { profile: string; + activation: RuntimeActivationIdentity; ready: boolean; conditions: HostingReadinessCondition[]; failures: string[]; @@ -430,6 +474,10 @@ namespaced by core as `plugin..`. ```jsonc { "profile": "container", + "activation": { + "runtimeId": "tenant-42/scout-primary", + "incarnationId": "pod-7f9c" + }, "ready": false, "conditions": [ { @@ -791,6 +839,7 @@ surfaces. | Activation observation | Readiness disposition | | --- | --- | + | Runtime activation identified | Add required `RuntimeActivationIdentified` over the resolved logical-runtime and unique-incarnation ids. OpenClaw-generated defaults preserve zero-configuration local behavior; host-supplied values make readiness attributable across restarts and replicas. | | Effective configuration resolved | Strengthen `ConfigLoaded` so `True` means the validated effective runtime snapshot is installed, not merely that a source file parsed. Use `ConfigNotLoaded`, `ConfigInvalid`, or `EffectiveConfigUnavailable` when that cannot be established. | | Hosting profile applied | Covered by required `ProfileSelected`; the reported profile is the effective value after flag, environment, config, and default precedence. | | Required plugins activated | Keep general `PluginsLoaded` advisory for compatibility, but add required `RequiredPluginsActivated` when a standard or operator profile names a plugin/provider as required. Missing, failed, or unavailable required activation must block readiness. | @@ -939,6 +988,7 @@ This first stack proves the core ready/result shape, explicit profile selection, built-in profile composition from reusable criteria, exact built-in container/reverse-proxy predicates, and node-mode rules backed by the live node registry. It does not yet implement the newly reconciled +`RuntimeActivationIdentified`, the activation summary, `RequiredPluginsActivated`, `RequiredSecretsAvailable`, or `ModelRoutingResolved` activation conditions, nor the artifact identity and profile-conformance conditions. Those remain completion work before the @@ -961,6 +1011,9 @@ The proposal does not require one all-or-nothing implementation landing: same canonical result. 6. Add the optional `openclaw ready` CLI projection over the canonical live Gateway result. +7. Add runtime/incarnation identity resolution, the required + `RuntimeActivationIdentified` condition, and the redacted activation summary + shared by readiness, health, and status. After contract acceptance and successful packaged Docker proof, a separate follow-up can make the profile matrix a blocking package-acceptance release From 4cb5132d92b71a0e9adfdd6f8f00d849962b4116 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 11 Jul 2026 20:15:26 -0700 Subject: [PATCH 45/98] docs(rfc): link runtime activation slice --- rfcs/0018-standard-hosting-profiles-and-ready-check.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/rfcs/0018-standard-hosting-profiles-and-ready-check.md b/rfcs/0018-standard-hosting-profiles-and-ready-check.md index 17de899f..8df8a727 100644 --- a/rfcs/0018-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0018-standard-hosting-profiles-and-ready-check.md @@ -927,6 +927,7 @@ conditions before adding profile-specific conditions: | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5723f664`) | | Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`399cf745`) | | Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`fe4c51c1`) | +| Runtime activation identity | https://github.com/giodl73-repo/openclaw/pull/42 | `user/giodl/hosting-runtime-activation` (`f4da151a2d1`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime @@ -956,6 +957,11 @@ branches but not yet promoted into blocking package-acceptance release checks: preserves the canonical successful result; and exit status fails closed for required failures, unknowns, transport errors, or a missing readiness contract. Advisory findings remain visible without changing exit success. +- PR 42 adds logical-runtime and process/container incarnation identity to the + live canonical result. Hosts may supply stable values through CLI or + environment; local runs remain zero-configuration, generated incarnations + survive in-process Gateway restarts, and invalid explicit identities fail + startup rather than silently falling back. The Docker planner resolves the lane with both package and functional-image requirements, and its existing 33 planner assertions remain green. After the @@ -987,8 +993,8 @@ contract. This first stack proves the core ready/result shape, explicit profile selection, built-in profile composition from reusable criteria, exact built-in container/reverse-proxy predicates, and node-mode rules backed by the -live node registry. It does not yet implement the newly reconciled -`RuntimeActivationIdentified`, the activation summary, +live node registry. PR 42 implements `RuntimeActivationIdentified` and the +activation summary. The stack does not yet implement the newly reconciled `RequiredPluginsActivated`, `RequiredSecretsAvailable`, or `ModelRoutingResolved` activation conditions, nor the artifact identity and profile-conformance conditions. Those remain completion work before the From 61eaa1ed0ba808c2a973e0ef635eb478d3905b06 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 11 Jul 2026 20:45:37 -0700 Subject: [PATCH 46/98] docs(rfc): refresh activation slice head --- rfcs/0018-standard-hosting-profiles-and-ready-check.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0018-standard-hosting-profiles-and-ready-check.md b/rfcs/0018-standard-hosting-profiles-and-ready-check.md index 8df8a727..108fb77e 100644 --- a/rfcs/0018-standard-hosting-profiles-and-ready-check.md +++ b/rfcs/0018-standard-hosting-profiles-and-ready-check.md @@ -927,7 +927,7 @@ conditions before adding profile-specific conditions: | Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5723f664`) | | Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`399cf745`) | | Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`fe4c51c1`) | -| Runtime activation identity | https://github.com/giodl73-repo/openclaw/pull/42 | `user/giodl/hosting-runtime-activation` (`f4da151a2d1`) | +| Runtime activation identity | https://github.com/giodl73-repo/openclaw/pull/42 | `user/giodl/hosting-runtime-activation` (`400cf831997`) | The stack includes one package-installed Docker conformance lane, `pnpm test:docker:hosting-profiles`, built incrementally across the runtime From e6dd2fe92c2422948492704cebcfe6861f7a6e65 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Tue, 14 Jul 2026 08:23:24 -0700 Subject: [PATCH 47/98] Split readiness conditions from hosting profiles --- ...0018-readiness-conditions-and-providers.md | 390 ++++++ ...andard-hosting-profiles-and-ready-check.md | 1074 ----------------- 2 files changed, 390 insertions(+), 1074 deletions(-) create mode 100644 rfcs/0018-readiness-conditions-and-providers.md delete mode 100644 rfcs/0018-standard-hosting-profiles-and-ready-check.md diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md new file mode 100644 index 00000000..3531728c --- /dev/null +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -0,0 +1,390 @@ +--- +title: Readiness Conditions and Providers +authors: + - Gio +created: 2026-07-09 +last_updated: 2026-07-14 +status: draft +issue: +rfc_pr: https://github.com/openclaw/rfcs/pull/33 +--- + +# Proposal: Readiness Conditions and Providers + +## Summary + +Modernize OpenClaw's existing Gateway readiness evaluator into one canonical, +structured condition result. Existing startup, drain, channel, and event-loop +observations become core conditions; activated plugins may register bounded, +observational readiness providers; and `/ready`, `/readyz`, health, status, and +an optional CLI project the same result. + +This RFC does not define hosting profiles. Standard Hosting Profiles are a +separate proposal that may compose conditions from this RFC into named support +contracts. + +## Motivation + +OpenClaw already exposes Gateway `/ready` and `/readyz`. Their fixed evaluator +answers important questions about startup, channel runtime health, drain state, +and event-loop health, but it is not an extensible readiness contract: + +- existing observations do not share an iterable condition shape; +- plugins cannot contribute bounded readiness observations; +- operators cannot promote a known plugin dependency to required; +- health and status can omit facts or describe them differently; and +- hosts must interpret legacy fields and add private scripts for missing facts. + +The result is avoidable ambiguity. A process may respond while its workspace is +full, startup dependencies are pending, the Gateway is draining, or a required +plugin-owned backend is unavailable. These are readiness questions, not new +liveness endpoints and not reasons for each host to invent a private protocol. + +The proposed invariant is: + +```text +core Gateway observations ++ core runtime observations ++ activated plugin-provider observations +-> one canonical readiness result +-> /ready, /readyz, health, status, optional CLI +``` + +Required `False` or `Unknown` conditions fail readiness. Advisory conditions +remain visible without causing an outage. Existing installations preserve their +current readiness behavior unless an operator explicitly requires an additional +provider condition. + +### Evidence from existing issues + +| Issue | Observed gap | Contract implication | +| --- | --- | --- | +| [openclaw#96084](https://github.com/openclaw/openclaw/issues/96084) | `/readyz` remains healthy when a PVC-backed workspace is full. | Workspace writability needs a bounded readiness condition. | +| [openclaw#78136](https://github.com/openclaw/openclaw/issues/78136) | Docker readiness remains healthy while the command queue is draining. | Admission state must remain a required readiness input. | +| [openclaw#73652](https://github.com/openclaw/openclaw/issues/73652) | The Gateway accepts connections before internal startup is ready. | Startup completion needs a stable required condition. | +| [openclaw#78954](https://github.com/openclaw/openclaw/issues/78954) | Channel/plugin sidecars can block a usable core Gateway. | Readiness needs explicit required versus advisory classification. | +| [openclaw#101083](https://github.com/openclaw/openclaw/issues/101083) | A channel can appear healthy while retrying a fatal login error. | Channel runtime truth should use the canonical result. | + +## Goals + +- Define one stable readiness-condition shape and aggregation rule. +- Normalize existing Gateway readiness observations into core conditions. +- Preserve existing response fields as compatibility projections. +- Add activation-scoped plugin readiness providers through the plugin SDK. +- Keep provider execution bounded, observational, enumerable, and fail-closed. +- Let operators explicitly select additional registered core or plugin + criteria as required or advisory without selecting a hosting profile. +- Project one result through HTTP readiness, health, status, and an optional + `openclaw ready` command. +- Add missing runtime status facts alongside conditions rather than creating a + parallel evidence store. +- Keep detailed readiness output authenticated or local while preserving the + compact unauthenticated probe response. + +## Non-Goals + +- Define standard or custom hosting profiles. +- Add profile selection, profile inheritance, or release profile conformance. +- Replace `openclaw.json` or create a second configuration system. +- Define OCC resources, placement, tenants, or an AgentHarness protocol. +- Make readiness depend on Doctor, policy, telemetry, or another optional + subsystem. +- Permit arbitrary runtime code, shell commands, or remote probes in config. +- Make readiness prove checkpoint durability, safe shutdown, compatibility, or + safe destruction. +- Standardize Docker, Kubernetes, or systemd probe intervals and retries. + +## Proposal + +### Canonical condition model + +Every readiness observation is represented as: + +```ts +type ReadinessConditionStatus = "True" | "False" | "Unknown"; +type ReadinessRequirement = "required" | "advisory"; + +type ReadinessCondition = { + type: string; + status: ReadinessConditionStatus; + requirement: ReadinessRequirement; + reason: string; + message: string; +}; + +type ReadinessResult = { + ready: boolean; + conditions: ReadinessCondition[]; + failures: string[]; + advisories: string[]; +}; +``` + +`type` is stable machine identity. `reason` is a stable machine-readable state +or failure reason. `message` is redacted operator guidance and is not part of +machine matching. + +Aggregation is deliberately simple: + +| Requirement | Effect of `False` or `Unknown` | +| --- | --- | +| `required` | `ready=false`; reason appears in `failures`. | +| `advisory` | Overall readiness is unchanged; reason appears in `advisories`. | + +An unobserved required fact is `Unknown`, never inferred as `True`. Duplicate +condition identities, invalid statuses, or malformed provider results are +converted to stable `Unknown` conditions or reject provider registration; they +must not disappear from the result. + +### Core conditions + +The first implementation normalizes the observations already owned by the +Gateway and adds generally applicable runtime facts where source evidence +justifies them. + +| Condition | Requirement | True when | Stable non-ready reasons | +| --- | --- | --- | --- | +| `GatewayStartupComplete` | Required | Startup dependencies and startup sidecars are no longer pending. | `GatewayStartupPending` | +| `GatewayAcceptingWork` | Required | The Gateway is not draining and can admit new work. | `GatewayDraining` | +| `ChannelRuntimeReady` | Required | No selected channel has an unsuppressed runtime-health failure under existing channel policy. | `ChannelRuntimeUnavailable` | +| `ChannelRuntimeSuppressed` | Advisory when present | A channel runtime failure is intentionally suppressed by existing autostart/crash-loop policy. | `ChannelRuntimeSuppressed` | +| `EventLoopHealthy` | Advisory initially | Existing event-loop health is within its healthy threshold. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | +| `GatewayResponding` | Required when observed remotely | The current operation successfully reached the live Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | +| `ConfigLoaded` | Required | The validated effective runtime config snapshot is installed. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | +| `WorkspaceWritable` | Required or advisory when selected | The effective workspace passes a bounded write, flush, and cleanup probe. It is not a new universal blocker by default. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | +| `PluginsLoaded` | Advisory | The activation-pinned plugin registry is available and selected plugins have no activation errors. | `PluginLoadFailures`, `PluginStatusUnavailable` | + +Changing an advisory core condition to required is a compatibility-sensitive +behavior change. It requires focused review and release notes because it can +change `/ready` from `200` to `503` for an existing deployment. + +Further startup facts such as required plugin activation, required secret +availability, or resolved model routing should use the same condition model, +but only after their owners expose bounded, redacted activation snapshots. +Readiness polling must not reload plugins, reacquire secrets, or issue a model +request. + +### Readiness providers + +Only an activated OpenClaw plugin can register executable provider code. Core +conditions continue to use internal evaluators. Operators and control planes +may reference provider IDs; they cannot inject callbacks through config. + +```ts +type PluginReadinessResult = { + status: "True" | "False" | "Unknown"; + reason: string; + message: string; +}; + +type PluginReadinessProvider = { + id: string; + description: string; + check(context: { + config: OpenClawConfig; + pluginConfig: unknown; + signal: AbortSignal; + }): Promise | PluginReadinessResult; +}; + +type RegisterReadinessCriterion = ( + provider: PluginReadinessProvider, +) => void; +``` + +Example: + +```ts +api.registerReadinessCriterion({ + id: "backend", + description: "Reports whether the plugin backend can accept work.", + async check({ pluginConfig, signal }) { + return (await probeBackend(pluginConfig, { signal })) + ? { + status: "True", + reason: "BackendReady", + message: "Backend is reachable.", + } + : { + status: "False", + reason: "BackendUnavailable", + message: "Backend is unreachable.", + }; + }, +}); +``` + +Core publishes the condition as `plugin..backend`. Registration is +bound to the activated plugin registry snapshot. Reload replaces the complete +provider set atomically with the next activation; stale callbacks do not remain +registered. + +Provider descriptors are enumerable without exposing callbacks. Status and +future diagnostics can list provider identity, description, owning plugin, and +activation generation without executing the provider. + +Providers must be: + +- read-only and observational; +- idempotent under repeated invocation; +- safe under concurrent invocation or protected by core coalescing; +- cancellation-aware; +- free of blocking synchronous I/O; and +- redacted by construction. + +Core owns namespacing, validation, invocation, deadlines, cancellation, +coalescing, caching, error conversion, and result ordering. A provider cannot +alter another provider's condition or any core condition. + +### Operator-selected readiness conditions + +OpenClaw's universal Gateway lifecycle conditions always apply and cannot be +removed. Beyond that baseline, an operator may explicitly select registered +core or plugin criteria through Gateway readiness config without selecting a +hosting profile: + +```json5 +{ + gateway: { + readiness: { + requiredCriteria: [ + "openclaw.workspace-writable", + "plugin.storage.backend", + ], + advisoryCriteria: ["plugin.metrics.exporter"], + }, + }, +} +``` + +Provider criteria are advisory unless selected as required. Unknown selected +IDs fail validation or produce required `Unknown` during activation; they +cannot be silently ignored. Configuration changes are applied through the +normal validated config lifecycle. This RFC does not add a policy language or +a way to redefine criteria semantics. + +This explicit list is a complete standalone use of RFC 0018. An operator can +say exactly which additional observations must pass for its deployment without +creating or selecting a profile. RFC 0023 adds reusable, named, release-tested +presets over the same selection mechanism. + +### Bounded evaluation + +Readiness is a hot operational endpoint and must return within code-owned +limits even when a provider is slow or broken. + +The initial implementation uses layered bounds: + +- a one-second deadline per plugin provider; +- a one-second deadline for the workspace probe; +- concurrent evaluation of independent observations; +- cancellation signals for cooperative providers; and +- an independent two-second outer watchdog for the complete result. + +A timeout becomes `Unknown` with a stable reason. A required timeout returns +`503`; an advisory timeout remains visible without blocking. The outer watchdog +fails closed rather than allowing `/ready` or `/readyz` to hang. + +In-process timers cannot interrupt synchronous JavaScript that blocks the event +loop. Providers therefore may not perform blocking synchronous I/O. Process or +worker isolation for malicious plugins is outside this RFC. + +### Canonical projections + +`/ready` and `/readyz` remain the authoritative host probes. Authenticated or +local callers receive the structured result; unauthenticated remote probes +retain a redacted boolean response. `HEAD` behavior remains unchanged. + +The same result is projected through Gateway health and status. A surface that +did not observe a required live fact reports `Unknown`; it does not synthesize +success. `/health` and `/healthz` remain shallow liveness and do not acquire +readiness semantics. + +An optional `openclaw ready` command may be a thin client of the live Gateway +result: + +- human output lists non-`True` conditions; +- `--json` preserves the canonical result; and +- exit status is nonzero for required failure, required unknown, transport + failure, or a missing readiness contract. + +The CLI must not implement a second evaluator. + +### Compatibility + +Existing `ready`, `failing`, `suppressed`, `eventLoop`, and `uptimeMs` fields +remain compatibility projections during migration. New consumers use +`conditions`, `failures`, and `advisories`. + +The migration order is: + +1. emit canonical conditions beside legacy fields; +2. make every projection consume the same canonical evaluator; +3. migrate internal and external consumers; and +4. consider legacy-field removal only through a separate compatibility review. + +Existing installations gain structured output but do not gain new required +workspace or plugin dependencies. Registering or implementing an additional +criterion does not make it required. Only explicit operator configuration or a +separately selected standard profile changes the additional readiness gate. + +### Readiness transitions + +A later implementation may emit bounded, redacted events when overall +readiness or a condition changes. Event names, initial observation, +deduplication, restart behavior, and behavior without active polling require a +separate review. Telemetry sinks, dashboards, alerting, and retention remain +host responsibilities. + +### Relationship to Standard Hosting Profiles + +Standard Hosting Profiles depend on this RFC rather than sharing its acceptance +decision. A profile is a named preset of required and advisory criteria plus a +support promise. It cannot change condition evaluation, provider lifecycle, or +aggregation. Operators that do not need that support contract use +`gateway.readiness` directly. + +This separation allows OpenClaw to accept structured readiness and provider +extensibility without committing to profile names, profile selection config, +runtime activation identity, or a release support matrix. + +### Implementation plan + +The draft implementation will be restacked into a readiness-only series: + +| Slice | Draft PR | Intended scope | +| --- | --- | --- | +| Canonical core conditions | [PR 17](https://github.com/giodl73-repo/openclaw/pull/17) | Normalize existing Gateway observations and compatibility projections. | +| Workspace readiness | [PR 22](https://github.com/giodl73-repo/openclaw/pull/22) | Add the bounded `WorkspaceWritable` condition without profile behavior. | +| Readiness providers | [PR 23](https://github.com/giodl73-repo/openclaw/pull/23) | Add activation-scoped provider registration and operator-required criteria, without custom profiles. | +| Canonical readiness CLI | [PR 27](https://github.com/giodl73-repo/openclaw/pull/27) | Add a thin CLI projection of the live result. | + +Profile selection, node-mode composition, activation identity, and packaged +profile release conformance move to the Standard Hosting Profiles RFC and its +separate implementation stack. + +## Rationale + +This extends a surface OpenClaw already owns. It does not add a new health +service, policy engine, or hosted envelope. Conditions make the current +evaluator explainable; providers give plugin-owned dependencies a bounded home; +and canonical projections prevent HTTP, status, health, and CLI from drifting. + +Keeping providers advisory by default is the critical compatibility rule. A +plugin can improve diagnostics without gaining the power to take down the +Gateway. Operators retain the explicit decision to make a dependency required. + +Separating profiles keeps this RFC independently useful and easier to accept. +OpenClaw can modernize readiness first, then decide separately whether named +runtime postures should become release-tested support promises. + +## Unresolved questions + +- Is `gateway.readiness` the correct config home for operator-required provider + IDs, or should requirement selection use another existing Gateway surface? +- Which existing advisory observations, if any, should become required in the + first compatibility-reviewed implementation? +- Should any non-plugin core owner need a public registration API, or should + core conditions remain internal evaluators? +- What cache lifetime best balances probe cost and freshness for plugin + providers? diff --git a/rfcs/0018-standard-hosting-profiles-and-ready-check.md b/rfcs/0018-standard-hosting-profiles-and-ready-check.md deleted file mode 100644 index 108fb77e..00000000 --- a/rfcs/0018-standard-hosting-profiles-and-ready-check.md +++ /dev/null @@ -1,1074 +0,0 @@ ---- -title: Readiness Conditions and Standard Hosting Profiles -authors: - - Gio -created: 2026-07-09 -last_updated: 2026-07-10 -status: draft -issue: -rfc_pr: https://github.com/openclaw/rfcs/pull/33 ---- - -# Proposal: Readiness Conditions and Standard Hosting Profiles - -## Summary - -Add a canonical readiness-condition model and project one result through -Gateway `/ready`, `/readyz`, health, and status. Normalize existing fixed -Gateway signals into core conditions, let plugins publish additional conditions -through readiness providers, and let standard hosting profiles compose -conditions into named, OpenClaw-owned, release-tested support contracts. The -condition model is independently useful without selecting a non-default -profile, and profiles do not add a second config system, generate config, or -replace existing Gateway readiness. - -## Motivation - -OpenClaw can be hosted today and already exposes Gateway `/ready` and `/readyz`. -Those probes cover Gateway startup, channel runtime health, drain state, and -event-loop health. What they do not identify is the selected hosting model or -the config/runtime predicates that make that model supportable. Hosts therefore -cannot answer one higher-level question before routing traffic: - -```text -Is this OpenClaw instance ready under the hosting profile it was started with? -``` - -Today this readiness surface is a purpose-built, Gateway-owned evaluator over a -fixed set of lifecycle signals. It is not a general readiness framework: -plugins cannot register readiness callbacks, operators cannot enumerate or -compose reusable criteria, and releases do not validate named hosting profiles. -This RFC preserves the existing evaluator as an authoritative required input -and adds a provider and composition contract around it: - -```text -existing fixed Gateway readiness -+ standard-profile conditions -+ plugin-provider conditions --> canonical /ready and /readyz result -``` - -The proposal does not move existing lifecycle checks into plugins or permit a -profile to weaken, replace, or bypass them. - -Without that contract, downstream hosts compensate with private startup checks, -baked config, environment restore lists, persistence wrappers, and adapter-only -readiness logic. That makes hosted OpenClaw harder to test upstream and harder -to upgrade downstream. - -A concrete example is a container that starts successfully with a loopback-only -Gateway. Existing lifecycle readiness can correctly report that the process is -healthy while the selected container topology is unusable from outside the -container. The missing information is not another liveness probe; it is the -runtime assertion that this process satisfies the container support contract. - -Profiles turn the broad claim "OpenClaw supports hosted deployments" into a -reviewable support matrix and a supportable subset that issues can be validated -against: - -```text -OpenClaw supports these profiles. -Each profile has stable readiness conditions. -Each release can test those conditions. -Hosts can prove which profile they are running. -``` - -This gives bug reports and release tests a reproducible starting point. Instead -of debugging an unbounded hosted configuration, maintainers can ask for the -selected profile and its stable condition result. Profiles complement maturity -work by turning a support claim into executable release evidence. - -### Evidence From Existing Issues - -The proposal generalizes recurring operator failures already reported against -OpenClaw. The issues ask for truthful readiness under additional runtime facts; -they do not require each fact to introduce a new hosting profile. - -| Issue | Observed gap | Contract implication | -| --- | --- | --- | -| [openclaw#96084](https://github.com/openclaw/openclaw/issues/96084) | `/readyz` remains healthy when a PVC-backed workspace is full and writes fail with `ENOSPC`. | Workspace writability should be an observable status fact with a stable readiness condition. | -| [openclaw#78136](https://github.com/openclaw/openclaw/issues/78136) | Docker health and readiness remain healthy while the command queue is draining and rejects model work. | Admission/drain state must participate in required readiness, not only process liveness. | -| [openclaw#73652](https://github.com/openclaw/openclaw/issues/73652) | The Gateway accepts connections before internal startup is ready. | Readiness must represent the actual startup admission boundary. | -| [openclaw#78954](https://github.com/openclaw/openclaw/issues/78954) | Channel/plugin sidecars can block reaching a usable core Gateway state. | Conditions need required versus advisory classification. | -| [openclaw#43886](https://github.com/openclaw/openclaw/issues/43886) | A Docker Gateway configured for LAN still listens on loopback. | Container readiness must evaluate effective bind state rather than configured intent alone. | - -Other reports show the same need at additional projections: systemd can declare -the service started before Gateway readiness -([openclaw#66512](https://github.com/openclaw/openclaw/issues/66512)), and a -channel can report healthy while retrying a fatal login error -([openclaw#101083](https://github.com/openclaw/openclaw/issues/101083)). One -canonical condition result lets HTTP probes, status, service managers, and -future telemetry consume the same runtime truth. - -## Goals - -- Define built-in hosting profiles for `local`, `container`, `reverse-proxy`, - and `node-mode`. -- Make `local` the default profile when no profile is selected. -- Add a canonical readiness result with stable condition `type`, `status`, - `reason`, and human-readable `message`. -- Expose the same readiness result through existing HTTP readiness, status, and - health surfaces. -- Add explicit profile selection through config, environment, and Gateway - startup. -- Let a hosting profile declare the minimal activation facts required for its - supported runtime shape, and report the resolved runtime activation identity - through readiness and status. -- Keep OpenClaw generic: no Lobster, Scout, Microsoft, tenant, Teams, Kusto, or - product-specific host concepts. -- Keep the first implementation in core so readiness works without optional - plugins. -- Define the requirement class, exact truth predicates, and stable non-ready - reasons for every built-in profile condition. -- Let plugins register namespaced advisory criteria through the existing plugin - lifecycle, and let operators promote them only through additive custom - profiles. -- Make readiness providers enumerable and self-describing so status, operators, - and future doctor tooling can discover the active criterion catalog. -- Leave room for later doctor/lint conformance findings that recommend fixes - for config that does not match the selected built-in profile. - -## Non-Goals - -- Replace `openclaw.json`. -- Define OCC resources or require OCC before hosted readiness works. -- Define the remote AgentHarness event protocol. -- Standardize a host's storage backend, auth provider, telemetry sink, tenant - routing, UI, deployment system, or worker-pool model. -- Define an OCC-style instance resource, placement model, replica identity, or - tenant lifecycle API. -- Put assistant deltas, tool frames, approvals, patches, compaction events, or - harness protocol frames into the hosting contract. -- Allow arbitrary operator-defined conditions to redefine built-in profile - semantics or built-in condition names. -- Encode host-specific probe intervals, retries, start periods, or timeout - values into OpenClaw profile config. -- Make readiness depend on doctor, lint, policy, or another optional - conformance layer. - -## Proposal - -The RFC has two pieces that can be reviewed together or split if maintainers -prefer: - -1. Standard hosting profiles: named support contracts for the OpenClaw runtime. -2. A canonical ready check: a host-facing pass/fail surface for the selected - profile. - -These pieces compose but are separable. The canonical condition/result model -is useful without adding any non-default profile. A generally required runtime -invariant, such as accepting work rather than draining, can extend existing -Gateway readiness. A new OpenClaw-owned fact, such as workspace writability, -can add a criterion to the existing `local` contract inherited by the hosted -profiles. Neither change requires defining a new profile. - -A new profile is justified only when OpenClaw wants to name and release-test a -distinct support posture that selects a different composition or requirement -class for existing criteria. Profiles organize readiness criteria into support -contracts; they are not the extension mechanism for every readiness fix. - -OpenClaw should expose a standard hostee contract: - -```text -profile selection -+ validated runtime activation context -+ runtime status/config facts -+ readiness condition evaluation --> ready/not-ready result -``` - -Five constraints keep this narrow: - -1. A profile does not write, merge, or repair configuration. -2. Operators may continue to configure every OpenClaw setting directly. -3. Profile readiness is an additional conjunction with existing Gateway - readiness, never a replacement for it. -4. Built-in profiles evaluate facts owned by OpenClaw core. Plugins may publish - advisory namespaced criteria; only an operator-defined profile can make one - required. Policy and doctor may consume the result but are not dependencies. -5. Only required conditions affect the binary ready result. Advisory conditions - remain visible without turning a useful diagnostic into an outage. - -The runtime activation context is the small entry point into this contract. It -identifies this activation and references the configuration, host integration, -and restore inputs selected by the launcher. It does not duplicate those -systems' data. Each referenced owner validates and activates its own input, -publishes its own status evidence, and contributes readiness conditions. The -profile only declares which activation facts and resulting conditions are -required for the named support posture. - -The contract is not a parallel hosted config tree. Existing OpenClaw config -continues to own Gateway, proxy, plugin, model, session, node, and state -behavior. A hosting profile decides which existing runtime status/config facts -must be true before the instance is considered ready. If a criterion needs a -fact that status does not expose yet, the implementation should add that -missing status field. Plugin-owned dependencies use the readiness registration -contract below rather than a host-specific endpoint or global evidence store. - -### Standard profiles - -OpenClaw should ship a small catalog of standard profile definitions rather -than ask every host to invent one. Operators can still configure the underlying -OpenClaw settings; the profile names the support contract. These profiles are -implemented in core, which is why the schema calls their ids "built-in," but -their product role is to be OpenClaw's documented and release-gated standard -profiles. - -A profile names the expected ingress/runtime posture, not the packaging -technology. A Gateway directly reachable through its container listener uses -`container`. A Gateway in a container behind a trusted identity proxy uses -`reverse-proxy`. New profile names should be added only when they define a -distinct OpenClaw-owned invariant and conformance scenario. - -Profiles should be declarative compositions of reusable readiness criteria. A -built-in profile references reserved OpenClaw condition ids. Each criterion -is a named rule over OpenClaw runtime status/config fields and has one -OpenClaw-owned evaluator that emits the runtime readiness condition. - -| Profile | Purpose | Built-in criteria | Status fields read | Emitted readiness signals | -| --- | --- | --- | --- | --- | -| `local` | Developer/local foreground process readiness. | `RuntimeActivationIdentified`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, `PluginsLoaded`, release-evidence conditions, plus `RequiredPluginsActivated` when required activation is declared | resolved runtime/incarnation identity, effective runtime config and secrets snapshots, model-route resolution, default workspace write evidence, Gateway reachability, selected plugin activation status, packaged artifact identity/conformance metadata | Required: `ProfileSelected`, `RuntimeActivationIdentified`, `ConfigLoaded`, `RequiredSecretsAvailable`, `ModelRoutingResolved`, `WorkspaceWritable`, `GatewayResponding`, and any declared `RequiredPluginsActivated`. Advisory by default: general `PluginsLoaded`, `ArtifactIdentityAvailable`, and `SelectedProfileConformant`. `ExpectedArtifactMatched` is required when a host supplies an expectation. | -| `container` | One OpenClaw service hosted by Docker, Compose, or a similar supervisor. | `local` + `ContainerStateReady` | effective Gateway mode, resolved bind host, and port | Core signals plus `ContainerStateReady`. | -| `reverse-proxy` | Gateway running behind a trusted reverse proxy. | `local` + `TrustedProxyReady` | Gateway trusted-proxy auth config | Core signals plus `TrustedProxyReady`. | -| `node-mode` | Gateway/controller for one or more controlled execution nodes. | `local` + `NodePairingReady`, `ControlledTargetsReady`, `CommandApprovalReady`, `ControlChannelReady` | pairing store, live node registry, paired command grants, `gateway.nodes.allowCommands` | Core signals plus the four node-mode conditions. | - -`node-mode` must stay product-neutral. A controlled target can be a desktop, -sandbox, VM, pod, browser, or another execution surface. OpenClaw should not -assume one node maps to exactly one target. - -### Built-in truth predicates - -Profile readiness is composed with, and does not replace, the existing Gateway -readiness result. Final `/ready` and `/readyz` readiness is true only when the -existing startup/channel/drain/event-loop evaluation is ready and every -required condition listed for the selected profile is `True`. `False` and -`Unknown` required conditions block profile readiness. Non-`True` advisory -conditions are reported but do not change the binary result. - -The condition contract and aggregation rules are shared across surfaces; the -observed status may differ with probe depth and observation time. A status -surface that did not observe a required fact reports `Unknown` and cannot claim -ready. A status operation that successfully probes the Gateway may project that -observation as `True`. Missing required evidence must never become a positive -readiness result. - -| Condition | Requirement | True when | Stable non-ready reasons | -| --- | --- | --- | --- | -| `GatewayStartupComplete` | Required | Gateway startup dependencies and startup sidecars are no longer pending. | `GatewayStartupPending` | -| `GatewayAcceptingWork` | Required | The Gateway is not draining and can admit new work. | `GatewayDraining` | -| `ChannelRuntimeReady` | Required | No selected channel has an unsuppressed runtime-health failure under the existing channel readiness policy. | `ChannelRuntimeUnavailable` | -| `ChannelRuntimeSuppressed` | Advisory when present | One or more channel runtime failures are intentionally suppressed by the existing autostart/crash-loop policy. | `ChannelRuntimeSuppressed` | -| `EventLoopHealthy` | Advisory | The existing event-loop health observation is within its healthy threshold. It remains advisory unless a separate compatibility-reviewed change intentionally makes it gate readiness. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | -| `ProfileSelected` | Required | The runtime resolved and reports the selected built-in or configured custom profile. The default is `local`. | None; invalid explicit values fail selection before startup. | -| `RuntimeActivationIdentified` | Required | The runtime has resolved non-empty logical-runtime and unique-incarnation identities. OpenClaw-generated local defaults satisfy this condition when the launcher supplies neither value. | `RuntimeIdentityInvalid`, `IncarnationIdentityInvalid`, `ActivationIdentityUnavailable` | -| `ConfigLoaded` | Required | The validated effective runtime configuration snapshot is installed after normal precedence and activation processing; parsing a source file alone is insufficient. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | -| `RequiredPluginsActivated` | Required when a standard or operator profile declares required plugin/provider activation | Every declared required plugin/provider is present and activated without an activation error. General selected-plugin health remains advisory through `PluginsLoaded`. | `RequiredPluginMissing`, `RequiredPluginActivationFailed`, `RequiredPluginStatusUnavailable` | -| `RequiredSecretsAvailable` | Required | Every secret declared startup-required by the selected profile or effective runtime route is available in the installed redacted secrets snapshot. Optional and lazy credentials do not block readiness. | `RequiredSecretMissing`, `RequiredSecretActivationFailed`, `RequiredSecretStatusUnavailable` | -| `ModelRoutingResolved` | Required when the selected runtime role accepts agent work | The effective default or selected model route resolves to a configured provider after config and secret activation. Evaluation reads the startup snapshot and does not issue a model request. | `ModelRouteMissing`, `ModelProviderUnavailable`, `ModelRouteStatusUnavailable` | -| `ArtifactIdentityAvailable` | Advisory by default | The runtime can report a stable packaged artifact identity containing at least OpenClaw version and build/package identity. Source and development runs may report `Unknown` without becoming unready. | `ArtifactIdentityUnavailable`, `DevelopmentArtifact` | -| `SelectedProfileConformant` | Advisory by default; operator profiles may promote it to required | Embedded release evidence is bound to the running artifact identity and records a passing packaged conformance result for the selected standard profile and condition-contract version. It does not rerun conformance at readiness time. | `ProfileConformanceMissing`, `ProfileConformanceFailed`, `ProfileConformanceStale`, `ProfileConformanceArtifactMismatch` | -| `ExpectedArtifactMatched` | Required when the host supplies an expected artifact identity | The running artifact identity matches the immutable identity selected by the host for this deployment. Absence of a host expectation omits the condition. | `ExpectedArtifactMismatch`, `ExpectedArtifactNotVerifiable` | -| `RequiredClawBusCapabilitiesAvailable` | Required when the selected standard or operator profile declares hosted duplex capabilities | The active generation-bound ClawBus peer negotiated every required canonical OpenClaw family/provider ID and version. It reads the live negotiated session snapshot and does not probe the remote service on every readiness call. | `ClawBusUnavailable`, `ClawBusGenerationMismatch`, `ClawBusCapabilityMissing`, `ClawBusStatusUnavailable` | -| `WorkspaceWritable` | Required for all built-in profiles | The running Gateway resolves the effective default-agent workspace and completes a write, flush, and cleanup probe. The probe is cached and coalesced so readiness polling does not cause unbounded filesystem work. Non-probing command fallbacks do not invent positive evidence. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | -| `GatewayResponding` | Required | The running Gateway is evaluating its own readiness request, or the current status/health operation successfully probed that Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | -| `PluginsLoaded` | Advisory | The Gateway-pinned plugin registry is available and every selected plugin has no activation error. Explicitly disabled plugins do not report an advisory. | `PluginLoadFailures`, `PluginStatusUnavailable` | -| `ContainerStateReady` | Required for `container` | The effective Gateway mode is `local` and the resolved listener host is not loopback. The port has already passed normal config validation. Config-only status reports `Unknown` when an `auto` bind has not been resolved. | `ContainerGatewayRemote`, `ContainerGatewayLoopback`, `ContainerBindNotResolved` | -| `TrustedProxyReady` | Required for `reverse-proxy` | Auth mode is `trusted-proxy`, `trustedProxy.userHeader` is non-empty, and `gateway.trustedProxies` contains at least one address/CIDR. Loopback is valid for a same-host proxy. | `TrustedProxyAuthMissing`, `TrustedProxyHeaderMissing`, `TrustedProxySourcesMissing` | -| `NodePairingReady` | Required for `node-mode` | The pairing store is readable and contains at least one approved pairing. | `NodePairingUnavailable`, `NodePairingTimedOut`, `NodePairingPending`, `NodePairingMissing` | -| `ControlledTargetsReady` | Required for `node-mode` | The live Gateway node registry contains at least one connected node whose id is approved in the pairing store. Persisted pairing alone is insufficient. | `ControlledTargetsDisconnected` | -| `CommandApprovalReady` | Required for `node-mode` | A connected paired node advertises at least one command that is granted by pairing or `gateway.nodes.allowCommands` and not removed by `gateway.nodes.denyCommands`. A deny-only list is not approval evidence. | `CommandApprovalMissing` | -| `ControlChannelReady` | Required for `node-mode` | At least one connected node session is correlated to an approved pairing. Gateway HTTP responsiveness alone is insufficient. | `ControlChannelUnavailable` | - -### Packaged profile evidence - -Release conformance produces immutable metadata; readiness consumes it. The -minimum record is intentionally small: - -```ts -type HostingProfileConformanceRecord = { - schemaVersion: 1; - artifact: { - openclawVersion: string; - packageIdentity: string; - digest: string; - }; - profile: BuiltInHostingProfileId; - conditionContractVersion: number; - requiredConditionTypes: string[]; - result: "passed" | "failed"; - suiteIdentity: string; - completedAt: string; - provenance?: { - builder?: string; - sourceRevision?: string; - attestationRef?: string; - }; -}; -``` - -The release process binds the record to the same immutable package/image -identity reported by the runtime. OpenClaw validates the schema, digest, -selected profile, condition-contract version, and result before emitting -`SelectedProfileConformant=True`. Unknown fields are tolerated for forward -compatibility, but unknown schema or condition-contract versions report -`Unknown`, never success. - -The record contains no tenant, operator, secret, or runtime health data. Build -signing and attestation may protect provenance, but this RFC does not prescribe -one supply-chain system. A host that requires stronger provenance validates it -before deployment and supplies the expected immutable artifact identity; -readiness then proves only that the admitted artifact is the process now -running. - -### Profile selection - -OpenClaw should not require an explicit profile to run. If no profile is -selected, the effective profile is `local`. - -Profile selection should be visible in normal hosting mechanisms: - -- config: `hosting.profile` -- environment: `OPENCLAW_HOSTING_PROFILE` -- startup: `openclaw gateway run --hosting-profile ` - -Built-in ids are closed, while operator profiles are additive and namespaced: - -```ts -type BuiltInHostingProfileId = - | "local" - | "container" - | "reverse-proxy" - | "node-mode"; - -type OperatorHostingProfile = { - extends: BuiltInHostingProfileId; - requiredCriteria?: string[]; - advisoryCriteria?: string[]; -}; - -type RuntimeActivationIdentity = { - runtimeId: string; - incarnationId: string; -}; - -type HostingConfig = { - profile?: string; - profiles?: Record; -}; - -type OpenClawConfig = { - hosting?: HostingConfig; - // Existing OpenClaw fields remain unchanged. -}; -``` - -`hosting` and each profile definition are strict objects. Operator profile names -must match `/` using lowercase alphanumeric DNS-label-like -segments. A selected custom profile must exist in `hosting.profiles`. Each -custom profile extends exactly one built-in profile and can only add criteria; -it cannot remove or demote inherited requirements. A criterion cannot be both -required and advisory in the same profile. - -The runtime activation identity is startup metadata, not another OpenClaw -config document. `runtimeId` identifies the logical runtime across restarts; -`incarnationId` identifies one process or container execution. A launcher may -supply stable values through startup arguments, environment, or a mounted -activation descriptor. OpenClaw generates local defaults when they are absent, -so existing installations and the `local` profile remain zero-configuration. - -Configuration sources, host-bundle selection, and restore selection stay in -their owning contracts rather than being copied into this identity. Those -owners publish the effective config generation, selected bundle identity and -version, and restored state generation after successful activation. Their -readiness providers contribute the corresponding conditions, and a profile may -promote those conditions to required. This avoids a circular config-source -reference and prevents Hosting Profiles from becoming a second configuration, -integration, or continuity system. - -The environment variable and startup flag accept built-in ids or a namespaced -custom id. Runtime resolution validates a custom id against the loaded config. -The `local` default is resolved at runtime and does not need to be persisted. - -Selection precedence is deterministic: - -```text -gateway startup flag > environment > openclaw.json > local default -``` - -An invalid value from any explicitly supplied source is a startup/config error; -it must not silently fall through to a lower-priority source or to `local`. -The effective value after precedence resolution is the profile reported by all -readiness and status surfaces. - -The selected profile should be reported in `/ready`, `/readyz`, `status --json`, -and Gateway health so hosts and release tests can assert that the running -process selected the intended profile. The optional `openclaw ready` CLI -wrapper projects that same live result for operators and scripts; it does not -evaluate a second local readiness model. - -Those surfaces should also report a redacted activation summary containing the -runtime id, incarnation id, effective config generation, selected host-bundle -identity/version, and restored state generation when available. They must not -echo source contents, credentials, or host-private metadata. This makes the -ready result attributable to the exact activation being supervised. - -### Ready result - -Readiness should use Kubernetes-style conditions: - -```ts -type CoreReadinessCriterionId = - | "GatewayStartupComplete" - | "GatewayAcceptingWork" - | "ChannelRuntimeReady" - | "ChannelRuntimeSuppressed" - | "EventLoopHealthy" - | "ProfileSelected" - | "RuntimeActivationIdentified" - | "ConfigLoaded" - | "RequiredPluginsActivated" - | "RequiredSecretsAvailable" - | "ModelRoutingResolved" - | "ArtifactIdentityAvailable" - | "SelectedProfileConformant" - | "ExpectedArtifactMatched" - | "RequiredClawBusCapabilitiesAvailable" - | "WorkspaceWritable" - | "GatewayResponding" - | "PluginsLoaded" - | "ContainerStateReady" - | "TrustedProxyReady" - | "NodePairingReady" - | "ControlledTargetsReady" - | "CommandApprovalReady" - | "ControlChannelReady"; - -type HostingReadinessConditionType = - | CoreReadinessCriterionId - | (string & {}); - -type HostingReadinessCondition = { - type: HostingReadinessConditionType; - status: "True" | "False" | "Unknown"; - requirement: "required" | "advisory"; - reason: string; - message: string; -}; - -type HostingReadinessResult = { - profile: string; - activation: RuntimeActivationIdentity; - ready: boolean; - conditions: HostingReadinessCondition[]; - failures: string[]; - advisories: string[]; -}; -``` - -Every field in `HostingReadinessResult` is required whenever the result is -present; empty `conditions`, `failures`, or `advisories` are serialized as empty -arrays rather than omitted. Built-in condition types and the stable reasons in -the truth-predicate table are reserved by OpenClaw. Plugin criteria are -namespaced by core as `plugin..`. - -```jsonc -{ - "profile": "container", - "activation": { - "runtimeId": "tenant-42/scout-primary", - "incarnationId": "pod-7f9c" - }, - "ready": false, - "conditions": [ - { - "type": "ProfileSelected", - "status": "True", - "requirement": "required", - "reason": "ProfileSelected", - "message": "Runtime selected the container hosting profile." - }, - { - "type": "GatewayResponding", - "status": "False", - "requirement": "required", - "reason": "GatewayUnavailable", - "message": "Gateway did not respond to the readiness request." - } - ], - "failures": ["GatewayUnavailable"], - "advisories": [] -} -``` - -Hosts and tests should key on `type`, `status`, `requirement`, and `reason`. -`failures` is the deduplicated set of non-`True` required-condition reasons. -`advisories` is the set of non-`True` advisory-condition reasons. Existing -Gateway startup, drain, channel, and event-loop observations are projected into -the same canonical condition model rather than remaining a permanent parallel -readiness system. `message` is for operators and should remain non-normative. - -`conditions` has map semantics keyed by `type`; a built-in result contains at -most one condition of each type, and consumers must not depend on array order. -`failures` and `advisories` have deduplicated set semantics, and their order is -not contractual. Condition and reason identity is stable; `message` wording is -not. - -The object above is the one canonical public result. Transports may embed or -flatten that object exactly once, but implementations must not serialize a -second nested copy that gives consumers another contract or source of drift. - -### Transport projections - -The existing HTTP readiness envelope remains backward compatible: - -```ts -type DetailedGatewayReadyResponse = HostingReadinessResult & { - // Existing Gateway readiness fields. - ready: boolean; - failing: string[]; - suppressed?: string[]; - uptimeMs: number; - eventLoop?: GatewayEventLoopHealth; -}; - -type ReadinessEvaluationErrorResponse = { - ready: false; - failing: ["internal"]; - uptimeMs: 0; -}; - -type RedactedRemoteReadyResponse = { - ready: boolean; -}; - -type GatewayReadyHttpBody = - | DetailedGatewayReadyResponse - | ReadinessEvaluationErrorResponse - | RedactedRemoteReadyResponse; -``` - -For local or authenticated detailed `GET /ready` and `GET /readyz` requests, -the canonical fields are flattened once into this existing Gateway envelope. -`ready` is true only when every required core, profile, and selected provider -condition is `True`. `failing` and `suppressed` remain compatibility projections -of the normalized Gateway lifecycle/channel conditions; new consumers should -use `conditions`, `failures`, and `advisories`. HTTP is `200` when `ready` is -true and `503` otherwise. `HEAD` returns the same status without a body. -Unauthenticated remote probes retain the redacted shape `{ "ready": boolean }` -and do not disclose condition details. - -Normalization must preserve current behavior. Startup-pending, draining, and -unsuppressed channel failures remain required and continue to make readiness -false. Existing event-loop health is initially advisory because the current -evaluator reports it diagnostically without changing `ready`. Changing that -requirement class later requires compatibility review and release coverage. - -If readiness evaluation itself throws before it can produce the canonical -object, the existing detailed fail-closed response is -`{ "ready": false, "failing": ["internal"], "uptimeMs": 0 }`; an -unauthenticated remote caller still receives only `{ "ready": false }`. This -exception envelope is not a second readiness model and must never report ready. - -Gateway health and `status --json` embed the canonical object once: - -```ts -type HealthReadinessProjection = { - readiness?: HostingReadinessResult; -}; - -type StatusReadinessProjection = { - readiness: HostingReadinessResult; -}; -``` - -The optional health field preserves existing observation-depth and -compatibility behavior. A surface that cannot authoritatively observe required -runtime evidence must omit the result or report the affected condition as -`Unknown`; it must never invent a positive observation. When `readiness` is -present, all five canonical fields are required. Text status is a human summary -of this object and is not a separate machine-readable schema. - -### Compatibility and operational cost - -No explicit selection is required. Existing installations resolve to `local`, -and their Gateway/session/plugin configuration remains unchanged. Selecting a -profile does not enable auth, change bind addresses, install plugins, move -state, or provision nodes. It only changes which runtime-owned facts must be -true for profile readiness. - -Plugin activation errors are advisory in the default profile. They remain -visible through stable conditions and the `advisories` list without changing an -existing healthy readiness response from 200 to 503. Explicitly disabled -plugins do not report an advisory. - -This keeps the operational contract familiar to container hosts: - -```text -host supplies config and selects a supported runtime shape -OpenClaw starts using its normal config semantics -host waits for the existing readiness endpoint -readiness explains both lifecycle and profile conformance -``` - -Hosts that do not set a profile retain the existing endpoints and configuration -model, with `local` as the reported and evaluated support contract. - -### Why this belongs in core - -Doctor can explain or repair static misconfiguration, and policy can restrict -what configuration is allowed. Neither is the right owner for a workload's -live readiness contract: both are optional, while `/ready` is consumed during -startup and continuously by supervisors. Core already owns the authoritative -Gateway, plugin, proxy, pairing, and live-node facts used here. The smallest -reliable implementation is therefore a projection over those facts at the -existing core readiness boundary. - -Keeping the predicates in core also makes the support promise testable in the -OpenClaw release matrix. Downstream hosts remain responsible for tenant routing, -deployment, storage destinations, telemetry backends, and product policy. - -### Extensible criteria and operator profiles - -Built-in profile conditions remain stable and OpenClaw-owned. Operators cannot -redefine what `local`, `container`, or `node-mode` means. They can define a -namespaced profile that extends one built-in profile and adds reusable built-in -or plugin criteria. - -Plugins register self-describing observed-state providers during normal -activation: - -```ts -type PluginReadinessResult = { - status: "True" | "False" | "Unknown"; - reason: string; - message: string; -}; - -type PluginReadinessProvider = { - id: string; - description: string; - check: (context: { - config: OpenClawConfig; - pluginConfig: unknown; - signal: AbortSignal; - }) => Promise | PluginReadinessResult; -}; - -type RegisterReadinessCriterion = ( - provider: PluginReadinessProvider, -) => void; - -api.registerReadinessCriterion({ - id: "backend", - description: "Reports whether the plugin backend can accept work.", - check: async ({ config, pluginConfig, signal }) => { - // Return PluginReadinessResult. - }, -}); -``` - -`registerReadinessCriterion` is available to an activated OpenClaw plugin -through its normal `OpenClawPluginApi`. Registration installs the descriptor and -callback into the Gateway-pinned registry for that plugin activation. Core -criteria use internal core evaluators; operators, host config, and OCC do not -register executable callbacks. They only select profiles and reference full -provider ids. - -The `check` member is the provider callback. The Gateway readiness evaluator -invokes it asynchronously with the effective OpenClaw config, that plugin's -resolved config, and an `AbortSignal`. The callback returns one observed -condition result. Core validates and namespaces the result before adding it to -the canonical readiness projection. - -The registration is a readiness provider: a lifecycle-owned producer with a -stable identity, owner, description, and bounded evaluator. Core owns -namespacing, lifecycle, enumeration, timeout, caching, coalescing, -invalid-result, error, and missing-registration behavior. Registrations live in -the existing Gateway-pinned plugin registry, so plugin load rollback and reload -replace the provider with the rest of that registry. There is no process-global -hosting registry and no downstream-specific publication path. - -The active provider catalog is enumerable from that pinned registry. Detailed -readiness and status expose each evaluated provider through its canonical -condition type; future doctor or administrative surfaces may list the same -descriptor catalog without inventing another registration mechanism. Provider -identity is the namespaced condition type. Plugin-owned reasons must be stable -within that identity, and messages are non-normative and must not contain -credentials, tokens, personal data, or thrown error details. - -Every active plugin provider is evaluated and reported as advisory by default, -even when the selected profile does not reference it. Installing a plugin may -therefore add advisory conditions, but cannot make an otherwise ready built-in -profile unready. A plugin cannot choose its requirement class. An operator -promotes a criterion by listing its full id in a custom profile's -`requiredCriteria`. A required criterion that is absent, times out, throws, or -reports `False` or `Unknown` blocks readiness. An absent selected criterion -emits `Unknown` with `CriterionUnavailable`. Plugin failures use generic -messages so readiness does not expose thrown error details. - -The initial implementation evaluates registered checks concurrently, supplies -an `AbortSignal`, uses a one-second deadline, and caches/coalesces each result -for five seconds. These mechanics are core-owned rather than profile-authored -numeric values. - -A provider check is an observational probe, not a lifecycle or repair hook. It -must be read-only, idempotent, safe under concurrent and repeated invocation, -avoid blocking synchronous I/O, and honor the supplied `AbortSignal`. It must -not start dependencies, rewrite config, repair state, or emit durable audit -claims. The cache duration bounds how stale a reported observation may be; a -cached result is not historical or audit-grade evidence. - -### Evaluation budgets and fail-closed behavior - -Every readiness condition must have a bounded evaluation strategy in code. A -condition may read an already-owned in-memory snapshot, perform a finite pass -over configured runtime state, or use a core-owned timeout and cache. It must -not introduce unbounded readiness-path I/O. - -| Condition family | Code-owned bound | -| --- | --- | -| Startup, drain, Gateway response, effective config, required plugin activation, required secret availability, model-route resolution, artifact identity, packaged profile conformance, expected-artifact match, negotiated ClawBus capabilities, profile, proxy, and event-loop conditions | Constant-time reads over existing runtime/config/activation/build-metadata/session snapshots. Readiness does not reload plugins, resolve secrets, call a model, probe host services, or rerun conformance tests. | -| Channel runtime | One finite pass over the current in-memory channel snapshot, cached for one second. | -| Workspace writability | One-second hard timeout with five-second cache/coalescing. | -| Node mode | Pairing reads have a one-second condition-level deadline and one-second cache; live sessions and command policy are finite in-memory passes. Timeout emits `NodePairingTimedOut` before the outer watchdog is needed. | -| Plugin providers | All providers run concurrently; each has a core-enforced one-second `Promise.race` deadline and five-second cache/coalescing. The deadline does not depend on the callback honoring cancellation. | -| Complete readiness evaluation | Independent two-second outer watchdog around workspace, provider, and node evaluation, which run concurrently. | - -Timeout, throw, invalid result, or missing registration becomes `Unknown` with a -stable reason. It blocks readiness when required and remains visible without -blocking when advisory. If the complete evaluation exceeds its outer deadline, -the existing HTTP exception path returns `503` and never reports ready. - -An in-process timer cannot interrupt JavaScript that synchronously blocks the -Node.js event loop. Core evaluators therefore use bounded snapshot work, and the -plugin contract forbids blocking synchronous I/O or computation. Stronger -isolation against a malicious plugin would require worker/process execution and -is outside this RFC; it is not implied by `AbortSignal`. - -### Profile inheritance and support ownership - -In v1, every operator profile extends exactly one standard profile and inherits -all of its required and advisory criteria. It may add requirements, but cannot remove, -replace, or demote the inherited contract. This gives custom hosting models a -known OpenClaw support baseline instead of allowing each operator to redefine -what a healthy Gateway means. - -Support ownership follows the composition: - -- OpenClaw owns, documents, and release-tests each standard profile and its - inherited criteria. -- An extended profile retains that OpenClaw-tested baseline. A failure in an - inherited criterion can be reproduced against and supported as the built-in - profile it extends. -- The plugin or operator owns added provider semantics and the additional - support promise made by the extended profile. OpenClaw does not certify an - arbitrary downstream composition merely because it inherits a built-in. - -A namespaced profile is therefore still an operator's own profile. Requiring -`extends` in v1 gives the first implementation a known release-tested baseline. -A later revision may allow an operator profile to compose its own provider set -without extending a standard profile. Such a profile would be operator-owned -and would still be conjoined with universal Gateway lifecycle readiness; custom -composition must never replace or bypass core startup, drain, channel, or -event-loop readiness. - -Built-in profile names and condition names remain reserved. Operators configure -the underlying OpenClaw settings; they do not redefine built-in semantics. - -`node-mode` requires at least one approved, connected, controllable target. It -does not prove that every target desired by OCC or a host platform is present; -desired fleet cardinality remains a control-plane concern. Pairing snapshots -used by frequent readiness probes should be briefly cached or event-driven, -while live node sessions and current command policy are evaluated on each -observation. - -Condition identity and requirement class are part of the support contract. -Changing an advisory condition to required, adding a new required condition to -an existing profile, or changing a stable reason can alter host behavior and -must receive compatibility review, release notes, and profile conformance -coverage. New diagnostics should default to advisory unless failure means the -named runtime shape cannot perform its supported role. - -Built-in profiles also should not encode host-specific numeric probe values. -Intervals, retries, start periods, and timeouts belong in Docker, Compose, -Kubernetes, systemd, Nomad, ECS, or another host manifest. OpenClaw can document -recommended host manifests, and a later doctor/lint conformance pass can emit -findings and fix recommendations when config does not match the selected -profile, but core `/ready` should not depend on that optional repair path. - -### OCC and AgentHarness alignment - -This RFC does not conflict with OCC or the remote AgentHarness RFC. OCC can -compile declarative desired state into OpenClaw config, selected profile, and -host policy. The runtime plane still owns readiness evaluation, channel ingress, -session routing, cell supervision, and AgentHarness event streams. - -In that model: - -```text -OCC/control plane: desired state, tenant identity, admission, restrictions, -quotas, policy compilation, provisioning, audit indexing. - -OpenClaw/runtime plane: startup, Gateway, sessions, cells/nodes, harness -execution, runtime status fields, ready/not-ready projection. -``` - -OCC should not be in the hot path for assistant deltas, tool events, approvals, -patches, compaction events, or harness protocol frames. - -### Completion roadmap - -The first implementation stack establishes the contract, but it does not make -the support promise complete by itself. The remaining work is grouped below so -that readiness does not become another collection of partially overlapping -surfaces. - -1. **Finish the canonical core conditions.** Existing Gateway startup, drain, - unsuppressed channel, and event-loop observations must be represented as - conditions rather than maintained as a second readiness model. Startup - validation that determines whether this process can serve belongs here as - readiness evidence; it does not require a separate ignition endpoint. - Config-loaded, Gateway-responsive, required-plugin, workspace, selected - topology, and node-mode evidence should use the same condition vocabulary. - Legacy `failing`, `suppressed`, and `eventLoop` fields remain compatibility - projections during migration. - - The earlier Runtime Activation inventory is reconciled explicitly below. - These are startup facts needed to serve a normal request, not general policy - conformance checks: - - | Activation observation | Readiness disposition | - | --- | --- | - | Runtime activation identified | Add required `RuntimeActivationIdentified` over the resolved logical-runtime and unique-incarnation ids. OpenClaw-generated defaults preserve zero-configuration local behavior; host-supplied values make readiness attributable across restarts and replicas. | - | Effective configuration resolved | Strengthen `ConfigLoaded` so `True` means the validated effective runtime snapshot is installed, not merely that a source file parsed. Use `ConfigNotLoaded`, `ConfigInvalid`, or `EffectiveConfigUnavailable` when that cannot be established. | - | Hosting profile applied | Covered by required `ProfileSelected`; the reported profile is the effective value after flag, environment, config, and default precedence. | - | Required plugins activated | Keep general `PluginsLoaded` advisory for compatibility, but add required `RequiredPluginsActivated` when a standard or operator profile names a plugin/provider as required. Missing, failed, or unavailable required activation must block readiness. | - | Required secrets available | Add required `RequiredSecretsAvailable` over the installed startup secrets snapshot. It reports only redacted availability and stable reasons; it never exposes secret values. Optional or lazy credentials do not block readiness until a selected profile declares them startup-required. | - | Model routing resolved | Add required `ModelRoutingResolved` when the selected runtime role is expected to accept agent work. It proves that the effective default/selected model route resolves to a configured provider after config and secret activation; it does not perform a billable model request on every readiness poll. | - - `RequiredPluginsActivated`, `RequiredSecretsAvailable`, and - `ModelRoutingResolved` must be implemented as bounded reads over activation - snapshots produced during normal startup. Readiness polling must not reload - plugins, resolve secrets again, contact a model, or mutate configuration. - - Other early hosted-start candidates do not become universal core - conditions. Brokered egress may be a required provider condition in a - derived managed profile. A no-runtime-secrets rule is conformance, not a - liveness probe. Workspace restoration, single-writer ownership, checkpoint - publication, and durable-state freshness belong to Runtime Continuity unless - a specific profile requires a bounded readiness observation before serving. -2. **Unify every projection.** `/ready`, `/readyz`, Gateway health, status, and - the optional `openclaw ready` command must be projections of one canonical - evaluation, with the same effective profile, condition identities, - requirement classes, reasons, and overall result. `/health` and `/healthz` - remain shallow liveness checks. Detailed output remains available only to - appropriately authenticated or local callers; unauthenticated probes keep a - compact result. -3. **Complete the bounded provider facility.** Active providers must remain - activation-scoped, enumerable, self-describing, observational, and advisory - by default. Core owns concurrent evaluation, per-provider deadlines, - cancellation, invalid-result handling, cache/coalescing, and an independent - outer evaluation deadline so a plugin cannot stall `/ready` or `/readyz`. - Operators may promote a provider condition to required only through an - additive operator profile. -4. **Prove the standard profiles as packaged workloads.** Run the Docker lane - against the package-installed release candidate for `local`, `container`, - `reverse-proxy`, and `node-mode`, including deterministic failure and - recovery cases. The current workspace-full and node-pairing scenarios must - be executed on Linux/container infrastructure, not only planned or unit - tested. Publish an artifact-bound conformance record containing the profile - id, OpenClaw artifact/version, condition-contract version, condition set, - result, and test evidence so a host can distinguish a supported release from - an untested configuration. Package that bounded metadata with the release so - readiness can emit `ArtifactIdentityAvailable` and - `SelectedProfileConformant` without rerunning tests. A host may also supply - an immutable expected artifact identity; when present, - `ExpectedArtifactMatched` is required and prevents a different build from - becoming ready under the deployment's support claim. -5. **Promote accepted profiles into release conformance.** Once maintainers - accept the condition and profile contracts and the packaged Docker proof is - reliable, make that matrix a blocking package-acceptance gate. A built-in - profile is a release-tested support promise, not merely a convenient bundle - of settings. Changes to required conditions or stable reasons require - compatibility review and release notes. -6. **Add stable readiness transition evidence.** Emit bounded, redacted events - when the effective profile or overall readiness changes, including the - previous and current result and changed condition identities. Event naming, - initial observation, deduplication, restart behavior, and operation when no - caller polls readiness must be specified before telemetry becomes a stable - contract. OpenClaw owns event semantics; hosts own fleet sinks, dashboards, - alerts, and retention. -7. **Add non-blocking operator guidance.** A later Doctor/lint pass may compare - the selected profile with effective config and host-facing recommendations, - report structured findings, and suggest safe fixes. Doctor, policy, and - optional plugins must never be dependencies of the core readiness path, and - built-in profiles must not absorb Docker-, Kubernetes-, or systemd-specific - retry counts and probe intervals. - -Readiness answers whether this runtime can accept and serve work now. It does -not prove that the latest mutable state has been durably published. Drain, -checkpoint publication, dirty/synced state, and a generation-fenced -safe-to-destroy result belong to the separate Runtime Continuity and Safe -Shutdown contract. A runtime may be ready but dirty, or not ready but already -synced; neither surface should be made an alias for the other. - -### Implementation branches - -The initial implementation is being prepared as draft branches in the OpenClaw -fork before upstream OpenClaw PRs are opened. The first slice normalizes the -existing Gateway startup, drain, channel, and event-loop outputs into core -conditions before adding profile-specific conditions: - -| Slice | Fork PR | Branch | -| --- | --- | --- | -| Core conditions and local profile | https://github.com/giodl73-repo/openclaw/pull/17 | `user/giodl/hosting-ready-local` (`cc9c4246`) | -| Standard profile selection and predicates | https://github.com/giodl73-repo/openclaw/pull/18 | `user/giodl/hosting-profile-selection` (`39a3b947`) | -| Node-mode readiness | https://github.com/giodl73-repo/openclaw/pull/19 | `user/giodl/hosting-node-mode-readiness` (`270f7a3d`) | -| Workspace writability readiness | https://github.com/giodl73-repo/openclaw/pull/22 | `user/giodl/hosting-workspace-readiness` (`5723f664`) | -| Readiness providers and operator profiles | https://github.com/giodl73-repo/openclaw/pull/23 | `user/giodl/hosting-readiness-registry` (`399cf745`) | -| Canonical readiness CLI | https://github.com/giodl73-repo/openclaw/pull/27 | `user/giodl/hosting-ready-cli` (`fe4c51c1`) | -| Runtime activation identity | https://github.com/giodl73-repo/openclaw/pull/42 | `user/giodl/hosting-runtime-activation` (`400cf831997`) | - -The stack includes one package-installed Docker conformance lane, -`pnpm test:docker:hosting-profiles`, built incrementally across the runtime -branches but not yet promoted into blocking package-acceptance release checks: - -- PR 17 normalizes startup, drain, channel, and event-loop observations into - core conditions, proves an unset profile defaults to `local`, and preserves - the legacy readiness fields while canonical aggregation drives HTTP status. -- PR 18 proves a LAN-bound `container` profile returns 200 and a loopback-bound - `container` profile returns 503 with `ContainerGatewayLoopback`. It also - proves a configured trusted-proxy posture returns 200 for `reverse-proxy` - while token auth returns 503 with `TrustedProxyAuthMissing`, and projects the - canonical result into Gateway health without a duplicate nested payload. -- PR 19 starts a real node host and proves `node-mode` transitions from 503 to - 200 only after approved pairing, a correlated live target, an advertised - approved command, and a connected control channel are all observed. -- PR 22 adds `WorkspaceWritable` to every built-in profile without defining a - new profile or changing the HTTP probe implementation. Its Docker scenario - fills a workspace `tmpfs` to `ENOSPC`, expects 503 with - `WorkspaceStorageFull`, removes the fill file, and expects recovery to 200 - without restarting OpenClaw. -- PR 23 adds activation-scoped, self-describing, enumerable readiness providers - and additive operator profiles while preserving standard-profile requirements - and canonical `/ready` projection. -- PR 27 adds `openclaw ready` as an optional operator convenience over the live - Gateway result. Human output lists every structured condition; `--json` - preserves the canonical successful result; and exit status fails closed for - required failures, unknowns, transport errors, or a missing readiness - contract. Advisory findings remain visible without changing exit success. -- PR 42 adds logical-runtime and process/container incarnation identity to the - live canonical result. Hosts may supply stable values through CLI or - environment; local runs remain zero-configuration, generated incarnations - survive in-process Gateway restarts, and invalid explicit identities fail - startup rather than silently falling back. - -The Docker planner resolves the lane with both package and functional-image -requirements, and its existing 33 planner assertions remain green. After the -condition/provider amendments, the latest focused provider-registry, provider -evaluation, hosting config, Gateway readiness, node/workspace timeout, and -status projection run passes 120 routed assertions. The corrected PR 17 health, -status, and legacy-condition run passes another 114 assertions. - -The workspace-readiness composed branch passed 188 focused profile, -Gateway-probe, health-state, status, node, and workspace assertions. After the -restack, the Docker planner passes all 33 assertions on Linux. - -Making this lane a blocking package-acceptance release gate is intentionally a -follow-up after maintainers accept the contract and packaged Docker execution -is proven. Draft fork PR 21 demonstrates that separate six-line workflow/docs -change without coupling the initial implementation to a permanent release -obligation. - -Actual execution of the new workspace `tmpfs` failure/recovery scenario remains -pending because Docker Desktop was unavailable on the authoring host. The -scenario, package-installed lane, and deterministic plan are implemented, but -the draft stack does not claim a local or brokered runtime pass yet. - -The lane is the reproducible behavior proof for upstream review. A brokered -Linux/Crabbox execution should be attached before the implementation PRs are -promoted upstream; the draft branches do not depend on Crabbox to define the -contract. - -This first stack proves the core ready/result shape, explicit profile -selection, built-in profile composition from reusable criteria, exact built-in -container/reverse-proxy predicates, and node-mode rules backed by the -live node registry. PR 42 implements `RuntimeActivationIdentified` and the -activation summary. The stack does not yet implement the newly reconciled -`RequiredPluginsActivated`, `RequiredSecretsAvailable`, or -`ModelRoutingResolved` activation conditions, nor the artifact identity and -profile-conformance conditions. Those remain completion work before the -standard-profile matrix can become a release support gate. - -### Incremental adoption - -The proposal does not require one all-or-nothing implementation landing: - -1. Land the condition shape, normalize existing Gateway startup, drain, - channel, and event-loop observations into core conditions, and add the - default `local` projection across readiness, health, and status surfaces. -2. Add explicit selection plus `container` and `reverse-proxy` predicates over - effective runtime facts. -3. Add `node-mode` using pairing and live node-registry evidence. -4. Add a generally applicable workspace-writability criterion to every - existing profile, proving that criteria can extend readiness without adding - a profile. -5. Add plugin criterion registration and additive operator profiles over the - same canonical result. -6. Add the optional `openclaw ready` CLI projection over the canonical live - Gateway result. -7. Add runtime/incarnation identity resolution, the required - `RuntimeActivationIdentified` condition, and the redacted activation summary - shared by readiness, health, and status. - -After contract acceptance and successful packaged Docker proof, a separate -follow-up can make the profile matrix a blocking package-acceptance release -gate. - -The first slice is independently useful because it creates one canonical, -explainable result without introducing non-local hosting behavior. If the -profile catalog needs further design, maintainers can accept that foundation -without committing to every proposed profile at once. - -## Rationale - -This follows the normal contract between a host and a hosted workload. The host -selects a runtime shape and supplies configuration. The workload starts, -publishes runtime status, evaluates readiness criteria over that status, and -reports stable conditions. - -Putting the result into `ready`, `status`, and `health` is preferable to a -special "hosted OpenClaw" command tree. "Hosted" is a runtime posture and support -profile, not the primary CLI noun. - -Standard profiles make the support promise concrete. Instead of one broad -hosted-deployment claim, OpenClaw can say which standard profiles it supports, -which conditions are stable, and which release tests prove them. An operator -profile preserves the tested baseline it inherits while clearly identifying -the additional criteria whose support belongs to the operator or plugin owner. - -Artifact and profile-conformance conditions keep that support promise on the -same host-facing result. They are not a general compatibility, upgrade, or -migration framework. Release jobs produce immutable evidence; readiness only -checks that the running artifact, selected profile, and supplied host -expectation match that evidence. Restore-version compatibility remains part of -Runtime State Continuity. - -This is intentionally less powerful than a general profile or policy engine. -Its value comes from OpenClaw owning a small number of built-in definitions and -testing them release after release. Operator profiles are constrained to -additive composition; they cannot rewrite the support boundary downstream. - -The ready check is intentionally smaller than the profile model. Container -hosters can use it directly as their readiness probe, while hosts that already -have their own probe plumbing can still benefit from standard profiles and -stable readiness conditions. - -## Unresolved questions - -- Which additional advisory conditions would improve supportability without - weakening the meaning of required profile conformance? -- Should non-plugin runtime drivers need a separate criterion registration - surface, or is activation-scoped plugin registration sufficient? -- Which stable telemetry event names should accompany readiness transitions in a - follow-up PR? From f4c28e58d3930c6ae5e40ac0adaf2cf4f9b37bbf Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Tue, 14 Jul 2026 09:45:22 -0700 Subject: [PATCH 48/98] Clarify readiness-only implementation stack --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 3531728c..9d463952 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -350,7 +350,7 @@ runtime activation identity, or a release support matrix. ### Implementation plan -The draft implementation will be restacked into a readiness-only series: +The draft implementation is restacked into a readiness-only series: | Slice | Draft PR | Intended scope | | --- | --- | --- | @@ -363,6 +363,10 @@ Profile selection, node-mode composition, activation identity, and packaged profile release conformance move to the Standard Hosting Profiles RFC and its separate implementation stack. +The earlier consolidated draft remains useful behavior evidence, but it is not +the proposed landing shape. The slices above can land without accepting profile +names, profile selection, runtime activation identity, or release conformance. + ## Rationale This extends a surface OpenClaw already owns. It does not add a new health From 00ef697e96fadc65c787f900b1a0efeaa4d9bcf4 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Tue, 14 Jul 2026 12:50:21 -0700 Subject: [PATCH 49/98] docs(rfc-0018): specify readiness failure containment --- rfcs/0018-readiness-conditions-and-providers.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 9d463952..58a1904e 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -149,6 +149,7 @@ justifies them. | `ChannelRuntimeReady` | Required | No selected channel has an unsuppressed runtime-health failure under existing channel policy. | `ChannelRuntimeUnavailable` | | `ChannelRuntimeSuppressed` | Advisory when present | A channel runtime failure is intentionally suppressed by existing autostart/crash-loop policy. | `ChannelRuntimeSuppressed` | | `EventLoopHealthy` | Advisory initially | Existing event-loop health is within its healthy threshold. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | +| `ReadinessEvaluationComplete` | Required when emitted | The bounded canonical evaluation completed. This failure-only guard condition is emitted when the evaluator cannot produce its normal condition set. | `ReadinessEvaluationTimedOut`, `ReadinessEvaluationFailed` | | `GatewayResponding` | Required when observed remotely | The current operation successfully reached the live Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `ConfigLoaded` | Required | The validated effective runtime config snapshot is installed. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | | `WorkspaceWritable` | Required or advisory when selected | The effective workspace passes a bounded write, flush, and cleanup probe. It is not a new universal blocker by default. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | @@ -283,7 +284,14 @@ The initial implementation uses layered bounds: A timeout becomes `Unknown` with a stable reason. A required timeout returns `503`; an advisory timeout remains visible without blocking. The outer watchdog -fails closed rather than allowing `/ready` or `/readyz` to hang. +fails closed with a required `ReadinessEvaluationComplete=Unknown` condition +rather than allowing `/ready`, `/readyz`, health, or status to hang or reject. +Unexpected error details are not copied into the public result. + +Core retains ownership of a provider invocation after its deadline. If a +provider ignores cancellation and remains pending, later readiness polls reuse +the stable timeout result and do not start another invocation. A new invocation +may begin only after the original callback settles and the result cache expires. In-process timers cannot interrupt synchronous JavaScript that blocks the event loop. Providers therefore may not perform blocking synchronous I/O. Process or From 4256e818338adf001933ce015162647519fca95f Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Tue, 14 Jul 2026 13:25:18 -0700 Subject: [PATCH 50/98] docs(rfc-0018): identify primary implementation --- rfcs/0018-readiness-conditions-and-providers.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 58a1904e..b5728270 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -358,7 +358,14 @@ runtime activation identity, or a release support matrix. ### Implementation plan -The draft implementation is restacked into a readiness-only series: +The primary implementation for this RFC is +[openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). +It is one upstream draft PR with four ordered commits, exact-head tests, and +package-installed Docker proof. Reviewers should use that PR for the proposed +landing shape and current validation state. + +The fork PRs below expose the same four commits as optional smaller review +slices. They are supporting review aids, not alternative landing PRs: | Slice | Draft PR | Intended scope | | --- | --- | --- | From 37713589687eee52a6b25f9173f2c0437a85ca42 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Tue, 14 Jul 2026 20:35:16 -0700 Subject: [PATCH 51/98] docs(rfc-0018): refresh implementation proof --- rfcs/0018-readiness-conditions-and-providers.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index b5728270..d7b23b1a 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -360,9 +360,14 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream draft PR with four ordered commits, exact-head tests, and -package-installed Docker proof. Reviewers should use that PR for the proposed -landing shape and current validation state. +It is one upstream draft PR with four ordered commits at exact head +`89d8607aab9f`, exact-head tests, and package-installed Docker proof. The final +package proves `/ready` and `/readyz` transition `200 -> 503 -> 200` for a +selected workspace failure and recovery, `/healthz` remains live, and +`openclaw ready --json` exits `0 -> 1 -> 0` with the same canonical condition. +A published-package upgrade lane also proves that existing installations do +not silently acquire opt-in criteria. Reviewers should use that PR for the +proposed landing shape and current validation state. The fork PRs below expose the same four commits as optional smaller review slices. They are supporting review aids, not alternative landing PRs: From b481e12bb93133cf065a92a9a553cf1bf33c53d7 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Wed, 15 Jul 2026 07:42:11 -0700 Subject: [PATCH 52/98] docs(rfc-0018): refresh readiness implementation head --- rfcs/0018-readiness-conditions-and-providers.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index d7b23b1a..c560ba3c 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -361,8 +361,9 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). It is one upstream draft PR with four ordered commits at exact head -`89d8607aab9f`, exact-head tests, and package-installed Docker proof. The final -package proves `/ready` and `/readyz` transition `200 -> 503 -> 200` for a +`17b34f792d8`, rebased onto OpenClaw `main` at `4e78d91c0f9`, with exact-head +tests and package-installed Docker proof. The final package proves `/ready` and +`/readyz` transition `200 -> 503 -> 200` for a selected workspace failure and recovery, `/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with the same canonical condition. A published-package upgrade lane also proves that existing installations do From 85328ab49b3b35cfb050f7720afa1b22b2858e2a Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Wed, 15 Jul 2026 17:09:22 -0700 Subject: [PATCH 53/98] docs(rfc-0018): add readiness v1 specification --- ...0018-readiness-conditions-and-providers.md | 8 +- rfcs/0018/readiness-v1-spec.md | 377 ++++++++++++++++++ 2 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 rfcs/0018/readiness-v1-spec.md diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index c560ba3c..e8475602 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -3,7 +3,7 @@ title: Readiness Conditions and Providers authors: - Gio created: 2026-07-09 -last_updated: 2026-07-14 +last_updated: 2026-07-15 status: draft issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 @@ -96,6 +96,12 @@ provider condition. ## Proposal +The implementer-facing v1 contract is captured in +[`0018/readiness-v1-spec.md`](0018/readiness-v1-spec.md). This RFC remains the +design rationale, compatibility argument, and rollout plan; the sidecar is the +concise schema, provider-lifecycle, evaluation, projection, and conformance +reference for OpenClaw runtime and plugin implementations. + ### Canonical condition model Every readiness observation is represented as: diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md new file mode 100644 index 00000000..52ab2af4 --- /dev/null +++ b/rfcs/0018/readiness-v1-spec.md @@ -0,0 +1,377 @@ +# Readiness v1 Specification + +This document is the implementer-facing specification for RFC 0018, Readiness +Conditions and Providers. The RFC explains the motivation, compatibility +strategy, and rollout plan. This file defines the v1 condition model, provider +lifecycle, operator selection, bounded evaluation, aggregation, and projection +contract that OpenClaw runtimes, plugins, and hosts can build against. + +Status: draft, tied to RFC 0018. + +## Scope + +This specification defines: + +- the canonical readiness condition and result shapes; +- stable identity and reason requirements; +- required and advisory aggregation; +- the core condition namespace and baseline lifecycle conditions; +- plugin readiness-provider registration and activation lifecycle; +- operator selection of additional required or advisory criteria; +- deadlines, cancellation, coalescing, caching, and error conversion; +- HTTP, health, status, and CLI projections; and +- compatibility and conformance requirements. + +This specification does not define: + +- standard or custom hosting profiles; +- checkpoint durability, safe shutdown, or restore compatibility; +- arbitrary shell, network, or script probes configured by operators; +- orchestration retry intervals or restart policy; or +- telemetry sinks, dashboards, alerting, or retention. + +## Terminology + +- **Condition**: one bounded observation about the current runtime activation. +- **Criterion**: an enumerable condition definition that can be selected for + evaluation. +- **Provider**: activated plugin code that implements one plugin-owned + criterion. +- **Requirement**: whether a non-true condition blocks readiness. +- **Universal condition**: a core lifecycle condition that always participates + and cannot be removed by operator configuration. +- **Canonical result**: the single aggregated result consumed by all readiness + projections. +- **Projection**: an HTTP, health, status, or CLI representation of the + canonical result; a projection is not a second evaluator. + +## Compatibility And Evolution + +Readiness v1 uses these compatibility rules: + +- condition `type` and `reason` values are stable machine contracts; +- `message` is redacted operator guidance and is not stable machine identity; +- adding an advisory criterion is backward compatible; +- making a criterion required, or adding a new universal required condition, + is compatibility-sensitive because it can change `200` to `503`; +- unknown optional result fields must be ignored by v1 consumers; +- legacy readiness fields remain projections during migration; and +- implementing or registering a criterion does not select it or make it + required. + +## Canonical Data Model + +The canonical v1 shapes are: + +```ts +type ReadinessConditionStatus = "True" | "False" | "Unknown"; +type ReadinessRequirement = "required" | "advisory"; + +type ReadinessCondition = { + type: string; + status: ReadinessConditionStatus; + requirement: ReadinessRequirement; + reason: string; + message: string; +}; + +type ReadinessResult = { + ready: boolean; + conditions: ReadinessCondition[]; + failures: string[]; + advisories: string[]; +}; +``` + +Implementations may add optional metadata, but the fields above retain their +v1 meaning. + +### Identity + +Condition `type` values must be stable and unique within one result. Core uses +the public condition types defined below, such as `WorkspaceWritable`. A plugin +condition uses this namespace: + +- `plugin..` for plugin criteria. + +Configuration selects enumerable criterion IDs. Selectable public core +criteria use `openclaw.` and map to a core condition type. Not +every universal or built-in advisory condition is operator-selectable. Plugin +selectors are the same namespaced ID used by their emitted condition. Core and +plugin criterion IDs must not collide after normalization. A plugin-local ID is +trimmed, converted to lowercase, and must match +`^[a-z0-9][a-z0-9._-]*$`. Core prefixes the canonical activated plugin ID and +must reject an invalid or duplicate resulting ID. Configured selectors use the +canonical stored ID; consumers must not perform a second case-folding rule. + +`reason` must describe the observed state, not repeat the criterion identity. +Provider reasons must match `^[A-Za-z][A-Za-z0-9._-]{0,127}$`. Provider messages +must be valid text of at most 512 UTF-8 bytes after redaction. Reason and message +values must not contain secrets, paths with credentials, raw exception text, or +tenant content. Core validates these bounds before caching or projection; +invalid output becomes `CriterionInvalidResult`. + +### Status + +- `True` means the criterion was observed and satisfied. +- `False` means the criterion was observed and not satisfied. +- `Unknown` means the criterion was selected but could not be established + within the contract, including timeout, unavailable source state, or an + evaluator failure. + +An absent observation must never be inferred as `True`. A selected required +criterion that cannot be evaluated must be emitted as `Unknown`. + +### Aggregation + +Aggregation is deterministic: + +| Requirement | `True` | `False` or `Unknown` | +| --- | --- | --- | +| `required` | No failure. | `ready=false`; append the stable reason to `failures`. | +| `advisory` | No advisory. | Preserve readiness; append the stable reason to `advisories`. | + +The condition array must use this v1 order when present: + +1. `ReadinessEvaluationComplete` when the normal evaluation cannot complete; +2. `GatewayStartupComplete`, `GatewayAcceptingWork`, `ChannelRuntimeReady`, + `ChannelRuntimeSuppressed`, and `EventLoopHealthy`; +3. `ConfigLoaded` and `WorkspaceWritable`; +4. profile-owned conditions in the order defined by RFC 0023; +5. `GatewayResponding` and `PluginsLoaded`; and +6. remaining plugin conditions sorted by namespaced criterion ID. + +`failures` and `advisories` follow condition order and contain no duplicates. + +Malformed evaluator output must become a stable `Unknown` result or cause +registration/config validation to fail. It must not disappear from aggregation. + +## Core Criteria + +The initial public core criteria are: + +| Selector ID | Condition type | Default requirement | Stable non-true reasons | +| --- | --- | --- | --- | +| Not selectable | `GatewayStartupComplete` | Universal required | `GatewayStartupPending`, `GatewayStartupNotChecked` | +| Not selectable | `GatewayAcceptingWork` | Universal required | `GatewayDraining`, `GatewayAdmissionNotChecked` | +| Not selectable | `ChannelRuntimeReady` | Universal required | `ChannelRuntimeUnavailable`, `ChannelRuntimeNotChecked` | +| Not selectable | `ChannelRuntimeSuppressed` | Advisory when present | `ChannelRuntimeSuppressed` | +| Not selectable | `EventLoopHealthy` | Advisory | `EventLoopDegraded`, `EventLoopStatusUnavailable` | +| Not selectable | `ConfigLoaded` | Universal required | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | +| `openclaw.workspace-writable` | `WorkspaceWritable` | Selectable | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | +| Not selectable | `PluginsLoaded` | Advisory | `PluginLoadFailures`, `PluginStatusUnavailable` | + +Each condition is `True` only when the runtime observes the corresponding +startup, admission, channel, event-loop, config, workspace, or plugin predicate +described by RFC 0018. A successful condition uses a stable success reason that +normally matches its condition type. + +The evaluator may emit these failure-only guard conditions: + +| Condition type | Requirement | Predicate | +| --- | --- | --- | +| `ReadinessEvaluationComplete` | Required | The bounded canonical evaluation completed; otherwise `ReadinessEvaluationTimedOut` or `ReadinessEvaluationFailed`. | +| `GatewayResponding` | Required when the operation is remote | The caller reached the live Gateway; otherwise `GatewayUnavailable` or `GatewayNotChecked`. | + +Implementations must preserve existing Gateway readiness behavior while these +observations are normalized. `workspace-writable` remains unselected unless an +operator or a separately accepted profile selects it. + +## Plugin Readiness Providers + +Only activated OpenClaw plugins may register executable provider code. Runtime +configuration may select a provider ID but must not contain callbacks, scripts, +commands, or arbitrary probe definitions. + +The v1 plugin SDK contract is: + +```ts +type PluginReadinessResult = { + status: "True" | "False" | "Unknown"; + reason: string; + message: string; +}; + +type PluginReadinessProvider = { + id: string; + description: string; + check(context: { + config: OpenClawConfig; + pluginConfig: unknown; + signal: AbortSignal; + }): Promise | PluginReadinessResult; +}; + +type RegisterReadinessCriterion = ( + provider: PluginReadinessProvider, +) => void; +``` + +Registration through `api.registerReadinessCriterion` is scoped to the current +plugin activation. Core publishes the resulting ID as +`plugin..`. + +### Provider Requirements + +A provider must be: + +- observational and read-only; +- idempotent under repeated invocation; +- cancellation-aware; +- safe under concurrent invocation or core coalescing; +- free of blocking synchronous I/O; and +- redacted by construction. + +A provider must not mutate config, reload plugins, acquire or rotate secrets, +send model requests, change admission state, invoke tools, or alter another +condition. + +### Activation Lifecycle + +The registered provider set is bound to one activation-pinned plugin registry +snapshot. Plugin reload builds a complete replacement set and publishes it +atomically with the new activation. Publication aborts in-flight callbacks from +the prior generation, invalidates their cached results, and prevents late +settlement from entering the active result. Core must keep retained state +bounded when a callback ignores cancellation; an abandoned callback must not +retain an active registry or become selectable after replacement. + +Provider descriptors must be enumerable without invoking callbacks. At minimum +the descriptor contains the namespaced ID, description, owning plugin, and +activation generation. + +## Operator Selection + +Universal conditions always apply. Operators may select additional registered +core or plugin criteria without selecting a hosting profile: + +```json5 +{ + gateway: { + readiness: { + requiredCriteria: [ + "openclaw.workspace-writable", + "plugin.storage.backend", + ], + advisoryCriteria: ["plugin.metrics.exporter"], + }, + }, +} +``` + +Selection uses namespaced criterion IDs. The same ID must not appear in both +lists. Unknown IDs in either list must fail configuration validation when the +provider registry is known. During activation uncertainty, an unknown selected +ID produces `Unknown` with the requirement of its containing list. Unknown IDs +must never be silently ignored. + +Registration alone does not activate a plugin criterion. Only explicitly +selected criteria participate: `advisoryCriteria` selects them as advisory and +`requiredCriteria` selects them as required. Operator selection may strengthen +a selectable criterion from advisory to required but must not weaken universal +required conditions. + +## Bounded Evaluation + +Readiness is a hot operational path and must complete within code-owned bounds. +The initial v1 limits are: + +- one second per plugin provider; +- one second for the workspace observation; +- concurrent evaluation of independent observations; and +- an independent two-second outer deadline for the complete result. + +Core owns deadlines, cancellation, coalescing, caching, error conversion, and +result ordering. A timed-out criterion becomes `Unknown` with a stable timeout +reason. Unexpected exceptions become `Unknown`; raw exception text is not +copied into public output. + +Universal core observations consume already-owned runtime snapshots and must +not perform request-time network I/O. Plugin providers should report from +asynchronously refreshed local state when an observation can exceed the normal +probe path. Blocking synchronous work is invalid even though the outer watchdog +bounds cooperative asynchronous work. + +Plugin-provider failures use these core-owned reasons: + +- `CriterionNotRegistered` when a selected provider is unavailable; +- `CriterionInvalidResult` when output violates the provider result shape; +- `CriterionTimedOut` when the provider exceeds its deadline; and +- `CriterionCheckFailed` when invocation throws or rejects. + +If the outer deadline expires, the evaluator must return a required +`ReadinessEvaluationComplete=Unknown` condition with reason +`ReadinessEvaluationTimedOut`. The HTTP request must not hang or reject. + +Core retains ownership of an invocation after its deadline. If a provider +ignores cancellation and remains pending, later polls reuse the stable timeout +result and must not start another invocation. A new invocation may start only +after the prior callback settles and the cache expires. + +Successful and failed provider or workspace observations may be cached for at +most five seconds. Config generation, plugin activation generation, effective +workspace identity, or selected-criterion changes invalidate affected entries +immediately. Admission, drain, startup, channel, and event-loop snapshots are +not made stale by this cache. A late result from an invalidated generation is +discarded. + +## Projections + +All projections consume the same canonical result. + +### HTTP + +- `/ready` and `/readyz` are authoritative readiness probes. +- A ready result returns `200`; a non-ready result returns `503`. +- `HEAD` compatibility remains unchanged. +- Authenticated or local callers may receive the structured result. +- Unauthenticated remote callers receive only a compact redacted response. +- `/health` and `/healthz` remain shallow liveness probes and do not acquire + readiness semantics. + +### Health And Status + +Gateway health and status project the canonical result or a bounded summary of +it. A surface that did not observe a required live fact reports `Unknown`; it +must not synthesize success. Descriptor enumeration must not execute providers. + +### CLI + +An `openclaw ready` command, when implemented, is a client of the live Gateway +result: + +- human output lists non-true conditions; +- `--json` preserves the canonical result; and +- exit status is nonzero for required failure, required unknown, transport + failure, or absence of a supported readiness contract. + +The CLI must not implement condition evaluation independently. + +## Legacy Projection + +Existing `ready`, `failing`, `suppressed`, `eventLoop`, and `uptimeMs` fields +remain compatibility projections during migration. Implementations must first +emit canonical conditions beside legacy fields, then move every surface to the +canonical evaluator. Legacy removal requires a separate compatibility review. + +## Conformance Checklist + +An implementation conforms to readiness v1 when it proves: + +- existing unconfigured readiness behavior is unchanged; +- universal startup, admission, and selected-channel failures return `503`; +- additional criteria do not become required without explicit selection; +- required `False` and `Unknown` return `503`; +- advisory `False` and `Unknown` remain visible while returning `200` when all + required conditions are true; +- provider timeout, exception, malformed output, and ignored cancellation all + return within the outer deadline; +- cache entries expire within five seconds and invalidate on relevant config, + workspace, selection, and plugin-generation changes; +- reload atomically replaces provider descriptors and callbacks, discards late + results, and remains bounded across repeated never-settling providers; +- unknown selected criteria fail closed; +- `/ready`, `/readyz`, health, status, and CLI do not disagree about the same + observed activation; and +- public output contains no raw exceptions, secrets, credentials, or tenant + content. From 74e309b1a05f6aa7663818eb8079eec9b91299c2 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Wed, 22 Jul 2026 18:18:41 -0700 Subject: [PATCH 54/98] docs(rfc): refresh readiness implementation evidence --- ...0018-readiness-conditions-and-providers.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index e8475602..5fc23364 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -366,15 +366,16 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream draft PR with four ordered commits at exact head -`17b34f792d8`, rebased onto OpenClaw `main` at `4e78d91c0f9`, with exact-head -tests and package-installed Docker proof. The final package proves `/ready` and -`/readyz` transition `200 -> 503 -> 200` for a -selected workspace failure and recovery, `/healthz` remains live, and -`openclaw ready --json` exits `0 -> 1 -> 0` with the same canonical condition. -A published-package upgrade lane also proves that existing installations do -not silently acquire opt-in criteria. Reviewers should use that PR for the -proposed landing shape and current validation state. +It is one upstream PR with four ordered commits at exact head `d1450aeb7f9`, +rebased onto OpenClaw `main` at `eccf02f04ac`. The refreshed branch passes +220 focused readiness, Gateway, status, config, plugin-SDK, CLI, and config-help +tests; formatting, documentation indexing, SDK surface, and SDK API-baseline +checks also pass. The package-installed Docker lane proves `/ready` and +`/readyz` transition `200 -> 503 -> 200` for a selected workspace failure +and recovery, `/healthz` remains live, and `openclaw ready --json` exits +`0 -> 1 -> 0` with the same canonical condition. Exact-head remote container +and published-upgrade proof must be refreshed before landing. Reviewers should +use that PR for the proposed landing shape and current validation state. The fork PRs below expose the same four commits as optional smaller review slices. They are supporting review aids, not alternative landing PRs: From 2e76fc5217dfce7b377824dc04ab22a659da6689 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Wed, 22 Jul 2026 19:49:06 -0700 Subject: [PATCH 55/98] docs(rfc-0018): refresh implementation status --- ...0018-readiness-conditions-and-providers.md | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 5fc23364..bd8b218d 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -366,18 +366,19 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with four ordered commits at exact head `d1450aeb7f9`, +It is one upstream PR with five ordered commits at exact head `208dc2db604`, rebased onto OpenClaw `main` at `eccf02f04ac`. The refreshed branch passes -220 focused readiness, Gateway, status, config, plugin-SDK, CLI, and config-help -tests; formatting, documentation indexing, SDK surface, and SDK API-baseline -checks also pass. The package-installed Docker lane proves `/ready` and -`/readyz` transition `200 -> 503 -> 200` for a selected workspace failure -and recovery, `/healthz` remains live, and `openclaw ready --json` exits -`0 -> 1 -> 0` with the same canonical condition. Exact-head remote container -and published-upgrade proof must be refreshed before landing. Reviewers should -use that PR for the proposed landing shape and current validation state. - -The fork PRs below expose the same four commits as optional smaller review +focused readiness, Gateway, status, health, CLI, and method-metadata tests; +production and test type checks, dead-export checks, deprecation guards, +documentation indexing, changed-file lint, and plugin-SDK surface checks also +pass. A prior package-installed Docker lane proved `/ready` and `/readyz` +transition `200 -> 503 -> 200` for a selected workspace failure and recovery, +`/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with +the same canonical condition. Exact-head remote container and published-upgrade +proof must be refreshed before landing. Reviewers should use that PR for the +proposed landing shape and current validation state. + +The fork PRs below expose the implementation as optional smaller review slices. They are supporting review aids, not alternative landing PRs: | Slice | Draft PR | Intended scope | From dc08f1aa1e876533a240bfa790e861ce342fea74 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Wed, 22 Jul 2026 20:15:22 -0700 Subject: [PATCH 56/98] docs(rfc-0018): record timeout recovery --- rfcs/0018-readiness-conditions-and-providers.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index bd8b218d..c65dc432 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -366,12 +366,14 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with five ordered commits at exact head `208dc2db604`, +It is one upstream PR with six ordered commits at exact head `21cbc1bcf6c`, rebased onto OpenClaw `main` at `eccf02f04ac`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; production and test type checks, dead-export checks, deprecation guards, documentation indexing, changed-file lint, and plugin-SDK surface checks also -pass. A prior package-installed Docker lane proved `/ready` and `/readyz` +pass. Timed-out plugin checks are cached for their bounded TTL and then retried, +even when the plugin ignored cancellation. A prior package-installed Docker +lane proved `/ready` and `/readyz` transition `200 -> 503 -> 200` for a selected workspace failure and recovery, `/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with the same canonical condition. Exact-head remote container and published-upgrade From e3b925c1bedfa5b51f2c32edc4ab6b489d3cca0d Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Wed, 22 Jul 2026 20:25:11 -0700 Subject: [PATCH 57/98] docs(rfc-0018): record protocol sync --- rfcs/0018-readiness-conditions-and-providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index c65dc432..0bfe4ea1 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -366,7 +366,7 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with six ordered commits at exact head `21cbc1bcf6c`, +It is one upstream PR with seven ordered commits at exact head `27fa73911d5`, rebased onto OpenClaw `main` at `eccf02f04ac`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; production and test type checks, dead-export checks, deprecation guards, From d5ebf61962021f45a6cc8e01f43f87edc0ee74c2 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Wed, 22 Jul 2026 20:33:29 -0700 Subject: [PATCH 58/98] docs(rfc-0018): refresh implementation head --- rfcs/0018-readiness-conditions-and-providers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 0bfe4ea1..b022606e 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -366,8 +366,8 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with seven ordered commits at exact head `27fa73911d5`, -rebased onto OpenClaw `main` at `eccf02f04ac`. The refreshed branch passes +It is one upstream PR with seven ordered commits at exact head `5e7a713545a`, +rebased onto OpenClaw `main` at `f7d61b43529`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; production and test type checks, dead-export checks, deprecation guards, documentation indexing, changed-file lint, and plugin-SDK surface checks also From c5656967d2f5a1a4b1c4c863660893532ecb16ea Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 08:29:02 -0700 Subject: [PATCH 59/98] docs(rfc-0018): specify readiness safety bounds --- ...0018-readiness-conditions-and-providers.md | 44 ++++++++++++------- rfcs/0018/readiness-v1-spec.md | 44 +++++++++++-------- 2 files changed, 53 insertions(+), 35 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index b022606e..35c27551 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -3,7 +3,7 @@ title: Readiness Conditions and Providers authors: - Gio created: 2026-07-09 -last_updated: 2026-07-15 +last_updated: 2026-07-23 status: draft issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 @@ -158,7 +158,7 @@ justifies them. | `ReadinessEvaluationComplete` | Required when emitted | The bounded canonical evaluation completed. This failure-only guard condition is emitted when the evaluator cannot produce its normal condition set. | `ReadinessEvaluationTimedOut`, `ReadinessEvaluationFailed` | | `GatewayResponding` | Required when observed remotely | The current operation successfully reached the live Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `ConfigLoaded` | Required | The validated effective runtime config snapshot is installed. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | -| `WorkspaceWritable` | Required or advisory when selected | The effective workspace passes a bounded write, flush, and cleanup probe. It is not a new universal blocker by default. | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | +| `WorkspaceWritable` | Required or advisory when selected | The effective workspace exists and passes a bounded write, flush, and cleanup probe. It is not a new universal blocker by default. | `WorkspaceMissing`, `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `PluginsLoaded` | Advisory | The activation-pinned plugin registry is available and selected plugins have no activation errors. | `PluginLoadFailures`, `PluginStatusUnavailable` | Changing an advisory core condition to required is a compatibility-sensitive @@ -226,9 +226,10 @@ bound to the activated plugin registry snapshot. Reload replaces the complete provider set atomically with the next activation; stale callbacks do not remain registered. -Provider descriptors are enumerable without exposing callbacks. Status and -future diagnostics can list provider identity, description, owning plugin, and -activation generation without executing the provider. +Provider descriptors are enumerable without invoking callbacks. The active +registry exposes provider identity, description, owning plugin, and source; the +registry snapshot itself is the activation-generation boundary. Future status +or diagnostics may project that descriptor catalog without executing providers. Providers must be: @@ -243,6 +244,12 @@ Core owns namespacing, validation, invocation, deadlines, cancellation, coalescing, caching, error conversion, and result ordering. A provider cannot alter another provider's condition or any core condition. +Provider `reason` values use a bounded machine-readable token grammar. Public +messages must be non-empty, contain no NUL bytes, and fit within 512 UTF-8 +bytes after core redaction. Invalid output becomes +`CriterionInvalidResult=Unknown`; raw provider output never bypasses these +checks. + ### Operator-selected readiness conditions OpenClaw's universal Gateway lifecycle conditions always apply and cannot be @@ -264,11 +271,12 @@ hosting profile: } ``` -Provider criteria are advisory unless selected as required. Unknown selected -IDs fail validation or produce required `Unknown` during activation; they -cannot be silently ignored. Configuration changes are applied through the -normal validated config lifecycle. This RFC does not add a policy language or -a way to redefine criteria semantics. +Provider criteria are advisory unless selected as required. Selector syntax is +validated in config. A syntactically valid ID that is not present in the active +registry produces `CriterionNotRegistered=Unknown` with its selected +requirement; it cannot be silently ignored. Configuration changes are applied +through the normal validated config lifecycle. This RFC does not add a policy +language or a way to redefine criteria semantics. This explicit list is a complete standalone use of RFC 0018. An operator can say exactly which additional observations must pass for its deployment without @@ -298,6 +306,9 @@ Core retains ownership of a provider invocation after its deadline. If a provider ignores cancellation and remains pending, later readiness polls reuse the stable timeout result and do not start another invocation. A new invocation may begin only after the original callback settles and the result cache expires. +Publishing a replacement plugin registry or effective config snapshot aborts +the prior generation, clears its cache, and prevents late settlement from +entering the active result. In-process timers cannot interrupt synchronous JavaScript that blocks the event loop. Providers therefore may not perform blocking synchronous I/O. Process or @@ -366,14 +377,13 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with seven ordered commits at exact head `5e7a713545a`, -rebased onto OpenClaw `main` at `f7d61b43529`. The refreshed branch passes +It is one upstream PR with nine ordered commits at exact head `788a58e612f`, +rebased onto OpenClaw `main` at `29d5dcfac6a`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; -production and test type checks, dead-export checks, deprecation guards, -documentation indexing, changed-file lint, and plugin-SDK surface checks also -pass. Timed-out plugin checks are cached for their bounded TTL and then retried, -even when the plugin ignored cancellation. A prior package-installed Docker -lane proved `/ready` and `/readyz` +production typing also passes. Timed-out plugin checks remain single-flight +until the original callback settles, even when the plugin ignores cancellation; +provider output is bounded, validated, and redacted. A prior package-installed +Docker lane proved `/ready` and `/readyz` transition `200 -> 503 -> 200` for a selected workspace failure and recovery, `/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with the same canonical condition. Exact-head remote container and published-upgrade diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 52ab2af4..a72e3316 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -158,7 +158,7 @@ The initial public core criteria are: | Not selectable | `ChannelRuntimeSuppressed` | Advisory when present | `ChannelRuntimeSuppressed` | | Not selectable | `EventLoopHealthy` | Advisory | `EventLoopDegraded`, `EventLoopStatusUnavailable` | | Not selectable | `ConfigLoaded` | Universal required | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | -| `openclaw.workspace-writable` | `WorkspaceWritable` | Selectable | `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | +| `openclaw.workspace-writable` | `WorkspaceWritable` | Selectable | `WorkspaceMissing`, `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | Not selectable | `PluginsLoaded` | Advisory | `PluginLoadFailures`, `PluginStatusUnavailable` | Each condition is `True` only when the runtime observes the corresponding @@ -226,19 +226,27 @@ A provider must not mutate config, reload plugins, acquire or rotate secrets, send model requests, change admission state, invoke tools, or alter another condition. +Provider `reason` must match `^[A-Za-z][A-Za-z0-9._-]{0,127}$`. Provider +`message` must be non-empty after trimming, contain no NUL bytes, and be at +most 512 UTF-8 bytes after core redaction. Output that violates these rules +becomes `CriterionInvalidResult=Unknown`; no raw provider exception or +unvalidated message is projected. + ### Activation Lifecycle The registered provider set is bound to one activation-pinned plugin registry -snapshot. Plugin reload builds a complete replacement set and publishes it -atomically with the new activation. Publication aborts in-flight callbacks from -the prior generation, invalidates their cached results, and prevents late -settlement from entering the active result. Core must keep retained state -bounded when a callback ignores cancellation; an abandoned callback must not -retain an active registry or become selectable after replacement. +and effective config snapshot. Plugin or config reload publishes replacement +snapshot identities. Publication aborts in-flight callbacks from the prior +generation, invalidates their cached results, and prevents late settlement from +entering the active result. Core must keep retained state bounded when a +callback ignores cancellation; an abandoned callback must not retain an active +registry or become selectable after replacement. Provider descriptors must be enumerable without invoking callbacks. At minimum -the descriptor contains the namespaced ID, description, owning plugin, and -activation generation. +the active registry entry contains the namespaced ID, description, owning +plugin, and source. The registry snapshot identity is the activation-generation +boundary; a future projection may expose the descriptor catalog without +executing providers. ## Operator Selection @@ -260,10 +268,10 @@ core or plugin criteria without selecting a hosting profile: ``` Selection uses namespaced criterion IDs. The same ID must not appear in both -lists. Unknown IDs in either list must fail configuration validation when the -provider registry is known. During activation uncertainty, an unknown selected -ID produces `Unknown` with the requirement of its containing list. Unknown IDs -must never be silently ignored. +lists. Configuration validates selector syntax. A syntactically valid selected +ID absent from the active registry produces `CriterionNotRegistered=Unknown` +with the requirement of its containing list. Unknown IDs must never be silently +ignored. Registration alone does not activate a plugin criterion. Only explicitly selected criteria participate: `advisoryCriteria` selects them as advisory and @@ -309,11 +317,11 @@ result and must not start another invocation. A new invocation may start only after the prior callback settles and the cache expires. Successful and failed provider or workspace observations may be cached for at -most five seconds. Config generation, plugin activation generation, effective -workspace identity, or selected-criterion changes invalidate affected entries -immediately. Admission, drain, startup, channel, and event-loop snapshots are -not made stale by this cache. A late result from an invalidated generation is -discarded. +most five seconds. Replacement effective-config or plugin-registry snapshots, +effective workspace identity, or selected-criterion changes invalidate affected +entries immediately. Admission, drain, startup, channel, and event-loop +snapshots are not made stale by this cache. A late result from an invalidated +generation is discarded. ## Projections From 4beac5d57115ea9d755c888213cdb3f45227aa09 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 08:30:11 -0700 Subject: [PATCH 60/98] docs(rfc-0018): refresh implementation head --- rfcs/0018-readiness-conditions-and-providers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 35c27551..77dd7a75 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -377,8 +377,8 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with nine ordered commits at exact head `788a58e612f`, -rebased onto OpenClaw `main` at `29d5dcfac6a`. The refreshed branch passes +It is one upstream PR with nine ordered commits at exact head `a8e61ac0691`, +rebased onto OpenClaw `main` at `4f4d89574a9`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; production typing also passes. Timed-out plugin checks remain single-flight until the original callback settles, even when the plugin ignores cancellation; From 585cb3e94cd8c465142a67283d1f5668d8fb0ce0 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 09:17:04 -0700 Subject: [PATCH 61/98] docs(rfc-0018): fence readiness generations --- rfcs/0018-readiness-conditions-and-providers.md | 2 +- rfcs/0018/readiness-v1-spec.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 77dd7a75..023d8721 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -377,7 +377,7 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with nine ordered commits at exact head `a8e61ac0691`, +It is one upstream PR with eleven ordered commits at exact head `813104950f5`, rebased onto OpenClaw `main` at `4f4d89574a9`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; production typing also passes. Timed-out plugin checks remain single-flight diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index a72e3316..88749bfc 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -235,8 +235,8 @@ unvalidated message is projected. ### Activation Lifecycle The registered provider set is bound to one activation-pinned plugin registry -and effective config snapshot. Plugin or config reload publishes replacement -snapshot identities. Publication aborts in-flight callbacks from the prior +and effective config snapshot. Plugin or config reload atomically publishes one +replacement config-and-registry snapshot identity. Publication aborts in-flight callbacks from the prior generation, invalidates their cached results, and prevents late settlement from entering the active result. Core must keep retained state bounded when a callback ignores cancellation; an abandoned callback must not retain an active @@ -348,7 +348,7 @@ must not synthesize success. Descriptor enumeration must not execute providers. An `openclaw ready` command, when implemented, is a client of the live Gateway result: -- human output lists non-true conditions; +- human output lists all conditions with pass, fail, or warning classification; - `--json` preserves the canonical result; and - exit status is nonzero for required failure, required unknown, transport failure, or absence of a supported readiness contract. From 1bccbd47369b2b53b86196b30cb3bba4362b9a7c Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 10:03:33 -0700 Subject: [PATCH 62/98] docs(rfc-0018): record generation recovery proof --- rfcs/0018-readiness-conditions-and-providers.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 023d8721..59bee7be 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -377,12 +377,14 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with eleven ordered commits at exact head `813104950f5`, -rebased onto OpenClaw `main` at `4f4d89574a9`. The refreshed branch passes +It is one upstream PR with twelve ordered commits at exact head `ac04dca2b21`, +rebased onto OpenClaw `main` at `b8a47b23384`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; -production typing also passes. Timed-out plugin checks remain single-flight +production typing and unused-export checks also pass. Timed-out plugin checks remain single-flight until the original callback settles, even when the plugin ignores cancellation; -provider output is bounded, validated, and redacted. A prior package-installed +provider output is bounded, validated, and redacted. Config publication fences +provider and workspace evidence by runtime generation, including recovery when +a retired filesystem probe never settles. A prior package-installed Docker lane proved `/ready` and `/readyz` transition `200 -> 503 -> 200` for a selected workspace failure and recovery, `/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with From 934d89036110e52d40faf2766f148cd4f08afc0d Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 10:11:48 -0700 Subject: [PATCH 63/98] docs(rfc-0018): bound workspace generation recovery --- rfcs/0018-readiness-conditions-and-providers.md | 10 ++++++++-- rfcs/0018/readiness-v1-spec.md | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 59bee7be..7b29a3e2 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -310,6 +310,11 @@ Publishing a replacement plugin registry or effective config snapshot aborts the prior generation, clears its cache, and prevents late settlement from entering the active result. +Workspace probes use the same generation fence but permit one replacement +probe when the effective workspace changes, so a blocked retired filesystem +does not pin the new workspace. At most two workspace probes may remain in +flight; further generations fail closed until capacity returns. + In-process timers cannot interrupt synchronous JavaScript that blocks the event loop. Providers therefore may not perform blocking synchronous I/O. Process or worker isolation for malicious plugins is outside this RFC. @@ -377,14 +382,15 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with twelve ordered commits at exact head `ac04dca2b21`, +It is one upstream PR with thirteen ordered commits at exact head `8fbc1210762`, rebased onto OpenClaw `main` at `b8a47b23384`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; production typing and unused-export checks also pass. Timed-out plugin checks remain single-flight until the original callback settles, even when the plugin ignores cancellation; provider output is bounded, validated, and redacted. Config publication fences provider and workspace evidence by runtime generation, including recovery when -a retired filesystem probe never settles. A prior package-installed +a retired filesystem probe never settles, while retaining a strict two-probe +ceiling across repeated generation changes. A prior package-installed Docker lane proved `/ready` and `/readyz` transition `200 -> 503 -> 200` for a selected workspace failure and recovery, `/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 88749bfc..1fe78d6a 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -323,6 +323,11 @@ entries immediately. Admission, drain, startup, channel, and event-loop snapshots are not made stale by this cache. A late result from an invalidated generation is discarded. +A changed workspace identity may start one replacement probe while a retired +probe remains blocked. No more than two workspace probes may remain in flight; +additional generations fail closed with `WorkspaceProbeTimedOut` until probe +capacity returns. + ## Projections All projections consume the same canonical result. From 9e87932863c6a561853430e0a419d7484914d145 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 10:23:06 -0700 Subject: [PATCH 64/98] docs(rfc-0018): record native baseline verification --- rfcs/0018-readiness-conditions-and-providers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 7b29a3e2..9e272d06 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -382,7 +382,7 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with thirteen ordered commits at exact head `8fbc1210762`, +It is one upstream PR with fourteen ordered commits at exact head `c1919669c3f`, rebased onto OpenClaw `main` at `b8a47b23384`. The refreshed branch passes focused readiness, Gateway, status, health, CLI, and method-metadata tests; production typing and unused-export checks also pass. Timed-out plugin checks remain single-flight From bf783ba317fabc6cd87ac79cb652209ca62e6a48 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 18:49:51 -0700 Subject: [PATCH 65/98] docs(rfc-0018): group follow-on readiness adoption --- ...0018-readiness-conditions-and-providers.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 9e272d06..8f8af313 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -416,6 +416,40 @@ The earlier consolidated draft remains useful behavior evidence, but it is not the proposed landing shape. The slices above can land without accepting profile names, profile selection, runtime activation identity, or release conformance. +#### Follow-on condition adoption + +The framework should not grow through one PR per condition. Follow-on adoption +is grouped by the OpenClaw owners that already maintain the underlying runtime +facts. Each bucket is one reviewable implementation unit; individual conditions +may be deferred when their owner does not yet expose a bounded activation +snapshot. + +| Bucket | Candidate conditions | Existing owner evidence | Proposed PR scope | +| --- | --- | --- | --- | +| Runtime activation integrity | `SecretsReady`, `ModelRouteReady`, `ConfigCurrent`, stronger `PluginsLoaded` semantics | Degraded secret-owner snapshots, model-auth and route resolution state, runtime config/reloader state, plugin activation and configured-unavailable state | Project activation-pinned facts into selectable or advisory conditions. Do not resolve secrets, contact a model, or reload plugins during readiness evaluation. | +| Agent execution capabilities | `ContextEngineReady`, `ToolCatalogReady`, `McpRuntimeReady`, `SandboxReady` or `HarnessReady` | Context-engine and tool-schema quarantine records, MCP runtime ownership, sandbox and harness runtime state | Let each selected execution owner publish a bounded condition. Optional capabilities remain advisory unless explicitly selected as required. | +| State and background services | `StateReady`, `RestoreComplete`, `DeliveryRuntimeReady`, `SchedulerReady` | State/store activation, restore fencing, delivery runtime and queue state, cron lifecycle state | Report whether configured stateful services can accept new work. Historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. | +| Hosted dependencies | `EgressReady`, `ManagedConfigApplied`, `HostBindingsReady` | Brokered transport state, effective config generation, and host-integration binding owners | Allow hosted integrations to contribute ordinary readiness conditions through the same provider contract. Keep Lobster, OCC, tenant, and deployment policy out of the core condition schema. | + +These buckets are adoption work over the v1 framework, not prerequisites for +accepting it. They do not change the v1 aggregation algorithm or make a newly +implemented condition required by default. A condition becomes required only +through explicit `gateway.readiness` selection or a separately accepted Hosting +Profile composition. + +Every adoption PR must preserve the owner boundary: + +1. expose or reuse a redacted, activation-scoped status fact; +2. map that fact to `True`, `False`, or `Unknown` without mutation; +3. bound evaluation through the v1 provider and outer-evaluator deadlines; +4. test ready, failed, unknown, timeout, recovery, and generation replacement; +5. prove that HTTP, RPC, health, status, and CLI project the same result. + +Readiness evaluation must not perform model inference, credential acquisition, +unbounded network discovery, migration, repair, restore, or queue draining. +Those operations remain owner workflows; readiness only observes their current +activation state. + ## Rationale This extends a surface OpenClaw already owns. It does not add a new health From 826b73156eaaf88023672fd4affb1134c6b9dcf0 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 23 Jul 2026 20:48:56 -0700 Subject: [PATCH 66/98] docs(rfc): make canonical readiness opt-in --- ...0018-readiness-conditions-and-providers.md | 43 ++++++++++++------- rfcs/0018/readiness-v1-spec.md | 34 +++++++++++---- 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 8f8af313..31b2263a 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -13,11 +13,13 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/33 ## Summary -Modernize OpenClaw's existing Gateway readiness evaluator into one canonical, -structured condition result. Existing startup, drain, channel, and event-loop +Add an opt-in canonical, structured condition result around OpenClaw's existing +Gateway readiness evaluator. Existing startup, drain, channel, and event-loop observations become core conditions; activated plugins may register bounded, -observational readiness providers; and `/ready`, `/readyz`, health, status, and -an optional CLI project the same result. +observational readiness providers; and configured `/ready`, `/readyz`, health, +status, and an optional CLI project the same result. Without readiness +configuration or another separately accepted activation contract, the existing +Gateway decision path remains authoritative. This RFC does not define hosting profiles. Standard Hosting Profiles are a separate proposal that may compose conditions from this RFC into named support @@ -52,8 +54,8 @@ core Gateway observations Required `False` or `Unknown` conditions fail readiness. Advisory conditions remain visible without causing an outage. Existing installations preserve their -current readiness behavior unless an operator explicitly requires an additional -provider condition. +current readiness path unless an operator adds `gateway.readiness` or selects a +separately accepted Standard Hosting Profile. ### Evidence from existing issues @@ -342,18 +344,27 @@ The CLI must not implement a second evaluator. ### Compatibility +Canonical readiness evaluation is opt-in. When `gateway.readiness` and any +separately accepted activation contract are both absent, the Gateway invokes +only its legacy lifecycle and channel checker; provider or runtime-evaluator +failure cannot create a new `503`. Presence of `gateway.readiness`, including +an empty object, activates bounded canonical evaluation. A separately accepted +Standard Hosting Profile may also activate canonical evaluation as part of +profile selection. + Existing `ready`, `failing`, `suppressed`, `eventLoop`, and `uptimeMs` fields remain compatibility projections during migration. New consumers use `conditions`, `failures`, and `advisories`. The migration order is: -1. emit canonical conditions beside legacy fields; -2. make every projection consume the same canonical evaluator; -3. migrate internal and external consumers; and -4. consider legacy-field removal only through a separate compatibility review. +1. preserve the legacy decision path when canonical readiness is not activated; +2. emit canonical conditions beside legacy fields after activation; +3. make every activated projection consume the same canonical evaluator; +4. migrate internal and external consumers; and +5. consider legacy-field removal only through a separate compatibility review. -Existing installations gain structured output but do not gain new required +Activated installations gain structured output but do not gain new required workspace or plugin dependencies. Registering or implementing an additional criterion does not make it required. Only explicit operator configuration or a separately selected standard profile changes the additional readiness gate. @@ -382,10 +393,12 @@ runtime activation identity, or a release support matrix. The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -It is one upstream PR with fourteen ordered commits at exact head `c1919669c3f`, -rebased onto OpenClaw `main` at `b8a47b23384`. The refreshed branch passes -focused readiness, Gateway, status, health, CLI, and method-metadata tests; -production typing and unused-export checks also pass. Timed-out plugin checks remain single-flight +Its upgrade boundary keeps unconfigured probes on the legacy checker and makes +the presence of `gateway.readiness` the explicit canonical activation signal. +It is one upstream PR with fifteen ordered commits at exact head `e49485d1c79`. +The opt-in compatibility amendment passes 130 focused readiness, live Gateway, +HTTP/RPC, health, selector, and CLI assertions; type-aware lint, formatting, and +diff checks pass. Timed-out plugin checks remain single-flight until the original callback settles, even when the plugin ignores cancellation; provider output is bounded, validated, and redacted. Config publication fences provider and workspace evidence by runtime generation, including recovery when diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 1fe78d6a..3b7a49cd 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -39,7 +39,8 @@ This specification does not define: criterion. - **Requirement**: whether a non-true condition blocks readiness. - **Universal condition**: a core lifecycle condition that always participates - and cannot be removed by operator configuration. + once canonical readiness is activated and cannot be removed by operator + configuration. - **Canonical result**: the single aggregated result consumed by all readiness projections. - **Projection**: an HTTP, health, status, or CLI representation of the @@ -49,6 +50,12 @@ This specification does not define: Readiness v1 uses these compatibility rules: +- absence of both `gateway.readiness` and another separately accepted + activation contract preserves the legacy Gateway readiness decision path and + does not execute the canonical runtime evaluator; +- presence of `gateway.readiness`, including an empty object, activates v1; +- a separately accepted Standard Hosting Profile may activate v1 through its + profile-selection contract; - condition `type` and `reason` values are stable machine contracts; - `message` is redacted operator guidance and is not stable machine identity; - adding an advisory criterion is backward compatible; @@ -173,9 +180,9 @@ The evaluator may emit these failure-only guard conditions: | `ReadinessEvaluationComplete` | Required | The bounded canonical evaluation completed; otherwise `ReadinessEvaluationTimedOut` or `ReadinessEvaluationFailed`. | | `GatewayResponding` | Required when the operation is remote | The caller reached the live Gateway; otherwise `GatewayUnavailable` or `GatewayNotChecked`. | -Implementations must preserve existing Gateway readiness behavior while these -observations are normalized. `workspace-writable` remains unselected unless an -operator or a separately accepted profile selects it. +Implementations must preserve existing unconfigured Gateway readiness behavior +while these observations are normalized. `workspace-writable` remains +unselected unless an operator or a separately accepted profile selects it. ## Plugin Readiness Providers @@ -330,7 +337,10 @@ capacity returns. ## Projections -All projections consume the same canonical result. +Once v1 is activated, all projections consume the same canonical result. When +neither direct readiness configuration nor another separately accepted +activation contract is present, `/ready` and `/readyz` retain the legacy Gateway +decision path and must not invoke providers or the canonical runtime evaluator. ### HTTP @@ -363,15 +373,23 @@ The CLI must not implement condition evaluation independently. ## Legacy Projection Existing `ready`, `failing`, `suppressed`, `eventLoop`, and `uptimeMs` fields -remain compatibility projections during migration. Implementations must first -emit canonical conditions beside legacy fields, then move every surface to the -canonical evaluator. Legacy removal requires a separate compatibility review. +remain compatibility projections during migration. Implementations preserve the +legacy path before activation, emit canonical conditions beside legacy fields +after activation, then move every activated surface to the canonical evaluator. +Legacy removal requires a separate compatibility review. ## Conformance Checklist An implementation conforms to readiness v1 when it proves: - existing unconfigured readiness behavior is unchanged; +- unconfigured probes do not execute providers or the canonical runtime + evaluator; +- an explicit empty `gateway.readiness` object activates canonical evaluation + without selecting additional criteria; +- implementations that support Standard Hosting Profiles prove that profile + selection activates canonical evaluation without requiring a separate + `gateway.readiness` section; - universal startup, admission, and selected-channel failures return `503`; - additional criteria do not become required without explicit selection; - required `False` and `Unknown` return `503`; From cf7231c71ff4c026811672ab8a22d7b2a5aab265 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 06:15:33 -0700 Subject: [PATCH 67/98] docs(rfc): refresh readiness implementation evidence --- rfcs/0018-readiness-conditions-and-providers.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 31b2263a..f9c41f73 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -395,10 +395,10 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with fifteen ordered commits at exact head `e49485d1c79`. -The opt-in compatibility amendment passes 130 focused readiness, live Gateway, -HTTP/RPC, health, selector, and CLI assertions; type-aware lint, formatting, and -diff checks pass. Timed-out plugin checks remain single-flight +It is one upstream PR with fourteen ordered commits at exact head `c21cf2903f4`. +The opt-in compatibility amendment passes 154 focused readiness, live Gateway, +HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, +formatting, and diff checks pass. Timed-out plugin checks remain single-flight until the original callback settles, even when the plugin ignores cancellation; provider output is bounded, validated, and redacted. Config publication fences provider and workspace evidence by runtime generation, including recovery when From 34afb0015e5e7d43f7ec4e21138ad6f4b45c6712 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 07:27:05 -0700 Subject: [PATCH 68/98] docs(rfc): record capability readiness evidence --- ...0018-readiness-conditions-and-providers.md | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index f9c41f73..c37d2fd2 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -3,7 +3,7 @@ title: Readiness Conditions and Providers authors: - Gio created: 2026-07-09 -last_updated: 2026-07-23 +last_updated: 2026-07-24 status: draft issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 @@ -444,6 +444,24 @@ snapshot. | State and background services | `StateReady`, `RestoreComplete`, `DeliveryRuntimeReady`, `SchedulerReady` | State/store activation, restore fencing, delivery runtime and queue state, cron lifecycle state | Report whether configured stateful services can accept new work. Historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. | | Hosted dependencies | `EgressReady`, `ManagedConfigApplied`, `HostBindingsReady` | Brokered transport state, effective config generation, and host-integration binding owners | Allow hosted integrations to contribute ordinary readiness conditions through the same provider contract. Keep Lobster, OCC, tenant, and deployment policy out of the core condition schema. | +The first two buckets have fork evidence slices stacked directly on the exact +head of the primary readiness implementation. They remain optional follow-on +work and are not prerequisites for accepting this RFC: + +- [Runtime activation integrity PR 153](https://github.com/giodl73-repo/openclaw/pull/153) + adds selectable `ConfigCurrent`, `ModelRouteReady`, and `SecretsReady` + conditions plus quarantine-aware plugin activation evidence. +- [Agent execution capabilities PR 154](https://github.com/giodl73-repo/openclaw/pull/154) + adds selectable context-engine, tool-catalog, MCP, sandbox, and harness + conditions. MCP discovery is captured for every configured agent when the + Gateway accepts a runtime configuration; readiness evaluation does not + connect to MCP servers or start any execution surface. + +The capability slice passes 14 focused assertions, production and source-test +typechecks, type-aware lint, formatting, and diff checks. Its review found and +fixed an initial default-agent-only MCP snapshot so the final evidence covers +all configured agent workspaces. + These buckets are adoption work over the v1 framework, not prerequisites for accepting it. They do not change the v1 aggregation algorithm or make a newly implemented condition required by default. A condition becomes required only From 6c9c9d7e3418c512606ad3132c7e6ed2d9c3ab53 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 08:37:17 -0700 Subject: [PATCH 69/98] docs(rfc): record state service readiness evidence --- ...0018-readiness-conditions-and-providers.md | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index c37d2fd2..42b864bd 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -441,10 +441,10 @@ snapshot. | --- | --- | --- | --- | | Runtime activation integrity | `SecretsReady`, `ModelRouteReady`, `ConfigCurrent`, stronger `PluginsLoaded` semantics | Degraded secret-owner snapshots, model-auth and route resolution state, runtime config/reloader state, plugin activation and configured-unavailable state | Project activation-pinned facts into selectable or advisory conditions. Do not resolve secrets, contact a model, or reload plugins during readiness evaluation. | | Agent execution capabilities | `ContextEngineReady`, `ToolCatalogReady`, `McpRuntimeReady`, `SandboxReady` or `HarnessReady` | Context-engine and tool-schema quarantine records, MCP runtime ownership, sandbox and harness runtime state | Let each selected execution owner publish a bounded condition. Optional capabilities remain advisory unless explicitly selected as required. | -| State and background services | `StateReady`, `RestoreComplete`, `DeliveryRuntimeReady`, `SchedulerReady` | State/store activation, restore fencing, delivery runtime and queue state, cron lifecycle state | Report whether configured stateful services can accept new work. Historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. | +| State and background services | `StateReady`, `DeliveryRuntimeReady`, `SchedulerReady`; defer `RestoreComplete` until a restore fence exists | State/store activation, delivery runtime ownership, cron lifecycle and startup recovery state | Report whether configured stateful services can accept new work. Historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. Do not infer restore completion from database-open, fleet-restore, or config-migration state. | | Hosted dependencies | `EgressReady`, `ManagedConfigApplied`, `HostBindingsReady` | Brokered transport state, effective config generation, and host-integration binding owners | Allow hosted integrations to contribute ordinary readiness conditions through the same provider contract. Keep Lobster, OCC, tenant, and deployment policy out of the core condition schema. | -The first two buckets have fork evidence slices stacked directly on the exact +The first three buckets have fork evidence slices stacked directly on the exact head of the primary readiness implementation. They remain optional follow-on work and are not prerequisites for accepting this RFC: @@ -456,11 +456,20 @@ work and are not prerequisites for accepting this RFC: conditions. MCP discovery is captured for every configured agent when the Gateway accepts a runtime configuration; readiness evaluation does not connect to MCP servers or start any execution surface. - -The capability slice passes 14 focused assertions, production and source-test -typechecks, type-aware lint, formatting, and diff checks. Its review found and -fixed an initial default-agent-only MCP snapshot so the final evidence covers -all configured agent workspaces. +- [State and background services PR 155](https://github.com/giodl73-repo/openclaw/pull/155) + adds selectable state-database, durable session-delivery, and scheduler + lifecycle conditions. Owners publish synchronous process-local snapshots; + readiness does not open SQLite, install delivery recovery, import or start + cron, scan queues, or run recovery. `RestoreComplete` remains deferred until + OpenClaw owns a generic restore generation and admission fence. + +The capability slice passes 14 focused assertions and the state/background +slice passes 145 focused assertions. Both pass production and source-test +typechecks, type-aware lint, formatting, and diff checks. Capability review +found and fixed an initial default-agent-only MCP snapshot so the final evidence +covers all configured agent workspaces. State/background review verified +disabled, starting, recovery-pending, active, stopped, failed, repaired, and +stale-generation transitions without adding probe-side I/O. These buckets are adoption work over the v1 framework, not prerequisites for accepting it. They do not change the v1 aggregation algorithm or make a newly From 4016693493458fc896f2a74e74143d713a6e2907 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 09:12:59 -0700 Subject: [PATCH 70/98] docs(rfc): add host binding readiness composition --- ...0018-readiness-conditions-and-providers.md | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 42b864bd..992fec08 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -442,11 +442,13 @@ snapshot. | Runtime activation integrity | `SecretsReady`, `ModelRouteReady`, `ConfigCurrent`, stronger `PluginsLoaded` semantics | Degraded secret-owner snapshots, model-auth and route resolution state, runtime config/reloader state, plugin activation and configured-unavailable state | Project activation-pinned facts into selectable or advisory conditions. Do not resolve secrets, contact a model, or reload plugins during readiness evaluation. | | Agent execution capabilities | `ContextEngineReady`, `ToolCatalogReady`, `McpRuntimeReady`, `SandboxReady` or `HarnessReady` | Context-engine and tool-schema quarantine records, MCP runtime ownership, sandbox and harness runtime state | Let each selected execution owner publish a bounded condition. Optional capabilities remain advisory unless explicitly selected as required. | | State and background services | `StateReady`, `DeliveryRuntimeReady`, `SchedulerReady`; defer `RestoreComplete` until a restore fence exists | State/store activation, delivery runtime ownership, cron lifecycle and startup recovery state | Report whether configured stateful services can accept new work. Historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. Do not infer restore completion from database-open, fleet-restore, or config-migration state. | -| Hosted dependencies | `EgressReady`, `ManagedConfigApplied`, `HostBindingsReady` | Brokered transport state, effective config generation, and host-integration binding owners | Allow hosted integrations to contribute ordinary readiness conditions through the same provider contract. Keep Lobster, OCC, tenant, and deployment policy out of the core condition schema. | +| Hosted dependencies | `HostBindingsReady`; defer `EgressReady` and `ManagedConfigApplied` until their owners publish authoritative facts | RFC 0020 host-integration bundle and owner-generation evidence | Project required host bindings through the ordinary readiness selector. Keep network probing, config inference, Lobster, OCC, tenant, and deployment policy out of the condition evaluator. | -The first three buckets have fork evidence slices stacked directly on the exact -head of the primary readiness implementation. They remain optional follow-on -work and are not prerequisites for accepting this RFC: +All four buckets now have fork evidence slices. The first three are stacked +directly on the exact head of the primary readiness implementation. The fourth +is stacked on an explicit composition of that readiness head with RFC 0020 host +integration package 3. They remain optional follow-on work and are not +prerequisites for accepting this RFC: - [Runtime activation integrity PR 153](https://github.com/giodl73-repo/openclaw/pull/153) adds selectable `ConfigCurrent`, `ModelRouteReady`, and `SecretsReady` @@ -462,10 +464,22 @@ work and are not prerequisites for accepting this RFC: readiness does not open SQLite, install delivery recovery, import or start cron, scan queues, or run recovery. `RestoreComplete` remains deferred until OpenClaw owns a generic restore generation and admission fence. - -The capability slice passes 14 focused assertions and the state/background -slice passes 145 focused assertions. Both pass production and source-test -typechecks, type-aware lint, formatting, and diff checks. Capability review +- [Hosted dependencies PR 156](https://github.com/giodl73-repo/openclaw/pull/156) + adds selectable `openclaw.host-bindings-ready` and projects the active RFC + 0020 host-integration bundle plus owner-published generation evidence into + `HostBindingsReady`. Required bindings fail closed for missing, + incompatible, unresolved, stale, degraded, or unavailable state. Optional + binding failures remain visible without blocking the aggregate condition. + Evaluation is synchronous, in-memory, and bounded before inventory + projection. Generic `EgressReady` remains with concrete dispatcher and + traffic-policy owners; `ManagedConfigApplied` remains deferred until Managed + Config publishes an authoritative applied/effective generation. + +The capability slice passes 14 focused assertions, the state/background slice +passes 145 focused assertions, and the hosted-binding composition passes 19 +focused unit assertions plus 69 Gateway readiness assertions. The first two +pass production and source-test typechecks; all three pass lint, formatting, +diff checks, and independent review. Capability review found and fixed an initial default-agent-only MCP snapshot so the final evidence covers all configured agent workspaces. State/background review verified disabled, starting, recovery-pending, active, stopped, failed, repaired, and From e61239b5ad413e17f7dce6e1954afbbb34943bbd Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 09:45:22 -0700 Subject: [PATCH 71/98] docs(rfc): complete host binding readiness evidence --- ...0018-readiness-conditions-and-providers.md | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 992fec08..c203a2a9 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -465,20 +465,25 @@ prerequisites for accepting this RFC: cron, scan queues, or run recovery. `RestoreComplete` remains deferred until OpenClaw owns a generic restore generation and admission fence. - [Hosted dependencies PR 156](https://github.com/giodl73-repo/openclaw/pull/156) - adds selectable `openclaw.host-bindings-ready` and projects the active RFC - 0020 host-integration bundle plus owner-published generation evidence into - `HostBindingsReady`. Required bindings fail closed for missing, - incompatible, unresolved, stale, degraded, or unavailable state. Optional - binding failures remain visible without blocking the aggregate condition. - Evaluation is synchronous, in-memory, and bounded before inventory - projection. Generic `EgressReady` remains with concrete dispatcher and - traffic-policy owners; `ManagedConfigApplied` remains deferred until Managed - Config publishes an authoritative applied/effective generation. + adds selectable `openclaw.host-bindings-ready` and connects RFC 0020 bundle + declarations to the active core/plugin criterion catalog. Selecting the + aggregate includes referenced criteria as advisory detail without requiring + operators to repeat the bundle's selectors. A required contribution fails + the aggregate for missing, incompatible, unresolved, stale, degraded, or + unavailable owner state, and when a declared criterion is absent, `False`, + or `Unknown`; optional contributions remain visible without blocking it. + Status and Doctor name unresolved selectors, recursive aggregate references + are prohibited, and manifests are capped at 64 unique selectors. Evaluation + uses one bounded in-memory bundle/evidence snapshot. Real endpoint coverage + proves `/ready` returns `200 -> 503 -> 200` across owner-generation failure + and recovery. Generic `EgressReady`, `ManagedConfigApplied`, and + `RestoreComplete` remain deferred until their owners publish authoritative + facts. The capability slice passes 14 focused assertions, the state/background slice -passes 145 focused assertions, and the hosted-binding composition passes 19 -focused unit assertions plus 69 Gateway readiness assertions. The first two -pass production and source-test typechecks; all three pass lint, formatting, +passes 145 focused assertions, and the hosted-binding composition passes 142 +focused assertions including the real Gateway endpoint transition. The first +two pass production and source-test typechecks; all three pass lint, formatting, diff checks, and independent review. Capability review found and fixed an initial default-agent-only MCP snapshot so the final evidence covers all configured agent workspaces. State/background review verified From 720167e74bd8a0c6dfe381f48f0f276d6f64c344 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 12:01:43 -0700 Subject: [PATCH 72/98] docs(rfc): add session storage readiness --- ...0018-readiness-conditions-and-providers.md | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index c203a2a9..93732b5b 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -440,8 +440,8 @@ snapshot. | Bucket | Candidate conditions | Existing owner evidence | Proposed PR scope | | --- | --- | --- | --- | | Runtime activation integrity | `SecretsReady`, `ModelRouteReady`, `ConfigCurrent`, stronger `PluginsLoaded` semantics | Degraded secret-owner snapshots, model-auth and route resolution state, runtime config/reloader state, plugin activation and configured-unavailable state | Project activation-pinned facts into selectable or advisory conditions. Do not resolve secrets, contact a model, or reload plugins during readiness evaluation. | -| Agent execution capabilities | `ContextEngineReady`, `ToolCatalogReady`, `McpRuntimeReady`, `SandboxReady` or `HarnessReady` | Context-engine and tool-schema quarantine records, MCP runtime ownership, sandbox and harness runtime state | Let each selected execution owner publish a bounded condition. Optional capabilities remain advisory unless explicitly selected as required. | -| State and background services | `StateReady`, `DeliveryRuntimeReady`, `SchedulerReady`; defer `RestoreComplete` until a restore fence exists | State/store activation, delivery runtime ownership, cron lifecycle and startup recovery state | Report whether configured stateful services can accept new work. Historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. Do not infer restore completion from database-open, fleet-restore, or config-migration state. | +| Agent execution capabilities | `ContextEngineReady`, `ToolCatalogReady`, `McpRuntimeReady`, `SandboxReady` or `HarnessReady`; defer `SkillsReady` until bounded owner evidence exists | Context-engine and tool-schema quarantine records, MCP runtime ownership, sandbox and harness runtime state | Let each selected execution owner publish a bounded condition. Optional capabilities remain advisory unless explicitly selected as required. Do not rebuild the skill inventory in the readiness path. | +| State and background services | `StateReady`, `SessionStorageReady`, `DeliveryRuntimeReady`, `SchedulerReady`; defer `RestoreComplete` until a restore fence exists | State/store activation, bounded persistence-location probes, delivery runtime ownership, cron lifecycle and startup recovery state | Report whether configured stateful services can accept new work. A selected storage probe may perform a capped write/fsync/unlink check, but historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. Do not infer restore completion from database-open, fleet-restore, or config-migration state. | | Hosted dependencies | `HostBindingsReady`; defer `EgressReady` and `ManagedConfigApplied` until their owners publish authoritative facts | RFC 0020 host-integration bundle and owner-generation evidence | Project required host bindings through the ordinary readiness selector. Keep network probing, config inference, Lobster, OCC, tenant, and deployment policy out of the condition evaluator. | All four buckets now have fork evidence slices. The first three are stacked @@ -457,13 +457,18 @@ prerequisites for accepting this RFC: adds selectable context-engine, tool-catalog, MCP, sandbox, and harness conditions. MCP discovery is captured for every configured agent when the Gateway accepts a runtime configuration; readiness evaluation does not - connect to MCP servers or start any execution surface. + connect to MCP servers or start any execution surface. `SkillsReady` remains + deferred because the current skill inventory path is not a bounded readiness + source; the skills owner must first publish an activation snapshot or index. - [State and background services PR 155](https://github.com/giodl73-repo/openclaw/pull/155) - adds selectable state-database, durable session-delivery, and scheduler - lifecycle conditions. Owners publish synchronous process-local snapshots; - readiness does not open SQLite, install delivery recovery, import or start - cron, scan queues, or run recovery. `RestoreComplete` remains deferred until - OpenClaw owns a generic restore generation and admission fence. + adds selectable state-database, session-storage, durable session-delivery, + and scheduler lifecycle conditions. Owners publish synchronous process-local + snapshots. The selected storage condition uses a one-second, target-capped, + concurrency-capped, generation-safe write/fsync/unlink probe over resolved + persistence parents; failures are redacted. Readiness does not open SQLite, + install delivery recovery, import or start cron, scan queues, or run recovery. + `RestoreComplete` remains deferred until OpenClaw owns a generic restore + generation and admission fence. - [Hosted dependencies PR 156](https://github.com/giodl73-repo/openclaw/pull/156) adds selectable `openclaw.host-bindings-ready` and connects RFC 0020 bundle declarations to the active core/plugin criterion catalog. Selecting the From bb4d65a06d3b002253e1aea3bb6d6c8bf79e6a4f Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 14:56:41 -0700 Subject: [PATCH 73/98] docs(rfc-0018): add core owner adoption --- ...0018-readiness-conditions-and-providers.md | 25 +++++++++++++++---- rfcs/0018/readiness-v1-spec.md | 22 +++++++++++++--- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 93732b5b..6a6ebad1 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -162,16 +162,21 @@ justifies them. | `ConfigLoaded` | Required | The validated effective runtime config snapshot is installed. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | | `WorkspaceWritable` | Required or advisory when selected | The effective workspace exists and passes a bounded write, flush, and cleanup probe. It is not a new universal blocker by default. | `WorkspaceMissing`, `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `PluginsLoaded` | Advisory | The activation-pinned plugin registry is available and selected plugins have no activation errors. | `PluginLoadFailures`, `PluginStatusUnavailable` | +| `ConfigCurrent` | Required or advisory when selected | The accepted effective config does not require restart. | `ConfigRestartRequired` | +| `ModelRouteReady` | Required or advisory when selected | The selected model route has usable provider authentication. | `ModelRouteUnavailable`, `ModelAuthUnavailable` | +| `SecretsReady` | Required or advisory when selected | Required secret owners resolved during activation. | `SecretOwnersUnavailable` | +| `SessionStorageReady` | Required or advisory when selected | Session storage passes its bounded write, flush, and cleanup probe. | `SessionStorageMissing`, `SessionStorageFull`, `SessionStorageNotWritable`, `SessionStorageProbeFailed`, `SessionStorageProbeTimedOut` | +| `ContextEngineReady`, `ToolCatalogReady`, `McpRuntimeReady`, `SandboxReady`, `HarnessReady` | Required or advisory when selected | Each configured execution capability has activation evidence from its owning subsystem. An intentionally unconfigured optional capability is satisfied. | Owner-specific unavailable, failed, or unobserved reasons. | +| `StateReady`, `DeliveryRuntimeReady`, `SchedulerReady` | Required or advisory when selected | Existing state and background-service snapshots report their current observed status. | Owner-specific unavailable, degraded, or unobserved reasons. | Changing an advisory core condition to required is a compatibility-sensitive behavior change. It requires focused review and release notes because it can change `/ready` from `200` to `503` for an existing deployment. -Further startup facts such as required plugin activation, required secret -availability, or resolved model routing should use the same condition model, -but only after their owners expose bounded, redacted activation snapshots. -Readiness polling must not reload plugins, reacquire secrets, or issue a model -request. +These selectable core conditions consume bounded, redacted observations from +their owning subsystems. Readiness polling must not reload plugins, reacquire +secrets, issue a model request, connect MCP servers, start a sandbox or harness, +open the state database, or start a scheduler. ### Readiness providers @@ -411,6 +416,16 @@ the same canonical condition. Exact-head remote container and published-upgrade proof must be refreshed before landing. Reviewers should use that PR for the proposed landing shape and current validation state. +The first core-owner adoption is consolidated in +[openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), +stacked at exact readiness head `c21cf2903f4`. It adds selectable activation, +execution-capability, session-storage, state, delivery, and scheduler +observations without selecting any of them by default. Fork PRs +[#153](https://github.com/giodl73-repo/openclaw/pull/153), +[#154](https://github.com/giodl73-repo/openclaw/pull/154), and +[#155](https://github.com/giodl73-repo/openclaw/pull/155) preserve the three +owner-area review slices; PR 113421 is the intended merge unit. + The fork PRs below expose the implementation as optional smaller review slices. They are supporting review aids, not alternative landing PRs: diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 3b7a49cd..7692c85c 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -146,7 +146,7 @@ The condition array must use this v1 order when present: 3. `ConfigLoaded` and `WorkspaceWritable`; 4. profile-owned conditions in the order defined by RFC 0023; 5. `GatewayResponding` and `PluginsLoaded`; and -6. remaining plugin conditions sorted by namespaced criterion ID. +6. remaining selected core and plugin conditions sorted by condition type. `failures` and `advisories` follow condition order and contain no duplicates. @@ -166,12 +166,26 @@ The initial public core criteria are: | Not selectable | `EventLoopHealthy` | Advisory | `EventLoopDegraded`, `EventLoopStatusUnavailable` | | Not selectable | `ConfigLoaded` | Universal required | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | | `openclaw.workspace-writable` | `WorkspaceWritable` | Selectable | `WorkspaceMissing`, `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | +| `openclaw.config-current` | `ConfigCurrent` | Selectable | `ConfigRestartRequired` | +| `openclaw.model-route-ready` | `ModelRouteReady` | Selectable | `ModelRouteUnavailable`, `ModelAuthUnavailable` | +| `openclaw.secrets-ready` | `SecretsReady` | Selectable | `SecretOwnersUnavailable` | +| `openclaw.session-storage-ready` | `SessionStorageReady` | Selectable | `SessionStorageMissing`, `SessionStorageFull`, `SessionStorageNotWritable`, `SessionStorageProbeFailed`, `SessionStorageProbeTimedOut`, `SessionStorageNotChecked` | +| `openclaw.context-engine-ready` | `ContextEngineReady` | Selectable | Owner-defined bounded activation reasons. | +| `openclaw.tool-catalog-ready` | `ToolCatalogReady` | Selectable | Owner-defined bounded activation reasons. | +| `openclaw.mcp-runtime-ready` | `McpRuntimeReady` | Selectable | Owner-defined bounded activation reasons. | +| `openclaw.sandbox-ready` | `SandboxReady` | Selectable | Owner-defined bounded activation reasons. | +| `openclaw.harness-ready` | `HarnessReady` | Selectable | Owner-defined bounded activation reasons. | +| `openclaw.state-ready` | `StateReady` | Selectable | Owner-defined bounded state reasons. | +| `openclaw.delivery-runtime-ready` | `DeliveryRuntimeReady` | Selectable | Owner-defined bounded delivery reasons. | +| `openclaw.scheduler-ready` | `SchedulerReady` | Selectable | Owner-defined bounded scheduler reasons. | | Not selectable | `PluginsLoaded` | Advisory | `PluginLoadFailures`, `PluginStatusUnavailable` | Each condition is `True` only when the runtime observes the corresponding -startup, admission, channel, event-loop, config, workspace, or plugin predicate -described by RFC 0018. A successful condition uses a stable success reason that -normally matches its condition type. +startup, admission, channel, event-loop, config, activation, workspace, +execution-capability, state, background-service, or plugin predicate described +by RFC 0018. A successful condition uses a stable success reason that normally +matches its condition type. Selectable owner criteria must observe existing +snapshots and must not initiate the subsystem work they report. The evaluator may emit these failure-only guard conditions: From 443c53c5edad2882535713b06e9c5b468c2442c2 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Fri, 24 Jul 2026 16:05:28 -0700 Subject: [PATCH 74/98] docs(rfc-0018): add canonical selectors and policy example --- ...0018-readiness-conditions-and-providers.md | 20 +++++++++++++++---- rfcs/0018/readiness-v1-spec.md | 11 ++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 6a6ebad1..b4041dbc 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -156,12 +156,12 @@ justifies them. | `GatewayAcceptingWork` | Required | The Gateway is not draining and can admit new work. | `GatewayDraining` | | `ChannelRuntimeReady` | Required | No selected channel has an unsuppressed runtime-health failure under existing channel policy. | `ChannelRuntimeUnavailable` | | `ChannelRuntimeSuppressed` | Advisory when present | A channel runtime failure is intentionally suppressed by existing autostart/crash-loop policy. | `ChannelRuntimeSuppressed` | -| `EventLoopHealthy` | Advisory initially | Existing event-loop health is within its healthy threshold. | `EventLoopDegraded`, `EventLoopStatusUnavailable` | +| `EventLoopHealthy` | Advisory by default; selectable | Existing event-loop health is within its healthy threshold. | `EventLoopDegraded`, `EventLoopStatusUnavailable`, `CriterionEvaluationUnavailable` | | `ReadinessEvaluationComplete` | Required when emitted | The bounded canonical evaluation completed. This failure-only guard condition is emitted when the evaluator cannot produce its normal condition set. | `ReadinessEvaluationTimedOut`, `ReadinessEvaluationFailed` | | `GatewayResponding` | Required when observed remotely | The current operation successfully reached the live Gateway. | `GatewayUnavailable`, `GatewayNotChecked` | | `ConfigLoaded` | Required | The validated effective runtime config snapshot is installed. | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | | `WorkspaceWritable` | Required or advisory when selected | The effective workspace exists and passes a bounded write, flush, and cleanup probe. It is not a new universal blocker by default. | `WorkspaceMissing`, `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | -| `PluginsLoaded` | Advisory | The activation-pinned plugin registry is available and selected plugins have no activation errors. | `PluginLoadFailures`, `PluginStatusUnavailable` | +| `PluginsLoaded` | Advisory by default; selectable | The activation-pinned plugin registry is available and selected plugins have no activation errors. | `PluginLoadFailures`, `PluginStatusUnavailable`, `CriterionEvaluationUnavailable` | | `ConfigCurrent` | Required or advisory when selected | The accepted effective config does not require restart. | `ConfigRestartRequired` | | `ModelRouteReady` | Required or advisory when selected | The selected model route has usable provider authentication. | `ModelRouteUnavailable`, `ModelAuthUnavailable` | | `SecretsReady` | Required or advisory when selected | Required secret owners resolved during activation. | `SecretOwnersUnavailable` | @@ -233,6 +233,14 @@ bound to the activated plugin registry snapshot. Reload replaces the complete provider set atomically with the next activation; stale callbacks do not remain registered. +The bundled Policy plugin is the concrete v1 example. When activated, it +registers `plugin.policy.conformant`, reuses its existing policy evaluator, and +reports `True` when evaluation has no findings, `False` with a bounded finding +count when findings exist, and `Unknown` when policy checks are disabled. The +provider remains inert until an operator selects it. Selecting it as advisory +exposes drift without changing `/readyz` from `200`; selecting it as required +makes nonconformance block readiness. + Provider descriptors are enumerable without invoking callbacks. The active registry exposes provider identity, description, owning plugin, and source; the registry snapshot itself is the activation-generation boundary. Future status @@ -272,7 +280,11 @@ hosting profile: "openclaw.workspace-writable", "plugin.storage.backend", ], - advisoryCriteria: ["plugin.metrics.exporter"], + advisoryCriteria: [ + "openclaw.event-loop-healthy", + "plugin.metrics.exporter", + "plugin.policy.conformant", + ], }, }, } @@ -454,7 +466,7 @@ snapshot. | Bucket | Candidate conditions | Existing owner evidence | Proposed PR scope | | --- | --- | --- | --- | -| Runtime activation integrity | `SecretsReady`, `ModelRouteReady`, `ConfigCurrent`, stronger `PluginsLoaded` semantics | Degraded secret-owner snapshots, model-auth and route resolution state, runtime config/reloader state, plugin activation and configured-unavailable state | Project activation-pinned facts into selectable or advisory conditions. Do not resolve secrets, contact a model, or reload plugins during readiness evaluation. | +| Runtime activation integrity | `SecretsReady`, `ModelRouteReady`, `ConfigCurrent`, selectable `PluginsLoaded`, selectable `EventLoopHealthy` | Degraded secret-owner snapshots, model-auth and route resolution state, runtime config/reloader state, plugin activation and configured-unavailable state, Gateway event-loop snapshot | Project activation-pinned facts and existing canonical Gateway facts into selectable or advisory conditions. Do not resolve secrets, contact a model, reload plugins, or create a second event-loop probe during readiness evaluation. | | Agent execution capabilities | `ContextEngineReady`, `ToolCatalogReady`, `McpRuntimeReady`, `SandboxReady` or `HarnessReady`; defer `SkillsReady` until bounded owner evidence exists | Context-engine and tool-schema quarantine records, MCP runtime ownership, sandbox and harness runtime state | Let each selected execution owner publish a bounded condition. Optional capabilities remain advisory unless explicitly selected as required. Do not rebuild the skill inventory in the readiness path. | | State and background services | `StateReady`, `SessionStorageReady`, `DeliveryRuntimeReady`, `SchedulerReady`; defer `RestoreComplete` until a restore fence exists | State/store activation, bounded persistence-location probes, delivery runtime ownership, cron lifecycle and startup recovery state | Report whether configured stateful services can accept new work. A selected storage probe may perform a capped write/fsync/unlink check, but historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. Do not infer restore completion from database-open, fleet-restore, or config-migration state. | | Hosted dependencies | `HostBindingsReady`; defer `EgressReady` and `ManagedConfigApplied` until their owners publish authoritative facts | RFC 0020 host-integration bundle and owner-generation evidence | Project required host bindings through the ordinary readiness selector. Keep network probing, config inference, Lobster, OCC, tenant, and deployment policy out of the condition evaluator. | diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 7692c85c..2c14c610 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -163,7 +163,7 @@ The initial public core criteria are: | Not selectable | `GatewayAcceptingWork` | Universal required | `GatewayDraining`, `GatewayAdmissionNotChecked` | | Not selectable | `ChannelRuntimeReady` | Universal required | `ChannelRuntimeUnavailable`, `ChannelRuntimeNotChecked` | | Not selectable | `ChannelRuntimeSuppressed` | Advisory when present | `ChannelRuntimeSuppressed` | -| Not selectable | `EventLoopHealthy` | Advisory | `EventLoopDegraded`, `EventLoopStatusUnavailable` | +| `openclaw.event-loop-healthy` | `EventLoopHealthy` | Advisory unless selected as required | `EventLoopDegraded`, `EventLoopStatusUnavailable`, `CriterionEvaluationUnavailable` | | Not selectable | `ConfigLoaded` | Universal required | `ConfigNotLoaded`, `ConfigInvalid`, `EffectiveConfigUnavailable` | | `openclaw.workspace-writable` | `WorkspaceWritable` | Selectable | `WorkspaceMissing`, `WorkspaceStorageFull`, `WorkspaceNotWritable`, `WorkspaceProbeFailed`, `WorkspaceProbeTimedOut`, `WorkspaceNotChecked` | | `openclaw.config-current` | `ConfigCurrent` | Selectable | `ConfigRestartRequired` | @@ -178,7 +178,7 @@ The initial public core criteria are: | `openclaw.state-ready` | `StateReady` | Selectable | Owner-defined bounded state reasons. | | `openclaw.delivery-runtime-ready` | `DeliveryRuntimeReady` | Selectable | Owner-defined bounded delivery reasons. | | `openclaw.scheduler-ready` | `SchedulerReady` | Selectable | Owner-defined bounded scheduler reasons. | -| Not selectable | `PluginsLoaded` | Advisory | `PluginLoadFailures`, `PluginStatusUnavailable` | +| `openclaw.plugins-loaded` | `PluginsLoaded` | Advisory unless selected as required | `PluginLoadFailures`, `PluginStatusUnavailable`, `CriterionEvaluationUnavailable` | Each condition is `True` only when the runtime observes the corresponding startup, admission, channel, event-loop, config, activation, workspace, @@ -232,6 +232,13 @@ Registration through `api.registerReadinessCriterion` is scoped to the current plugin activation. Core publishes the resulting ID as `plugin..`. +The bundled Policy plugin demonstrates this contract with +`plugin.policy.conformant`. It reuses the plugin's existing policy evaluation, +returns only bounded summary text, and is not evaluated until selected through +`gateway.readiness`. Advisory selection does not affect the overall readiness +decision; required selection fails closed for findings, disabled evaluation, +provider failure, or timeout. + ### Provider Requirements A provider must be: From 533438cce12f1c288b7c824b357726ef1f587347 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 10:01:38 -0700 Subject: [PATCH 75/98] docs(rfc-0018): refresh implementation stack --- rfcs/0018-readiness-conditions-and-providers.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index b4041dbc..368727a3 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -412,7 +412,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with fourteen ordered commits at exact head `c21cf2903f4`. +It is one upstream PR with fourteen ordered commits at exact head `f1af3de0a9b1`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -430,7 +430,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `c21cf2903f4`. It adds selectable activation, +stacked at exact readiness head `f1af3de0a9b1` and exact implementation head +`785a11b05e9c`. It adds selectable activation, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From e8683d3144dd39448c91c330b60128f9cce5b2f7 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 10:19:59 -0700 Subject: [PATCH 76/98] docs(rfc-0018): advance rebased implementation heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 368727a3..b49036fc 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -412,7 +412,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with fourteen ordered commits at exact head `f1af3de0a9b1`. +It is one upstream PR with fifteen ordered commits at exact head `5861bcd70c6a`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -430,8 +430,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `f1af3de0a9b1` and exact implementation head -`785a11b05e9c`. It adds selectable activation, +stacked at exact readiness head `5861bcd70c6a` and exact implementation head +`ce9ef81b24d6`. It adds selectable activation, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From 7449f2d532db46630c318f94e77b4f6d2530cf30 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 12:44:53 -0700 Subject: [PATCH 77/98] docs(rfc-0018): specify readiness subjects --- ...0018-readiness-conditions-and-providers.md | 102 ++++++-- rfcs/0018/readiness-subjects-v1-spec.md | 247 ++++++++++++++++++ rfcs/0018/readiness-v1-spec.md | 38 ++- 3 files changed, 366 insertions(+), 21 deletions(-) create mode 100644 rfcs/0018/readiness-subjects-v1-spec.md diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index b49036fc..f6e605ab 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -3,7 +3,7 @@ title: Readiness Conditions and Providers authors: - Gio created: 2026-07-09 -last_updated: 2026-07-24 +last_updated: 2026-07-25 status: draft issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 @@ -16,8 +16,9 @@ rfc_pr: https://github.com/openclaw/rfcs/pull/33 Add an opt-in canonical, structured condition result around OpenClaw's existing Gateway readiness evaluator. Existing startup, drain, channel, and event-loop observations become core conditions; activated plugins may register bounded, -observational readiness providers; and configured `/ready`, `/readyz`, health, -status, and an optional CLI project the same result. Without readiness +observational readiness providers; every condition identifies the runtime +subject it observed; and configured `/ready`, `/readyz`, health, status, and an +optional CLI project the same result. Without readiness configuration or another separately accepted activation contract, the existing Gateway decision path remains authoritative. @@ -32,6 +33,8 @@ answers important questions about startup, channel runtime health, drain state, and event-loop health, but it is not an extensible readiness contract: - existing observations do not share an iterable condition shape; +- a result cannot identify whether a failed fact belongs to the Gateway, + configuration generation, plugin, node, storage backend, or another subject; - plugins cannot contribute bounded readiness observations; - operators cannot promote a known plugin dependency to required; - health and status can omit facts or describe them differently; and @@ -70,6 +73,8 @@ separately accepted Standard Hosting Profile. ## Goals - Define one stable readiness-condition shape and aggregation rule. +- Define one bounded identity package so conditions can reference core- and + plugin-owned subjects without copying identity fields into every condition. - Normalize existing Gateway readiness observations into core conditions. - Preserve existing response fields as compatibility projections. - Add activation-scoped plugin readiness providers through the plugin SDK. @@ -98,11 +103,13 @@ separately accepted Standard Hosting Profile. ## Proposal -The implementer-facing v1 contract is captured in -[`0018/readiness-v1-spec.md`](0018/readiness-v1-spec.md). This RFC remains the -design rationale, compatibility argument, and rollout plan; the sidecar is the -concise schema, provider-lifecycle, evaluation, projection, and conformance -reference for OpenClaw runtime and plugin implementations. +The implementer-facing v1 contracts are captured in +[`0018/readiness-v1-spec.md`](0018/readiness-v1-spec.md) and the focused +[`0018/readiness-subjects-v1-spec.md`](0018/readiness-subjects-v1-spec.md) +sidecar. This RFC remains the design rationale, compatibility argument, and +rollout plan; the sidecars are the concise schema, identity, provider-lifecycle, +evaluation, projection, and conformance references for OpenClaw runtime and +plugin implementations. ### Canonical condition model @@ -114,6 +121,9 @@ type ReadinessRequirement = "required" | "advisory"; type ReadinessCondition = { type: string; + subjectRef: string; + relatedSubjectRefs?: string[]; + observedAtMs?: number; status: ReadinessConditionStatus; requirement: ReadinessRequirement; reason: string; @@ -121,6 +131,8 @@ type ReadinessCondition = { }; type ReadinessResult = { + evaluatedAtMs: number; + identity: ReadinessIdentity; ready: boolean; conditions: ReadinessCondition[]; failures: string[]; @@ -128,9 +140,10 @@ type ReadinessResult = { }; ``` -`type` is stable machine identity. `reason` is a stable machine-readable state -or failure reason. `message` is redacted operator guidance and is not part of -machine matching. +`type` identifies the condition contract. The stable comparison key is +`(subjectRef, type)`. `reason` is a stable machine-readable state or failure +reason. `message` is redacted operator guidance and is not part of machine +matching. Aggregation is deliberately simple: @@ -144,6 +157,44 @@ condition identities, invalid statuses, or malformed provider results are converted to stable `Unknown` conditions or reject provider registration; they must not disappear from the result. +### Subject identity + +Readiness is an aggregate over independently owned runtime objects. A Gateway +serving incarnation, active configuration generation, plugin activation, +paired node, model route, storage backend, sandbox, and harness do not share one +useful lifetime. The canonical result therefore declares subjects once and lets +conditions reference them: + +```ts +type ReadinessSubject = { + ref: string; + kind: string; + id?: string; + generation?: string; + parentRef?: string; +}; + +type ReadinessIdentity = { + producerRef: string; + subjects: ReadinessSubject[]; +}; +``` + +`subjectRef` names the primary object whose state the condition describes. +`relatedSubjectRefs` names bounded dependencies without changing condition +ownership. An aggregate condition uses an explicit aggregate subject and lists +its members as related subjects. Atomic per-subject conditions remain preferred +when individual failures matter. + +Core reserves `openclaw/*` references. A plugin declares local `kind` and `key` +values; core derives `plugin.//`, validates every +reference, collapses identical declarations, and rejects conflicting +declarations. Subject `ref` is the stable role used for comparison; `id` and +`generation` identify what currently occupies that role. Subjects and +conditions are deterministically ordered. The focused identity and +reconciliation contract is normative in +[`0018/readiness-subjects-v1-spec.md`](0018/readiness-subjects-v1-spec.md). + ### Core conditions The first implementation normalizes the observations already owned by the @@ -186,6 +237,9 @@ may reference provider IDs; they cannot inject callbacks through config. ```ts type PluginReadinessResult = { + subjectRef?: string; + relatedSubjectRefs?: string[]; + observedAtMs?: number; status: "True" | "False" | "Unknown"; reason: string; message: string; @@ -198,6 +252,7 @@ type PluginReadinessProvider = { config: OpenClawConfig; pluginConfig: unknown; signal: AbortSignal; + subjects: PluginReadinessSubjectCollector; }): Promise | PluginReadinessResult; }; @@ -212,14 +267,21 @@ Example: api.registerReadinessCriterion({ id: "backend", description: "Reports whether the plugin backend can accept work.", - async check({ pluginConfig, signal }) { + async check({ pluginConfig, signal, subjects }) { + const backend = subjects.declare({ + kind: "backend", + key: "primary", + identity: { id: "configured-backend" }, + }); return (await probeBackend(pluginConfig, { signal })) ? { + subjectRef: backend, status: "True", reason: "BackendReady", message: "Backend is reachable.", } : { + subjectRef: backend, status: "False", reason: "BackendUnavailable", message: "Backend is unreachable.", @@ -233,6 +295,15 @@ bound to the activated plugin registry snapshot. Reload replaces the complete provider set atomically with the next activation; stale callbacks do not remain registered. +Each invocation receives a fresh subject collector bound to the activated +plugin namespace. `declare` returns a canonical subject reference and records a +bounded declaration for reconciliation. A provider may reference documented +core subjects but cannot declare or replace them. If a provider omits +`subjectRef`, core assigns the criterion's default plugin-owned subject. Invalid, +unresolved, conflicting, or excessive declarations become +`CriterionInvalidResult=Unknown`; partial raw identity output is never +projected. + The bundled Policy plugin is the concrete v1 example. When activated, it registers `plugin.policy.conformant`, reuses its existing policy evaluator, and reports `True` when evaluation has no findings, `False` with a bounded finding @@ -402,9 +473,10 @@ support promise. It cannot change condition evaluation, provider lifecycle, or aggregation. Operators that do not need that support contract use `gateway.readiness` directly. -This separation allows OpenClaw to accept structured readiness and provider -extensibility without committing to profile names, profile selection config, -runtime activation identity, or a release support matrix. +This separation allows OpenClaw to accept structured, subject-aware readiness +and provider extensibility without committing to profile names, profile +selection config, or a release support matrix. Profiles reuse the identity +package rather than adding a profile-only activation envelope. ### Implementation plan diff --git a/rfcs/0018/readiness-subjects-v1-spec.md b/rfcs/0018/readiness-subjects-v1-spec.md new file mode 100644 index 00000000..6346cd21 --- /dev/null +++ b/rfcs/0018/readiness-subjects-v1-spec.md @@ -0,0 +1,247 @@ +# Readiness Subjects v1 Specification + +This document is the focused identity and reconciliation specification for RFC +0018. The parent readiness specification defines condition evaluation, +aggregation, and projections. This sidecar defines how one canonical readiness +result identifies the producer and the independently owned subjects observed by +its conditions. + +Status: draft, tied to RFC 0018. + +## Goals + +- Make repeated readiness results safely diffable. +- Identify which runtime object owns each condition. +- Let multiple conditions reference one subject without copying identity data. +- Let a condition identify bounded related dependencies. +- Let core and plugins contribute subjects without global-name collisions. +- Preserve owner-defined identity and generation semantics. + +This specification does not create a general OpenClaw resource store, require a +hosting profile, define tenant identity, retain readiness history, or authorize +providers to discover arbitrary remote resources. + +## Data Model + +```ts +type ReadinessSubject = { + ref: string; + kind: string; + id?: string; + generation?: string; + parentRef?: string; +}; + +type ReadinessIdentity = { + producerRef: string; + subjects: ReadinessSubject[]; +}; + +type ReadinessCondition = { + type: string; + subjectRef: string; + relatedSubjectRefs?: string[]; + observedAtMs?: number; + status: "True" | "False" | "Unknown"; + requirement: "required" | "advisory"; + reason: string; + message: string; +}; + +type ReadinessResult = { + evaluatedAtMs: number; + identity: ReadinessIdentity; + ready: boolean; + conditions: ReadinessCondition[]; + failures: string[]; + advisories: string[]; +}; +``` + +`evaluatedAtMs` is the Unix epoch time when core assembled the canonical result. +`observedAtMs` is optional and records when the owning subsystem captured the +underlying fact. An omitted `observedAtMs` means the observation was made during +the current evaluation or its capture time is unavailable; it must not be +invented from cache insertion time. + +## References And Identity + +`ref` is a canonical stable role within readiness results. `id` identifies the +current object occupying that role. `generation` distinguishes owner-defined +revisions of the same object. Consumers compare subjects by `ref`, then inspect +`id` and `generation` to detect replacement or revision. + +Examples: + +```text +openclaw/process/current +openclaw/gateway/current +openclaw/config/active +openclaw/node/desktop-7 +plugin.storage/backend/primary +``` + +Core references use the reserved `openclaw/` prefix. Plugin references use: + +```text +plugin.// +``` + +Plugin `kind` and `key` values are trimmed, lowercased, and must match +`^[a-z0-9][a-z0-9._-]{0,63}$`. Core constructs the reference; providers do not +submit a global reference for declarations. Subject `kind` is the canonical +owner-qualified kind, for example `plugin.storage.backend`. + +`id` and `generation`, when present, are opaque bounded values. Consumers must +not parse them or infer security authority from them. Owners define their +lifetime semantics. IDs are not credentials and must not contain secrets, +tenant content, credential-bearing paths, or raw connection strings. + +## Producer + +`producerRef` identifies the subject that assembled and owns the readiness +decision. A live Gateway result uses its Gateway serving-incarnation subject. +That subject begins when one Gateway serving lifecycle initializes and ends when +that lifecycle is disposed. A subsequent Gateway start, including one in the +same OS process, receives a new ID. Config reload, condition transition, drain, +and repeated evaluation do not change the Gateway subject ID. + +The Gateway subject may have an `openclaw/process/current` parent. Process and +Gateway identities are distinct because one process may create more than one +Gateway serving lifecycle over time. OpenClaw generates an opaque random ID by +default. A host-supplied startup override must preserve the same uniqueness and +immutability contract. + +A non-live diagnostic projection may use its own producer subject and may +declare an unresolved Gateway subject without an `id`. It must report live +Gateway facts as `Unknown`, not borrow a stale Gateway identity. + +## Condition Subjects + +Every condition has exactly one `subjectRef`. The pair +`(subjectRef, condition.type)` is unique within one canonical result and is the +stable comparison key across results. + +`relatedSubjectRefs` is an optional bounded list of other subjects involved in +the observation. The primary subject remains accountable for the condition. +For example, `ModelRouteReady` may target a route and relate its selected model +and credential owner. + +An observation over a collection uses an explicit aggregate subject: + +```json +{ + "type": "NodeModeCapacityReady", + "subjectRef": "openclaw/node-set/scout-desktops", + "relatedSubjectRefs": [ + "openclaw/node/desktop-7", + "openclaw/node/desktop-9" + ] +} +``` + +When individual failures matter, owners should emit one condition per subject +instead of hiding them behind an aggregate. + +## Plugin Subject Collector + +Each selected plugin-provider invocation receives a fresh collector bound to +the activated plugin ID: + +```ts +type PluginReadinessSubjectCollector = { + declare(input: { + kind: string; + key: string; + identity?: { + id?: string; + generation?: string; + }; + parentRef?: string; + }): string; +}; +``` + +`declare` validates the local name, constructs and returns the canonical `ref`, +and records the declaration for the current invocation. Providers use that +returned value as `subjectRef` or `relatedSubjectRefs`. A provider may reference +documented core subjects but may not declare, replace, or mutate them. + +If a provider emits no explicit primary subject, core assigns: + +```text +plugin./criterion/ +``` + +This preserves a stable subject for simple providers while allowing richer +providers to identify their actual backend, route, or integration. + +## Reconciliation + +Core reconciles declarations into one map keyed by canonical `ref` before +projection: + +1. Validate all references, kinds, IDs, generations, and parent references. +2. Reject declarations outside the caller's namespace. +3. Collapse byte-equivalent duplicate declarations. +4. Reject conflicting declarations for the same `ref`; never use last-writer + wins. +5. Require every primary, related, parent, and producer reference to resolve. +6. Omit unreferenced subjects except the producer and its parent chain. +7. Sort subjects by `ref`, related references lexicographically, and conditions + by the ordering in the parent readiness specification with `subjectRef` as a + deterministic tie-breaker. + +Invalid plugin declarations or references convert that provider's condition to +`CriterionInvalidResult=Unknown` on its default subject. Invalid core-owned +identity state fails the outer evaluation closed with +`ReadinessEvaluationComplete=Unknown`. No partial invalid identity package may +be projected or cached. + +## Bounds + +V1 enforces these maximums per canonical result: + +- 128 subjects; +- 64 plugin-declared subjects per provider invocation; +- 16 related subjects per condition; +- 192 characters per canonical reference; +- 128 characters each for `kind`, `id`, and `generation`; and +- one parent reference per subject with no cycles. + +Provider deadlines and outer readiness deadlines include declaration and +reconciliation work. Subject declaration must perform no I/O. + +## Diff Semantics + +Consumers may compare canonical results as follows: + +- changed `producerRef` target ID means a different readiness authority; +- unchanged `ref` with changed `id` means the role has a different object; +- unchanged `id` with changed `generation` means the owner advanced that + object's revision; +- unchanged `(subjectRef, type)` with changed status or reason means the same + subject's condition transitioned; and +- disappearance of a condition means its criterion is no longer selected or + its owner is no longer active, not that it became `True`. + +OpenClaw need not retain result history. Hosts and telemetry consumers may store +and diff bounded canonical results. + +## Conformance + +An implementation conforms when it proves: + +- one Gateway serving lifecycle retains one producer subject across repeated + evaluations and receives a new ID after disposal and restart; +- all condition and related references resolve; +- `(subjectRef, type)` is unique; +- plugin namespaces cannot collide with core or another plugin; +- duplicate equal declarations collapse and conflicts fail closed; +- missing, malformed, cyclic, or excessive declarations return bounded + structured failure; +- deterministic ordering is stable across equivalent provider completion + orders; +- provider timeout and cancellation behavior remains bounded while subjects are + collected; and +- public subject fields contain no secrets or unredacted owner data. diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 2c14c610..1f9138e4 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -4,7 +4,9 @@ This document is the implementer-facing specification for RFC 0018, Readiness Conditions and Providers. The RFC explains the motivation, compatibility strategy, and rollout plan. This file defines the v1 condition model, provider lifecycle, operator selection, bounded evaluation, aggregation, and projection -contract that OpenClaw runtimes, plugins, and hosts can build against. +contract that OpenClaw runtimes, plugins, and hosts can build against. The +focused subject identity and reconciliation contract is defined in +[`readiness-subjects-v1-spec.md`](readiness-subjects-v1-spec.md). Status: draft, tied to RFC 0018. @@ -13,7 +15,7 @@ Status: draft, tied to RFC 0018. This specification defines: - the canonical readiness condition and result shapes; -- stable identity and reason requirements; +- stable condition, subject identity, and reason requirements; - required and advisory aggregation; - the core condition namespace and baseline lifecycle conditions; - plugin readiness-provider registration and activation lifecycle; @@ -43,6 +45,8 @@ This specification does not define: configuration. - **Canonical result**: the single aggregated result consumed by all readiness projections. +- **Subject**: one core- or plugin-owned runtime object observed by conditions. +- **Producer**: the subject that assembled and owns one readiness decision. - **Projection**: an HTTP, health, status, or CLI representation of the canonical result; a projection is not a second evaluator. @@ -76,6 +80,9 @@ type ReadinessRequirement = "required" | "advisory"; type ReadinessCondition = { type: string; + subjectRef: string; + relatedSubjectRefs?: string[]; + observedAtMs?: number; status: ReadinessConditionStatus; requirement: ReadinessRequirement; reason: string; @@ -83,6 +90,8 @@ type ReadinessCondition = { }; type ReadinessResult = { + evaluatedAtMs: number; + identity: ReadinessIdentity; ready: boolean; conditions: ReadinessCondition[]; failures: string[]; @@ -90,12 +99,13 @@ type ReadinessResult = { }; ``` -Implementations may add optional metadata, but the fields above retain their -v1 meaning. +`ReadinessIdentity` and subject reconciliation are normative in the focused +subject sidecar. Implementations may add optional metadata, but the fields above +retain their v1 meaning. ### Identity -Condition `type` values must be stable and unique within one result. Core uses +The pair `(subjectRef, type)` must be stable and unique within one result. Core uses the public condition types defined below, such as `WorkspaceWritable`. A plugin condition uses this namespace: @@ -118,6 +128,13 @@ values must not contain secrets, paths with credentials, raw exception text, or tenant content. Core validates these bounds before caching or projection; invalid output becomes `CriterionInvalidResult`. +Every primary, related, parent, and producer reference must resolve in the +result identity package. Subjects are declared once and deterministically +ordered. Core owns the `openclaw/*` namespace; plugins receive +`plugin./*`. Identity declarations, conflict behavior, bounds, +Gateway serving-incarnation lifetime, and diff semantics are defined by +[`readiness-subjects-v1-spec.md`](readiness-subjects-v1-spec.md). + ### Status - `True` means the criterion was observed and satisfied. @@ -208,6 +225,9 @@ The v1 plugin SDK contract is: ```ts type PluginReadinessResult = { + subjectRef?: string; + relatedSubjectRefs?: string[]; + observedAtMs?: number; status: "True" | "False" | "Unknown"; reason: string; message: string; @@ -220,6 +240,7 @@ type PluginReadinessProvider = { config: OpenClawConfig; pluginConfig: unknown; signal: AbortSignal; + subjects: PluginReadinessSubjectCollector; }): Promise | PluginReadinessResult; }; @@ -318,7 +339,7 @@ The initial v1 limits are: - an independent two-second outer deadline for the complete result. Core owns deadlines, cancellation, coalescing, caching, error conversion, and -result ordering. A timed-out criterion becomes `Unknown` with a stable timeout +subject reconciliation, and result ordering. A timed-out criterion becomes `Unknown` with a stable timeout reason. Unexpected exceptions become `Unknown`; raw exception text is not copied into public output. @@ -423,6 +444,11 @@ An implementation conforms to readiness v1 when it proves: - reload atomically replaces provider descriptors and callbacks, discards late results, and remains bounded across repeated never-settling providers; - unknown selected criteria fail closed; +- every condition and relationship resolves to one reconciled subject; +- plugin subject declarations are namespaced, bounded, deterministic, and + conflict-safe; +- one live Gateway serving lifecycle retains one producer identity across + repeated evaluations and receives a new identity after restart; - `/ready`, `/readyz`, health, status, and CLI do not disagree about the same observed activation; and - public output contains no raw exceptions, secrets, credentials, or tenant From 634aea3e6560fe222b44aaffd4cecd97c37c3733 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 13:25:49 -0700 Subject: [PATCH 78/98] docs(rfc-0018): clarify subject reconciliation --- rfcs/0018/readiness-subjects-v1-spec.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rfcs/0018/readiness-subjects-v1-spec.md b/rfcs/0018/readiness-subjects-v1-spec.md index 6346cd21..f8345721 100644 --- a/rfcs/0018/readiness-subjects-v1-spec.md +++ b/rfcs/0018/readiness-subjects-v1-spec.md @@ -165,7 +165,9 @@ type PluginReadinessSubjectCollector = { `declare` validates the local name, constructs and returns the canonical `ref`, and records the declaration for the current invocation. Providers use that returned value as `subjectRef` or `relatedSubjectRefs`. A provider may reference -documented core subjects but may not declare, replace, or mutate them. +documented core subjects and may parent its subjects to its own or a documented +core subject. It may not declare, replace, mutate, or parent into another +plugin's namespace. If a provider emits no explicit primary subject, core assigns: @@ -183,9 +185,11 @@ projection: 1. Validate all references, kinds, IDs, generations, and parent references. 2. Reject declarations outside the caller's namespace. -3. Collapse byte-equivalent duplicate declarations. -4. Reject conflicting declarations for the same `ref`; never use last-writer - wins. +3. Merge compatible declarations for the same `ref` when one declaration only + fills an absent `id`, `generation`, or `parentRef`; this lets an owner enrich + a core placeholder without changing its canonical reference. +4. Reject different kinds or conflicting non-empty identity fields for the + same `ref`; never use last-writer wins. 5. Require every primary, related, parent, and producer reference to resolve. 6. Omit unreferenced subjects except the producer and its parent chain. 7. Sort subjects by `ref`, related references lexicographically, and conditions @@ -237,7 +241,8 @@ An implementation conforms when it proves: - all condition and related references resolve; - `(subjectRef, type)` is unique; - plugin namespaces cannot collide with core or another plugin; -- duplicate equal declarations collapse and conflicts fail closed; +- compatible declarations merge and conflicting non-empty declarations fail + closed; - missing, malformed, cyclic, or excessive declarations return bounded structured failure; - deterministic ordering is stable across equivalent provider completion From b99f6108ce81926f6aa3b47f162e20a647100dd1 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 16:31:27 -0700 Subject: [PATCH 79/98] docs(rfc-0018): advance subject-aware stack heads --- rfcs/0018-readiness-conditions-and-providers.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index f6e605ab..470d75d0 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -484,7 +484,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with fifteen ordered commits at exact head `5861bcd70c6a`. +It is one upstream PR with sixteen ordered commits at exact head `13b0acaa00f3`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -502,8 +502,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `5861bcd70c6a` and exact implementation head -`ce9ef81b24d6`. It adds selectable activation, +stacked at exact readiness head `13b0acaa00f3` and exact implementation head +`dbd540b18a0b`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), @@ -521,13 +521,13 @@ slices. They are supporting review aids, not alternative landing PRs: | Readiness providers | [PR 23](https://github.com/giodl73-repo/openclaw/pull/23) | Add activation-scoped provider registration and operator-required criteria, without custom profiles. | | Canonical readiness CLI | [PR 27](https://github.com/giodl73-repo/openclaw/pull/27) | Add a thin CLI projection of the live result. | -Profile selection, node-mode composition, activation identity, and packaged +Profile selection, node-mode composition, profile subject attribution, and packaged profile release conformance move to the Standard Hosting Profiles RFC and its separate implementation stack. The earlier consolidated draft remains useful behavior evidence, but it is not the proposed landing shape. The slices above can land without accepting profile -names, profile selection, runtime activation identity, or release conformance. +names, profile selection, profile subject attribution, or release conformance. #### Follow-on condition adoption From 1e19203ba729998beeaad40a2c41dce62b453f69 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 16:51:34 -0700 Subject: [PATCH 80/98] docs(rfc-0018): link subject identity review slice --- rfcs/0018-readiness-conditions-and-providers.md | 1 + 1 file changed, 1 insertion(+) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 470d75d0..1d277d09 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -520,6 +520,7 @@ slices. They are supporting review aids, not alternative landing PRs: | Workspace readiness | [PR 22](https://github.com/giodl73-repo/openclaw/pull/22) | Add the bounded `WorkspaceWritable` condition without profile behavior. | | Readiness providers | [PR 23](https://github.com/giodl73-repo/openclaw/pull/23) | Add activation-scoped provider registration and operator-required criteria, without custom profiles. | | Canonical readiness CLI | [PR 27](https://github.com/giodl73-repo/openclaw/pull/27) | Add a thin CLI projection of the live result. | +| Readiness subjects | [PR 161](https://github.com/giodl73-repo/openclaw/pull/161) | Add the shared producer/subject identity package and condition attribution used by core and plugins. | Profile selection, node-mode composition, profile subject attribution, and packaged profile release conformance move to the Standard Hosting Profiles RFC and its From 0c8543eb33198c40af0af16f6f211460dc5501e8 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 17:22:39 -0700 Subject: [PATCH 81/98] docs(rfc-0018): track latest main restack --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 1d277d09..07bca861 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -484,7 +484,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with sixteen ordered commits at exact head `13b0acaa00f3`. +It is one upstream PR with sixteen ordered commits at exact head `ddadb96d0f64`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -502,8 +502,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `13b0acaa00f3` and exact implementation head -`dbd540b18a0b`. It adds selectable core-owner criteria, +stacked at exact readiness head `ddadb96d0f64` and exact implementation head +`822d5a20d959`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From e129954922a632225d33d0c38557ab15a38ca4ce Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 17:44:00 -0700 Subject: [PATCH 82/98] docs(rfc-0018): record current-main implementation heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 07bca861..50f8c82a 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -484,7 +484,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with sixteen ordered commits at exact head `ddadb96d0f64`. +It is one upstream PR with seventeen ordered commits at exact head `e5834f2a18e7`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -502,8 +502,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `ddadb96d0f64` and exact implementation head -`822d5a20d959`. It adds selectable core-owner criteria, +stacked at exact readiness head `e5834f2a18e7` and exact implementation head +`24970fe0ee47`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From 5a4bb643a401fd7847155b87e69cd0207d3a7bf2 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 18:19:13 -0700 Subject: [PATCH 83/98] docs(rfc-0018): refresh implementation stack --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 50f8c82a..e87e6640 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -484,7 +484,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with seventeen ordered commits at exact head `e5834f2a18e7`. +It is one upstream PR with eighteen ordered commits at exact head `c65456659cfd`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -502,8 +502,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `e5834f2a18e7` and exact implementation head -`24970fe0ee47`. It adds selectable core-owner criteria, +stacked at exact readiness head `c65456659cfd` and exact implementation head +`2b32ecce5745`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From 489d3cbf7cff244326ced028c71cf9ec293cc402 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 18:33:29 -0700 Subject: [PATCH 84/98] docs(rfc-0018): align final readiness heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index e87e6640..1589cc60 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -484,7 +484,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with eighteen ordered commits at exact head `c65456659cfd`. +It is one upstream PR with eighteen ordered commits at exact head `57d627464a23`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -502,8 +502,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `c65456659cfd` and exact implementation head -`2b32ecce5745`. It adds selectable core-owner criteria, +stacked at exact readiness head `57d627464a23` and exact implementation head +`9257236adfa5`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From 189075cfcd6294e5fe239fd898d004d56bb0c8a4 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 18:48:20 -0700 Subject: [PATCH 85/98] docs(rfc-0018): align final readiness heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 1589cc60..8e09c800 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -484,7 +484,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with eighteen ordered commits at exact head `57d627464a23`. +It is one upstream PR with eighteen ordered commits at exact head `ca05a31a9b73`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -502,8 +502,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `57d627464a23` and exact implementation head -`9257236adfa5`. It adds selectable core-owner criteria, +stacked at exact readiness head `ca05a31a9b73` and exact implementation head +`0baf0be2c17e`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From a4e5fbea9fafaa887726b97f73670f61ca4fe7be Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 18:56:15 -0700 Subject: [PATCH 86/98] docs(rfc-0018): refresh exact implementation heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 8e09c800..e4b42cc6 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -484,7 +484,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with eighteen ordered commits at exact head `ca05a31a9b73`. +It is one upstream PR with eighteen ordered commits at exact head `28ad0cf76fa9`. The opt-in compatibility amendment passes 154 focused readiness, live Gateway, HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight @@ -502,8 +502,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `ca05a31a9b73` and exact implementation head -`0baf0be2c17e`. It adds selectable core-owner criteria, +stacked at exact readiness head `28ad0cf76fa9` and exact implementation head +`debd3a56a098`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From 716998095dd3bb08f45d4bf09b9404043d52db7d Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sat, 25 Jul 2026 22:04:39 -0700 Subject: [PATCH 87/98] docs(rfc-0018): define owner-scoped readiness identity --- ...0018-readiness-conditions-and-providers.md | 25 +++++--- rfcs/0018/readiness-subjects-v1-spec.md | 61 ++++++++++++++----- rfcs/0018/readiness-v1-spec.md | 22 +++++-- 3 files changed, 79 insertions(+), 29 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index e4b42cc6..16a6f42d 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -131,6 +131,7 @@ type ReadinessCondition = { }; type ReadinessResult = { + contractVersion: 1; evaluatedAtMs: number; identity: ReadinessIdentity; ready: boolean; @@ -190,7 +191,12 @@ Core reserves `openclaw/*` references. A plugin declares local `kind` and `key` values; core derives `plugin.//`, validates every reference, collapses identical declarations, and rejects conflicting declarations. Subject `ref` is the stable role used for comparison; `id` and -`generation` identify what currently occupies that role. Subjects and +`generation` identify what currently occupies that role. Identity follows +owner renewal boundaries: an optional host workload may contain an OS process, +which may create one or more Gateway serving lifecycles; each child receives a +new ID when that lifecycle is replaced. A generation changes only when the +same owner object is revised. Host-supplied correlation is a fingerprinted host +subject and never overrides the generated Gateway identity. Subjects and conditions are deterministically ordered. The focused identity and reconciliation contract is normative in [`0018/readiness-subjects-v1-spec.md`](0018/readiness-subjects-v1-spec.md). @@ -484,12 +490,13 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR with eighteen ordered commits at exact head `28ad0cf76fa9`. -The opt-in compatibility amendment passes 154 focused readiness, live Gateway, -HTTP/RPC, health, selector, registry, and CLI assertions; type-aware lint, -formatting, and diff checks pass. Timed-out plugin checks remain single-flight -until the original callback settles, even when the plugin ignores cancellation; -provider output is bounded, validated, and redacted. Config publication fences +It is one upstream PR at exact head `673e7a8c1ef2`. Focused readiness, live +Gateway, HTTP/RPC, health, selector, registry, subject, and CLI suites pass; +type-aware lint, formatting, and diff checks pass. Timed-out plugin checks +remain single-flight until the original callback settles, even across registry +replacement when the plugin ignores cancellation. Provider output is bounded, +validated, redacted, and accompanied by safe criterion-ID diagnostics. Config +publication fences provider and workspace evidence by runtime generation, including recovery when a retired filesystem probe never settles, while retaining a strict two-probe ceiling across repeated generation changes. A prior package-installed @@ -502,8 +509,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `28ad0cf76fa9` and exact implementation head -`debd3a56a098`. It adds selectable core-owner criteria, +stacked at exact readiness head `673e7a8c1ef2` and exact implementation head +`c398dd2c204c`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), diff --git a/rfcs/0018/readiness-subjects-v1-spec.md b/rfcs/0018/readiness-subjects-v1-spec.md index f8345721..9b023cc1 100644 --- a/rfcs/0018/readiness-subjects-v1-spec.md +++ b/rfcs/0018/readiness-subjects-v1-spec.md @@ -49,6 +49,7 @@ type ReadinessCondition = { }; type ReadinessResult = { + contractVersion: 1; evaluatedAtMs: number; identity: ReadinessIdentity; ready: boolean; @@ -93,8 +94,12 @@ submit a global reference for declarations. Subject `kind` is the canonical owner-qualified kind, for example `plugin.storage.backend`. `id` and `generation`, when present, are opaque bounded values. Consumers must -not parse them or infer security authority from them. Owners define their -lifetime semantics. IDs are not credentials and must not contain secrets, +not parse them or infer security authority from them. An ID is tied to the +renewal boundary of the object named by `kind`: it stays stable while that +object exists and changes when its owner replaces the object. A generation is +an owner-defined revision of that same object and changes without implying +replacement. Owners must omit either field when they cannot publish an +authoritative value. IDs are not credentials and must not contain secrets, tenant content, credential-bearing paths, or raw connection strings. ## Producer @@ -106,11 +111,20 @@ that lifecycle is disposed. A subsequent Gateway start, including one in the same OS process, receives a new ID. Config reload, condition transition, drain, and repeated evaluation do not change the Gateway subject ID. -The Gateway subject may have an `openclaw/process/current` parent. Process and -Gateway identities are distinct because one process may create more than one -Gateway serving lifecycle over time. OpenClaw generates an opaque random ID by -default. A host-supplied startup override must preserve the same uniqueness and -immutability contract. +The standard lifecycle hierarchy is: + +```text +openclaw/host-instance/current (optional host workload lifecycle) + -> openclaw/process/current (OS process lifecycle) + -> openclaw/gateway/current (Gateway serving lifecycle) +``` + +OpenClaw generates opaque random process and Gateway IDs. A host may provide a +stable workload-correlation input for the optional host subject, but core +publishes only a one-way fingerprint of that value. It does not replace the +process or Gateway identity. Reusing one host workload across process or +Gateway restarts therefore retains the parent host ID while renewing the child +IDs at their actual lifecycle boundaries. A non-live diagnostic projection may use its own producer subject and may declare an unresolved Gateway subject without an `id`. It must report live @@ -140,8 +154,10 @@ An observation over a collection uses an explicit aggregate subject: } ``` -When individual failures matter, owners should emit one condition per subject -instead of hiding them behind an aggregate. +When individual failures matter, an owner registers separate criteria or emits +bounded owner-native core conditions. One plugin readiness provider emits one +condition. Providers that observe an unbounded collection must use an aggregate +subject and may include only a deterministic bounded subset of related subjects. ## Plugin Subject Collector @@ -167,7 +183,10 @@ and records the declaration for the current invocation. Providers use that returned value as `subjectRef` or `relatedSubjectRefs`. A provider may reference documented core subjects and may parent its subjects to its own or a documented core subject. It may not declare, replace, mutate, or parent into another -plugin's namespace. +plugin's namespace. Declarations are order-independent: a plugin-local parent +may be declared before or after its child, and the completed graph is validated +after the provider returns. Externally supplied identity values are published +only as one-way fingerprints. If a provider emits no explicit primary subject, core assigns: @@ -206,6 +225,7 @@ be projected or cached. V1 enforces these maximums per canonical result: +- 256 conditions, failures, and advisories; - 128 subjects; - 64 plugin-declared subjects per provider invocation; - 16 related subjects per condition; @@ -214,7 +234,8 @@ V1 enforces these maximums per canonical result: - one parent reference per subject with no cycles. Provider deadlines and outer readiness deadlines include declaration and -reconciliation work. Subject declaration must perform no I/O. +reconciliation work. Subject declaration must perform no I/O. The wire schema +enforces these collection and string bounds before a result is accepted. ## Diff Semantics @@ -226,11 +247,18 @@ Consumers may compare canonical results as follows: object's revision; - unchanged `(subjectRef, type)` with changed status or reason means the same subject's condition transitioned; and -- disappearance of a condition means its criterion is no longer selected or - its owner is no longer active, not that it became `True`. +- when `ReadinessEvaluationComplete` is absent or `True`, disappearance of a + condition means its criterion is no longer selected or its owner is no longer + active, not that it became `True`; and +- when `ReadinessEvaluationComplete` is `False` or `Unknown`, consumers must + treat missing conditions as unobserved and must not infer deselection, + deactivation, or success. OpenClaw need not retain result history. Hosts and telemetry consumers may store -and diff bounded canonical results. +and diff bounded canonical results. Metrics may label stable condition type, +status, requirement, reason, subject kind, and selected profile. Dynamic `id`, +`generation`, node-specific `ref`, `message`, and related-subject values belong +only in bounded diagnostic events and must not become metric labels. ## Conformance @@ -238,6 +266,8 @@ An implementation conforms when it proves: - one Gateway serving lifecycle retains one producer subject across repeated evaluations and receives a new ID after disposal and restart; +- host, process, Gateway, and owner-resource IDs renew at their documented + lifecycle boundaries while generations revise only the same object; - all condition and related references resolve; - `(subjectRef, type)` is unique; - plugin namespaces cannot collide with core or another plugin; @@ -248,5 +278,6 @@ An implementation conforms when it proves: - deterministic ordering is stable across equivalent provider completion orders; - provider timeout and cancellation behavior remains bounded while subjects are - collected; and + collected; +- an incomplete evaluation cannot make consumers infer condition removal; and - public subject fields contain no secrets or unredacted owner data. diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 1f9138e4..41867b9f 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -90,6 +90,7 @@ type ReadinessCondition = { }; type ReadinessResult = { + contractVersion: 1; evaluatedAtMs: number; identity: ReadinessIdentity; ready: boolean; @@ -161,9 +162,9 @@ The condition array must use this v1 order when present: 2. `GatewayStartupComplete`, `GatewayAcceptingWork`, `ChannelRuntimeReady`, `ChannelRuntimeSuppressed`, and `EventLoopHealthy`; 3. `ConfigLoaded` and `WorkspaceWritable`; -4. profile-owned conditions in the order defined by RFC 0023; -5. `GatewayResponding` and `PluginsLoaded`; and -6. remaining selected core and plugin conditions sorted by condition type. +4. `GatewayResponding` and `PluginsLoaded`; and +5. remaining selected core, profile-contributed, and plugin conditions sorted + by condition type and then `subjectRef`. `failures` and `advisories` follow condition order and contain no duplicates. @@ -253,6 +254,11 @@ Registration through `api.registerReadinessCriterion` is scoped to the current plugin activation. Core publishes the resulting ID as `plugin..`. +Each provider invocation emits exactly one condition. A plugin registers +separate criteria for independently selectable resources or states; an +unbounded collection is summarized by one aggregate subject and a bounded, +deterministic set of related subjects. + The bundled Policy plugin demonstrates this contract with `plugin.policy.conformant`. It reuses the plugin's existing policy evaluation, returns only bounded summary text, and is not evaluated until selected through @@ -362,8 +368,10 @@ If the outer deadline expires, the evaluator must return a required Core retains ownership of an invocation after its deadline. If a provider ignores cancellation and remains pending, later polls reuse the stable timeout -result and must not start another invocation. A new invocation may start only -after the prior callback settles and the cache expires. +result and must not start another invocation, including after config or plugin +registry replacement. The callback is quarantined by canonical criterion ID +until it settles. A new invocation may start only after settlement and the +applicable cache or replacement-generation rules permit it. Successful and failed provider or workspace observations may be cached for at most five seconds. Replacement effective-config or plugin-registry snapshots, @@ -445,10 +453,14 @@ An implementation conforms to readiness v1 when it proves: results, and remains bounded across repeated never-settling providers; - unknown selected criteria fail closed; - every condition and relationship resolves to one reconciled subject; +- every canonical result has `contractVersion: 1` and satisfies the wire + cardinality and string bounds; - plugin subject declarations are namespaced, bounded, deterministic, and conflict-safe; - one live Gateway serving lifecycle retains one producer identity across repeated evaluations and receives a new identity after restart; +- process and optional host-workload parents renew independently at their own + lifecycle boundaries; - `/ready`, `/readyz`, health, status, and CLI do not disagree about the same observed activation; and - public output contains no raw exceptions, secrets, credentials, or tenant From 019a0025f60090414932ad0248153c2a885f0971 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 05:29:21 -0700 Subject: [PATCH 88/98] docs(rfc-0018): refresh implementation heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 16a6f42d..6eca5dab 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -490,7 +490,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR at exact head `673e7a8c1ef2`. Focused readiness, live +It is one upstream PR at exact head `64bba7771598`. Focused readiness, live Gateway, HTTP/RPC, health, selector, registry, subject, and CLI suites pass; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight until the original callback settles, even across registry @@ -509,8 +509,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `673e7a8c1ef2` and exact implementation head -`c398dd2c204c`. It adds selectable core-owner criteria, +stacked at exact readiness head `64bba7771598` and exact implementation head +`25026844df5a`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From d1fbb913517919f7ba783ed0291d0a001a4bfbec Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 05:49:09 -0700 Subject: [PATCH 89/98] docs(rfc-0018): refresh implementation heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 6eca5dab..cfddefd6 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -490,7 +490,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR at exact head `64bba7771598`. Focused readiness, live +It is one upstream PR at exact head `e94bea556ef5`. Focused readiness, live Gateway, HTTP/RPC, health, selector, registry, subject, and CLI suites pass; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight until the original callback settles, even across registry @@ -509,8 +509,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `64bba7771598` and exact implementation head -`25026844df5a`. It adds selectable core-owner criteria, +stacked at exact readiness head `e94bea556ef5` and exact implementation head +`ecbf85a22d04`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From aa4368258c3d2bbb3fa32aba57cb16c8582b3b9d Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 06:45:53 -0700 Subject: [PATCH 90/98] docs(rfc-0018): refresh implementation heads --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index cfddefd6..f6795f19 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -490,7 +490,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR at exact head `e94bea556ef5`. Focused readiness, live +It is one upstream PR at exact head `78bb3d052979`. Focused readiness, live Gateway, HTTP/RPC, health, selector, registry, subject, and CLI suites pass; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight until the original callback settles, even across registry @@ -509,8 +509,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `e94bea556ef5` and exact implementation head -`ecbf85a22d04`. It adds selectable core-owner criteria, +stacked at exact readiness head `78bb3d052979` and exact implementation head +`3f83761d559d`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From a9b4527f6628edbb04569f131b2c9a60e8f41291 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 06:53:43 -0700 Subject: [PATCH 91/98] docs(rfc-0018): align canonical CI head --- rfcs/0018-readiness-conditions-and-providers.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index f6795f19..4a76bd51 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -490,7 +490,7 @@ The primary implementation for this RFC is [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). Its upgrade boundary keeps unconfigured probes on the legacy checker and makes the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR at exact head `78bb3d052979`. Focused readiness, live +It is one upstream PR at exact head `6dce3555a511`. Focused readiness, live Gateway, HTTP/RPC, health, selector, registry, subject, and CLI suites pass; type-aware lint, formatting, and diff checks pass. Timed-out plugin checks remain single-flight until the original callback settles, even across registry @@ -509,8 +509,8 @@ proposed landing shape and current validation state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `78bb3d052979` and exact implementation head -`3f83761d559d`. It adds selectable core-owner criteria, +stacked at exact readiness head `6dce3555a511` and exact implementation head +`3a450e8625a7`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), From 1cbb2dedbf02b9173c805699a0c649549f21565d Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 07:30:37 -0700 Subject: [PATCH 92/98] docs: compare readiness identity with hosting platforms --- ...0018-readiness-conditions-and-providers.md | 14 +- rfcs/0018/readiness-platform-comparison.md | 188 ++++++++++++++++++ rfcs/0018/readiness-subjects-v1-spec.md | 9 + 3 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 rfcs/0018/readiness-platform-comparison.md diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 4a76bd51..16f729bb 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -3,7 +3,7 @@ title: Readiness Conditions and Providers authors: - Gio created: 2026-07-09 -last_updated: 2026-07-25 +last_updated: 2026-07-26 status: draft issue: rfc_pr: https://github.com/openclaw/rfcs/pull/33 @@ -106,10 +106,14 @@ separately accepted Standard Hosting Profile. The implementer-facing v1 contracts are captured in [`0018/readiness-v1-spec.md`](0018/readiness-v1-spec.md) and the focused [`0018/readiness-subjects-v1-spec.md`](0018/readiness-subjects-v1-spec.md) -sidecar. This RFC remains the design rationale, compatibility argument, and -rollout plan; the sidecars are the concise schema, identity, provider-lifecycle, -evaluation, projection, and conformance references for OpenClaw runtime and -plugin implementations. +sidecar. The non-normative +[`0018/readiness-platform-comparison.md`](0018/readiness-platform-comparison.md) +compares the contract with Kubernetes, Docker, systemd, ASP.NET Core, Spring +Boot, and OpenTelemetry and records the v1 gap disposition. This RFC remains +the design rationale, compatibility argument, and rollout plan; the normative +sidecars are the concise schema, identity, provider-lifecycle, evaluation, +projection, and conformance references for OpenClaw runtime and plugin +implementations. ### Canonical condition model diff --git a/rfcs/0018/readiness-platform-comparison.md b/rfcs/0018/readiness-platform-comparison.md new file mode 100644 index 00000000..3606220a --- /dev/null +++ b/rfcs/0018/readiness-platform-comparison.md @@ -0,0 +1,188 @@ +# Readiness Identity and Hosting Platform Comparison + +Status: non-normative design evidence for RFC 0018 +Last updated: 2026-07-26 + +## Purpose + +This sidecar compares RFC 0018 with established readiness and runtime identity +contracts. It tests whether OpenClaw is introducing unnecessary concepts and +records which adjacent-system features belong in readiness v1, in a host, or +in a later transport contract. + +The comparison is semantic rather than lexical. RFC 0018 is an in-process +hostee contract, not a workload orchestrator, telemetry backend, or control +plane. + +## Summary + +RFC 0018 combines two patterns that mature systems usually expose separately: + +1. a compact decision suitable for a container or service manager; and +2. structured current-state facts with enough identity to explain what was + evaluated and whether that object was revised or replaced. + +Kubernetes is the closest identity analogue. ASP.NET Core and Spring Boot are +the closest provider-composition analogues. Docker and systemd demonstrate why +the host-facing decision must remain small and bounded. OpenTelemetry confirms +the value of opaque instance identity and the danger of using dynamic identity +as unbounded metric dimensions. + +No comparison justifies another required v1 field. The main actionable result +is an atomic-observation invariant: one readiness result must not combine a +condition from one owner generation with identity from another. + +## Comparison Matrix + +| System | Composition | Identity and lifetime | Host-facing decision | RFC 0018 disposition | +| --- | --- | --- | --- | --- | +| Kubernetes | Container probes, Pod conditions, and readiness gates contribute to readiness. | Object name is a stable role; UID identifies one historical occurrence; generation and observed generation distinguish desired-state revision from observed status. | Readiness removes a Pod from service endpoints; liveness may restart it; startup delays both. | Reuse the condition and replacement/revision distinctions. Do not copy Kubernetes API storage, watch, or controller semantics. | +| Docker | One `HEALTHCHECK` command produces one container health state; the engine supplies interval, timeout, start period, and retries. | Container identity and restart history are engine-owned, outside the health payload. | `starting`, `healthy`, or `unhealthy`, plus bounded recent probe output. | Keep `/readyz` compact. Let Docker own scheduling and retries while OpenClaw explains the internal decision. | +| systemd | A service can notify readiness, status, process identity, reload, stop, and watchdog progress. | The service manager owns unit and process lifetime. | `READY=1` is a concise transition consumed by the manager. | Keep supervision host-owned. OpenClaw conditions add detail behind the service-level decision rather than replacing the manager. | +| ASP.NET Core Health Checks | Registered checks can be selected by tags and grouped into readiness and liveness endpoints. | Check registration names components, but the standard result does not model replacement identity or parent lifetime. | Aggregated `Healthy`, `Degraded`, or `Unhealthy` results map to endpoints. | Reuse selectable providers and required/advisory aggregation; retain stronger execution bounds and subject identity. | +| Spring Boot Actuator | Health contributors form nested components and configurable health groups, including readiness and liveness groups. | Component paths are stable names; incarnation and semantic generation are not first-class health fields. | Group status is exposed through probe endpoints such as `/readyz`. | Reuse owner-contributed components and named compositions. Avoid pulling external dependencies into liveness or making every contributor required. | +| OpenTelemetry | Resources and entities attach identity to telemetry from services, processes, containers, and orchestrators. | `service.instance.id` distinguishes concurrently running service instances and should be opaque and unambiguous. | OpenTelemetry reports observations; it does not decide traffic admission. | Allow bounded diagnostic correlation. Do not turn subject IDs, generations, or node references into metric labels or authority identities. | + +## Kubernetes Mapping + +Kubernetes provides the strongest precedent for separating a logical role from +the object currently occupying it: + +| RFC 0018 | Closest Kubernetes concept | Important difference | +| --- | --- | --- | +| Subject `ref` | Resource name and scope | A readiness reference is a diagnostic role within one result, not an API resource URL. | +| Subject `id` | Object UID | Both change when an object is replaced. RFC 0018 IDs are owner-scoped opaque values, not cluster-global resource identifiers. | +| Subject `generation` | `metadata.generation` plus status `observedGeneration` | RFC 0018 generation is an owner-defined revision of the active object, not a desired-state counter maintained by an API server. | +| Subject `parentRef` | Owner/dependent or workload hierarchy | RFC 0018 hierarchy expresses diagnostic lifetime and correlation only. It does not imply garbage collection, placement, or authorization. | +| `(subjectRef, condition.type)` | Condition type on one object | RFC 0018 makes the subject explicit because one Gateway result aggregates independently owned runtime objects. | +| `status`, `reason`, `message` | Kubernetes condition fields | RFC 0018 adds `requirement` so advisory degradation remains visible without removing traffic. | + +Kubernetes `resourceVersion` is intentionally not an analogue for RFC 0018 +generation. It is an opaque API-server concurrency and watch token. RFC 0018 +has no object store or watch protocol in v1. + +Kubernetes also validates the separation among startup, readiness, and +liveness. OpenClaw's shallow health/liveness surface answers whether the +process can respond. Canonical readiness answers whether the selected runtime +facts permit new work. Restart, retry, grace-period, and traffic-routing policy +remain host responsibilities. + +## Application Framework Mapping + +ASP.NET Core and Spring Boot show that reusable, owner-registered checks are a +normal application framework facility. Their filtering, tags, health groups, +contributors, and nested components are close to RFC 0018 criteria, selectors, +providers, and subjects. + +RFC 0018 is intentionally stricter at the plugin boundary: + +- registration is activation-scoped and enumerable; +- configured unknown criteria fail closed; +- provider work is observational and cancellation-aware; +- per-provider and outer deadlines bound response time even when a callback + ignores cancellation; +- cardinality, strings, relationships, and output are bounded; +- malformed or incomplete output becomes structured `Unknown`; and +- one reconciled identity package makes object replacement visible. + +Those constraints are necessary because OpenClaw plugins are a broader and more +dynamic extension surface than ordinary application-local dependency injection. + +## Container and Service-Manager Mapping + +Docker and systemd consume a small answer and own the reaction. That is the +correct boundary for OpenClaw too: + +```text +OpenClaw owners and plugins -> canonical current-state conditions + -> one bounded ready decision +Docker / Kubernetes / systemd -> polling, retries, routing, restart, rollout +``` + +The host does not need to understand every OpenClaw subsystem to decide whether +to send work. OpenClaw does not need to own container IDs, restart policy, probe +cadence, or deployment history. Detailed authenticated or local output explains +the same decision used by the compact probe; it must not become a second result. + +## Telemetry Mapping + +OpenTelemetry's `service.instance.id` supports the RFC's choice of opaque +incarnation IDs. It also highlights an integration rule: identity is useful +only when its producer and lifetime are unambiguous. A host correlation value +may add an optional fingerprinted host subject, but it cannot replace the +Gateway-generated serving-incarnation identity. + +Signals, logs, and support bundles may preserve bounded subject IDs and +generations for diagnostic joins. Metrics may use bounded dimensions such as +condition type, status, requirement, reason, and subject kind. Dynamic IDs, +generations, node references, messages, and related-subject lists must not +become metric labels. + +## Gap Assessment + +### Required for v1 + +- **Atomic observation binding.** Every emitted condition and related subject + must resolve against one reconciled evaluation snapshot. If an owner or + plugin activation changes during evaluation, generation fencing must discard + the late result or fail the evaluation closed rather than mix lifetimes. +- **Lifecycle replacement proof.** Conformance must prove stable identity + across repeated polls and changed IDs across process, Gateway, plugin, node, + and owner-resource replacement at their documented renewal boundaries. +- **Incomplete-result diff safety.** Consumers must not infer success, + deselection, or deletion from an absent condition when + `ReadinessEvaluationComplete` is `False` or `Unknown`. +- **Projection consistency.** `/ready`, `/readyz`, authenticated health/status, + and the optional CLI must expose the same observed decision and identity. + +### Deliberately host-owned + +- probe cadence, timeout, retry threshold, startup grace period, and restart; +- traffic removal, draining orchestration, rollout, and rollback; +- retained history, fleet indexing, alerting, and tenant routing; and +- authorization identity, workload placement, and control-plane resource IDs. + +### Deferred until a transport requires them + +- `lastTransitionTime`, because OpenClaw does not retain readiness history; +- a `resourceVersion`, ETag, monotonic sequence, or watch cursor, because v1 is + a current polling contract rather than a list/watch API; +- a condition freshness TTL, because synchronous evaluation is bounded and an + incomplete evaluation already fails closed; stored projections must apply + their own staleness policy; and +- a generic lifecycle phase, because explicit conditions describe startup, + serving, degradation, and drain without creating an ambiguous state machine. + +If OpenClaw later adds cached remote reads, a readiness watch, or retained +transition events, that transport should define cursor, freshness, and +transition semantics without changing the meaning of the v1 current result. + +## Validation Consequences + +The implementation and release proof should include this matrix: + +| Transition | Expected identity behavior | Expected decision behavior | +| --- | --- | --- | +| Repeated poll, no owner change | Same refs, IDs, and generations | Same condition keys; timestamps may advance. | +| Condition failure and recovery | Same subject ID and generation unless the owner revised | Required `200 -> 503 -> 200`; advisory remains `200`. | +| Config revision in one Gateway lifecycle | Same Gateway ID; changed config generation | Conditions bind to the new reconciled generation only. | +| Gateway dispose and restart in one process | New Gateway ID; stable process ID | No late condition from the prior Gateway appears. | +| Process or container replacement | New process ID; host identity follows its documented boundary | Host decides restart and routing behavior. | +| Plugin reload or node replacement | New owner ID or generation according to that owner's contract | Late provider output is discarded or represented as incomplete. | + +The exact packaged container restart matrix remains a landing proof item. Unit +tests establish the schema and generation fences but do not replace that host +integration evidence. + +## Primary Sources + +- [Kubernetes object names and UIDs](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/) +- [Kubernetes API concepts and `resourceVersion`](https://kubernetes.io/docs/reference/using-api/api-concepts/) +- [Kubernetes API conventions for conditions and generations](https://github.com/kubernetes/community/blob/main/contributors/devel/sig-architecture/api-conventions.md) +- [Kubernetes liveness, readiness, and startup probes](https://kubernetes.io/docs/concepts/workloads/pods/probes/) +- [Dockerfile `HEALTHCHECK`](https://docs.docker.com/reference/dockerfile/#healthcheck) +- [systemd service notification protocol](https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html) +- [ASP.NET Core health checks](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks) +- [Spring Boot Actuator endpoints and Kubernetes probes](https://docs.spring.io/spring-boot/reference/actuator/endpoints.html#actuator.endpoints.kubernetes-probes) +- [OpenTelemetry service resource conventions](https://opentelemetry.io/docs/specs/semconv/resource/service/) + diff --git a/rfcs/0018/readiness-subjects-v1-spec.md b/rfcs/0018/readiness-subjects-v1-spec.md index 9b023cc1..1671fddd 100644 --- a/rfcs/0018/readiness-subjects-v1-spec.md +++ b/rfcs/0018/readiness-subjects-v1-spec.md @@ -215,6 +215,12 @@ projection: by the ordering in the parent readiness specification with `subjectRef` as a deterministic tie-breaker. +The complete identity package and all condition references must come from one +reconciled evaluation snapshot. If an owner identity, owner generation, or +plugin activation changes while a condition is in flight, the evaluator must +discard that late result or fail the evaluation closed. It must not attach an +observation from one owner generation to the identity of another. + Invalid plugin declarations or references convert that provider's condition to `CriterionInvalidResult=Unknown` on its default subject. Invalid core-owned identity state fails the outer evaluation closed with @@ -277,6 +283,9 @@ An implementation conforms when it proves: structured failure; - deterministic ordering is stable across equivalent provider completion orders; +- every condition is bound to the same reconciled identity snapshot and late + results from a replaced owner or activation generation are discarded or fail + closed; - provider timeout and cancellation behavior remains bounded while subjects are collected; - an incomplete evaluation cannot make consumers infer condition removal; and From 59aeff2e407ff66bef62c9a35bfc1e6e69b902d2 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 11:32:32 -0700 Subject: [PATCH 93/98] docs: record readiness lifecycle package proof --- rfcs/0018-readiness-conditions-and-providers.md | 12 ++++++++---- rfcs/0018/readiness-platform-comparison.md | 10 ++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 16f729bb..a570205c 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -507,14 +507,18 @@ ceiling across repeated generation changes. A prior package-installed Docker lane proved `/ready` and `/readyz` transition `200 -> 503 -> 200` for a selected workspace failure and recovery, `/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with -the same canonical condition. Exact-head remote container and published-upgrade -proof must be refreshed before landing. Reviewers should use that PR for the -proposed landing shape and current validation state. +the same canonical condition. The +[exact-head package-installed profile matrix](https://github.com/giodl73-repo/openclaw/actions/runs/30214165737) +also proves the RFC 0018 surfaces, repeated-poll stability, and host-stable, +process-and-Gateway-renewing container restart semantics on dependent head +`e9c1988c5e59`. Standalone published-upgrade proof remains separate. Reviewers +should use the primary PR for the proposed landing shape and current validation +state. The first core-owner adoption is consolidated in [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), stacked at exact readiness head `6dce3555a511` and exact implementation head -`3a450e8625a7`. It adds selectable core-owner criteria, +`9cc02c5d89c`. It adds selectable core-owner criteria, execution-capability, session-storage, state, delivery, and scheduler observations without selecting any of them by default. Fork PRs [#153](https://github.com/giodl73-repo/openclaw/pull/153), diff --git a/rfcs/0018/readiness-platform-comparison.md b/rfcs/0018/readiness-platform-comparison.md index 3606220a..8607b564 100644 --- a/rfcs/0018/readiness-platform-comparison.md +++ b/rfcs/0018/readiness-platform-comparison.md @@ -170,9 +170,12 @@ The implementation and release proof should include this matrix: | Process or container replacement | New process ID; host identity follows its documented boundary | Host decides restart and routing behavior. | | Plugin reload or node replacement | New owner ID or generation according to that owner's contract | Late provider output is discarded or represented as incomplete. | -The exact packaged container restart matrix remains a landing proof item. Unit -tests establish the schema and generation fences but do not replace that host -integration evidence. +The +[exact packaged container matrix](https://github.com/giodl73-repo/openclaw/actions/runs/30214165737) +proves this restart boundary on dependent implementation head `e9c1988c5e59`: +the same host workload retains its fingerprinted host identity while process +and Gateway identities renew. Unit tests additionally establish schema and +generation fences. ## Primary Sources @@ -185,4 +188,3 @@ integration evidence. - [ASP.NET Core health checks](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks) - [Spring Boot Actuator endpoints and Kubernetes probes](https://docs.spring.io/spring-boot/reference/actuator/endpoints.html#actuator.endpoints.kubernetes-probes) - [OpenTelemetry service resource conventions](https://opentelemetry.io/docs/specs/semconv/resource/service/) - From de09c88ded911bf7d57c65d2f6876efe2e82ec02 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 15:08:10 -0700 Subject: [PATCH 94/98] docs(readiness): define operator facilities roadmap --- ...0018-readiness-conditions-and-providers.md | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index a570205c..9ddf719a 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -537,6 +537,33 @@ slices. They are supporting review aids, not alternative landing PRs: | Canonical readiness CLI | [PR 27](https://github.com/giodl73-repo/openclaw/pull/27) | Add a thin CLI projection of the live result. | | Readiness subjects | [PR 161](https://github.com/giodl73-repo/openclaw/pull/161) | Add the shared producer/subject identity package and condition attribution used by core and plugins. | +#### Operator facilities roadmap + +The canonical result should replace private polling, JSON-diff, and startup +scripts with a small set of ordinary operator facilities. These are follow-on +consumers of this RFC, not additions to the evaluation model: + +1. **Observe transitions.** Add `openclaw ready --watch` over the existing RPC. + Poll sequentially with a timeout per call, emit an initial snapshot followed + by semantic changes, suppress timestamp-only churn, identify condition + changes by `(subjectRef, type)`, and report producer or subject-lifetime + replacement. Continue through not-ready and unavailable states so recovery + remains observable. `--json` emits versioned JSON Lines. Fork + [PR 167](https://github.com/giodl73-repo/openclaw/pull/167) is the first + bounded implementation slice. +2. **Inspect and wait.** Add read-only criterion/provider enumeration after + registry metadata is enumerable, and add a bounded startup wait convenience + over the same canonical result. Neither facility may create a second + evaluator. +3. **Diagnose and operate.** Let existing Doctor, telemetry, support-bundle, + and update owners consume snapshots and transitions for remediation, + secret-safe evidence capture, transition telemetry, and pre/post-upgrade + comparison. Readiness remains observational and does not absorb those + subsystems. + +Profile discovery, validation, conformance artifacts, and release gates belong +to the separate Standard Hosting Profiles RFC. + Profile selection, node-mode composition, profile subject attribution, and packaged profile release conformance move to the Standard Hosting Profiles RFC and its separate implementation stack. From 24dcd76be622d9611c6127fa3aee1ce08e9899a9 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Sun, 26 Jul 2026 16:49:17 -0700 Subject: [PATCH 95/98] docs(readiness): specify criterion catalog --- ...0018-readiness-conditions-and-providers.md | 17 +++++--- rfcs/0018/readiness-v1-spec.md | 42 ++++++++++++++++++- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 9ddf719a..e9d48a02 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -324,8 +324,10 @@ makes nonconformance block readiness. Provider descriptors are enumerable without invoking callbacks. The active registry exposes provider identity, description, owning plugin, and source; the -registry snapshot itself is the activation-generation boundary. Future status -or diagnostics may project that descriptor catalog without executing providers. +registry snapshot itself is the activation-generation boundary. A read-only +catalog projection may expose the selectable core and plugin descriptors, +current required/advisory selection, and selected-but-unregistered IDs without +exposing source paths or executing providers. Providers must be: @@ -551,10 +553,13 @@ consumers of this RFC, not additions to the evaluation model: remains observable. `--json` emits versioned JSON Lines. Fork [PR 167](https://github.com/giodl73-repo/openclaw/pull/167) is the first bounded implementation slice. -2. **Inspect and wait.** Add read-only criterion/provider enumeration after - registry metadata is enumerable, and add a bounded startup wait convenience - over the same canonical result. Neither facility may create a second - evaluator. +2. **Inspect and wait.** Add read-only criterion/provider enumeration and a + bounded startup wait convenience over the same canonical result. Neither + facility may create a second evaluator. Fork + [PR 169](https://github.com/giodl73-repo/openclaw/pull/169) implements the + catalog as `readiness.catalog` plus `openclaw ready criteria list|inspect`, + reading one activation-pinned config/registry snapshot without invoking a + provider. 3. **Diagnose and operate.** Let existing Doctor, telemetry, support-bundle, and update owners consume snapshots and transitions for remediation, secret-safe evidence capture, transition telemetry, and pre/post-upgrade diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 41867b9f..c8643292 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -300,8 +300,40 @@ registry or become selectable after replacement. Provider descriptors must be enumerable without invoking callbacks. At minimum the active registry entry contains the namespaced ID, description, owning plugin, and source. The registry snapshot identity is the activation-generation -boundary; a future projection may expose the descriptor catalog without -executing providers. +boundary. + +### Criterion Catalog Projection + +An authenticated read-only projection may enumerate configurable criteria from +one activation-pinned config and registry snapshot. The v1 catalog has this +shape: + +```ts +type ReadinessCriterionCatalog = { + catalogVersion: 1; + criteria: Array<{ + id: string; + description?: string; + owner: + | { kind: "core" } + | { kind: "plugin"; pluginId: string; pluginName?: string } + | { kind: "unresolved" }; + registered: boolean; + selection: "required" | "advisory" | "unselected"; + }>; +}; +``` + +The projection lists selectable core criteria and all descriptors in the active +plugin registry. A selected ID absent from that registry remains visible with +`registered: false` and unresolved ownership. Results are sorted by criterion +ID. Registration source paths, plugin configuration, callback references, and +provider results are not projected. + +Catalog enumeration is deterministic for one config/registry snapshot and must +not invoke readiness evaluation, provider callbacks, probes, reload, repair, or +network I/O. It remains available when canonical readiness is not selected so +an operator can discover criteria before changing configuration. ## Operator Selection @@ -420,6 +452,10 @@ result: The CLI must not implement condition evaluation independently. +Criterion list and inspect commands are clients of the live catalog projection. +They may filter descriptors for presentation but must not execute a criterion +or infer registration from a readiness result. + ## Legacy Projection Existing `ready`, `failing`, `suppressed`, `eventLoop`, and `uptimeMs` fields @@ -451,6 +487,8 @@ An implementation conforms to readiness v1 when it proves: workspace, selection, and plugin-generation changes; - reload atomically replaces provider descriptors and callbacks, discards late results, and remains bounded across repeated never-settling providers; +- catalog enumeration reflects one active config/registry snapshot, reports + selected missing IDs, and never invokes provider callbacks; - unknown selected criteria fail closed; - every condition and relationship resolves to one reconciled subject; - every canonical result has `contractVersion: 1` and satisfies the wire From 6e50eb4bc8f845c8bb193247dfee46e84eedcd3c Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Mon, 27 Jul 2026 00:30:14 -0700 Subject: [PATCH 96/98] docs(readiness): specify bounded startup wait --- .../0018-readiness-conditions-and-providers.md | 7 ++++++- rfcs/0018/readiness-v1-spec.md | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index e9d48a02..598e69fb 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -559,7 +559,12 @@ consumers of this RFC, not additions to the evaluation model: [PR 169](https://github.com/giodl73-repo/openclaw/pull/169) implements the catalog as `readiness.catalog` plus `openclaw ready criteria list|inspect`, reading one activation-pinned config/registry snapshot without invoking a - provider. + provider. Fork [PR 171](https://github.com/giodl73-repo/openclaw/pull/171) + implements startup waiting as `openclaw ready --wait [duration]`. It polls + sequentially, bounds each call by the remaining total budget, independently + aborts slow connection setup at the deadline, and emits only the final + canonical observation. Because waiting belongs to `ready`, Docker, + Kubernetes, systemd, OCC, and local launchers can use the same facility. 3. **Diagnose and operate.** Let existing Doctor, telemetry, support-bundle, and update owners consume snapshots and transitions for remediation, secret-safe evidence capture, transition telemetry, and pre/post-upgrade diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index c8643292..5f11ece9 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -456,6 +456,22 @@ Criterion list and inspect commands are clients of the live catalog projection. They may filter descriptors for presentation but must not execute a criterion or infer registration from a readiness result. +A bounded CLI wait mode is a client of repeated live Gateway results. It must: + +- use one explicit total deadline that covers config, credential, TLS, + connection, and RPC setup; +- run attempts sequentially and cap each per-call timeout by the remaining + total budget; +- retry both unavailable and not-ready observations without overlapping calls; +- emit only the final observation; +- preserve the canonical result unchanged for successful JSON output and for a + final observed not-ready result; and +- exit nonzero at timeout or transport failure. + +The wait facility must not evaluate conditions locally. Launcher-specific +commands may delegate to it, but they must not define another readiness or +deadline model. + ## Legacy Projection Existing `ready`, `failing`, `suppressed`, `eventLoop`, and `uptimeMs` fields @@ -489,6 +505,8 @@ An implementation conforms to readiness v1 when it proves: results, and remains bounded across repeated never-settling providers; - catalog enumeration reflects one active config/registry snapshot, reports selected missing IDs, and never invokes provider callbacks; +- bounded CLI waiting aborts slow pre-request setup at its total deadline, + never overlaps evaluations, and emits only its final observation; - unknown selected criteria fail closed; - every condition and relationship resolves to one reconciled subject; - every canonical result has `contractVersion: 1` and satisfies the wire From 5728ffe4a3e4d6b4f39c996ae39d4f4c853aa903 Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Mon, 27 Jul 2026 05:59:54 -0700 Subject: [PATCH 97/98] docs(readiness): specify subject lifetime output --- rfcs/0018-readiness-conditions-and-providers.md | 8 +++++++- rfcs/0018/readiness-v1-spec.md | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index 598e69fb..b6ce309c 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -435,7 +435,8 @@ readiness semantics. An optional `openclaw ready` command may be a thin client of the live Gateway result: -- human output lists non-`True` conditions; +- human output lists all conditions and identifies the existing lifetime and + generation of primary and related subjects behind non-`True` conditions; - `--json` preserves the canonical result; and - exit status is nonzero for required failure, required unknown, transport failure, or a missing readiness contract. @@ -565,6 +566,11 @@ consumers of this RFC, not additions to the evaluation model: aborts slow connection setup at the deadline, and emits only the final canonical observation. Because waiting belongs to `ready`, Docker, Kubernetes, systemd, OCC, and local launchers can use the same facility. + Fork [PR 172](https://github.com/giodl73-repo/openclaw/pull/172) completes + the human diagnostic projection by showing the existing kind, ID, + generation, and parent reference for primary and related subjects behind a + non-`True` condition. Healthy human output and canonical JSON remain + unchanged. 3. **Diagnose and operate.** Let existing Doctor, telemetry, support-bundle, and update owners consume snapshots and transitions for remediation, secret-safe evidence capture, transition telemetry, and pre/post-upgrade diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 5f11ece9..95825227 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -446,6 +446,9 @@ An `openclaw ready` command, when implemented, is a client of the live Gateway result: - human output lists all conditions with pass, fail, or warning classification; +- when identity is available, human output for non-`True` conditions identifies + the existing kind, ID, generation, and parent reference of each affected + primary and related subject; - `--json` preserves the canonical result; and - exit status is nonzero for required failure, required unknown, transport failure, or absence of a supported readiness contract. @@ -507,6 +510,8 @@ An implementation conforms to readiness v1 when it proves: selected missing IDs, and never invokes provider callbacks; - bounded CLI waiting aborts slow pre-request setup at its total deadline, never overlaps evaluations, and emits only its final observation; +- CLI subject-lifetime explanation is derived only from the canonical identity + package and does not alter canonical JSON or evaluate conditions locally; - unknown selected criteria fail closed; - every condition and relationship resolves to one reconciled subject; - every canonical result has `contractVersion: 1` and satisfies the wire From fae4ea1636c1e0ad08f6bd234cb7e43bab0c984a Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Mon, 27 Jul 2026 15:30:40 -0700 Subject: [PATCH 98/98] docs: align readiness RFC with upstream stack --- ...0018-readiness-conditions-and-providers.md | 114 +++++++----------- rfcs/0018/readiness-platform-comparison.md | 4 +- rfcs/0018/readiness-v1-spec.md | 45 ++++--- 3 files changed, 77 insertions(+), 86 deletions(-) diff --git a/rfcs/0018-readiness-conditions-and-providers.md b/rfcs/0018-readiness-conditions-and-providers.md index b6ce309c..50448f7a 100644 --- a/rfcs/0018-readiness-conditions-and-providers.md +++ b/rfcs/0018-readiness-conditions-and-providers.md @@ -314,7 +314,8 @@ unresolved, conflicting, or excessive declarations become `CriterionInvalidResult=Unknown`; partial raw identity output is never projected. -The bundled Policy plugin is the concrete v1 example. When activated, it +The bundled Policy plugin is an optional example of this contract. Readiness +does not depend on Policy being installed or enabled. When activated, Policy registers `plugin.policy.conformant`, reuses its existing policy evaluator, and reports `True` when evaluation has no findings, `False` with a bounded finding count when findings exist, and `Unknown` when policy checks are disabled. The @@ -493,52 +494,33 @@ package rather than adding a profile-only activation envelope. ### Implementation plan -The primary implementation for this RFC is -[openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018). -Its upgrade boundary keeps unconfigured probes on the legacy checker and makes -the presence of `gateway.readiness` the explicit canonical activation signal. -It is one upstream PR at exact head `6dce3555a511`. Focused readiness, live -Gateway, HTTP/RPC, health, selector, registry, subject, and CLI suites pass; -type-aware lint, formatting, and diff checks pass. Timed-out plugin checks -remain single-flight until the original callback settles, even across registry -replacement when the plugin ignores cancellation. Provider output is bounded, -validated, redacted, and accompanied by safe criterion-ID diagnostics. Config -publication fences -provider and workspace evidence by runtime generation, including recovery when -a retired filesystem probe never settles, while retaining a strict two-probe -ceiling across repeated generation changes. A prior package-installed -Docker lane proved `/ready` and `/readyz` -transition `200 -> 503 -> 200` for a selected workspace failure and recovery, -`/healthz` remains live, and `openclaw ready --json` exits `0 -> 1 -> 0` with -the same canonical condition. The -[exact-head package-installed profile matrix](https://github.com/giodl73-repo/openclaw/actions/runs/30214165737) -also proves the RFC 0018 surfaces, repeated-poll stability, and host-stable, -process-and-Gateway-renewing container restart semantics on dependent head -`e9c1988c5e59`. Standalone published-upgrade proof remains separate. Reviewers -should use the primary PR for the proposed landing shape and current validation -state. - -The first core-owner adoption is consolidated in -[openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421), -stacked at exact readiness head `6dce3555a511` and exact implementation head -`9cc02c5d89c`. It adds selectable core-owner criteria, -execution-capability, session-storage, state, delivery, and scheduler -observations without selecting any of them by default. Fork PRs -[#153](https://github.com/giodl73-repo/openclaw/pull/153), -[#154](https://github.com/giodl73-repo/openclaw/pull/154), and -[#155](https://github.com/giodl73-repo/openclaw/pull/155) preserve the three -owner-area review slices; PR 113421 is the intended merge unit. - -The fork PRs below expose the implementation as optional smaller review -slices. They are supporting review aids, not alternative landing PRs: - -| Slice | Draft PR | Intended scope | -| --- | --- | --- | -| Canonical core conditions | [PR 17](https://github.com/giodl73-repo/openclaw/pull/17) | Normalize existing Gateway observations and compatibility projections. | -| Workspace readiness | [PR 22](https://github.com/giodl73-repo/openclaw/pull/22) | Add the bounded `WorkspaceWritable` condition without profile behavior. | -| Readiness providers | [PR 23](https://github.com/giodl73-repo/openclaw/pull/23) | Add activation-scoped provider registration and operator-required criteria, without custom profiles. | -| Canonical readiness CLI | [PR 27](https://github.com/giodl73-repo/openclaw/pull/27) | Add a thin CLI projection of the live result. | -| Readiness subjects | [PR 161](https://github.com/giodl73-repo/openclaw/pull/161) | Add the shared producer/subject identity package and condition attribution used by core and plugins. | +The RFC has two direct upstream implementation PRs, in landing order: + +1. [openclaw/openclaw#104018](https://github.com/openclaw/openclaw/pull/104018) + at exact head `2f131c6e220` adds the opt-in canonical evaluator, bounded + providers, subject identity, shared HTTP/RPC/status/health projections, and + the `openclaw ready` CLI. Unconfigured probes remain on the legacy checker. +2. [openclaw/openclaw#113421](https://github.com/openclaw/openclaw/pull/113421) + at exact head `c1d7f394f86` adds selectable core-owner observations for + runtime activation, execution capability, session storage, state, delivery, + and scheduling. None becomes required by being implemented. + +Focused readiness, live Gateway, HTTP/RPC, health, selector, registry, subject, +CLI, and owner-adoption suites pass; type-aware lint, formatting, and diff +checks pass. Timed-out plugin checks remain single-flight until the original +callback settles, including across registry replacement when a plugin ignores +cancellation. Provider output is bounded, validated, and redacted. Config +publication fences provider and workspace evidence by runtime generation, +including recovery when a retired filesystem probe never settles while +retaining a strict two-probe ceiling across repeated generation changes. + +The +[exact-head package-installed Docker matrix](https://github.com/giodl73-repo/openclaw/actions/runs/30289122192) +proves the RFC 0018 surfaces as part of the dependent profile stack: `/ready` +and `/readyz` transition `200 -> 503 -> 200`, `/healthz` remains live, +`openclaw ready --json` exits `0 -> 1 -> 0`, repeated polls retain identity, +and container restart preserves host identity while renewing process and +Gateway lifetimes. Standalone published-upgrade proof remains separate. #### Operator facilities roadmap @@ -551,23 +533,18 @@ consumers of this RFC, not additions to the evaluation model: by semantic changes, suppress timestamp-only churn, identify condition changes by `(subjectRef, type)`, and report producer or subject-lifetime replacement. Continue through not-ready and unavailable states so recovery - remains observable. `--json` emits versioned JSON Lines. Fork - [PR 167](https://github.com/giodl73-repo/openclaw/pull/167) is the first - bounded implementation slice. + remains observable. `--json` emits versioned JSON Lines. 2. **Inspect and wait.** Add read-only criterion/provider enumeration and a bounded startup wait convenience over the same canonical result. Neither - facility may create a second evaluator. Fork - [PR 169](https://github.com/giodl73-repo/openclaw/pull/169) implements the - catalog as `readiness.catalog` plus `openclaw ready criteria list|inspect`, - reading one activation-pinned config/registry snapshot without invoking a - provider. Fork [PR 171](https://github.com/giodl73-repo/openclaw/pull/171) - implements startup waiting as `openclaw ready --wait [duration]`. It polls + facility may create a second evaluator. The catalog should use + `readiness.catalog` plus `openclaw ready criteria list|inspect`, reading one + activation-pinned config/registry snapshot without invoking a provider. + Startup waiting should use `openclaw ready --wait [duration]`. It polls sequentially, bounds each call by the remaining total budget, independently aborts slow connection setup at the deadline, and emits only the final canonical observation. Because waiting belongs to `ready`, Docker, Kubernetes, systemd, OCC, and local launchers can use the same facility. - Fork [PR 172](https://github.com/giodl73-repo/openclaw/pull/172) completes - the human diagnostic projection by showing the existing kind, ID, + The human diagnostic projection should show the existing kind, ID, generation, and parent reference for primary and related subjects behind a non-`True` condition. Healthy human output and canonical JSON remain unchanged. @@ -603,24 +580,23 @@ snapshot. | State and background services | `StateReady`, `SessionStorageReady`, `DeliveryRuntimeReady`, `SchedulerReady`; defer `RestoreComplete` until a restore fence exists | State/store activation, bounded persistence-location probes, delivery runtime ownership, cron lifecycle and startup recovery state | Report whether configured stateful services can accept new work. A selected storage probe may perform a capped write/fsync/unlink check, but historical dead letters and individual job failures remain diagnostics or advisories rather than universal blockers. Do not infer restore completion from database-open, fleet-restore, or config-migration state. | | Hosted dependencies | `HostBindingsReady`; defer `EgressReady` and `ManagedConfigApplied` until their owners publish authoritative facts | RFC 0020 host-integration bundle and owner-generation evidence | Project required host bindings through the ordinary readiness selector. Keep network probing, config inference, Lobster, OCC, tenant, and deployment policy out of the condition evaluator. | -All four buckets now have fork evidence slices. The first three are stacked -directly on the exact head of the primary readiness implementation. The fourth -is stacked on an explicit composition of that readiness head with RFC 0020 host +Validated prototypes cover all four buckets. The first three depend only on +the primary readiness implementation. The fourth also depends on RFC 0020 host integration package 3. They remain optional follow-on work and are not prerequisites for accepting this RFC: -- [Runtime activation integrity PR 153](https://github.com/giodl73-repo/openclaw/pull/153) - adds selectable `ConfigCurrent`, `ModelRouteReady`, and `SecretsReady` +- Runtime activation integrity adds selectable `ConfigCurrent`, + `ModelRouteReady`, and `SecretsReady` conditions plus quarantine-aware plugin activation evidence. -- [Agent execution capabilities PR 154](https://github.com/giodl73-repo/openclaw/pull/154) - adds selectable context-engine, tool-catalog, MCP, sandbox, and harness +- Agent execution capabilities adds selectable context-engine, tool-catalog, + MCP, sandbox, and harness conditions. MCP discovery is captured for every configured agent when the Gateway accepts a runtime configuration; readiness evaluation does not connect to MCP servers or start any execution surface. `SkillsReady` remains deferred because the current skill inventory path is not a bounded readiness source; the skills owner must first publish an activation snapshot or index. -- [State and background services PR 155](https://github.com/giodl73-repo/openclaw/pull/155) - adds selectable state-database, session-storage, durable session-delivery, +- State and background services adds selectable state-database, + session-storage, durable session-delivery, and scheduler lifecycle conditions. Owners publish synchronous process-local snapshots. The selected storage condition uses a one-second, target-capped, concurrency-capped, generation-safe write/fsync/unlink probe over resolved @@ -628,8 +604,8 @@ prerequisites for accepting this RFC: install delivery recovery, import or start cron, scan queues, or run recovery. `RestoreComplete` remains deferred until OpenClaw owns a generic restore generation and admission fence. -- [Hosted dependencies PR 156](https://github.com/giodl73-repo/openclaw/pull/156) - adds selectable `openclaw.host-bindings-ready` and connects RFC 0020 bundle +- Hosted dependencies adds selectable `openclaw.host-bindings-ready` and + connects RFC 0020 bundle declarations to the active core/plugin criterion catalog. Selecting the aggregate includes referenced criteria as advisory detail without requiring operators to repeat the bundle's selectors. A required contribution fails diff --git a/rfcs/0018/readiness-platform-comparison.md b/rfcs/0018/readiness-platform-comparison.md index 8607b564..0196e2a9 100644 --- a/rfcs/0018/readiness-platform-comparison.md +++ b/rfcs/0018/readiness-platform-comparison.md @@ -171,8 +171,8 @@ The implementation and release proof should include this matrix: | Plugin reload or node replacement | New owner ID or generation according to that owner's contract | Late provider output is discarded or represented as incomplete. | The -[exact packaged container matrix](https://github.com/giodl73-repo/openclaw/actions/runs/30214165737) -proves this restart boundary on dependent implementation head `e9c1988c5e59`: +[exact packaged container matrix](https://github.com/giodl73-repo/openclaw/actions/runs/30289122192) +proves this restart boundary on dependent profile head `18c42a7f26a`: the same host workload retains its fingerprinted host identity while process and Gateway identities renew. Unit tests additionally establish schema and generation fences. diff --git a/rfcs/0018/readiness-v1-spec.md b/rfcs/0018/readiness-v1-spec.md index 95825227..490afe34 100644 --- a/rfcs/0018/readiness-v1-spec.md +++ b/rfcs/0018/readiness-v1-spec.md @@ -259,8 +259,10 @@ separate criteria for independently selectable resources or states; an unbounded collection is summarized by one aggregate subject and a bounded, deterministic set of related subjects. -The bundled Policy plugin demonstrates this contract with -`plugin.policy.conformant`. It reuses the plugin's existing policy evaluation, +The bundled Policy plugin is an optional demonstration of this contract; core +readiness does not depend on Policy being installed or enabled. When activated, +it registers `plugin.policy.conformant`. It reuses the plugin's existing policy +evaluation, returns only bounded summary text, and is not evaluated until selected through `gateway.readiness`. Advisory selection does not affect the overall readiness decision; required selection fails closed for findings, disabled evaluation, @@ -302,11 +304,11 @@ the active registry entry contains the namespaced ID, description, owning plugin, and source. The registry snapshot identity is the activation-generation boundary. -### Criterion Catalog Projection +### Optional Criterion Catalog Projection -An authenticated read-only projection may enumerate configurable criteria from -one activation-pinned config and registry snapshot. The v1 catalog has this -shape: +An implementation may expose an authenticated read-only projection that +enumerates configurable criteria from one activation-pinned config and registry +snapshot. When implemented, the v1 catalog has this shape: ```ts type ReadinessCriterionCatalog = { @@ -446,15 +448,23 @@ An `openclaw ready` command, when implemented, is a client of the live Gateway result: - human output lists all conditions with pass, fail, or warning classification; -- when identity is available, human output for non-`True` conditions identifies - the existing kind, ID, generation, and parent reference of each affected - primary and related subject; +- when identity is available, human output may identify the affected subject; - `--json` preserves the canonical result; and - exit status is nonzero for required failure, required unknown, transport failure, or absence of a supported readiness contract. The CLI must not implement condition evaluation independently. +### Optional CLI Facilities + +The following facilities are compatible extensions over the same live result. +They are not required for core readiness v1 conformance. When implemented, they +must follow the contracts below. + +Human output for non-`True` conditions may identify the existing kind, ID, +generation, and parent reference of each affected primary and related subject. +It must derive that explanation only from the canonical identity package. + Criterion list and inspect commands are clients of the live catalog projection. They may filter descriptors for presentation but must not execute a criterion or infer registration from a readiness result. @@ -506,12 +516,6 @@ An implementation conforms to readiness v1 when it proves: workspace, selection, and plugin-generation changes; - reload atomically replaces provider descriptors and callbacks, discards late results, and remains bounded across repeated never-settling providers; -- catalog enumeration reflects one active config/registry snapshot, reports - selected missing IDs, and never invokes provider callbacks; -- bounded CLI waiting aborts slow pre-request setup at its total deadline, - never overlaps evaluations, and emits only its final observation; -- CLI subject-lifetime explanation is derived only from the canonical identity - package and does not alter canonical JSON or evaluate conditions locally; - unknown selected criteria fail closed; - every condition and relationship resolves to one reconciled subject; - every canonical result has `contractVersion: 1` and satisfies the wire @@ -526,3 +530,14 @@ An implementation conforms to readiness v1 when it proves: observed activation; and - public output contains no raw exceptions, secrets, credentials, or tenant content. + +### Optional Facility Conformance + +An implementation that adds the optional operator facilities must also prove: + +- catalog enumeration reflects one active config/registry snapshot, reports + selected missing IDs, and never invokes provider callbacks; +- bounded CLI waiting aborts slow pre-request setup at its total deadline, + never overlaps evaluations, and emits only its final observation; and +- CLI subject-lifetime explanation is derived only from the canonical identity + package and does not alter canonical JSON or evaluate conditions locally.