@openwop/openwop-conformance 1.21.0 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +43 -2
  2. package/README.md +61 -63
  3. package/api/asyncapi.yaml +108 -38
  4. package/api/openapi.yaml +34 -6
  5. package/coverage.md +389 -202
  6. package/fixtures/connection-packs/connection-pack-github.json +31 -0
  7. package/fixtures.md +120 -101
  8. package/package.json +1 -1
  9. package/schemas/README.md +4 -0
  10. package/schemas/capabilities.schema.json +127 -0
  11. package/schemas/connection-pack-manifest.schema.json +161 -0
  12. package/schemas/export-bundle.schema.json +66 -0
  13. package/schemas/goal.schema.json +104 -0
  14. package/schemas/proposal.schema.json +84 -0
  15. package/schemas/run-event-payloads.schema.json +86 -7
  16. package/schemas/run-event.schema.json +17 -3
  17. package/schemas/run-options.schema.json +1 -2
  18. package/schemas/run-snapshot.schema.json +2 -1
  19. package/schemas/suspend-request.schema.json +5 -0
  20. package/src/scenarios/connection-pack-manifest-valid.test.ts +122 -0
  21. package/src/scenarios/connection-pack-no-credential-material.test.ts +125 -0
  22. package/src/scenarios/connection-pack-reach-exclusive.test.ts +85 -0
  23. package/src/scenarios/connection-pack-write-reconsent.test.ts +91 -0
  24. package/src/scenarios/connection-provider-resolution.test.ts +153 -0
  25. package/src/scenarios/cross-host-traceparent-propagation.test.ts +3 -3
  26. package/src/scenarios/export-bundle-portability.test.ts +120 -0
  27. package/src/scenarios/fixtures-valid.test.ts +34 -0
  28. package/src/scenarios/goal-standing-continuation.test.ts +139 -0
  29. package/src/scenarios/grpc-transport.test.ts +108 -0
  30. package/src/scenarios/i18n-negotiation.test.ts +181 -0
  31. package/src/scenarios/interrupt-token-matrix.test.ts +2 -2
  32. package/src/scenarios/media-url-inline-cap.test.ts +5 -3
  33. package/src/scenarios/proposal-reviewable-learning.test.ts +129 -0
  34. package/src/scenarios/spec-corpus-validity.test.ts +107 -0
  35. package/src/scenarios/stream-text-fixture.test.ts +212 -0
  36. package/src/scenarios/version-fold.test.ts +193 -0
  37. package/src/scenarios/wasm-pack-memory-cap.test.ts +4 -2
  38. package/src/scenarios/webhook-tenant-isolation.test.ts +184 -0
@@ -64,6 +64,11 @@
64
64
  "type": "number",
65
65
  "minimum": 0,
66
66
  "description": "RFC 0084. Engine-side cost ceiling clamping `RunOptions.configurable.budget.maxCostUsd`. Optional; only meaningful with `capabilities.budget`."
67
+ },
68
+ "maxRequestBodyBytes": {
69
+ "type": "integer",
70
+ "minimum": 1,
71
+ "description": "RFC 0094 §H. Maximum REST request body size (bytes) the host accepts. Optional v1 field per `capabilities.md` §3 (previously documented as reserved — the closed `limits` object made advertising it a schema-validation failure). Hosts that advertise it MUST enforce it."
67
72
  }
68
73
  },
69
74
  "additionalProperties": false,
@@ -279,6 +284,34 @@
279
284
  "items": { "type": "string", "enum": ["rest", "mcp", "a2a", "grpc"] },
280
285
  "description": "Optional v1 transport advertisement. REST is required whether or not this field is present."
281
286
  },
287
+ "grpc": {
288
+ "type": "object",
289
+ "description": "RFC 0094 §H. gRPC transport advertisement per `grpc-transport.md` §\"Capability advertisement\". Optional — absent ⇒ the host exposes no gRPC transport. A host that exposes the gRPC surface advertises this block AND includes `\"grpc\"` in `supportedTransports`. REST + SSE remain exposed regardless.",
290
+ "required": ["supported", "service", "tls"],
291
+ "properties": {
292
+ "supported": {
293
+ "type": "boolean",
294
+ "description": "Toggle — `true` when the gRPC surface is live."
295
+ },
296
+ "endpoint": {
297
+ "type": "string",
298
+ "minLength": 1,
299
+ "pattern": "^grpcs?://",
300
+ "description": "Full URI: `grpc://` (cleartext, intra-trusted-network only) OR `grpcs://` (TLS). Hosts SHOULD require TLS in production."
301
+ },
302
+ "service": {
303
+ "type": "string",
304
+ "const": "openwop.v1.Engine",
305
+ "description": "Canonical service name. v1 hosts MUST use `openwop.v1.Engine` per `grpc-transport.md` §\"Field semantics\"."
306
+ },
307
+ "tls": {
308
+ "type": "string",
309
+ "enum": ["required", "optional", "disabled"],
310
+ "description": "TLS posture. Production hosts MUST set `\"required\"`."
311
+ }
312
+ },
313
+ "additionalProperties": false
314
+ },
282
315
  "configurable": {
283
316
  "type": "object",
284
317
  "description": "Optional v1 per-run overlay schema — what `RunOptions.configurable` keys this server honors."
@@ -403,6 +436,22 @@
403
436
  },
404
437
  "additionalProperties": false
405
438
  },
439
+ "connections": {
440
+ "type": "object",
441
+ "description": "RFC 0095 (`Draft`). Connection packs — portable, registry-distributable provider definitions (`kind: \"connection\"`, `connection-pack-manifest.schema.json`) that the RFC 0045/0047 `provider` string resolves against. Only useful alongside `oauth.supported` (RFC 0047) or `credentials.supported` (RFC 0046); a host SHOULD NOT advertise this block without at least one of those.",
442
+ "required": ["packsSupported"],
443
+ "properties": {
444
+ "supported": {
445
+ "type": "boolean",
446
+ "description": "OPTIONAL convenience flag mirroring the other capability families. RFC 0095 keys behavior on `packsSupported`; hosts MAY also advertise `supported` for family-shape uniformity."
447
+ },
448
+ "packsSupported": {
449
+ "type": "boolean",
450
+ "description": "RFC 0095 §C. When `true`, the host installs `kind: \"connection\"` registry packs and MUST implement the §B.6 resolution contract: an RFC 0045 connector's `auth.provider` (or an RFC 0047 `host.oauth` provider string) resolves against the installed connection pack whose `provider.id` matches, with installed-vs-built-in precedence per SemVer §11 and `connection_provider_unresolved` / `connection_provider_conflict` diagnostics. When `false` or absent, connection packs are not loaded and provider resolution stays implementation-defined."
451
+ }
452
+ },
453
+ "additionalProperties": false
454
+ },
406
455
  "credentials": {
407
456
  "type": "object",
408
457
  "description": "RFC 0046 (`Draft`). Portable credential resolution + lifecycle contract — sibling to `secrets`, first-class store-at-rest + workspace sharing + two-key-overlap rotation. A pack references a credential by `{ ref, scope }` (see `credential-reference.schema.json`); the host resolves it into the node sandbox ONLY — never into inputs, persisted variables, channels, any run.* event payload, the debug bundle, or replay state (SECURITY invariant `credential-payload-redaction`). Supersedes the informal BYOK annex; the `secrets` advertisement stays valid.",
@@ -1070,6 +1119,54 @@
1070
1119
  "type": "boolean",
1071
1120
  "default": false,
1072
1121
  "description": "RFC 0063 (`Active`). When `true`, host honors the optional `outputAttestation` block on `core.subWorkflow`: computes a content checksum (RFC 8785 JCS + SHA-256, the `replay.md` recipe) over a child's harvested outputs and surfaces it as the additive optional `attestation` object on the existing `core.workflowChain.event { phase: 'output.harvested' }` (RFC 0037) BEFORE applying `outputMapping`; when the config sets `requireApproval: true`, suspends the parent via an `approval` interrupt (RFC 0051) before merge and fails closed (no `accept`/`edit-accept` ⇒ no merge). Reuses RFC 0051's `approval` kind + RFC 0049 scopes for `principalScope` — no new interrupt kind, event type, or error code. Hosts that omit / `false` this flag treat `outputAttestation` as inert (blind merge, today's behavior)."
1122
+ },
1123
+ "proposals": {
1124
+ "type": "object",
1125
+ "description": "RFC 0096 (`Active`). Reviewable learning — the host synthesizes reusable artifacts (skills/packs/templates/automations) from run/tool traces as INERT, reviewable drafts that MUST NOT influence the resolution, planning, or execution of any run until an authorized principal activates them. A host advertising this serves the `/v1/host/sample/proposals` surface (promotable to `/v1/proposals`) and emits the content-free `proposal.created` / `proposal.activated` events. Activation is delegated to RFC 0051 approval-gate or RFC 0049 RBAC — no new authorization path. On `apply` the installed artifact MUST byte-match the last-persisted `artifact` (no silent re-synthesis). Hosts that omit this block do not synthesize proposals; the conformance scenarios skip cleanly.",
1126
+ "additionalProperties": false,
1127
+ "required": ["artifactKinds", "activation"],
1128
+ "properties": {
1129
+ "artifactKinds": {
1130
+ "type": "array",
1131
+ "items": { "type": "string", "enum": ["agent-pack", "workflow-chain-pack", "prompt-template", "automation"] },
1132
+ "uniqueItems": true,
1133
+ "description": "Which reusable artifact kinds the host can propose. `agent-pack` (RFC 0003), `workflow-chain-pack` (RFC 0013), `prompt-template` (RFC 0027), `automation` (RFC 0052 scheduled job)."
1134
+ },
1135
+ "duplicationDetection": {
1136
+ "type": "boolean",
1137
+ "default": false,
1138
+ "description": "When `true`, the host populates `Proposal.duplicateOf` with an existing artifact ref the proposal restates/overlaps (the 'Curator' duplication signal)."
1139
+ },
1140
+ "activation": {
1141
+ "type": "string",
1142
+ "enum": ["approval-gate", "direct-rbac"],
1143
+ "description": "`approval-gate`: `apply` MUST drive an RFC 0051 gate (role/scope/quorum, audited override) and MUST NOT install unless granted/overridden. `direct-rbac`: `apply` requires only the RFC 0049 scope the host advertises for activation."
1144
+ }
1145
+ }
1146
+ },
1147
+ "goals": {
1148
+ "type": "object",
1149
+ "description": "RFC 0097 (`Active`). Standing goals — a durable objective with explicit completion criteria, evaluated by a host-side judge (RFC 0090 verifier or host evaluator), that keeps an agent working across turns/runs until the judge is satisfied, a declared RFC 0058 bound is crossed, or the agent escalates (RFC 0044). A host advertising this serves `/v1/host/sample/goals` (promotable to `/v1/goals`) and emits the content-free `goal.evaluated` / `goal.closed` events. Completion MUST be the judge's verdict — a client MUST NOT set `state: satisfied` directly. Continuation MUST be bounded. Hosts that omit this block do not run standing goals; the conformance scenarios skip cleanly.",
1150
+ "additionalProperties": false,
1151
+ "required": ["judge", "continuation"],
1152
+ "properties": {
1153
+ "judge": {
1154
+ "type": "string",
1155
+ "enum": ["verifier", "host"],
1156
+ "description": "`verifier`: completion is an RFC 0090 verifier verdict. `host`: an opaque host evaluator."
1157
+ },
1158
+ "continuation": {
1159
+ "type": "array",
1160
+ "items": { "type": "string", "enum": ["schedule", "commitment", "heartbeat", "manual"] },
1161
+ "uniqueItems": true,
1162
+ "description": "How a goal re-engages work between judge checks. `schedule` (RFC 0052), `commitment` (RFC 0068), `heartbeat` (RFC 0060), `manual`."
1163
+ },
1164
+ "requiresBounds": {
1165
+ "type": "boolean",
1166
+ "default": true,
1167
+ "description": "When `true` (default), a goal MUST declare valid RFC 0058 `bounds` before it may activate; a `POST /goals` without bounds returns 422. The host MUST stop continuation and set `state: bound-exceeded` when any declared bound (iteration count / accumulated cost / wall-clock deadline) is crossed."
1168
+ }
1169
+ }
1073
1170
  }
1074
1171
  },
1075
1172
  "additionalProperties": true
@@ -1930,6 +2027,36 @@
1930
2027
  }
1931
2028
  },
1932
2029
  "additionalProperties": false
2030
+ },
2031
+ "portability": {
2032
+ "type": "object",
2033
+ "description": "RFC 0098 (`Active`). Export/import of a tenant's reusable estate (agents 0070, packs 0003/0013, prompt templates 0027, connection *refs* 0045/0095, schedules 0052, roster/org-chart 0086/0087). An export bundle carries NO credential values — only refs to be re-bound at the destination (RFC 0046/0079). Import maps the estate onto the destination's RFC 0048 identity, MUST offer a no-write dry-run plan, MUST be idempotent, and is gated by an RFC 0049 scope. A host advertising this serves `/v1/host/sample/{export,import}` (promotable to `/v1/{export,import}`) and emits the content-free `import.applied` event. Hosts that omit this block neither export nor import; the conformance scenarios skip cleanly.",
2034
+ "additionalProperties": false,
2035
+ "properties": {
2036
+ "export": {
2037
+ "type": "boolean",
2038
+ "default": false,
2039
+ "description": "Host can emit an export bundle for the caller's tenant/workspace via `GET /export`."
2040
+ },
2041
+ "import": {
2042
+ "type": "boolean",
2043
+ "default": false,
2044
+ "description": "Host can import an export bundle via `POST /import`. When `true`, `dryRun` MUST also be `true` (a no-write plan preview is mandatory)."
2045
+ },
2046
+ "kinds": {
2047
+ "type": "array",
2048
+ "items": { "type": "string", "enum": ["agent", "pack", "prompt-template", "connection-ref", "schedule", "roster", "org-chart"] },
2049
+ "uniqueItems": true,
2050
+ "description": "Estate kinds this host can export/import."
2051
+ },
2052
+ "dryRun": {
2053
+ "type": "boolean",
2054
+ "default": true,
2055
+ "description": "Import supports a no-write plan preview (`POST /import?dryRun=true`). MUST be true if `import` is true."
2056
+ }
2057
+ },
2058
+ "if": { "properties": { "import": { "const": true } }, "required": ["import"] },
2059
+ "then": { "properties": { "dryRun": { "const": true } }, "required": ["dryRun"] }
1933
2060
  }
1934
2061
  },
1935
2062
  "additionalProperties": true
@@ -0,0 +1,161 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v1/connection-pack-manifest.schema.json",
4
+ "title": "ConnectionPackManifest",
5
+ "description": "RFC 0095. Manifest for a published OpenWOP connection pack — `pack.json` at the pack root with `kind: \"connection\"`. Peer to and disjoint from `node-pack-manifest.schema.json` (RFC 0003), `prompt-pack-manifest.schema.json` (RFC 0028), and `workflow-chain-pack-manifest.schema.json` (RFC 0013) via the `kind` discriminator. A connection pack is a portable PROVIDER definition — the authorize/token/revoke endpoints, the read/write OAuth scope catalog, and how the integration is reached (an MCP server, an OpenAPI surface, or a core integration node). It carries NO secret: the OAuth client credential is a host concern (RFC 0047), supplied out of band. When installed, it makes an RFC 0045 connector's `auth.provider` / an RFC 0047 `host.oauth` provider string resolve against `provider.id` instead of host-locked code. See `spec/v1/connection-packs.md`.",
6
+ "type": "object",
7
+ "required": ["name", "version", "kind", "engines", "provider"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "name": {
11
+ "type": "string",
12
+ "description": "Reverse-DNS pack name per `node-packs.md` §Naming. Reserved scopes are identical (`core.*` / `vendor.<org>.*` / `community.<author>.*` / `private.<host>.*`). Mirror of `prompt-pack-manifest.schema.json#/properties/name`.",
13
+ "pattern": "^(core|vendor|community|private)\\.[a-z][a-z0-9_-]*(\\.[a-z][a-zA-Z0-9_-]*)+$",
14
+ "minLength": 1,
15
+ "maxLength": 256
16
+ },
17
+ "version": {
18
+ "type": "string",
19
+ "description": "Pack-level SemVer 2.0.0.",
20
+ "pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$"
21
+ },
22
+ "kind": {
23
+ "type": "string",
24
+ "const": "connection",
25
+ "description": "Pack kind discriminator. MUST be the literal string `\"connection\"` for this schema."
26
+ },
27
+ "description": { "type": "string", "maxLength": 1024 },
28
+ "author": { "type": "string" },
29
+ "license": { "type": "string", "description": "SPDX license identifier (e.g., `Apache-2.0`)." },
30
+ "homepage": { "type": "string", "format": "uri" },
31
+ "repository": { "type": "string", "format": "uri" },
32
+ "keywords": {
33
+ "type": "array",
34
+ "items": { "type": "string", "maxLength": 64 },
35
+ "maxItems": 50
36
+ },
37
+ "engines": {
38
+ "type": "object",
39
+ "required": ["openwop"],
40
+ "additionalProperties": false,
41
+ "properties": {
42
+ "openwop": { "type": "string", "description": "SemVer range of the openwop spec version this pack targets." }
43
+ }
44
+ },
45
+ "provider": {
46
+ "type": "object",
47
+ "description": "The portable provider definition. Exactly one per connection pack.",
48
+ "required": ["id", "displayName", "category", "auth", "reach"],
49
+ "additionalProperties": false,
50
+ "properties": {
51
+ "id": {
52
+ "type": "string",
53
+ "pattern": "^[a-z][a-z0-9-]*$",
54
+ "description": "Stable provider id an RFC 0045/0047 `provider` string resolves to, e.g. `github`."
55
+ },
56
+ "displayName": { "type": "string", "minLength": 1 },
57
+ "category": {
58
+ "type": "string",
59
+ "enum": ["communication", "docs", "crm", "dev", "storage", "email-calendar", "ticketing", "data-warehouse", "marketing", "finance", "hr", "esignature", "support", "project-management", "payments", "other"]
60
+ },
61
+ "auth": {
62
+ "type": "object",
63
+ "required": ["kind"],
64
+ "additionalProperties": false,
65
+ "properties": {
66
+ "kind": { "type": "string", "enum": ["oauth2", "api_key", "bearer", "basic"] },
67
+ "authFlow": { "type": "string", "enum": ["pkce", "client_credentials", "manual", "none"] },
68
+ "scopeModel": {
69
+ "type": "string",
70
+ "enum": ["groups", "coarse", "capabilities"],
71
+ "default": "groups",
72
+ "description": "`groups` = read/write scope groups (Google/Jira/Graph). `coarse` = a single read-vs-write toggle (Stripe Connect read_only/read_write). `capabilities` = consent is a static developer-portal capability set, not per-request scopes (Notion)."
73
+ },
74
+ "endpoints": {
75
+ "type": "object",
76
+ "additionalProperties": false,
77
+ "description": "Fixed, manifest-declared https endpoints (RFC 0095 §B.3). Never derived from runtime user input — not an SSRF surface.",
78
+ "properties": {
79
+ "authorize": { "type": "string", "format": "uri", "pattern": "^https://" },
80
+ "token": { "type": "string", "format": "uri", "pattern": "^https://" },
81
+ "revoke": { "type": "string", "format": "uri", "pattern": "^https://" }
82
+ }
83
+ },
84
+ "scopes": {
85
+ "type": "object",
86
+ "additionalProperties": false,
87
+ "description": "Read/write scope groups. `write` is requested as a SEPARATE re-consent step (RFC 0095 §B.4).",
88
+ "properties": {
89
+ "read": { "type": "array", "items": { "$ref": "#/$defs/ScopeGroup" } },
90
+ "write": { "type": "array", "items": { "$ref": "#/$defs/ScopeGroup" } }
91
+ }
92
+ },
93
+ "instanceUrlTemplate": {
94
+ "type": "string",
95
+ "description": "For per-account-host providers (Snowflake/NetSuite/ServiceNow): a template the host fills per connection, e.g. `https://{account}.snowflakecomputing.com`. Its presence signals the provider cannot use a single global OAuth app."
96
+ }
97
+ }
98
+ },
99
+ "reach": {
100
+ "type": "object",
101
+ "minProperties": 1,
102
+ "maxProperties": 1,
103
+ "additionalProperties": false,
104
+ "description": "Exactly ONE of mcp | openapi | integration — which core node injects the resolved credential (RFC 0095 §B.5).",
105
+ "properties": {
106
+ "mcp": {
107
+ "type": "object",
108
+ "required": ["server"],
109
+ "additionalProperties": false,
110
+ "properties": {
111
+ "server": {
112
+ "type": "object",
113
+ "required": ["url", "transport"],
114
+ "additionalProperties": false,
115
+ "properties": {
116
+ "url": { "type": "string", "format": "uri", "pattern": "^https://" },
117
+ "transport": { "type": "string", "enum": ["http", "sse"] }
118
+ }
119
+ }
120
+ }
121
+ },
122
+ "openapi": {
123
+ "type": "object",
124
+ "required": ["ref"],
125
+ "additionalProperties": false,
126
+ "properties": {
127
+ "ref": { "type": "string", "description": "URL or in-pack path of the OpenAPI document for core.openwop.http.openapi-call." }
128
+ }
129
+ },
130
+ "integration": {
131
+ "type": "object",
132
+ "required": ["node"],
133
+ "additionalProperties": false,
134
+ "properties": {
135
+ "node": { "type": "string", "description": "A core.openwop.integration.* node typeId." }
136
+ }
137
+ }
138
+ }
139
+ },
140
+ "consumerNodes": {
141
+ "type": "array",
142
+ "items": { "type": "string" },
143
+ "description": "The core node typeIds that consume this provider's credential (e.g. core.openwop.mcp.invoke-tool)."
144
+ },
145
+ "docsUrl": { "type": "string", "format": "uri" }
146
+ }
147
+ }
148
+ },
149
+ "$defs": {
150
+ "ScopeGroup": {
151
+ "type": "object",
152
+ "required": ["key", "label", "scopes"],
153
+ "additionalProperties": false,
154
+ "properties": {
155
+ "key": { "type": "string", "pattern": "^[a-z][a-z0-9._-]*$" },
156
+ "label": { "type": "string", "minLength": 1 },
157
+ "scopes": { "type": "array", "items": { "type": "string" }, "description": "The provider's raw scope strings, e.g. `https://www.googleapis.com/auth/drive.readonly`." }
158
+ }
159
+ }
160
+ }
161
+ }
@@ -0,0 +1,66 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v1/export-bundle.schema.json",
4
+ "title": "ExportBundle",
5
+ "description": "RFC 0098 §B. A portable agent-platform export bundle — a tenant's reusable estate (agents, packs, prompt templates, connection refs, schedules, roster/org-chart) composed for migration between openwop hosts (or import from an external platform via an adapter). The bundle MUST NOT contain credential VALUES: `connection-ref` items carry only refs/provider ids per RFC 0046/0079; the importer reports unbound refs in `secretsToRebind` and re-binds secrets at the destination. All imported entities are re-owned to the caller's RFC 0048 identity; `source.originPrincipal` is informational only and grants no access. Gated on the `portability` capability.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["bundleVersion", "source", "items"],
9
+ "properties": {
10
+ "bundleVersion": {
11
+ "const": "1",
12
+ "description": "Bundle schema version. Importers MUST reject a bundleVersion they do not understand."
13
+ },
14
+ "source": {
15
+ "type": "object",
16
+ "additionalProperties": false,
17
+ "required": ["origin"],
18
+ "description": "Provenance of the bundle. Informational only — never a source of authority at the destination.",
19
+ "properties": {
20
+ "origin": {
21
+ "type": "string",
22
+ "minLength": 1,
23
+ "description": "Origin host base URL or adapter id (e.g. 'adapter:openclaw')."
24
+ },
25
+ "exportedAt": { "type": "string", "format": "date-time" },
26
+ "originPrincipal": {
27
+ "type": ["string", "null"],
28
+ "default": null,
29
+ "description": "Opaque source identity, informational only. MUST NOT grant any access at the destination."
30
+ }
31
+ }
32
+ },
33
+ "items": {
34
+ "type": "array",
35
+ "description": "The estate, in arbitrary order; `dependsOn` edges define apply order (topological; a cycle is a 422).",
36
+ "items": {
37
+ "type": "object",
38
+ "additionalProperties": false,
39
+ "required": ["kind", "ref", "payload"],
40
+ "properties": {
41
+ "kind": {
42
+ "type": "string",
43
+ "enum": ["agent", "pack", "prompt-template", "connection-ref", "schedule", "roster", "org-chart"],
44
+ "description": "Estate kind. `agent` (RFC 0070), `pack` (RFC 0003/0013), `prompt-template` (RFC 0027), `connection-ref` (RFC 0045/0095 — refs only), `schedule` (RFC 0052), `roster` (RFC 0086), `org-chart` (RFC 0087)."
45
+ },
46
+ "ref": {
47
+ "type": "string",
48
+ "minLength": 1,
49
+ "description": "Stable id within the bundle, used as the target of `dependsOn` edges."
50
+ },
51
+ "dependsOn": {
52
+ "type": "array",
53
+ "items": { "type": "string" },
54
+ "default": [],
55
+ "description": "Refs of other items that MUST be applied before this one (topological order)."
56
+ },
57
+ "payload": {
58
+ "type": "object",
59
+ "description": "The kind's existing schema (RFC 0070 manifest, 0003/0013 pack, 0027 template, 0045/0095 connection *ref*, 0052 job, 0086 roster, 0087 org-chart). Deliberately open here because each kind validates against its own schema. For `connection-ref`, the payload MUST carry only refs/provider ids — a literal credential value is rejected (422).",
60
+ "$comment": "Intentionally open object — validated against the kind's own schema; connection-ref payloads MUST NOT contain credential values (export-bundle-no-credential-material)."
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,104 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v1/goal.schema.json",
4
+ "title": "Goal",
5
+ "description": "RFC 0097 §B. A standing goal — a durable objective with explicit completion criteria, evaluated by a host-side judge (RFC 0090 verifier verdict or an opaque host evaluator), that keeps an agent working across turns and runs until the judge is satisfied, a declared RFC 0058 bound is crossed, or the agent escalates (RFC 0044). Completion MUST be the judge's verdict — a client MUST NOT set `state: satisfied` directly. Continuation MUST be bounded. `objective` and any verdict payload are SR-1 redaction-safe. Gated on the `agents.goals` capability.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["id", "objective", "state", "completion", "continuation", "bounds", "owner", "createdAt"],
9
+ "properties": {
10
+ "id": {
11
+ "type": "string",
12
+ "minLength": 1,
13
+ "description": "Host-assigned identifier."
14
+ },
15
+ "objective": {
16
+ "type": "string",
17
+ "description": "The standing objective. SR-1 redaction-safe — no secrets/PII."
18
+ },
19
+ "state": {
20
+ "type": "string",
21
+ "enum": ["active", "satisfied", "escalated", "abandoned", "bound-exceeded"],
22
+ "description": "Lifecycle state. `satisfied` is set ONLY by the host on a judge verdict, never by a client. `bound-exceeded` is set when a declared bound is crossed; `escalated` when an RFC 0044 confidence-escalation interrupt fires against the goal; `abandoned` on explicit abandon."
23
+ },
24
+ "completion": {
25
+ "type": "object",
26
+ "additionalProperties": false,
27
+ "required": ["check"],
28
+ "description": "How the goal's completion is judged.",
29
+ "properties": {
30
+ "check": {
31
+ "type": "string",
32
+ "enum": ["verifier", "host"],
33
+ "description": "`verifier`: completion is an RFC 0090 verifier verdict. `host`: an opaque host evaluator."
34
+ },
35
+ "verifierRef": {
36
+ "type": ["string", "null"],
37
+ "default": null,
38
+ "description": "RFC 0090 verifier id when `check = verifier`."
39
+ },
40
+ "lastVerdict": {
41
+ "type": ["object", "null"],
42
+ "default": null,
43
+ "additionalProperties": false,
44
+ "description": "Most recent judge verdict. Content-free re: objective text. Non-deterministic judge output — MUST be persisted (carried in the `goal.evaluated` event / checkpoint) and never recomputed on replay/fork.",
45
+ "properties": {
46
+ "satisfied": { "type": "boolean" },
47
+ "confidence": { "type": "number", "minimum": 0, "maximum": 1 },
48
+ "runId": { "type": "string", "description": "The run this verdict evaluated (RFC 0040 causation-compatible)." }
49
+ }
50
+ }
51
+ }
52
+ },
53
+ "continuation": {
54
+ "type": "object",
55
+ "additionalProperties": false,
56
+ "required": ["mode"],
57
+ "description": "How the goal re-engages work between judge checks.",
58
+ "properties": {
59
+ "mode": {
60
+ "type": "string",
61
+ "enum": ["schedule", "commitment", "heartbeat", "manual"],
62
+ "description": "`schedule` (RFC 0052), `commitment` (RFC 0068), `heartbeat` (RFC 0060), `manual`."
63
+ },
64
+ "armRef": {
65
+ "type": ["string", "null"],
66
+ "default": null,
67
+ "description": "The RFC 0052 job / RFC 0068 commitment / RFC 0060 heartbeat that re-engages work for this goal."
68
+ }
69
+ }
70
+ },
71
+ "bounds": {
72
+ "type": "object",
73
+ "additionalProperties": false,
74
+ "description": "RFC 0058 execution bounds. The host MUST stop continuation and set `state: bound-exceeded` when any declared bound is crossed. When `agents.goals.requiresBounds` is true, at least one bound MUST be present before the goal may activate.",
75
+ "properties": {
76
+ "maxLoopIterations": { "type": "integer", "minimum": 1, "description": "RFC 0058. Max contributing iterations before the goal is bound-exceeded." },
77
+ "runTimeoutMs": { "type": "integer", "minimum": 0, "description": "RFC 0058. Wall-clock deadline (ms) for the standing goal." },
78
+ "maxCostUsd": { "type": "number", "minimum": 0, "description": "RFC 0084. Accumulated cost ceiling across contributing runs." }
79
+ }
80
+ },
81
+ "progress": {
82
+ "type": "object",
83
+ "additionalProperties": false,
84
+ "description": "Continuation progress so far.",
85
+ "properties": {
86
+ "iterations": { "type": "integer", "minimum": 0 },
87
+ "contributingRunIds": { "type": "array", "items": { "type": "string" }, "description": "RFC 0040 causation-compatible." }
88
+ }
89
+ },
90
+ "owner": {
91
+ "type": "object",
92
+ "additionalProperties": false,
93
+ "required": ["tenant"],
94
+ "description": "RFC 0048 identity triple. Redaction-safe — `principal` is an opaque id, never PII or credential material.",
95
+ "properties": {
96
+ "tenant": { "type": "string", "minLength": 1 },
97
+ "workspace": { "type": "string", "minLength": 1 },
98
+ "principal": { "type": "string", "minLength": 1 }
99
+ }
100
+ },
101
+ "createdAt": { "type": "string", "format": "date-time" },
102
+ "updatedAt": { "type": "string", "format": "date-time" }
103
+ }
104
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v1/proposal.schema.json",
4
+ "title": "Proposal",
5
+ "description": "RFC 0096 §B. A reviewable-learning proposal — an INERT, draft-state reusable artifact (skill/pack/template/automation) the host synthesized from run/tool traces, that MUST NOT influence the resolution, planning, or execution of any run while in any state other than `applied`. Activation is delegated to RFC 0051 approval-gate or RFC 0049 RBAC (no new authorization path). On `apply` the installed artifact MUST byte-match the last-persisted `artifact` (no silent re-synthesis). `rationale` and `provenance.sourceRunIds` are SR-1 redaction-safe (no secrets/PII). Gated on the `agents.proposals` capability.",
6
+ "type": "object",
7
+ "additionalProperties": false,
8
+ "required": ["id", "kind", "state", "artifact", "provenance", "owner", "createdAt"],
9
+ "properties": {
10
+ "id": {
11
+ "type": "string",
12
+ "minLength": 1,
13
+ "description": "Host-assigned identifier, stable across revisions."
14
+ },
15
+ "kind": {
16
+ "type": "string",
17
+ "enum": ["agent-pack", "workflow-chain-pack", "prompt-template", "automation"],
18
+ "description": "The reusable artifact kind. `agent-pack` (RFC 0003), `workflow-chain-pack` (RFC 0013), `prompt-template` (RFC 0027), `automation` (RFC 0052 scheduled job)."
19
+ },
20
+ "state": {
21
+ "type": "string",
22
+ "enum": ["draft", "revised", "applied", "rejected", "archived"],
23
+ "description": "Lifecycle state. Only `applied` may influence a run. `draft`/`revised` are inert; `rejected`/`archived` are terminal-inert."
24
+ },
25
+ "title": {
26
+ "type": "string",
27
+ "description": "Human-facing label. SR-1 redaction-safe."
28
+ },
29
+ "rationale": {
30
+ "type": "string",
31
+ "description": "Plain-language justification. SR-1 redaction-safe — no secrets/PII."
32
+ },
33
+ "artifact": {
34
+ "type": "object",
35
+ "description": "The proposed artifact, shaped by `kind` (an RFC 0003 pack manifest, an RFC 0013 chain pack, an RFC 0027 template, an RFC 0052 job spec). Inert until applied. Deliberately open (`additionalProperties` not constrained here) because the payload conforms to the kind's own existing schema, validated by the host at `apply` (malformed-for-kind ⇒ 422).",
36
+ "$comment": "Intentionally open object — the artifact body is validated against the kind's own schema, not this envelope."
37
+ },
38
+ "provenance": {
39
+ "type": "object",
40
+ "additionalProperties": false,
41
+ "required": ["sourceRunIds"],
42
+ "description": "Where the proposal came from.",
43
+ "properties": {
44
+ "sourceRunIds": {
45
+ "type": "array",
46
+ "items": { "type": "string", "minLength": 1 },
47
+ "description": "Runs whose traces produced this proposal (RFC 0040 causation-compatible). SR-1 redaction-safe."
48
+ },
49
+ "synthesizerModel": {
50
+ "type": "string",
51
+ "description": "Opaque identifier of the model/process that synthesized the draft."
52
+ }
53
+ }
54
+ },
55
+ "duplicateOf": {
56
+ "type": ["string", "null"],
57
+ "default": null,
58
+ "description": "Existing artifact ref this proposal restates/overlaps, when `agents.proposals.duplicationDetection` is on. `null` when unknown or detection is off."
59
+ },
60
+ "owner": {
61
+ "type": "object",
62
+ "additionalProperties": false,
63
+ "required": ["tenant"],
64
+ "description": "RFC 0048 identity triple that owns this proposal. Redaction-safe — `principal` is an opaque id, never PII or credential material. Single-tenant hosts populate at least `tenant`.",
65
+ "properties": {
66
+ "tenant": { "type": "string", "minLength": 1, "description": "Top-level isolation boundary." },
67
+ "workspace": { "type": "string", "minLength": 1, "description": "Optional sub-tenant within the tenant (RFC 0048 workspace)." },
68
+ "principal": { "type": "string", "minLength": 1, "description": "Acting identity (user or agent) — opaque id, never PII." }
69
+ }
70
+ },
71
+ "activation": {
72
+ "type": ["object", "null"],
73
+ "default": null,
74
+ "description": "Populated only when `state: applied`: the RFC 0051 approval reference (if `activation = approval-gate`) and the resulting installed artifact ref.",
75
+ "additionalProperties": false,
76
+ "properties": {
77
+ "approvalId": { "type": ["string", "null"], "description": "RFC 0051 approval/gate id when activation routed through an approval gate." },
78
+ "installedArtifactRef": { "type": "string", "description": "Ref of the artifact installed on `apply` (RFC 0043 install path)." }
79
+ }
80
+ },
81
+ "createdAt": { "type": "string", "format": "date-time" },
82
+ "updatedAt": { "type": "string", "format": "date-time" }
83
+ }
84
+ }