OpenWOP openwop.dev
RFC details authors, dates, what it affects, review history
FieldValue
RFC0096
TitleReviewable Learning — Skill/Automation Proposal Lifecycle
StatusAccepted
Author(s)David Tufts (@davidscotttufts)
Created2026-06-13
Updated2026-10-24 (Active → Accepted; RFC 0156 §B review deferred by steward exemption (2026-10-17). Evidence tier: tier-1 — the tripwire named below is met: openwop-app's certified 2.46.21 production cut 209c (build commit:34bfefddc, revision openwop-app-backend-01032-9ff, 480/0/0, --verify --host-key VERIFIED) passes the success-path and byte-match legs live through RFC 0249's operations: a client-submitted prompt-template draft is not served, listed or renderable (0249.draft-inert, proposal-inert-until-applied), an authorized apply installs it, and the installed template is JCS-equal to the last revision and not the original (0249.readback-byte-match, proposal-no-resynthesis). Scope: prompt-template only; the other three kinds have no v2 read-back and are disclosed in the facet (RFC 0249 G2–G4).) · 2026-10-24 (repository work (1) and (2) below are proposed as RFC 0249 (Draft): normative v2 operations, client-submitted drafts and a JCS-checkable installedArtifact read-back, phase 1 prompt-template) · 2026-10-19 (Accepted → Active, steward decision: neither Accepted witness shows an install. openwop-app's 7/7 rested on a fake installedArtifactRef and it now refuses apply and no longer advertises agents.proposals; MyndHyve's evidence is the unscoped-apply 403 only. See the 2026-10-19 correction note below. Repository work still open, so not Parked (README rule 3): (1) §Conformance scenario 1, inertness, and scenario 3, no re-synthesis, have no behavioral leg, and scenario 2 tests only the denied half; (2) the spec does not say how a client or conformance driver reads an installed artifact back, which the byte-match leg needs: a resolvable installedArtifactRef or a per-kind registry read. Once both land, park on the tripwire: a host advertising agents.proposals passes the success-path and byte-match legs live.) · 2026-06-14 (Active → Accepted: non-steward live witness — MyndHyve advertises agents.proposals at the locked shape on live rev workflow-runtime-00269-ljm and serves the host-sample seams non-vacuously (apply-without-scope → 403), steward curl-verified; openwop-app reference host (rev 00174-6m6) serves the full surface + passed proposal-reviewable-learning 7/7 non-vacuous vs @openwop/openwop-conformance@1.24.0. CLI proposals group live-smoke green. Both legs of the §D Accepted bar met.) · 2026-06-13 (Draft → Active: spec floor landed — agents.proposals capability + proposal.schema.json + agent-memory.md §"Reviewable learning" + the proposal-inert-until-applied / proposal-no-resynthesis invariants + content-free proposal.created/proposal.activated events + 3 capability-gated scenarios. rule artifact kind dropped (no defining RFC). 7-day comment window bypassed by maintainer.)
Affectscapabilities.schema.json, spec/v1/agent-memory.md (new §), schemas/proposal.schema.json (new), api/openapi.yaml, conformance, @openwop/cli (proposals group)
Compatibilityadditive
Supersedes—
Superseded by—

Correction (2026-10-19) — one of the two Accepted witnesses was not a real install. The Updated line above credits the openwop-app reference host with proposal-reviewable-learning 7/7 non-vacuous. Re-graded in openwop-app ADR 0938 (feature-loop row 53, PR openwop/openwop-app#5019), that host's apply installed nothing. It returned installed:<kind>:<id>:<sha256-prefix>, a hash of the stored bytes, as installedArtifactRef, set state: applied and wrote no artifact anywhere, for all four kinds. Scenarios that check the returned ref and the state transition cannot tell that apart from an install, so the 7/7 witnessed the response shape, not §"Invariants" 3 (the installed artifact byte-matches). Nothing in that host could have been byte-matched.

Since 22bbffb04 (live 2026-10-19), openwop-app refuses apply with 409 proposal_not_installable for any kind it has no installer for, which is every kind today, and advertises agents.proposals only for kinds that do. So the capability is now absent from its discovery document, and it is no longer a witness for this RFC. The MyndHyve leg is untouched by this note, but its recorded evidence (apply-without-scope → 403) exercises authorization, not installation, so it also does not show an install.

This note does not change the Status. It asks the maintainers to re-check whether the §D Accepted bar is still met. The bar would be met by one live host whose apply produces an artifact a later read can fetch and byte-compare. The conformance gap, that no scenario reads the installed artifact back, is worth a suite issue either way.

Summary

Add an optional, capability-gated proposal lifecycle so a host can let an agent synthesize a reusable artifact — a skill (agent pack, RFC 0003), a workflow-chain pack (RFC 0013), a prompt template (RFC 0027), or a scheduled automation (RFC 0052) — from its own run/tool traces, and have that artifact remain inert until a human reviews and activates it. A Proposal is a durable, draft-state object with a typed artifact payload, a provenance pointer to the traces that produced it, a duplication signal against existing artifacts, and a small state machine (draft → revise → applied | rejected | archived). Activation is not a new authorization path — it is delegated to the RFC 0051 approval-gate semantics (role/scope/quorum, audited override). Hosts that omit the agents.proposals capability are unchanged; nothing about the run-execution wire changes.

Motivation

The competitive landscape for self-hosted agents (OpenClaw "Skill Workshop," Hermes self-improvement + "Curator") converges on one product-ready idea: an agent that improves from experience without silently mutating its own long-term behavior. The pattern that works is proposal-first — the agent drafts a reusable behavior, but the draft is inert until a human revises/approves it. This is materially safer than letting an agent rewrite its production behavior in place, and it is the single most-cited differentiator in the docs/ competitive feature analysis that drove the v1.x agent-platform RFC wave (0070, 0081, 0082, 0085, 0086).

openwop already has every downstream primitive but no upstream contract:

  • Artifacts a proposal can produce exist: agent packs (0003), workflow-chain packs (0013), prompt templates (0027), scheduled automations (0052).
  • Activation governance exists: RFC 0051 approvalGate binds role/scope/quorum + audited override; RFC 0049 RBAC; RFC 0043 registry-and-extension policy gates what may be installed.
  • Quality signal exists: RFC 0081 scorecards, RFC 0056 run feedback/annotation.

What is missing is the inert-draft object and its review state machine: where a synthesized-but-unapproved behavior lives, how it is revised, how it is shown to differ from what already exists (duplication detection — the "Curator" problem), and the hard invariant that it cannot affect any future run until explicitly activated. Today that is host-private: an A2A peer or the conformance suite cannot assert "this synthesized skill was inert until an authorized principal applied it." That invariant — no generated reusable behavior influences a run before review — is a safety + interop guarantee an operator depends on, so it belongs on the wire. The synthesis algorithm (what traces become what artifact) stays entirely a host choice; this RFC pins only the object shape, the lifecycle, the gate, and the inertness invariant.

Proposal

§A — capabilities.schema.json: additive optional sub-block under agents

   "agents": {
     "type": "object",
     "properties": {
+      "proposals": {
+        "type": "object",
+        "description": "Host synthesizes reusable artifacts from run/tool traces as inert, reviewable drafts (RFC 0096). Optional.",
+        "properties": {
+          "artifactKinds": {
+            "type": "array",
+            "description": "Which artifact kinds the host can propose.",
+            "items": { "enum": ["agent-pack", "workflow-chain-pack", "prompt-template", "automation"] }
+          },
+          "duplicationDetection": { "type": "boolean", "default": false },
+          "activation": {
+            "enum": ["approval-gate", "direct-rbac"],
+            "description": "`approval-gate` routes activation through an RFC 0051 gate; `direct-rbac` requires an RFC 0049 scope only."
+          }
+        },
+        "required": ["artifactKinds", "activation"]
+      }
     }
   }

A host advertises agents.proposals only if it serves the §C endpoints. The CLI (and any client) MUST capability-gate on this block and fail closed when it is absent.

§B — schemas/proposal.schema.json (new)

{
  "$id": "https://openwop.dev/spec/v1/proposal.schema.json",
  "type": "object",
  "required": ["id", "kind", "state", "artifact", "provenance", "createdAt", "owner"],
  "properties": {
    "id":    { "type": "string", "description": "Host-assigned, stable across revisions." },
    "kind":  { "enum": ["agent-pack", "workflow-chain-pack", "prompt-template", "automation"] },
    "state": { "enum": ["draft", "revised", "applied", "rejected", "archived"] },
    "title": { "type": "string" },
    "rationale": { "type": "string", "description": "Plain-language why, SR-1 redaction-safe (no secrets/PII)." },
    "artifact":  { "type": "object", "description": "The proposed artifact, shaped by `kind` (an RFC 0003 pack manifest, an RFC 0027 template, an RFC 0052 job spec, …). Inert until applied." },
    "provenance": {
      "type": "object",
      "required": ["sourceRunIds"],
      "properties": {
        "sourceRunIds": { "type": "array", "items": { "type": "string" }, "description": "Runs whose traces produced this proposal (RFC 0040 causation-compatible)." },
        "synthesizerModel": { "type": "string" }
      }
    },
    "duplicateOf": { "type": ["string", "null"], "default": null, "description": "Existing artifact ref this proposal restates/overlaps, if duplication detection is on." },
    "owner": { "type": "object", "additionalProperties": false, "required": ["tenant"], "properties": { "tenant": { "type": "string", "minLength": 1 }, "workspace": { "type": "string", "minLength": 1 }, "principal": { "type": "string", "minLength": 1 } }, "description": "RFC 0048 identity triple {tenant, workspace?, principal} — inlined (no standalone identity.schema.json in the corpus; matches run-snapshot.schema.json.owner)." },
    "activation": { "type": ["object", "null"], "description": "When applied: the RFC 0051 approval reference + the resulting installed artifact ref.", "default": null },
    "createdAt": { "type": "string", "format": "date-time" },
    "updatedAt": { "type": "string", "format": "date-time" }
  }
}

§C — Endpoints (host-extension /v1/host/sample/proposals, promotable to /v1/proposals)

Method + pathPurpose
GET /proposals[?state=&kind=]List proposals (tenant/workspace-scoped per RFC 0048).
GET /proposals/{id}One proposal, including the inert artifact.
PATCH /proposals/{id}Author edits the draft (revise): mutates artifact/title/rationale, sets state: revised. MUST NOT activate.
POST /proposals/{id}/applyActivate. MUST route through the advertised activation mode (§A); on success installs the artifact via the relevant pack/registry path (RFC 0043) and sets state: applied with activation populated.
POST /proposals/{id}/rejectstate: rejected with an optional reason.
DELETE /proposals/{id}state: archived (soft).

§D — Events (additive, content-free, redaction-safe)

Two new optional events, gated on agents.proposals:

  • proposal.created — { proposalId, kind, sourceRunIds, duplicateOf }. Emitted when the host synthesizes a draft. No artifact body, no rationale text (those live behind the authed read).
  • proposal.activated — { proposalId, kind, approvalId?, installedArtifactRef }. Emitted on successful apply.

§E — spec/v1/agent-memory.md normative prose (new section "Reviewable learning")

  1. A Proposal in any state other than applied MUST NOT influence the resolution, planning, or execution of any run. (The inertness invariant.)
  2. apply MUST be authorized: if activation = approval-gate, the host MUST drive an RFC 0051 gate and MUST NOT install the artifact unless the gate is granted (or overridden, which MUST be audited per RFC 0009/0010); if activation = direct-rbac, the caller MUST hold the RFC 0049 scope the host advertises for activation.
  3. On apply, the installed artifact MUST be the exact artifact payload last persisted on the proposal (no silent re-synthesis at activation).
  4. provenance.sourceRunIds and rationale MUST be SR-1 redaction-safe.

Examples

Positive — a draft agent-pack proposal is read, revised via PATCH, then apply drives an approval-gate; gate granted → installedArtifactRef returned, proposal.activated emitted.

Negative (fails validation / authorization) — POST /proposals/{id}/apply by a principal lacking the activation scope → 403, state stays revised, no artifact installed, no proposal.activated. A proposal whose artifact is malformed for its kind → 422.

Compatibility

Additive. New optional capability sub-block (agents.proposals), new schema, new host-extension endpoints, two new ignorable events. Guarantees: hosts that don't advertise agents.proposals neither serve the endpoints nor emit the events; existing clients never see proposals; the run-execution wire (RFC 0033 completion contract, RFC 0040 causation) is untouched. Lands in v1.x.

Conformance

  • Existing coverage: RFC 0051 approval-gate scenarios cover the activation path; RFC 0043 covers install policy.
  • New scenarios (ship with @openwop/openwop-conformance):

1. Inertness — a draft proposal whose artifact is a workflow-chain pack does not alter a run that would match it; only after apply does the behavior appear. 2. Gated activation — apply without the required role/scope is denied; with it (or a quorum-met gate) succeeds and emits proposal.activated. 3. No re-synthesis — the installed artifact byte-matches the last-persisted artifact.

  • New scenarios run only when agents.proposals is advertised.

Alternatives considered

  1. Let agents write skills/packs directly (no proposal object). Rejected: this is exactly the "agent silently mutates its production behavior" failure the market avoids; it makes the inertness invariant unexpressible and uncertifiable.
  2. Reuse RFC 0082 agent-deployment-lifecycle. Rejected: 0082 promotes an already-authored agent through environments; a proposal is a synthesized, not-yet-real artifact pending first review. Different object, different state machine; 0082 is a good downstream once an applied proposal becomes a deployable agent.
  3. Fold into RFC 0068 memory consolidation. Rejected: 0068 reconciles the memory corpus; a proposal produces an executable reusable artifact. Conflating them overloads one capability with two semantics.
  4. Do nothing. Rejected: leaves the single strongest market differentiator host-private and unverifiable.

Unresolved questions

  1. Should duplicateOf be a single ref or a ranked list (Curator-style near-duplicate cluster)?
  2. Should revise fork a new id (versioned proposals) or mutate in place (current draft: mutate, with updatedAt)?
  3. Does an applied proposal that is later found harmful get a first-class rollback, or is that just the artifact's own uninstall path (RFC 0043)?

Implementation notes (non-normative)

Reference host: surface under /v1/host/sample/proposals; the synthesizer is a host concern (an LLM pass over sourceRunIds traces). The @openwop/cli proposals group drives the lifecycle (list/get/revise/apply/reject/archive, --json on reads, exit codes 0 applied / 3 pending-review / 1 rejected|error). Sequencing: depends on RFC 0051 (Accepted) for activation; pairs naturally with the CLI approvals group already shipped.

Acceptance criteria

  • [x] Spec text merged (agent-memory.md §"Reviewable learning"; at v2, the agents.proposals facet and proposal.schema.json).
  • [x] capabilities.schema.json + proposal.schema.json updated; the v2 paths added by RFC 0249.
  • [x] ≥1 conformance scenario per §Conformance, capability-gated (v2-proposal-lifecycle, suite 2.46.21).
  • [x] CHANGELOG entry under the target v1.x (and 2.46.21 at v2).
  • [x] A host implements the surface and passes the new scenarios: openwop-app cut 209c (34bfefddc), through the v2 operations of RFC 0249.

References

  • RFC 0051 (approval/deployment gate) · RFC 0049 (RBAC) · RFC 0043 (registry & extension policy) · RFC 0003 (agent packs) · RFC 0013 (workflow-chain packs) · RFC 0027 (prompt templates) · RFC 0052 (scheduling) · RFC 0081 (scorecards) · RFC 0056 (run feedback/annotation) · RFC 0048 (identity triple) · RFC 0040 (cross-host causation).
  • Prior art: OpenClaw Skill Workshop (proposal-first skills); Hermes self-improvement + Curator (near-duplicate curation); Rust RFC "experimental → stabilized" gating.
  • Competitive feature analysis (docs/), the driver for the v1.x agent-platform RFC wave.

More proposals.

Edit this page on GitHub ↗