@openwop/openwop-conformance 1.72.2 → 1.98.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.
- package/CHANGELOG.md +36 -0
- package/README.md +2 -2
- package/api/asyncapi.yaml +58 -0
- package/api/openapi.yaml +4 -1
- package/dist/cli.js +107 -1
- package/dist/lib/profiles.js +70 -4
- package/package.json +2 -1
- package/schemas/CORPUS-STAMP.json +2 -2
- package/schemas/README.md +2 -0
- package/schemas/capabilities.schema.json +2054 -572
- package/schemas/certification-bundle-v2.schema.json +108 -0
- package/schemas/run-event-payloads.schema.json +3411 -857
- package/schemas/run-event.schema.json +31 -9
- package/schemas/workflow-definition.schema.json +492 -130
- package/schemas/workload-identity.schema.json +73 -0
- package/src/cli.ts +119 -1
- package/src/lib/a2a-fake-peer.ts +20 -0
- package/src/lib/behavior-gate.ts +42 -7
- package/src/lib/llm-cache-key-recipe.ts +51 -0
- package/src/lib/mcp-fake-server.ts +20 -0
- package/src/lib/profiles.ts +95 -4
- package/src/lib/requirement-ledger.ts +138 -0
- package/src/lib/requirement-registry.ts +62 -0
- package/src/scenarios/a2a-version-negotiation.test.ts +159 -0
- package/src/scenarios/capability-example-root-layout.test.ts +113 -0
- package/src/scenarios/certification-bundle-v2.test.ts +157 -0
- package/src/scenarios/certification-floor-enforcement.test.ts +115 -0
- package/src/scenarios/compensation-behavior.test.ts +164 -0
- package/src/scenarios/compensation-profile.test.ts +175 -0
- package/src/scenarios/contract-provenance.test.ts +209 -0
- package/src/scenarios/core-manifest-and-extension-registry.test.ts +198 -0
- package/src/scenarios/discovery-canonical-family-no-shadow.test.ts +219 -0
- package/src/scenarios/effect-identity-composition.test.ts +129 -0
- package/src/scenarios/effect-identity-cross-scope.test.ts +82 -0
- package/src/scenarios/mcp-version-negotiation.test.ts +159 -0
- package/src/scenarios/multi-region-effect-vocabulary.test.ts +175 -0
- package/src/scenarios/multi-region-idempotency.test.ts +17 -7
- package/src/scenarios/openapi-resolved-paths.test.ts +127 -0
- package/src/scenarios/protocol-version-grammar.test.ts +119 -0
- package/src/scenarios/requirement-ledger.test.ts +162 -0
- package/src/scenarios/rfc-0147-self-audit.test.ts +104 -0
- package/src/scenarios/rfc-lifecycle-coherence.test.ts +137 -0
- package/src/scenarios/semantic-digest-v2.test.ts +128 -0
- package/src/scenarios/semantic-digest-vectors.test.ts +140 -0
- package/src/scenarios/spec-corpus-validity.test.ts +22 -8
- package/src/scenarios/strict-behavior-gate.test.ts +120 -0
- package/src/scenarios/versioned-composition-profiles.test.ts +183 -0
- package/src/scenarios/workload-identity-behavior.test.ts +188 -0
- package/src/scenarios/workload-identity-profile.test.ts +175 -0
- package/vectors/semantic-request-digest-v2.json +236 -0
|
@@ -4,26 +4,58 @@
|
|
|
4
4
|
"title": "Capabilities",
|
|
5
5
|
"description": "openwop capability declaration returned from `GET /.well-known/openwop`. Required v1 fields identify the protocol version, envelope catalog, schema versions, and base limits. Optional v1 fields have stable shapes but MAY be omitted when unsupported.",
|
|
6
6
|
"type": "object",
|
|
7
|
-
"required": [
|
|
7
|
+
"required": [
|
|
8
|
+
"protocolVersion",
|
|
9
|
+
"supportedEnvelopes",
|
|
10
|
+
"schemaVersions",
|
|
11
|
+
"limits"
|
|
12
|
+
],
|
|
8
13
|
"properties": {
|
|
9
14
|
"protocolVersion": {
|
|
10
15
|
"type": "string",
|
|
11
|
-
"description": "openwop protocol version the server speaks
|
|
12
|
-
"
|
|
16
|
+
"description": "RFC 0149 \u00a7C \u2014 openwop protocol version the server speaks, as ASCII `<major>.<minor>` with no leading zero except zero itself. `1.0` and `1.12` are valid; `1`, `1.0.0`, `v1.0`, and `01.0` are not. The integer major is the hard compatibility boundary and the integer minor is the additive contract level; PATCH belongs to suite and SDK versions, not the spec version. Previously constrained only by `minLength: 1`, which admitted `v1.0`, `1.0.0`, and `banana` \u2014 a negotiation the wire could not decide, since neither integer can be extracted from an unconstrained string. Independent of `engineVersion` (which gates persisted-doc compatibility per version-negotiation.md).",
|
|
17
|
+
"pattern": "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$"
|
|
18
|
+
},
|
|
19
|
+
"contractProvenance": {
|
|
20
|
+
"type": "object",
|
|
21
|
+
"description": "RFC 0146 (`Active`). Which corpus revision this host's contract handling corresponds to \u2014 the copy it validates and serves against. OPTIONAL; absent \u21d2 UNSPECIFIED provenance, neither current nor stale, and a consumer MUST NOT infer a version from its absence. ADVISORY: a consumer MUST NOT reject a request, refuse interop, or fail a run solely because this differs from its own \u2014 v1.x corpus revisions are additive, so a host on an older revision is conformant and this field detects drift rather than making drift an error. Nothing else on the wire answers this: `protocolVersion` is `1.0` across the entire v1 line (the drift happens inside that value) and `schemaVersions` is per-envelope-type. NOT an integrity check \u2014 `corpusCommit` says WHICH contract, never whether the copy was modified.",
|
|
22
|
+
"properties": {
|
|
23
|
+
"suiteVersion": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "A published `@openwop/openwop-conformance` version, e.g. `1.73.0`. Mirrors `schemas/CORPUS-STAMP.json` so a host depending on the package can echo its own stamp rather than hand-maintaining a constant.",
|
|
26
|
+
"minLength": 1
|
|
27
|
+
},
|
|
28
|
+
"corpusCommit": {
|
|
29
|
+
"type": "string",
|
|
30
|
+
"description": "Full 40-character commit SHA of the openwop repository. A vendor build identifier does NOT belong here \u2014 `implementation` already exists for that.",
|
|
31
|
+
"pattern": "^[0-9a-f]{40}$"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"additionalProperties": false
|
|
13
35
|
},
|
|
14
36
|
"supportedEnvelopes": {
|
|
15
37
|
"type": "array",
|
|
16
|
-
"items": {
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1
|
|
41
|
+
},
|
|
17
42
|
"description": "Envelope `type` strings the engine recognizes (e.g., `prd.create`, `theme.create`, `tasks.create`, `clarification.request`)."
|
|
18
43
|
},
|
|
19
44
|
"schemaVersions": {
|
|
20
45
|
"type": "object",
|
|
21
|
-
"additionalProperties": {
|
|
46
|
+
"additionalProperties": {
|
|
47
|
+
"type": "integer",
|
|
48
|
+
"minimum": 0
|
|
49
|
+
},
|
|
22
50
|
"description": "Active schema version per envelope type (e.g., `{ \"prd.create\": 2 }`)."
|
|
23
51
|
},
|
|
24
52
|
"limits": {
|
|
25
53
|
"type": "object",
|
|
26
|
-
"required": [
|
|
54
|
+
"required": [
|
|
55
|
+
"clarificationRounds",
|
|
56
|
+
"schemaRounds",
|
|
57
|
+
"envelopesPerTurn"
|
|
58
|
+
],
|
|
27
59
|
"properties": {
|
|
28
60
|
"clarificationRounds": {
|
|
29
61
|
"type": "integer",
|
|
@@ -68,21 +100,26 @@
|
|
|
68
100
|
"maxRequestBodyBytes": {
|
|
69
101
|
"type": "integer",
|
|
70
102
|
"minimum": 1,
|
|
71
|
-
"description": "RFC 0094
|
|
103
|
+
"description": "RFC 0094 \u00a7H. Maximum REST request body size (bytes) the host accepts. Optional v1 field per `capabilities.md` \u00a73 (previously documented as reserved \u2014 the closed `limits` object made advertising it a schema-validation failure). Hosts that advertise it MUST enforce it."
|
|
72
104
|
}
|
|
73
105
|
},
|
|
74
106
|
"additionalProperties": false,
|
|
75
|
-
"description": "Hard limits enforced by the engine. See capabilities.md
|
|
107
|
+
"description": "Hard limits enforced by the engine. See capabilities.md \u00a73."
|
|
76
108
|
},
|
|
77
109
|
"envelopeStrictness": {
|
|
78
110
|
"type": "string",
|
|
79
|
-
"enum": [
|
|
80
|
-
|
|
111
|
+
"enum": [
|
|
112
|
+
"warn",
|
|
113
|
+
"strict"
|
|
114
|
+
],
|
|
115
|
+
"description": "AI Envelope schema-version drift handling per `spec/v1/ai-envelope.md` \u00a7\"Capability handshake integration\" (DRAFT v1.x). Optional in v1.x; default when absent is `warn`. Under `warn`, the engine MUST attempt validation against the advertised version of a kind and log `envelope_schema_version_drift` when the emitted `schemaVersion` is lower than advertised. Under `strict`, the same condition MUST cause refusal with `unknown_schema_version`. Emitted `schemaVersion` higher than advertised MUST refuse regardless of strictness."
|
|
81
116
|
},
|
|
82
117
|
"envelopeContracts": {
|
|
83
118
|
"type": "object",
|
|
84
|
-
"description": "AI Envelope contract-gating advertisement per `spec/v1/ai-envelope.md`
|
|
85
|
-
"required": [
|
|
119
|
+
"description": "AI Envelope contract-gating advertisement per `spec/v1/ai-envelope.md` \u00a7\"Capability handshake integration\" (DRAFT v1.x). Optional in v1.x. When `advertised: true`, the host's node-pack manifests carry `EnvelopeContract` blocks per `ai-envelope.md` \u00a7\"Envelope Contract\"; tooling and conformance scenarios gate on this flag. When `advertised: false` or the block is absent, hosts MAY accept envelopes without per-typeId `accepts[]` enforcement.",
|
|
120
|
+
"required": [
|
|
121
|
+
"advertised"
|
|
122
|
+
],
|
|
86
123
|
"properties": {
|
|
87
124
|
"advertised": {
|
|
88
125
|
"type": "boolean",
|
|
@@ -93,36 +130,48 @@
|
|
|
93
130
|
},
|
|
94
131
|
"envelopes": {
|
|
95
132
|
"type": "object",
|
|
96
|
-
"description": "Envelope LLM-contract advertisement container introduced by the RFC 0030
|
|
133
|
+
"description": "Envelope LLM-contract advertisement container introduced by the RFC 0030\u20130033 envelope-hardening track. Each sub-block is independently opt-in; hosts that adopt a subset advertise only the sub-blocks they implement. `additionalProperties: true` reserved for future RFCs that extend the track; host-private extensions go under `x-host-<host>-<key>` per `host-extensions.md` \u00a7\"Canonical-prefix table\".",
|
|
97
134
|
"additionalProperties": true,
|
|
98
135
|
"properties": {
|
|
99
136
|
"reasoning": {
|
|
100
137
|
"type": "object",
|
|
101
|
-
"description": "RFC 0030
|
|
138
|
+
"description": "RFC 0030 \u00a7A + \u00a7C. Host's envelope payload schemas support the OPTIONAL `reasoning` field on kinds where multi-step reasoning materially improves output quality; the host's system-prompt-injection helper instructs the model to populate it. Absent block = no advertisement (the field MAY still appear on envelope schemas; this advertisement signals the host's prompt-injection posture).",
|
|
102
139
|
"additionalProperties": false,
|
|
103
|
-
"required": [
|
|
140
|
+
"required": [
|
|
141
|
+
"supported"
|
|
142
|
+
],
|
|
104
143
|
"properties": {
|
|
105
144
|
"supported": {
|
|
106
145
|
"type": "boolean",
|
|
107
|
-
"description": "Host's envelope payload schemas carry `reasoning` (OPTIONAL) on kinds where reasoning materially improves output quality, per RFC 0030
|
|
146
|
+
"description": "Host's envelope payload schemas carry `reasoning` (OPTIONAL) on kinds where reasoning materially improves output quality, per RFC 0030 \u00a7A. Hosts SHOULD prompt the model to populate the field; hosts MUST NOT reject envelopes where `reasoning` is absent (the field is OPTIONAL by spec); hosts SHALL NOT route on `reasoning` contents."
|
|
108
147
|
},
|
|
109
148
|
"promptDirective": {
|
|
110
149
|
"type": "string",
|
|
111
|
-
"enum": [
|
|
112
|
-
|
|
150
|
+
"enum": [
|
|
151
|
+
"mandatory",
|
|
152
|
+
"advisory",
|
|
153
|
+
"off"
|
|
154
|
+
],
|
|
155
|
+
"description": "Strength of the host's system-prompt instruction to populate `reasoning`. `mandatory`: the directive is firmly worded (the host instructs the model very forcefully to emit `reasoning`). `advisory` (default when absent): the directive is suggestive. `off`: the host emits no directive \u2014 applications that want `reasoning` populated must inject the instruction themselves. Note: `mandatory` is a prompt-injection posture, NOT a wire-level refusal contract \u2014 hosts MUST NOT reject envelopes where `reasoning` is absent regardless of this value."
|
|
113
156
|
}
|
|
114
157
|
}
|
|
115
158
|
},
|
|
116
159
|
"tierOneSubsetCompliance": {
|
|
117
160
|
"type": "string",
|
|
118
|
-
"enum": [
|
|
119
|
-
|
|
161
|
+
"enum": [
|
|
162
|
+
"strict",
|
|
163
|
+
"warn",
|
|
164
|
+
"off"
|
|
165
|
+
],
|
|
166
|
+
"description": "RFC 0030 \u00a7B + \u00a7C. Host's self-attested compliance posture for the Tier-1 cross-vendor structured-output subset documented in `spec/v1/structured-output-subset.md`. `strict`: every host-served envelope schema passes the static subset-compliance check (object-root, `additionalProperties: false` everywhere, every property in `required`, no `oneOf`/`allOf`/`not`/`prefixItems`/`propertyNames`, no string format/pattern/length constraints, no number bounds, no array bounds, \u22645 nesting depth, \u2264100 property count). `warn`: host serves non-compliant schemas but logs the violations. `off` (default when absent): no self-attestation. The conformance-suite static-subset scenario gates on this flag."
|
|
120
167
|
},
|
|
121
168
|
"reliability": {
|
|
122
169
|
"type": "object",
|
|
123
170
|
"additionalProperties": false,
|
|
124
|
-
"required": [
|
|
125
|
-
|
|
171
|
+
"required": [
|
|
172
|
+
"supported"
|
|
173
|
+
],
|
|
174
|
+
"description": "RFC 0032 \u00a7C. Host emits the envelope-reliability event family on documented adverse paths. Hosts opt into the family via `supported: true` AND explicitly list the events they emit via `events[]`. Hosts that advertise `supported: true` MUST include at least `envelope.retry.exhausted` and `envelope.refusal` in `events[]` (the two MUST-tier events). The other four (`envelope.retry.attempted`, `envelope.truncated`, `envelope.nlToFormat.engaged`, `envelope.recovery.applied`) are SHOULD/MAY-tier per RFC 0032 \u00a7B and may be omitted.",
|
|
126
175
|
"properties": {
|
|
127
176
|
"supported": {
|
|
128
177
|
"type": "boolean",
|
|
@@ -148,23 +197,25 @@
|
|
|
148
197
|
"type": "integer",
|
|
149
198
|
"minimum": 1,
|
|
150
199
|
"maximum": 16,
|
|
151
|
-
"description": "Host's retry budget per envelope emission. Conformance scenarios use this to construct fixtures that exercise the retry-exhausted path. Independent of `capabilities.limits.schemaRounds` (which is the engine-side per-emission cap)
|
|
200
|
+
"description": "Host's retry budget per envelope emission. Conformance scenarios use this to construct fixtures that exercise the retry-exhausted path. Independent of `capabilities.limits.schemaRounds` (which is the engine-side per-emission cap) \u2014 `maxRetryAttempts` reports the host's actual configured value, not the spec's upper bound."
|
|
152
201
|
},
|
|
153
202
|
"completion": {
|
|
154
203
|
"type": "object",
|
|
155
204
|
"additionalProperties": false,
|
|
156
|
-
"required": [
|
|
157
|
-
|
|
205
|
+
"required": [
|
|
206
|
+
"distinguishesTruncation"
|
|
207
|
+
],
|
|
208
|
+
"description": "RFC 0033 \u00a7E. Host's self-attested envelope-completion contract posture \u2014 does the host distinguish truncation from schema-violation in its retry routing per RFC 0033 \u00a7A + \u00a7B + \u00a7C?",
|
|
158
209
|
"properties": {
|
|
159
210
|
"distinguishesTruncation": {
|
|
160
211
|
"type": "boolean",
|
|
161
|
-
"description": "Host implements RFC 0033's truncation-vs-schema-violation retry-routing distinction: truncation
|
|
212
|
+
"description": "Host implements RFC 0033's truncation-vs-schema-violation retry-routing distinction: truncation \u2192 increased output budget (NO corrective fragment); schema-violation \u2192 corrective system fragment (NO budget increase). When `false` or absent, the host conflates the two paths (legacy behavior); RFC 0033 conformance scenarios soft-skip."
|
|
162
213
|
},
|
|
163
214
|
"truncationBudgetMultiplier": {
|
|
164
215
|
"type": "number",
|
|
165
216
|
"minimum": 1,
|
|
166
217
|
"maximum": 8,
|
|
167
|
-
"description": "Host's per-attempt output-budget multiplier on truncation retries. Informational; clients MAY surface this in cost-estimation UIs. Defaults to 2 when absent and `distinguishesTruncation: true`. Spec recommendation is 2
|
|
218
|
+
"description": "Host's per-attempt output-budget multiplier on truncation retries. Informational; clients MAY surface this in cost-estimation UIs. Defaults to 2 when absent and `distinguishesTruncation: true`. Spec recommendation is 2\u00d7 per RFC 0033 \u00a7B."
|
|
168
219
|
}
|
|
169
220
|
}
|
|
170
221
|
}
|
|
@@ -174,26 +225,38 @@
|
|
|
174
225
|
},
|
|
175
226
|
"prompts": {
|
|
176
227
|
"type": "object",
|
|
177
|
-
"description": "RFC 0027 + RFC 0028 prompt-template support advertisement. The `supported` flag gates **node-execution resolution** of PromptRef values per RFC 0027 (Phase A); the separate `endpointsSupported` flag gates the **REST surface** at `/v1/prompts*` per RFC 0028 (Phase B). The two axes are independent
|
|
178
|
-
"required": [
|
|
228
|
+
"description": "RFC 0027 + RFC 0028 prompt-template support advertisement. The `supported` flag gates **node-execution resolution** of PromptRef values per RFC 0027 (Phase A); the separate `endpointsSupported` flag gates the **REST surface** at `/v1/prompts*` per RFC 0028 (Phase B). The two axes are independent \u2014 a host MAY implement Phase A composition without exposing the REST surface, and vice versa. Absent block = no support; consumers passing PromptRef values to such a host MUST tolerate the keys being treated as opaque strings.",
|
|
229
|
+
"required": [
|
|
230
|
+
"supported"
|
|
231
|
+
],
|
|
179
232
|
"properties": {
|
|
180
233
|
"supported": {
|
|
181
234
|
"type": "boolean",
|
|
182
|
-
"description": "RFC 0027 Phase A. When `true`, the host resolves PromptRef values in `WorkflowNode.config.{systemPromptRef, userPromptRef, additionalPromptRefs}` at node-execution time AND emits `prompt.composed` run events per spec/v1/prompts.md
|
|
235
|
+
"description": "RFC 0027 Phase A. When `true`, the host resolves PromptRef values in `WorkflowNode.config.{systemPromptRef, userPromptRef, additionalPromptRefs}` at node-execution time AND emits `prompt.composed` run events per spec/v1/prompts.md \u00a7\"Composition + observability\". Does NOT imply the `/v1/prompts*` REST surface is available \u2014 see `endpointsSupported` for that. False or absent = the PromptRef keys on `WorkflowNode.config` are treated as opaque strings and never composed."
|
|
183
236
|
},
|
|
184
237
|
"endpointsSupported": {
|
|
185
238
|
"type": "boolean",
|
|
186
|
-
"description": "RFC 0028
|
|
239
|
+
"description": "RFC 0028 \u00a7A. When `true`, the host serves the `/v1/prompts*` REST surface \u2014 at minimum the read endpoints (`listPromptTemplates`, `getPromptTemplate`, `renderPromptTemplate`). The mutating endpoints additionally require `mutableLibrary: true`; the pack-install path additionally requires `packsSupported: true`. False or absent = every `/v1/prompts*` request returns `501 capability_not_provided`. Independent of `supported` \u2014 a host MAY advertise `supported: true, endpointsSupported: false` (composition without library REST) or `supported: false, endpointsSupported: true` (library REST against an external resolver, e.g., a fa\u00e7ade host)."
|
|
187
240
|
},
|
|
188
241
|
"templateKinds": {
|
|
189
242
|
"type": "array",
|
|
190
|
-
"items": {
|
|
243
|
+
"items": {
|
|
244
|
+
"$ref": "./prompt-kind.schema.json"
|
|
245
|
+
},
|
|
191
246
|
"uniqueItems": true,
|
|
192
|
-
"description": "Subset of PromptKind values the host accepts. Defaults to all four (`system`, `user`, `few-shot`, `schema-hint`) when omitted. The $ref resolves to the shared `prompt-kind.schema.json` `$def` per RFC 0027
|
|
247
|
+
"description": "Subset of PromptKind values the host accepts. Defaults to all four (`system`, `user`, `few-shot`, `schema-hint`) when omitted. The $ref resolves to the shared `prompt-kind.schema.json` `$def` per RFC 0027 \u00a7A \u2014 uses a relative URI so redocly's lint walker resolves it against the local file rather than fetching the openwop.dev URL."
|
|
193
248
|
},
|
|
194
249
|
"variableSources": {
|
|
195
250
|
"type": "array",
|
|
196
|
-
"items": {
|
|
251
|
+
"items": {
|
|
252
|
+
"type": "string",
|
|
253
|
+
"enum": [
|
|
254
|
+
"input",
|
|
255
|
+
"variable",
|
|
256
|
+
"secret",
|
|
257
|
+
"context"
|
|
258
|
+
]
|
|
259
|
+
},
|
|
197
260
|
"uniqueItems": true,
|
|
198
261
|
"description": "Subset of PromptVariable.source values the host supports. `secret` SHOULD only appear when `capabilities.secrets.supported` is also true."
|
|
199
262
|
},
|
|
@@ -205,21 +268,25 @@
|
|
|
205
268
|
},
|
|
206
269
|
"observability": {
|
|
207
270
|
"type": "string",
|
|
208
|
-
"enum": [
|
|
271
|
+
"enum": [
|
|
272
|
+
"off",
|
|
273
|
+
"hashed",
|
|
274
|
+
"full"
|
|
275
|
+
],
|
|
209
276
|
"description": "How `prompt.composed` events expose resolved bodies. `off`: event not emitted. `hashed`: payload carries only sha256 + per-variable-binding hashes (no plaintext). `full`: payload carries the composed body with secret-sourced values redacted to `[REDACTED:<secretId>]` markers and untrusted segments wrapped in `<UNTRUSTED>` markers. Default when absent: `hashed`."
|
|
210
277
|
},
|
|
211
278
|
"packsSupported": {
|
|
212
279
|
"type": "boolean",
|
|
213
|
-
"description": "RFC 0028
|
|
280
|
+
"description": "RFC 0028 \u00a7C. When `true`, the host installs `kind: \"prompt\"` registry packs and exposes their templates at `GET /v1/prompts` with `meta.source: \"pack\"` + `meta.packName` + `meta.packVersion`. When `false` or absent, packs are not loaded; only host built-ins and (when `mutableLibrary: true`) user-created templates are visible."
|
|
214
281
|
},
|
|
215
282
|
"mutableLibrary": {
|
|
216
283
|
"type": "boolean",
|
|
217
|
-
"description": "RFC 0028
|
|
284
|
+
"description": "RFC 0028 \u00a7C. When `true`, the host honors the mutating endpoints `POST /v1/prompts`, `PUT /v1/prompts/{templateId}`, `DELETE /v1/prompts/{templateId}`. When `false` or absent, those endpoints return 501. Pack-sourced and host-built-in templates remain read-only even under `mutableLibrary: true` \u2014 deletion of those returns 403 per RFC 0028 \u00a7A."
|
|
218
285
|
},
|
|
219
286
|
"library": {
|
|
220
287
|
"type": "object",
|
|
221
288
|
"additionalProperties": false,
|
|
222
|
-
"description": "RFC 0028
|
|
289
|
+
"description": "RFC 0028 \u00a7C. Per-library configuration knobs that influence how clients call the prompt surface.",
|
|
223
290
|
"properties": {
|
|
224
291
|
"id": {
|
|
225
292
|
"type": "string",
|
|
@@ -240,17 +307,25 @@
|
|
|
240
307
|
"defaults": {
|
|
241
308
|
"type": "object",
|
|
242
309
|
"additionalProperties": false,
|
|
243
|
-
"description": "RFC 0029
|
|
310
|
+
"description": "RFC 0029 \u00a7B. Per-kind host-default PromptRefs that apply at resolution chain layer 4 (`host-defaults`) per `spec/v1/prompts.md` \u00a7\"Resolution chain (normative)\". Advertised so clients can preview the full chain at edit time without dispatching a node. Hosts MAY ship per-kind defaults; the openwop spec ships none.",
|
|
244
311
|
"properties": {
|
|
245
|
-
"system": {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
"
|
|
312
|
+
"system": {
|
|
313
|
+
"$ref": "./prompt-ref.schema.json"
|
|
314
|
+
},
|
|
315
|
+
"user": {
|
|
316
|
+
"$ref": "./prompt-ref.schema.json"
|
|
317
|
+
},
|
|
318
|
+
"few-shot": {
|
|
319
|
+
"$ref": "./prompt-ref.schema.json"
|
|
320
|
+
},
|
|
321
|
+
"schema-hint": {
|
|
322
|
+
"$ref": "./prompt-ref.schema.json"
|
|
323
|
+
}
|
|
249
324
|
}
|
|
250
325
|
},
|
|
251
326
|
"agentBindings": {
|
|
252
327
|
"type": "boolean",
|
|
253
|
-
"description": "RFC 0029
|
|
328
|
+
"description": "RFC 0029 \u00a7B. When `true`, the host honors `AgentManifest.promptOverrides[kind]` and `AgentManifest.promptLibraryRef` at resolution chain layer 2 (`agent-overrides` / `agent-library-default`) per `spec/v1/prompts.md` \u00a7\"Resolution chain (normative)\". When `false` or absent, layer 2 is skipped \u2014 the host applies only layers 1, 3, 4. Conformance scenarios for agent-binding resolution are gated on this flag."
|
|
254
329
|
}
|
|
255
330
|
},
|
|
256
331
|
"additionalProperties": false
|
|
@@ -263,9 +338,15 @@
|
|
|
263
338
|
"type": "object",
|
|
264
339
|
"description": "Optional v1 server identity (name + version + vendor).",
|
|
265
340
|
"properties": {
|
|
266
|
-
"name": {
|
|
267
|
-
|
|
268
|
-
|
|
341
|
+
"name": {
|
|
342
|
+
"type": "string"
|
|
343
|
+
},
|
|
344
|
+
"version": {
|
|
345
|
+
"type": "string"
|
|
346
|
+
},
|
|
347
|
+
"vendor": {
|
|
348
|
+
"type": "string"
|
|
349
|
+
}
|
|
269
350
|
},
|
|
270
351
|
"additionalProperties": false
|
|
271
352
|
},
|
|
@@ -281,17 +362,29 @@
|
|
|
281
362
|
},
|
|
282
363
|
"supportedTransports": {
|
|
283
364
|
"type": "array",
|
|
284
|
-
"items": {
|
|
365
|
+
"items": {
|
|
366
|
+
"type": "string",
|
|
367
|
+
"enum": [
|
|
368
|
+
"rest",
|
|
369
|
+
"mcp",
|
|
370
|
+
"a2a",
|
|
371
|
+
"grpc"
|
|
372
|
+
]
|
|
373
|
+
},
|
|
285
374
|
"description": "Optional v1 transport advertisement. REST is required whether or not this field is present."
|
|
286
375
|
},
|
|
287
376
|
"grpc": {
|
|
288
377
|
"type": "object",
|
|
289
|
-
"description": "RFC 0094
|
|
290
|
-
"required": [
|
|
378
|
+
"description": "RFC 0094 \u00a7H. gRPC transport advertisement per `grpc-transport.md` \u00a7\"Capability advertisement\". Optional \u2014 absent \u21d2 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.",
|
|
379
|
+
"required": [
|
|
380
|
+
"supported",
|
|
381
|
+
"service",
|
|
382
|
+
"tls"
|
|
383
|
+
],
|
|
291
384
|
"properties": {
|
|
292
385
|
"supported": {
|
|
293
386
|
"type": "boolean",
|
|
294
|
-
"description": "Toggle
|
|
387
|
+
"description": "Toggle \u2014 `true` when the gRPC surface is live."
|
|
295
388
|
},
|
|
296
389
|
"endpoint": {
|
|
297
390
|
"type": "string",
|
|
@@ -302,11 +395,15 @@
|
|
|
302
395
|
"service": {
|
|
303
396
|
"type": "string",
|
|
304
397
|
"const": "openwop.v1.Engine",
|
|
305
|
-
"description": "Canonical service name. v1 hosts MUST use `openwop.v1.Engine` per `grpc-transport.md`
|
|
398
|
+
"description": "Canonical service name. v1 hosts MUST use `openwop.v1.Engine` per `grpc-transport.md` \u00a7\"Field semantics\"."
|
|
306
399
|
},
|
|
307
400
|
"tls": {
|
|
308
401
|
"type": "string",
|
|
309
|
-
"enum": [
|
|
402
|
+
"enum": [
|
|
403
|
+
"required",
|
|
404
|
+
"optional",
|
|
405
|
+
"disabled"
|
|
406
|
+
],
|
|
310
407
|
"description": "TLS posture. Production hosts MUST set `\"required\"`."
|
|
311
408
|
}
|
|
312
409
|
},
|
|
@@ -314,16 +411,18 @@
|
|
|
314
411
|
},
|
|
315
412
|
"configurable": {
|
|
316
413
|
"type": "object",
|
|
317
|
-
"description": "Optional v1 per-run overlay schema
|
|
414
|
+
"description": "Optional v1 per-run overlay schema \u2014 what `RunOptions.configurable` keys this server honors."
|
|
318
415
|
},
|
|
319
416
|
"nodePackRuntimes": {
|
|
320
417
|
"type": "object",
|
|
321
|
-
"description": "Optional v1 advertisement of node-pack runtimes the host loads. See `node-packs.md`
|
|
418
|
+
"description": "Optional v1 advertisement of node-pack runtimes the host loads. See `node-packs.md` \u00a7runtime formats and RFC 0008 (WASM ABI). Hosts that don't load packs MAY omit this block entirely. NOTE: this block intentionally uses `additionalProperties: true` (here and on the nested runtime objects) so a future RFC may add a runtime type (e.g., `python-wasm`, `js-wasm`) without a breaking-change rev of this schema; the trade is that a strict-mode validator will accept arbitrary extra keys under these objects. A future RFC that promotes the open-set fields to first-class SHOULD tighten them to `additionalProperties: false` in the same RFC.",
|
|
322
419
|
"properties": {
|
|
323
420
|
"wasm": {
|
|
324
421
|
"type": "object",
|
|
325
422
|
"description": "WASM core-module runtime per RFC 0008. Hosts that load `runtime.language: \"wasm\"` packs MUST advertise `supported: true` and at least one entry in `abiVersions[]`. `additionalProperties: true` preserved for future RFC 0008 amendments (e.g., per-pack memory accounting fields).",
|
|
326
|
-
"required": [
|
|
423
|
+
"required": [
|
|
424
|
+
"supported"
|
|
425
|
+
],
|
|
327
426
|
"properties": {
|
|
328
427
|
"supported": {
|
|
329
428
|
"type": "boolean",
|
|
@@ -337,13 +436,13 @@
|
|
|
337
436
|
},
|
|
338
437
|
"uniqueItems": true,
|
|
339
438
|
"minItems": 1,
|
|
340
|
-
"description": "ABI versions the loader accepts. v1.1 hosts MUST include `1`. Packs declaring `openwop_abi_version()` outside this list MUST be rejected at load time per RFC 0008
|
|
439
|
+
"description": "ABI versions the loader accepts. v1.1 hosts MUST include `1`. Packs declaring `openwop_abi_version()` outside this list MUST be rejected at load time per RFC 0008 \u00a7H."
|
|
341
440
|
},
|
|
342
441
|
"maxMemoryBytes": {
|
|
343
442
|
"type": "integer",
|
|
344
443
|
"minimum": 1048576,
|
|
345
444
|
"maximum": 8589934592,
|
|
346
|
-
"description": "Per-pack memory ceiling enforced by the host loader. Range: 1 MiB
|
|
445
|
+
"description": "Per-pack memory ceiling enforced by the host loader. Range: 1 MiB \u2264 value \u2264 8 GiB. RFC 0008 \u00a7K \u2014 when a pack exceeds this, the host MUST emit `cap.breached` with `kind: \"wasm-memory\"`."
|
|
347
446
|
},
|
|
348
447
|
"loadedPacks": {
|
|
349
448
|
"type": "array",
|
|
@@ -352,7 +451,7 @@
|
|
|
352
451
|
"minLength": 1
|
|
353
452
|
},
|
|
354
453
|
"uniqueItems": true,
|
|
355
|
-
"description": "Pack names that passed instantiation (ABI check + load). Packs rejected per RFC 0008
|
|
454
|
+
"description": "Pack names that passed instantiation (ABI check + load). Packs rejected per RFC 0008 \u00a7H MUST NOT appear here. Hosts MAY advertise this for observability; conformance asserts rejection by absence (Track 7)."
|
|
356
455
|
}
|
|
357
456
|
},
|
|
358
457
|
"additionalProperties": true
|
|
@@ -361,7 +460,9 @@
|
|
|
361
460
|
"type": "object",
|
|
362
461
|
"description": "WASM Component Model variant (WIT-defined interfaces). Reserved for hosts that load `runtime.language: \"wasm-component\"` packs. `additionalProperties: true` preserved until the Component Model spec stabilises in the v1.x line; tighten in the RFC that promotes wasm-component to a first-class runtime alongside `wasm`.",
|
|
363
462
|
"properties": {
|
|
364
|
-
"supported": {
|
|
463
|
+
"supported": {
|
|
464
|
+
"type": "boolean"
|
|
465
|
+
}
|
|
365
466
|
},
|
|
366
467
|
"additionalProperties": true
|
|
367
468
|
}
|
|
@@ -380,7 +481,11 @@
|
|
|
380
481
|
"type": "array",
|
|
381
482
|
"items": {
|
|
382
483
|
"type": "string",
|
|
383
|
-
"enum": [
|
|
484
|
+
"enum": [
|
|
485
|
+
"http/json",
|
|
486
|
+
"http/protobuf",
|
|
487
|
+
"grpc"
|
|
488
|
+
]
|
|
384
489
|
},
|
|
385
490
|
"uniqueItems": true,
|
|
386
491
|
"description": "OTLP export protocols the host supports emitting. `http/json` and `http/protobuf` are mandatory for hosts advertising OTel emission; `grpc` is opt-in per Track 11."
|
|
@@ -391,7 +496,7 @@
|
|
|
391
496
|
"testSeams": {
|
|
392
497
|
"type": "object",
|
|
393
498
|
"additionalProperties": false,
|
|
394
|
-
"description": "RFC 0034
|
|
499
|
+
"description": "RFC 0034 \u2014 Conformance-only test seams under the host-extension namespace. Hosts that opt in expose introspection endpoints so cross-host conformance scenarios can verify BYOK canaries do not leak into OTel span attributes or debug-bundle exports. Production hosts SHOULD return 404 or 403 from these seams unless an env-gate (e.g., `OPENWOP_TEST_OTEL_SCRAPE=true`) is set.",
|
|
395
500
|
"properties": {
|
|
396
501
|
"otelScrape": {
|
|
397
502
|
"type": "boolean",
|
|
@@ -413,7 +518,9 @@
|
|
|
413
518
|
"secrets": {
|
|
414
519
|
"type": "object",
|
|
415
520
|
"description": "Optional v1 secret/credential resolution advertisement. Clients gate BYOK flows on this. Hosts that don't store credentials return `supported: false`.",
|
|
416
|
-
"required": [
|
|
521
|
+
"required": [
|
|
522
|
+
"supported"
|
|
523
|
+
],
|
|
417
524
|
"properties": {
|
|
418
525
|
"supported": {
|
|
419
526
|
"type": "boolean",
|
|
@@ -423,14 +530,21 @@
|
|
|
423
530
|
"type": "array",
|
|
424
531
|
"items": {
|
|
425
532
|
"type": "string",
|
|
426
|
-
"enum": [
|
|
533
|
+
"enum": [
|
|
534
|
+
"tenant",
|
|
535
|
+
"user",
|
|
536
|
+
"run",
|
|
537
|
+
"workspace"
|
|
538
|
+
]
|
|
427
539
|
},
|
|
428
540
|
"uniqueItems": true,
|
|
429
|
-
"description": "Subset of scopes the host implements. Tenant-scoped secrets are workspace-shared; user-scoped are per-end-user; run-scoped are ephemeral per-run; `workspace` (RFC 0046/0048) is the explicit sub-tenant scope. Appended `workspace` is additive
|
|
541
|
+
"description": "Subset of scopes the host implements. Tenant-scoped secrets are workspace-shared; user-scoped are per-end-user; run-scoped are ephemeral per-run; `workspace` (RFC 0046/0048) is the explicit sub-tenant scope. Appended `workspace` is additive \u2014 hosts that omit it are unaffected."
|
|
430
542
|
},
|
|
431
543
|
"resolution": {
|
|
432
544
|
"type": "string",
|
|
433
|
-
"enum": [
|
|
545
|
+
"enum": [
|
|
546
|
+
"host-managed"
|
|
547
|
+
],
|
|
434
548
|
"description": "Resolution mode. v1.x supports only `host-managed` (clients reference stored secrets via opaque ids); reserved for future modes."
|
|
435
549
|
}
|
|
436
550
|
},
|
|
@@ -438,8 +552,10 @@
|
|
|
438
552
|
},
|
|
439
553
|
"connections": {
|
|
440
554
|
"type": "object",
|
|
441
|
-
"description": "RFC 0095 (`Draft`). Connection packs
|
|
442
|
-
"required": [
|
|
555
|
+
"description": "RFC 0095 (`Draft`). Connection packs \u2014 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.",
|
|
556
|
+
"required": [
|
|
557
|
+
"packsSupported"
|
|
558
|
+
],
|
|
443
559
|
"properties": {
|
|
444
560
|
"supported": {
|
|
445
561
|
"type": "boolean",
|
|
@@ -447,7 +563,7 @@
|
|
|
447
563
|
},
|
|
448
564
|
"packsSupported": {
|
|
449
565
|
"type": "boolean",
|
|
450
|
-
"description": "RFC 0095
|
|
566
|
+
"description": "RFC 0095 \u00a7C. When `true`, the host installs `kind: \"connection\"` registry packs and MUST implement the \u00a7B.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 \u00a711 and `connection_provider_unresolved` / `connection_provider_conflict` diagnostics. When `false` or absent, connection packs are not loaded and provider resolution stays implementation-defined."
|
|
451
567
|
}
|
|
452
568
|
},
|
|
453
569
|
"additionalProperties": false
|
|
@@ -455,8 +571,10 @@
|
|
|
455
571
|
"selfHostedRunner": {
|
|
456
572
|
"type": "object",
|
|
457
573
|
"additionalProperties": false,
|
|
458
|
-
"description": "RFC 0122 (`Active`). The host routes a run's per-step model/tool dispatch to a user-controlled RUNNER that dials OUT to the host over a persistent channel (SSE receive + POST result) and holds the local credentials the host cannot reach (a subscription CLI login per RFC 0121, a private endpoint per RFC 0108). The host stays the sole orchestration/persistence/replay authority; the runner is a stateless dispatch executor. This is the discovery-time capability shape ONLY; the per-subject `SelfHostedRunnerRegistration` record stays OFF `/.well-known/openwop`. A host MUST NOT advertise `supported: true` until RFC 0122 reaches `Accepted` and the channel is honored (truthful-advertisement, `OPENWOP_REQUIRE_BEHAVIOR=true`). Absent block
|
|
459
|
-
"required": [
|
|
574
|
+
"description": "RFC 0122 (`Active`). The host routes a run's per-step model/tool dispatch to a user-controlled RUNNER that dials OUT to the host over a persistent channel (SSE receive + POST result) and holds the local credentials the host cannot reach (a subscription CLI login per RFC 0121, a private endpoint per RFC 0108). The host stays the sole orchestration/persistence/replay authority; the runner is a stateless dispatch executor. This is the discovery-time capability shape ONLY; the per-subject `SelfHostedRunnerRegistration` record stays OFF `/.well-known/openwop`. A host MUST NOT advertise `supported: true` until RFC 0122 reaches `Accepted` and the channel is honored (truthful-advertisement, `OPENWOP_REQUIRE_BEHAVIOR=true`). Absent block \u21d2 no runner advertisement.",
|
|
575
|
+
"required": [
|
|
576
|
+
"supported"
|
|
577
|
+
],
|
|
460
578
|
"properties": {
|
|
461
579
|
"supported": {
|
|
462
580
|
"type": "boolean",
|
|
@@ -464,21 +582,29 @@
|
|
|
464
582
|
},
|
|
465
583
|
"dispatchKinds": {
|
|
466
584
|
"type": "array",
|
|
467
|
-
"items": {
|
|
585
|
+
"items": {
|
|
586
|
+
"type": "string",
|
|
587
|
+
"enum": [
|
|
588
|
+
"model",
|
|
589
|
+
"tool"
|
|
590
|
+
]
|
|
591
|
+
},
|
|
468
592
|
"uniqueItems": true,
|
|
469
|
-
"description": "OPTIONAL. Which dispatch kinds the host routes to runners. A host MAY implement `model` first and add `tool` later behind the same capability gate (openwop-app ADR 0182 Phase 5 lands model-dispatch first). Absent
|
|
593
|
+
"description": "OPTIONAL. Which dispatch kinds the host routes to runners. A host MAY implement `model` first and add `tool` later behind the same capability gate (openwop-app ADR 0182 Phase 5 lands model-dispatch first). Absent \u21d2 implementation-defined, but a host SHOULD enumerate what it actually routes."
|
|
470
594
|
}
|
|
471
595
|
}
|
|
472
596
|
},
|
|
473
597
|
"purposePropagation": {
|
|
474
598
|
"type": "object",
|
|
475
599
|
"additionalProperties": false,
|
|
476
|
-
"description": "RFC 0128 (`Active`). Purpose-propagation
|
|
477
|
-
"required": [
|
|
600
|
+
"description": "RFC 0128 (`Active`). Purpose-propagation \u2014 the host reads and RE-EMITS `permittedPurposes` labels (opaque purpose strings riding the A2A `metadata.openwop.permittedPurposes` extension and the `TriggerEvent.permittedPurposes` field) on onward OpenWOP-envelope hops of the same data, narrowing at most and never widening; a `[]` label is honored as no-onward-use. This family advertises label PROPAGATION only \u2014 it does NOT claim the host enforces purpose limits on its own internal use (that is declared intent under the receiver's local governance, RFC 0128 \u00a74, deliberately not conformance-gated). A host MUST NOT advertise `supported: true` until RFC 0128 reaches `Accepted` and propagation is honored (truthful-advertisement, `OPENWOP_REQUIRE_BEHAVIOR=true`). Absent block \u21d2 labels pass through unread as unknown metadata (pre-RFC behavior).",
|
|
601
|
+
"required": [
|
|
602
|
+
"supported"
|
|
603
|
+
],
|
|
478
604
|
"properties": {
|
|
479
605
|
"supported": {
|
|
480
606
|
"type": "boolean",
|
|
481
|
-
"description": "RFC 0128. When `true`, the host preserves and re-emits received `permittedPurposes` labels per RFC 0128
|
|
607
|
+
"description": "RFC 0128. When `true`, the host preserves and re-emits received `permittedPurposes` labels per RFC 0128 \u00a73 (re-emit on OpenWOP-envelope onward hops; MAY narrow; MUST NOT widen; derived outputs never carry a purpose absent from any contributing labelled input; `[]` \u21d2 no onward hop)."
|
|
482
608
|
},
|
|
483
609
|
"propagatesOnward": {
|
|
484
610
|
"type": "boolean",
|
|
@@ -489,44 +615,63 @@
|
|
|
489
615
|
"dataResidency": {
|
|
490
616
|
"type": "object",
|
|
491
617
|
"additionalProperties": false,
|
|
492
|
-
"description": "RFC 0129 (`Active`). Data-residency
|
|
493
|
-
"required": [
|
|
618
|
+
"description": "RFC 0129 (`Active`). Data-residency \u2014 the host advertises the operator region codes it can pin a run to, and honors-or-rejects an OPTIONAL `residency.region` on run-creation (`POST /v1/runs`): accept iff the requested region is in `regions[]`, else reject `residency_unavailable` (never silently accept-and-ignore). This family advertises the ADMISSION decision only (falsifiable over the wire) \u2014 it does NOT assert that the run's data physically remains in-region (unobservable; declared operator intent under RFC 0129 \u00a74, not conformance-gated). A host MUST advertise a region in `regions[]` only if it can actually process a run entirely within it. Absent block \u21d2 the host makes no residency promise and MAY ignore or reject a `residency` constraint (but MUST NOT claim to honor it).",
|
|
619
|
+
"required": [
|
|
620
|
+
"supported",
|
|
621
|
+
"regions"
|
|
622
|
+
],
|
|
494
623
|
"properties": {
|
|
495
624
|
"supported": {
|
|
496
625
|
"const": true,
|
|
497
|
-
"description": "RFC 0129. Present-and-true when the host performs region admission control per
|
|
626
|
+
"description": "RFC 0129. Present-and-true when the host performs region admission control per \u00a73. The block is omitted entirely when the host offers no residency pinning."
|
|
498
627
|
},
|
|
499
628
|
"regions": {
|
|
500
629
|
"type": "array",
|
|
501
|
-
"items": {
|
|
630
|
+
"items": {
|
|
631
|
+
"type": "string",
|
|
632
|
+
"minLength": 1
|
|
633
|
+
},
|
|
502
634
|
"uniqueItems": true,
|
|
503
|
-
"description": "RFC 0129. Opaque operator region codes the host can pin a run to (e.g. `\"eu\"`, `\"us\"`, `\"eu-west-1\"`). No closed registry
|
|
635
|
+
"description": "RFC 0129. Opaque operator region codes the host can pin a run to (e.g. `\"eu\"`, `\"us\"`, `\"eu-west-1\"`). No closed registry \u2014 codes are the host's own vocabulary (a global region enum would be unfalsifiable). A host MUST advertise a code here only if it can process a run entirely within it; a run-create `residency.region` not in this list MUST be rejected `residency_unavailable`."
|
|
504
636
|
}
|
|
505
637
|
}
|
|
506
638
|
},
|
|
507
639
|
"anonymousActor": {
|
|
508
640
|
"type": "object",
|
|
509
641
|
"additionalProperties": false,
|
|
510
|
-
"description": "RFC 0132 (`Active`). Anonymous-actor authorization for public agent surfaces
|
|
511
|
-
"required": [
|
|
642
|
+
"description": "RFC 0132 (`Active`). Anonymous-actor authorization for public agent surfaces \u2014 an opaque, origin-bound, ephemeral, non-cross-linkable, non-PII principal (`run-snapshot.owner.principalKind: \"anonymous\"`) whose authority is a DEFAULT-DENY, explicit per-surface tool grant, never the default-on tool baseline (\u00a7C.1). Two tiers: `read` (tenant-scoped, no egress, no secret/BYOK reach \u2014 \u00a7C.2) and `bounded-write-egress` (writes/egress permitted ONLY behind a mandatory HITL/approval gate (RFC 0051) OR a hard rate-limit + per-session cap, over the RFC 0076 \u00a7B / RFC 0079 SSRF-guarded audience-bound egress path, never attaching a tenant credential out-of-audience \u2014 \u00a7C.3). Every anon tool call emits `authorization.decided` (RFC 0049) attributable to the opaque session id, carrying no PII/credential (\u00a7D). The block is OMITTED ENTIRELY when unsupported (const-true `supported`, `dataResidency`-style \u2014 never `supported: false`). Absent \u21d2 the host runs no tool-enabled public surface under RFC 0132 (e.g. a no-tools single-turn public gateway needs no advertisement).",
|
|
643
|
+
"required": [
|
|
644
|
+
"supported",
|
|
645
|
+
"tiers"
|
|
646
|
+
],
|
|
512
647
|
"properties": {
|
|
513
648
|
"supported": {
|
|
514
649
|
"const": true,
|
|
515
|
-
"description": "RFC 0132. Present-and-true when the host honors anonymous-actor authorization per
|
|
650
|
+
"description": "RFC 0132. Present-and-true when the host honors anonymous-actor authorization per \u00a7C. The block is omitted entirely when the host runs no tool-enabled public surface (never `supported: false`)."
|
|
516
651
|
},
|
|
517
652
|
"tiers": {
|
|
518
653
|
"type": "array",
|
|
519
654
|
"minItems": 1,
|
|
520
655
|
"uniqueItems": true,
|
|
521
|
-
"items": {
|
|
522
|
-
|
|
656
|
+
"items": {
|
|
657
|
+
"enum": [
|
|
658
|
+
"read",
|
|
659
|
+
"bounded-write-egress"
|
|
660
|
+
]
|
|
661
|
+
},
|
|
662
|
+
"description": "RFC 0132 \u00a7B. The anon capability tiers this host BEHAVIORALLY honors (truthful-advertisement \u2014 a tier the host does not enforce per \u00a7C is a dishonest claim; `OPENWOP_REQUIRE_BEHAVIOR=true` MUST fail it). `read`: tenant-scoped reads, no egress, no secrets (\u00a7C.2). `bounded-write-egress`: writes/egress ONLY behind a \u00a7C.3 control."
|
|
523
663
|
},
|
|
524
664
|
"writeEgressControls": {
|
|
525
665
|
"type": "array",
|
|
526
666
|
"minItems": 1,
|
|
527
667
|
"uniqueItems": true,
|
|
528
|
-
"items": {
|
|
529
|
-
|
|
668
|
+
"items": {
|
|
669
|
+
"enum": [
|
|
670
|
+
"hitl",
|
|
671
|
+
"rate-limit-session-cap"
|
|
672
|
+
]
|
|
673
|
+
},
|
|
674
|
+
"description": "RFC 0132 \u00a7B. REQUIRED and non-empty IFF `bounded-write-egress` \u2208 `tiers`; MUST be absent otherwise. The mandatory control(s) the host enforces before an anon write/egress: `hitl` = a per-action approval gate (RFC 0051 \u2014 the action suspends pending a human decision); `rate-limit-session-cap` = a hard per-IP/per-window rate limit AND a per-session action cap. A `bounded-write-egress` tier with no advertised control is the fail-open shape \u00a7B.2 forbids."
|
|
530
675
|
},
|
|
531
676
|
"failClosed": {
|
|
532
677
|
"const": true,
|
|
@@ -535,20 +680,40 @@
|
|
|
535
680
|
},
|
|
536
681
|
"allOf": [
|
|
537
682
|
{
|
|
538
|
-
"$comment": "RFC 0132
|
|
683
|
+
"$comment": "RFC 0132 \u00a7B.2 \u2014 writeEgressControls is REQUIRED and non-empty when bounded-write-egress is advertised, and MUST be absent otherwise (a control-less write/egress tier is the fail-open shape this RFC forbids).",
|
|
539
684
|
"if": {
|
|
540
|
-
"properties": {
|
|
541
|
-
|
|
685
|
+
"properties": {
|
|
686
|
+
"tiers": {
|
|
687
|
+
"contains": {
|
|
688
|
+
"const": "bounded-write-egress"
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
},
|
|
692
|
+
"required": [
|
|
693
|
+
"tiers"
|
|
694
|
+
]
|
|
695
|
+
},
|
|
696
|
+
"then": {
|
|
697
|
+
"required": [
|
|
698
|
+
"writeEgressControls"
|
|
699
|
+
]
|
|
542
700
|
},
|
|
543
|
-
"
|
|
544
|
-
|
|
701
|
+
"else": {
|
|
702
|
+
"not": {
|
|
703
|
+
"required": [
|
|
704
|
+
"writeEgressControls"
|
|
705
|
+
]
|
|
706
|
+
}
|
|
707
|
+
}
|
|
545
708
|
}
|
|
546
709
|
]
|
|
547
710
|
},
|
|
548
711
|
"credentials": {
|
|
549
712
|
"type": "object",
|
|
550
|
-
"description": "RFC 0046 (`Draft`). Portable credential resolution + lifecycle contract
|
|
551
|
-
"required": [
|
|
713
|
+
"description": "RFC 0046 (`Draft`). Portable credential resolution + lifecycle contract \u2014 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 \u2014 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.",
|
|
714
|
+
"required": [
|
|
715
|
+
"supported"
|
|
716
|
+
],
|
|
552
717
|
"properties": {
|
|
553
718
|
"supported": {
|
|
554
719
|
"type": "boolean",
|
|
@@ -556,7 +721,14 @@
|
|
|
556
721
|
},
|
|
557
722
|
"scopes": {
|
|
558
723
|
"type": "array",
|
|
559
|
-
"items": {
|
|
724
|
+
"items": {
|
|
725
|
+
"type": "string",
|
|
726
|
+
"enum": [
|
|
727
|
+
"user",
|
|
728
|
+
"workspace",
|
|
729
|
+
"tenant"
|
|
730
|
+
]
|
|
731
|
+
},
|
|
560
732
|
"uniqueItems": true,
|
|
561
733
|
"description": "Subset of resolution scopes the host implements. `workspace` is the RFC 0048 sub-tenant; `tenant` and `user` align with the `secrets.scopes` vocabulary."
|
|
562
734
|
},
|
|
@@ -566,7 +738,10 @@
|
|
|
566
738
|
},
|
|
567
739
|
"rotation": {
|
|
568
740
|
"type": "string",
|
|
569
|
-
"enum": [
|
|
741
|
+
"enum": [
|
|
742
|
+
"none",
|
|
743
|
+
"two-key-overlap"
|
|
744
|
+
],
|
|
570
745
|
"description": "`two-key-overlap`: old + new credential both resolve as valid during a grace window, then the old fails with `credential_not_found` (mirrors `openwop-auth-api-key-rotation`). `none`: no rotation surface."
|
|
571
746
|
},
|
|
572
747
|
"sharing": {
|
|
@@ -578,8 +753,10 @@
|
|
|
578
753
|
},
|
|
579
754
|
"feedback": {
|
|
580
755
|
"type": "object",
|
|
581
|
-
"description": "RFC 0056 (`Draft`). Non-blocking human/agent quality signals (rating / correction / label / flag) attached to a run, event, or node. Annotations are a per-run side-resource recorded via `POST /v1/runs/{runId}/annotations`, listed via `GET`, and surfaced live via the `run.annotated` SSE notification
|
|
582
|
-
"required": [
|
|
756
|
+
"description": "RFC 0056 (`Draft`). Non-blocking human/agent quality signals (rating / correction / label / flag) attached to a run, event, or node. Annotations are a per-run side-resource recorded via `POST /v1/runs/{runId}/annotations`, listed via `GET`, and surfaced live via the `run.annotated` SSE notification \u2014 they are NOT entries in the replayable run event log (see RFC 0056 \u00a7B/\u00a7D). Hosts that do not advertise `supported: true` return `501 capability_not_provided` on the annotation endpoints.",
|
|
757
|
+
"required": [
|
|
758
|
+
"supported"
|
|
759
|
+
],
|
|
583
760
|
"properties": {
|
|
584
761
|
"supported": {
|
|
585
762
|
"type": "boolean",
|
|
@@ -587,13 +764,28 @@
|
|
|
587
764
|
},
|
|
588
765
|
"targets": {
|
|
589
766
|
"type": "array",
|
|
590
|
-
"items": {
|
|
767
|
+
"items": {
|
|
768
|
+
"type": "string",
|
|
769
|
+
"enum": [
|
|
770
|
+
"run",
|
|
771
|
+
"event",
|
|
772
|
+
"node"
|
|
773
|
+
]
|
|
774
|
+
},
|
|
591
775
|
"uniqueItems": true,
|
|
592
776
|
"description": "Which annotation-target granularities the host accepts. Absent = `run` only."
|
|
593
777
|
},
|
|
594
778
|
"signals": {
|
|
595
779
|
"type": "array",
|
|
596
|
-
"items": {
|
|
780
|
+
"items": {
|
|
781
|
+
"type": "string",
|
|
782
|
+
"enum": [
|
|
783
|
+
"rating",
|
|
784
|
+
"correction",
|
|
785
|
+
"label",
|
|
786
|
+
"flag"
|
|
787
|
+
]
|
|
788
|
+
},
|
|
597
789
|
"uniqueItems": true,
|
|
598
790
|
"description": "Which signal kinds the host accepts. Absent = all four."
|
|
599
791
|
}
|
|
@@ -602,7 +794,7 @@
|
|
|
602
794
|
},
|
|
603
795
|
"replay": {
|
|
604
796
|
"type": "object",
|
|
605
|
-
"description": "Replay / fork surface (`spec/v1/replay.md`; profile `openwop-replay-fork`). DECLARED FOR THE FIRST TIME BY RFC 0140
|
|
797
|
+
"description": "Replay / fork surface (`spec/v1/replay.md`; profile `openwop-replay-fork`). DECLARED FOR THE FIRST TIME BY RFC 0140 \u2014 hosts have emitted this block since the fork endpoint shipped, but it was never in this schema and validated only via the root's `additionalProperties: true`. The pre-existing fields are declared here exactly as already emitted and consumed, so no host's current document is invalidated; `additionalProperties` stays permissive for the same reason.",
|
|
606
798
|
"properties": {
|
|
607
799
|
"supported": {
|
|
608
800
|
"type": "boolean",
|
|
@@ -610,7 +802,13 @@
|
|
|
610
802
|
},
|
|
611
803
|
"modes": {
|
|
612
804
|
"type": "array",
|
|
613
|
-
"items": {
|
|
805
|
+
"items": {
|
|
806
|
+
"type": "string",
|
|
807
|
+
"enum": [
|
|
808
|
+
"replay",
|
|
809
|
+
"branch"
|
|
810
|
+
]
|
|
811
|
+
},
|
|
614
812
|
"uniqueItems": true,
|
|
615
813
|
"description": "Fork modes the host implements. `replay` = deterministic re-execution; `branch` = divergent execution with an optional `runOptionsOverlay`. A host supporting only `branch` still satisfies the `openwop-replay-fork` predicate."
|
|
616
814
|
},
|
|
@@ -624,28 +822,43 @@
|
|
|
624
822
|
"windowSeconds": {
|
|
625
823
|
"type": "integer",
|
|
626
824
|
"minimum": 0,
|
|
627
|
-
"description": "How long a run stays fork-eligible (`replay.md`
|
|
825
|
+
"description": "How long a run stays fork-eligible (`replay.md` \u00a7\"Retention and garbage collection\"). OPTIONAL \u2014 the spec requires hosts to document retention, not to advertise the window."
|
|
628
826
|
}
|
|
629
827
|
},
|
|
630
828
|
"description": "OPTIONAL retention metadata."
|
|
631
829
|
},
|
|
632
830
|
"sideEffectSuppression": {
|
|
633
831
|
"type": "string",
|
|
634
|
-
"enum": [
|
|
832
|
+
"enum": [
|
|
833
|
+
"recorded-outcome",
|
|
834
|
+
"none"
|
|
835
|
+
],
|
|
635
836
|
"default": "none",
|
|
636
|
-
"description": "RFC 0140. An ASSURANCE ADVERTISEMENT of the mechanism by which the host meets `replay.md`
|
|
837
|
+
"description": "RFC 0140. An ASSURANCE ADVERTISEMENT of the mechanism by which the host meets `replay.md` \u00a7\"Determinism guarantees\" caveat 1 for a `mode:\"replay\"` fork \u2014 NOT a gate on the obligation, which is unconditional. `recorded-outcome`: a side-effecting node does NOT execute during a replay \u2014 the host reproduces the source run's recorded terminal outcome for the same `(nodeId, attempt)`, or fails the node closed with `replay_source_missing`. The guarantee is WHOLE-RUN: a host MUST NOT advertise it if any class of side-effecting node can still fire during a replay (a partial guarantee would violate `replay.md` \u00a7C.2 observable-state equivalence for the unsuppressed classes). `none` (default; absent means this) \u2014 NO mechanism is declared. The host remains bound by `replay.md` \u00a7\"Determinism guarantees\" caveat 1 (an unconditional MUST that a node calling an external API consult the durable invocation log, so the external system is NOT called twice) exactly as before; conformance simply has nothing to probe. This is NOT permission to re-fire effects. Scoped to `replay` mode; `branch` is a new execution whose effects the operator asked for."
|
|
637
838
|
}
|
|
638
839
|
}
|
|
639
840
|
},
|
|
640
841
|
"oauth": {
|
|
641
842
|
"type": "object",
|
|
642
843
|
"description": "RFC 0047 (`Draft`). Host performs OAuth 2.0 grants (authorization-code + refresh) on a user's behalf for connector nodes, stores the acquired token as a `host.credentials` (RFC 0046) entry, refreshes it transparently, and resolves it into the node sandbox as a bearer token. Token material NEVER crosses the wire (SECURITY invariant `credential-payload-redaction`). Distinct from `auth` host-authentication profiles (RFC 0010 = who is the caller; this = what third-party token a node holds).",
|
|
643
|
-
"required": [
|
|
844
|
+
"required": [
|
|
845
|
+
"supported"
|
|
846
|
+
],
|
|
644
847
|
"properties": {
|
|
645
|
-
"supported": {
|
|
848
|
+
"supported": {
|
|
849
|
+
"type": "boolean",
|
|
850
|
+
"description": "Host implements the host.oauth third-party token acquisition + refresh contract."
|
|
851
|
+
},
|
|
646
852
|
"grants": {
|
|
647
853
|
"type": "array",
|
|
648
|
-
"items": {
|
|
854
|
+
"items": {
|
|
855
|
+
"type": "string",
|
|
856
|
+
"enum": [
|
|
857
|
+
"authorization_code",
|
|
858
|
+
"client_credentials",
|
|
859
|
+
"refresh_token"
|
|
860
|
+
]
|
|
861
|
+
},
|
|
649
862
|
"uniqueItems": true,
|
|
650
863
|
"description": "OAuth 2.0 grant types the host performs on a node's behalf."
|
|
651
864
|
},
|
|
@@ -654,12 +867,32 @@
|
|
|
654
867
|
"description": "Provider catalog the host can acquire tokens for. A connector node's `auth.provider` MUST match an `id` here.",
|
|
655
868
|
"items": {
|
|
656
869
|
"type": "object",
|
|
657
|
-
"required": [
|
|
870
|
+
"required": [
|
|
871
|
+
"id"
|
|
872
|
+
],
|
|
658
873
|
"properties": {
|
|
659
|
-
"id": {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
874
|
+
"id": {
|
|
875
|
+
"type": "string",
|
|
876
|
+
"minLength": 1,
|
|
877
|
+
"description": "Stable provider id, e.g. `slack`, `google`."
|
|
878
|
+
},
|
|
879
|
+
"authUrl": {
|
|
880
|
+
"type": "string",
|
|
881
|
+
"format": "uri",
|
|
882
|
+
"description": "Authorization endpoint."
|
|
883
|
+
},
|
|
884
|
+
"tokenUrl": {
|
|
885
|
+
"type": "string",
|
|
886
|
+
"format": "uri",
|
|
887
|
+
"description": "Token endpoint."
|
|
888
|
+
},
|
|
889
|
+
"scopesSupported": {
|
|
890
|
+
"type": "array",
|
|
891
|
+
"items": {
|
|
892
|
+
"type": "string"
|
|
893
|
+
},
|
|
894
|
+
"description": "Scopes this provider exposes."
|
|
895
|
+
}
|
|
663
896
|
},
|
|
664
897
|
"additionalProperties": false
|
|
665
898
|
}
|
|
@@ -670,19 +903,40 @@
|
|
|
670
903
|
"authorization": {
|
|
671
904
|
"type": "object",
|
|
672
905
|
"description": "RFC 0049 (`Draft`). Maps an RFC 0048 principal's role to scopes (reusing the API-key scope grammar in `auth.md`) and surfaces authorization decisions as `authorization.decided` events. Fail-closed: an absent/unseeded role denies (SECURITY invariant `authorization-fail-closed`).",
|
|
673
|
-
"required": [
|
|
906
|
+
"required": [
|
|
907
|
+
"supported"
|
|
908
|
+
],
|
|
674
909
|
"properties": {
|
|
675
|
-
"supported": {
|
|
676
|
-
|
|
910
|
+
"supported": {
|
|
911
|
+
"type": "boolean",
|
|
912
|
+
"description": "Host implements the role\u2192scope authorization-decision contract."
|
|
913
|
+
},
|
|
914
|
+
"failClosed": {
|
|
915
|
+
"const": true,
|
|
916
|
+
"description": "Absent/unseeded role denies; resolver errors deny. MUST be true when present \u2014 see SECURITY invariant `authorization-fail-closed`."
|
|
917
|
+
},
|
|
677
918
|
"roles": {
|
|
678
919
|
"type": "array",
|
|
679
920
|
"description": "Role catalog. A principal's role resolves to this scope set; a request is authorized when any role-derived scope matches the required scope per the API-key scope-match semantics.",
|
|
680
921
|
"items": {
|
|
681
922
|
"type": "object",
|
|
682
|
-
"required": [
|
|
923
|
+
"required": [
|
|
924
|
+
"role",
|
|
925
|
+
"scopes"
|
|
926
|
+
],
|
|
683
927
|
"properties": {
|
|
684
|
-
"role": {
|
|
685
|
-
|
|
928
|
+
"role": {
|
|
929
|
+
"type": "string",
|
|
930
|
+
"minLength": 1
|
|
931
|
+
},
|
|
932
|
+
"scopes": {
|
|
933
|
+
"type": "array",
|
|
934
|
+
"items": {
|
|
935
|
+
"type": "string",
|
|
936
|
+
"minLength": 1
|
|
937
|
+
},
|
|
938
|
+
"uniqueItems": true
|
|
939
|
+
}
|
|
686
940
|
},
|
|
687
941
|
"additionalProperties": false
|
|
688
942
|
}
|
|
@@ -692,14 +946,19 @@
|
|
|
692
946
|
},
|
|
693
947
|
"runtimeCapabilities": {
|
|
694
948
|
"type": "array",
|
|
695
|
-
"items": {
|
|
949
|
+
"items": {
|
|
950
|
+
"type": "string",
|
|
951
|
+
"minLength": 1
|
|
952
|
+
},
|
|
696
953
|
"uniqueItems": true,
|
|
697
|
-
"description": "Optional v1 host-advertised opaque capability ids that NodeModules may declare in `NodeModule.requires`. Naming convention: dotted, domain-scoped (`chat.sendPrompt`, `canvas.write`, `secrets.byok`). Provider value shapes are documented per-capability alongside consumers, NOT in the protocol package
|
|
954
|
+
"description": "Optional v1 host-advertised opaque capability ids that NodeModules may declare in `NodeModule.requires`. Naming convention: dotted, domain-scoped (`chat.sendPrompt`, `canvas.write`, `secrets.byok`). Provider value shapes are documented per-capability alongside consumers, NOT in the protocol package \u2014 the protocol owns the *check*, not domain provider contracts. A client that submits a workflow whose nodes declare a `requires` entry SHOULD first verify the host advertises that capability; a host that lacks a capability MUST refuse to dispatch nodes that declare it, terminating the run with `RunSnapshot.error.code = 'capability_not_provided'`. See `capabilities.md` \u00a7\"Runtime capabilities\"."
|
|
698
955
|
},
|
|
699
956
|
"multiPartyConversation": {
|
|
700
957
|
"type": "object",
|
|
701
|
-
"description": "RFC 0101
|
|
702
|
-
"required": [
|
|
958
|
+
"description": "RFC 0101 \u2014 Multi-party group conversation (shared transcript + speaker attribution). When advertised with `supported: true`, the host honors the RFC 0101 normative contract: (1) it accepts an OPTIONAL `participants: AgentRef[]` roster on `conversation.opened` (`conversation-event.schema.json`); (2) it REQUIRES a `speakerId` (the roster INSTANCE id, `host:<id>` per RFC 0086) on every `role: 'agent'` turn; and (3) when a `participants` roster is present it MUST reject a turn whose `speakerId` is not a roster member. Absent block \u21d2 no advertisement: the host runs single-agent conversations (RFC 0005) and treats `participants`/`speakerId` as opaque, unenforced fields. Advertising `supported: true` without honoring (1)+(2)+(3) is a dishonest wire claim (`OPENWOP_REQUIRE_BEHAVIOR=true` fails the gated conformance scenarios). Host product policy \u2014 turn-taking order, round count, synchronous vs. async rounds \u2014 stays NON-normative (RFC 0101 \u00a7Spec); only roster membership, agent-turn attribution, and this capability are normative. Requires `conversationPrimitive: true` (RFC 0005) \u2014 this block extends the single-agent conversation primitive, it does not replace it.",
|
|
959
|
+
"required": [
|
|
960
|
+
"supported"
|
|
961
|
+
],
|
|
703
962
|
"additionalProperties": false,
|
|
704
963
|
"properties": {
|
|
705
964
|
"supported": {
|
|
@@ -709,14 +968,16 @@
|
|
|
709
968
|
"maxParticipants": {
|
|
710
969
|
"type": "integer",
|
|
711
970
|
"minimum": 2,
|
|
712
|
-
"description": "RFC 0101. OPTIONAL host ceiling on the size of the `conversation.opened.participants` roster. A multi-party council has at least 2 participants. When advertised, the host MUST reject a `conversation.opened` whose `participants` array exceeds this count. Absent
|
|
971
|
+
"description": "RFC 0101. OPTIONAL host ceiling on the size of the `conversation.opened.participants` roster. A multi-party council has at least 2 participants. When advertised, the host MUST reject a `conversation.opened` whose `participants` array exceeds this count. Absent \u21d2 the host does not bound the roster size on the wire."
|
|
713
972
|
}
|
|
714
973
|
}
|
|
715
974
|
},
|
|
716
975
|
"conversationTurnModelProvenance": {
|
|
717
976
|
"type": "object",
|
|
718
|
-
"description": "RFC 0109
|
|
719
|
-
"required": [
|
|
977
|
+
"description": "RFC 0109 \u2014 Conversation-turn model provenance. When advertised with `supported: true`, the host stamps the OPTIONAL `agent.model` object (`{ provider, model }`) on `role: 'agent'` conversation turns (`conversation-turn.schema.json`), recording which model produced the turn. The stamp is NON-SECRET + NON-PII (`additionalProperties: false` on `agent.model` forbids any credential/endpoint/prompt \u2014 the SR-1 guard) and is read VERBATIM on `:fork` (never re-resolved, so a forked transcript preserves the original provenance). Absent block \u21d2 no advertisement: the host omits `agent.model` and treats it as an opaque, unenforced field. Advertising `supported: true` without stamping is a dishonest wire claim (`OPENWOP_REQUIRE_BEHAVIOR=true` fails the gated scenario). Additive over RFC 0005 \u2014 extends the conversation primitive, does not replace it.",
|
|
978
|
+
"required": [
|
|
979
|
+
"supported"
|
|
980
|
+
],
|
|
720
981
|
"additionalProperties": false,
|
|
721
982
|
"properties": {
|
|
722
983
|
"supported": {
|
|
@@ -727,8 +988,10 @@
|
|
|
727
988
|
},
|
|
728
989
|
"channelPresence": {
|
|
729
990
|
"type": "object",
|
|
730
|
-
"description": "RFC 0110
|
|
731
|
-
"required": [
|
|
991
|
+
"description": "RFC 0110 \u2014 Channel presence (online + typing). When advertised with `supported: true`, the host emits the OPTIONAL `channel.presence` RunEvent (`channel-presence-payload.schema.json`) for a `type:'channel'` conversation, carrying the currently-present member subject refs + optional per-member typing. Presence is EPHEMERAL live state: the host MUST NOT persist it to the replayable event log / transcript and it MUST NOT affect replay or `:fork` (the load-bearing distinction from the persisted `conversation.exchanged` turn). Membership-gated: every ref MUST be a current participant and the event MUST NOT be delivered to a non-member (DEFAULT-DENY, CTI-1). NON-PII (opaque RFC 0041 subject refs only). Absent block \u21d2 no advertisement: the host emits no presence. Advertising `supported: true` without emitting is a dishonest wire claim (`OPENWOP_REQUIRE_BEHAVIOR=true` fails the gated scenario). Additive over RFC 0005.",
|
|
992
|
+
"required": [
|
|
993
|
+
"supported"
|
|
994
|
+
],
|
|
732
995
|
"additionalProperties": false,
|
|
733
996
|
"properties": {
|
|
734
997
|
"supported": {
|
|
@@ -739,78 +1002,111 @@
|
|
|
739
1002
|
},
|
|
740
1003
|
"multiAgent": {
|
|
741
1004
|
"type": "object",
|
|
742
|
-
"description": "RFC 0037
|
|
1005
|
+
"description": "RFC 0037 \u2014 Multi-agent execution model + handoff state machine. Hosts that advertise implement the supervisor\u2192dispatch\u2192harvest loop + the 4-state handoff state machine + the `core.workflowChain.event` emission contract per spec/v1/multi-agent-execution.md. Absent block = host implements RFCs 0006/0007/0022 individually with implementation flexibility on integration semantics; conformance scenarios gating on this flag soft-skip on absence.",
|
|
743
1006
|
"additionalProperties": false,
|
|
744
1007
|
"properties": {
|
|
745
1008
|
"executionModel": {
|
|
746
1009
|
"type": "object",
|
|
747
1010
|
"additionalProperties": false,
|
|
748
|
-
"required": [
|
|
1011
|
+
"required": [
|
|
1012
|
+
"supported",
|
|
1013
|
+
"version"
|
|
1014
|
+
],
|
|
749
1015
|
"if": {
|
|
750
|
-
"properties": {
|
|
751
|
-
|
|
1016
|
+
"properties": {
|
|
1017
|
+
"tier": {
|
|
1018
|
+
"const": "experimental"
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
"required": [
|
|
1022
|
+
"tier"
|
|
1023
|
+
]
|
|
752
1024
|
},
|
|
753
1025
|
"then": {
|
|
754
|
-
"required": [
|
|
1026
|
+
"required": [
|
|
1027
|
+
"experimentalUntil"
|
|
1028
|
+
]
|
|
755
1029
|
},
|
|
756
1030
|
"properties": {
|
|
757
1031
|
"supported": {
|
|
758
1032
|
"type": "boolean",
|
|
759
|
-
"description": "Host implements the execution loop + handoff state machine per spec/v1/multi-agent-execution.md
|
|
1033
|
+
"description": "Host implements the execution loop + handoff state machine per spec/v1/multi-agent-execution.md \u00a7\"Execution loop\" + \u00a7\"Handoff state machine\". When true, the host MUST emit `core.workflowChain.event` records on every handoff transition per the \u00a7\"Transition events\" table."
|
|
760
1034
|
},
|
|
761
1035
|
"tier": {
|
|
762
1036
|
"type": "string",
|
|
763
|
-
"enum": [
|
|
1037
|
+
"enum": [
|
|
1038
|
+
"stable",
|
|
1039
|
+
"experimental"
|
|
1040
|
+
],
|
|
764
1041
|
"default": "stable",
|
|
765
|
-
"description": "RFC 0042
|
|
1042
|
+
"description": "RFC 0042 \u2014 stability claim for this capability advertisement. `stable` (the default when absent) means the host commits to the wire shape across v1.x minors. `experimental` means the host advertises the surface as a preview; the wire shape MAY shift compatibly without notice until the underlying RFC graduates to `Accepted` and the host re-advertises as `stable`. Hosts MUST omit the field for capabilities whose underlying RFC is already `Accepted`."
|
|
766
1043
|
},
|
|
767
1044
|
"experimentalUntil": {
|
|
768
1045
|
"type": "string",
|
|
769
1046
|
"format": "date",
|
|
770
1047
|
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
|
|
771
|
-
"description": "RFC 0042
|
|
1048
|
+
"description": "RFC 0042 \u00a7B \u2014 required when `tier` is `experimental`. ISO-8601 `YYYY-MM-DD` no more than 12 months past the discovery response date. Reaching this date without graduating the underlying RFC to `Accepted` MUST result in the host either flipping tier to `stable` OR retracting the capability advertisement (or \u2014 with an open deprecation RFC \u2014 extending with a new `experimentalUntil` per \u00a7B sub-block 2)."
|
|
772
1049
|
},
|
|
773
1050
|
"version": {
|
|
774
1051
|
"type": "integer",
|
|
775
1052
|
"minimum": 1,
|
|
776
1053
|
"maximum": 6,
|
|
777
|
-
"description": "Profile version. 1 = Phase 1 (execution-loop framework + planner
|
|
1054
|
+
"description": "Profile version. 1 = Phase 1 (execution-loop framework + planner\u2192worker handoff). 2 = Phase 2 (confidence-floor escalation + agent-memory lifecycle, RFC 0039). 3 = Phase 3 (cross-host causation, RFC 0040). 4 = Phase 4 (replay determinism under nondeterministic models, RFC 0041). 5 = Phase 5 (stateful agent-loop lifecycle \u2014 per-iteration workspace+memory snapshot inputs, the observable `iteration` counter on `runOrchestrator.decided`, and stateful HITL resume, RFC 0061). 6 = Phase 6 (verifier/critic turn \u2014 the `agent.verified` event + `successCriteria` on the `terminate` decision, RFC 0090). A host advertising `version: N` MUST implement all phases 1..N additively."
|
|
778
1055
|
},
|
|
779
1056
|
"verifier": {
|
|
780
1057
|
"type": "object",
|
|
781
1058
|
"additionalProperties": false,
|
|
782
|
-
"required": [
|
|
783
|
-
|
|
1059
|
+
"required": [
|
|
1060
|
+
"supported"
|
|
1061
|
+
],
|
|
1062
|
+
"description": "RFC 0090 (`version >= 6`). The verifier/critic turn: the host emits `agent.verified` over a prior result and (optionally) gates commit on the verdict. Absent \u21d2 no verifier turn; conformance scenarios soft-skip.",
|
|
784
1063
|
"properties": {
|
|
785
|
-
"supported": {
|
|
786
|
-
|
|
1064
|
+
"supported": {
|
|
1065
|
+
"type": "boolean",
|
|
1066
|
+
"description": "Host emits `agent.verified` and honors RFC 0090 \u00a7A. Applies only when `version >= 6`."
|
|
1067
|
+
},
|
|
1068
|
+
"gating": {
|
|
1069
|
+
"type": "boolean",
|
|
1070
|
+
"description": "Host enforces the RFC 0090 \u00a7B commit-gating contract: a `fail` verdict blocks merge/terminate (fail-closed, composing RFC 0063); `revise` routes back to an actor turn. Absent/false \u21d2 the verdict is observability-only."
|
|
1071
|
+
}
|
|
787
1072
|
}
|
|
788
1073
|
},
|
|
789
1074
|
"confidenceEscalationFloor": {
|
|
790
1075
|
"type": "number",
|
|
791
1076
|
"minimum": 0.5,
|
|
792
1077
|
"maximum": 1.0,
|
|
793
|
-
"description": "RFC 0039
|
|
1078
|
+
"description": "RFC 0039 \u00a7A. Operator-declared confidence floor at or above the spec floor of 0.5; when an OrchestratorDecision carries `confidence` below this floor, the host MUST escalate via a `clarify` or `escalate` interrupt instead of executing the decision. Absent: the spec floor 0.5 applies. Values < 0.5 are non-conformant; values > 1.0 are nonsense. Applies only when `version >= 2`."
|
|
794
1079
|
},
|
|
795
1080
|
"confidenceEscalationInterruptKind": {
|
|
796
1081
|
"type": "string",
|
|
797
1082
|
"anyOf": [
|
|
798
|
-
{
|
|
799
|
-
|
|
800
|
-
|
|
1083
|
+
{
|
|
1084
|
+
"const": "clarification"
|
|
1085
|
+
},
|
|
1086
|
+
{
|
|
1087
|
+
"const": "approval"
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
"pattern": "^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$"
|
|
1091
|
+
}
|
|
801
1092
|
],
|
|
802
|
-
"description": "RFC 0044
|
|
1093
|
+
"description": "RFC 0044 \u2014 the literal `interrupt.kind` the host emits when escalating a below-floor confidence decision per RFC 0039 \u00a7A. `clarification` and `approval` are the canonical values matching the clarify-OR-approval choice in RFC 0039 \u00a7A; vendor-extension kinds use the canonical host-extension namespace `^x-host-<host>-<kind>$` per `spec/v1/host-extensions.md` \u00a7\"Canonical prefixes\". When advertised, hosts MUST emit an interrupt of the advertised kind on every confidence-escalation event AND the host's downstream `interrupt.md` mapping determines the `waiting-*` terminal status. Absent: conformance assumes the host uses one of the two canonical kinds (the relaxed assertion accepts either). Hosts using vendor kinds MUST also publish a non-normative kind-mapping document per RFC 0044 \u00a7C."
|
|
803
1094
|
},
|
|
804
1095
|
"crossChildMemoryConcurrency": {
|
|
805
1096
|
"type": "string",
|
|
806
|
-
"enum": [
|
|
807
|
-
|
|
1097
|
+
"enum": [
|
|
1098
|
+
"strict",
|
|
1099
|
+
"advisory"
|
|
1100
|
+
],
|
|
1101
|
+
"description": "RFC 0039 \u00a7B. Cross-child memory-write concurrency posture when version >= 2. `strict` (default when absent): the host serializes concurrent writes from sibling dispatched children to the parent's shared memory scope. `advisory`: the host opts out of the serialization MUST and documents last-write-wins semantics out-of-band. Hosts that choose advisory SHOULD also advertise their resolution rule under `crossChildMemoryConcurrencyResolution` (reserved field; follow-up clarification)."
|
|
808
1102
|
},
|
|
809
1103
|
"crossHostCausation": {
|
|
810
1104
|
"type": "object",
|
|
811
|
-
"description": "RFC 0040
|
|
1105
|
+
"description": "RFC 0040 \u00a7D \u2014 Phase 3 cross-host causation linking. When advertised, the host honors the cross-host `causationId` extension (a `causationHostId` field on event payloads pointing at the originating host), W3C `traceparent` propagation across MCP + A2A composition boundaries, and (when `ancestryEndpointSupported: true`) the `GET /v1/runs/{runId}/ancestry` cross-host parent-chain endpoint. Hosts advertising `version: 3` MUST advertise this sub-block with `supported: true` and a stable `hostId`.",
|
|
812
1106
|
"additionalProperties": false,
|
|
813
|
-
"required": [
|
|
1107
|
+
"required": [
|
|
1108
|
+
"supported"
|
|
1109
|
+
],
|
|
814
1110
|
"properties": {
|
|
815
1111
|
"supported": {
|
|
816
1112
|
"type": "boolean",
|
|
@@ -823,15 +1119,17 @@
|
|
|
823
1119
|
},
|
|
824
1120
|
"ancestryEndpointSupported": {
|
|
825
1121
|
"type": "boolean",
|
|
826
|
-
"description": "Host serves `GET /v1/runs/{runId}/ancestry` returning the cross-host parent chain per RFC 0040
|
|
1122
|
+
"description": "Host serves `GET /v1/runs/{runId}/ancestry` returning the cross-host parent chain per RFC 0040 \u00a7C. Optional even when crossHostCausation.supported is true \u2014 hosts that emit `causationHostId` but don't expose the ancestry-walking endpoint still satisfy the per-event chaining contract; this flag advertises the additional endpoint."
|
|
827
1123
|
}
|
|
828
1124
|
}
|
|
829
1125
|
},
|
|
830
1126
|
"replayDeterminism": {
|
|
831
1127
|
"type": "object",
|
|
832
|
-
"description": "RFC 0041
|
|
1128
|
+
"description": "RFC 0041 \u00a7D \u2014 Phase 4 replay determinism. When advertised, the host honors the LLM cache-key recipe in `replay.md` \u00a7\"LLM cache-key recipe\" as NORMATIVE (graduated from informative for version >= 4), emits `replay.divergedAtRefusal` events + fails with `replay_diverged_at_refusal` on refusal-divergence (RFC 0041 \u00a7B), and guarantees observable-output-sequence determinism per RFC 0041 \u00a7C. Hosts advertising `version: 4` MUST advertise this sub-block with `supported: true`.",
|
|
833
1129
|
"additionalProperties": false,
|
|
834
|
-
"required": [
|
|
1130
|
+
"required": [
|
|
1131
|
+
"supported"
|
|
1132
|
+
],
|
|
835
1133
|
"properties": {
|
|
836
1134
|
"supported": {
|
|
837
1135
|
"type": "boolean",
|
|
@@ -840,45 +1138,56 @@
|
|
|
840
1138
|
"llmCacheKeyRecipe": {
|
|
841
1139
|
"type": "string",
|
|
842
1140
|
"anyOf": [
|
|
843
|
-
{
|
|
844
|
-
|
|
1141
|
+
{
|
|
1142
|
+
"const": "spec-rfc-0041"
|
|
1143
|
+
},
|
|
1144
|
+
{
|
|
1145
|
+
"pattern": "^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$"
|
|
1146
|
+
}
|
|
845
1147
|
],
|
|
846
|
-
"description": "The LLM cache-key recipe the host honors. `spec-rfc-0041` = the canonical recipe in `replay.md`
|
|
1148
|
+
"description": "The LLM cache-key recipe the host honors. `spec-rfc-0041` = the canonical recipe in `replay.md` \u00a7\"LLM cache-key recipe\" \u00a7A + \u00a7B + \u00a7C. Vendor-specific recipes use the canonical host-extension namespace string matching `^x-host-<host>-<recipe-name>$` per `spec/v1/host-extensions.md` \u00a7\"Canonical prefixes\"; the matching algorithm MUST be documented at the host's discovery doc."
|
|
847
1149
|
},
|
|
848
1150
|
"refusalDivergenceEmission": {
|
|
849
1151
|
"type": "boolean",
|
|
850
|
-
"description": "Host emits `replay.divergedAtRefusal` events + fails replay with `error.code: replay_diverged_at_refusal` per RFC 0041
|
|
1152
|
+
"description": "Host emits `replay.divergedAtRefusal` events + fails replay with `error.code: replay_diverged_at_refusal` per RFC 0041 \u00a7B. Hosts advertising `version: 4` MUST set this to `true`."
|
|
851
1153
|
}
|
|
852
1154
|
}
|
|
853
1155
|
},
|
|
854
1156
|
"statefulResume": {
|
|
855
1157
|
"type": "boolean",
|
|
856
|
-
"description": "RFC 0061 (`version >= 5`). When `true`, a `clarify`/`escalate` HITL suspend resumes the execution loop at the SAME iteration
|
|
1158
|
+
"description": "RFC 0061 (`version >= 5`). When `true`, a `clarify`/`escalate` HITL suspend resumes the execution loop at the SAME iteration \u2014 the `runOrchestrator.decided.iteration` counter does not reset or skip \u2014 with the per-iteration memory (RFC 0039 MAE-3) + workspace (RFC 0059) snapshot lineage intact, so a mid-loop human interrupt does not lose progress. A distinct claim from plain replay re-entrancy (deterministic replay of a completed prefix); this is about a LIVE suspend preserving the counter. Omitted by hosts on `version < 5`."
|
|
857
1159
|
},
|
|
858
1160
|
"transcriptWindow": {
|
|
859
1161
|
"type": "integer",
|
|
860
1162
|
"minimum": 1,
|
|
861
|
-
"description": "RFC 0061 (`version >= 5`). Host-advertised count of recent event-log entries the host feeds each orchestrator turn as the iteration's transcript input (
|
|
1163
|
+
"description": "RFC 0061 (`version >= 5`). Host-advertised count of recent event-log entries the host feeds each orchestrator turn as the iteration's transcript input (\u00a7C input 3). Advertise-and-honor; not a fixed wire constant. Absent \u21d2 the host does not bound the transcript window on the wire."
|
|
862
1164
|
},
|
|
863
1165
|
"contextBudget": {
|
|
864
1166
|
"type": "object",
|
|
865
|
-
"description": "RFC 0111 (`Active`, `version >= 5`). Opt-in, token-denominated bound on the orchestrator transcript the host feeds each iteration, plus a declared summarization contract for turns evicted beyond that budget. SCOPE: governs the RFC 0061 per-iteration ORCHESTRATOR-LOOP transcript (`multi-agent-execution.md`
|
|
1167
|
+
"description": "RFC 0111 (`Active`, `version >= 5`). Opt-in, token-denominated bound on the orchestrator transcript the host feeds each iteration, plus a declared summarization contract for turns evicted beyond that budget. SCOPE: governs the RFC 0061 per-iteration ORCHESTRATOR-LOOP transcript (`multi-agent-execution.md` \u00a7\"Per-iteration state inputs\" input 3 \u2014 the same transcript `transcriptWindow` bounds), NOT a general chat-conversation history. A host whose orchestrator loop does not run real model turns (e.g. a mock supervisor) MUST NOT advertise this block, exactly as it MUST NOT dishonestly advertise `transcriptWindow`. Budget-only advertisement (`transcriptTokenBudget` + `tokenCounter` WITHOUT `summarization.supported`) is valid for a host that HAS a real orchestrator loop but does not summarize. Purely additive: a host that omits this block behaves exactly as today, including `transcriptWindow`'s `absent \u21d2 unbounded` default (NOT flipped by this RFC). Complements (does not replace) the event-count `transcriptWindow`; when both bound a turn the host MUST honor whichever is tighter. Summarization here is a NONDETERMINISTIC host output governed exactly like an RFC 0041 envelope: each substitution MUST be recorded as a `context.summarized` event whose `summaryRef` artifact replay reuses (never re-summarizes) per `multi-agent-execution.md` \u00a7\"Context economy (RFC 0111)\".",
|
|
866
1168
|
"additionalProperties": false,
|
|
867
1169
|
"properties": {
|
|
868
1170
|
"transcriptTokenBudget": {
|
|
869
1171
|
"type": "integer",
|
|
870
1172
|
"minimum": 1,
|
|
871
|
-
"description": "RFC 0111. Max tokens of transcript the host feeds any single orchestrator turn, measured in the unit named by `tokenCounter`. Advertise-and-honor; complements (does not replace) `transcriptWindow`. When both are present the host MUST honor whichever bound is tighter for a given turn. Absent
|
|
1173
|
+
"description": "RFC 0111. Max tokens of transcript the host feeds any single orchestrator turn, measured in the unit named by `tokenCounter`. Advertise-and-honor; complements (does not replace) `transcriptWindow`. When both are present the host MUST honor whichever bound is tighter for a given turn. Absent \u21d2 no token bound on the transcript (only the event-count `transcriptWindow`, if any, applies)."
|
|
872
1174
|
},
|
|
873
1175
|
"tokenCounter": {
|
|
874
1176
|
"type": "string",
|
|
875
|
-
"enum": [
|
|
876
|
-
|
|
1177
|
+
"enum": [
|
|
1178
|
+
"o200k_base",
|
|
1179
|
+
"cl100k_base",
|
|
1180
|
+
"chars",
|
|
1181
|
+
"host-defined"
|
|
1182
|
+
],
|
|
1183
|
+
"description": "RFC 0111. The unit `transcriptTokenBudget` is denominated in, so the bound is interpretable across hosts. REQUIRED when `transcriptTokenBudget` is present (enforced via the `if/then` clause). `o200k_base`/`cl100k_base` are tokenizer encodings; `chars` counts UTF-8/Unicode characters (a tokenizer-free unit a client can reason about directly); `host-defined` is an opaque host unit. Same enum as RFC 0113 `memory.injectionBudget.tokenCounter` \u2014 transcript (0111) and memory (0113) budgets denominate in one consistent vocabulary; no shared `$ref` (decoupled)."
|
|
877
1184
|
},
|
|
878
1185
|
"summarization": {
|
|
879
1186
|
"type": "object",
|
|
880
1187
|
"additionalProperties": false,
|
|
881
|
-
"required": [
|
|
1188
|
+
"required": [
|
|
1189
|
+
"supported"
|
|
1190
|
+
],
|
|
882
1191
|
"description": "RFC 0111. Declared contract for turns evicted beyond `transcriptTokenBudget`. When `supported: true`, the host MAY replace older in-window turns with a host-produced summary; it MUST keep the most recent `keepLastTurns` turns verbatim and MUST NOT summarize the active (most recent) turn. Each substitution MUST be recorded as a `context.summarized` event and is replay-governed under RFC 0041 (replay reuses the recorded `summaryRef`, never re-summarizes).",
|
|
883
1192
|
"properties": {
|
|
884
1193
|
"supported": {
|
|
@@ -887,19 +1196,32 @@
|
|
|
887
1196
|
},
|
|
888
1197
|
"strategy": {
|
|
889
1198
|
"type": "string",
|
|
890
|
-
"enum": [
|
|
891
|
-
|
|
1199
|
+
"enum": [
|
|
1200
|
+
"sliding-window",
|
|
1201
|
+
"recursive",
|
|
1202
|
+
"map-reduce"
|
|
1203
|
+
],
|
|
1204
|
+
"description": "RFC 0111. Informational descriptor of the host's summarization strategy. `sliding-window` keeps a recent verbatim tail and summarizes the prefix; `recursive` folds prior summaries into new ones; `map-reduce` summarizes chunks then combines. Does not change the replay-determinism contract \u2014 all strategies record `context.summarized` and reuse `summaryRef` on replay."
|
|
892
1205
|
},
|
|
893
1206
|
"keepLastTurns": {
|
|
894
1207
|
"type": "integer",
|
|
895
1208
|
"minimum": 0,
|
|
896
|
-
"description": "RFC 0111. Number of most-recent turns kept verbatim at the head of the window; older in-window turns MAY be replaced by a summary. The active (most recent) turn MUST NOT be summarized regardless of this value. Absent
|
|
1209
|
+
"description": "RFC 0111. Number of most-recent turns kept verbatim at the head of the window; older in-window turns MAY be replaced by a summary. The active (most recent) turn MUST NOT be summarized regardless of this value. Absent \u21d2 host-defined verbatim floor."
|
|
897
1210
|
}
|
|
898
1211
|
}
|
|
899
1212
|
}
|
|
900
1213
|
},
|
|
901
|
-
"if": {
|
|
902
|
-
|
|
1214
|
+
"if": {
|
|
1215
|
+
"required": [
|
|
1216
|
+
"transcriptTokenBudget"
|
|
1217
|
+
]
|
|
1218
|
+
},
|
|
1219
|
+
"then": {
|
|
1220
|
+
"required": [
|
|
1221
|
+
"transcriptTokenBudget",
|
|
1222
|
+
"tokenCounter"
|
|
1223
|
+
]
|
|
1224
|
+
}
|
|
903
1225
|
}
|
|
904
1226
|
}
|
|
905
1227
|
}
|
|
@@ -907,13 +1229,15 @@
|
|
|
907
1229
|
},
|
|
908
1230
|
"modelCapabilities": {
|
|
909
1231
|
"type": "object",
|
|
910
|
-
"description": "RFC 0031. Host implements model-capability gating + (optional) substitution per `NodeModule.requiredModelCapabilities` + `NodeModule.fallbackModel`. Distinct from `runtimeCapabilities` which gates on HOST capabilities
|
|
1232
|
+
"description": "RFC 0031. Host implements model-capability gating + (optional) substitution per `NodeModule.requiredModelCapabilities` + `NodeModule.fallbackModel`. Distinct from `runtimeCapabilities` which gates on HOST capabilities \u2014 `modelCapabilities` gates on MODEL capabilities (structured-output support, discriminator-enum support, long-context, native reasoning, function-calling). Absent block = no advertisement; NodeModules' `requiredModelCapabilities` are treated as opaque metadata and dispatch proceeds without checks.",
|
|
911
1233
|
"additionalProperties": false,
|
|
912
|
-
"required": [
|
|
1234
|
+
"required": [
|
|
1235
|
+
"supported"
|
|
1236
|
+
],
|
|
913
1237
|
"properties": {
|
|
914
1238
|
"supported": {
|
|
915
1239
|
"type": "boolean",
|
|
916
|
-
"description": "Host honors `NodeModule.requiredModelCapabilities` and emits `model.capability.substituted` / `model.capability.insufficient` events per RFC 0031
|
|
1240
|
+
"description": "Host honors `NodeModule.requiredModelCapabilities` and emits `model.capability.substituted` / `model.capability.insufficient` events per RFC 0031 \u00a7B + \u00a7D. When `false` or absent, the fields are treated as opaque metadata and dispatch proceeds without capability checks."
|
|
917
1241
|
},
|
|
918
1242
|
"advertised": {
|
|
919
1243
|
"type": "array",
|
|
@@ -922,23 +1246,35 @@
|
|
|
922
1246
|
"pattern": "^([a-z][a-z0-9-]*|x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*)$"
|
|
923
1247
|
},
|
|
924
1248
|
"uniqueItems": true,
|
|
925
|
-
"description": "Capability identifiers the host's active model advertises. Clients MAY introspect this at install time to determine whether their NodeModules' `requiredModelCapabilities` are satisfiable without fallback. Spec-reserved identifiers per RFC 0031
|
|
1249
|
+
"description": "Capability identifiers the host's active model advertises. Clients MAY introspect this at install time to determine whether their NodeModules' `requiredModelCapabilities` are satisfiable without fallback. Spec-reserved identifiers per RFC 0031 \u00a7C + RFC 0055: `structured-output`, `discriminator-enum`, `long-context`, `reasoning` (model-native thinking-tokens), `function-calling`, `vision-input` (model accepts image content in the prompt), `audio-input` (model accepts audio content), `audio-output` (model emits audio content), `image-output` (model emits images directly in its completion, distinct from the host-side `aiProviders.imageGeneration` tool surface). This is an open, pattern-validated registry \u2014 NOT a closed enum; growth requires an RFC. Host-private extensions MUST prefix with `x-host-<host>-`."
|
|
926
1250
|
},
|
|
927
1251
|
"substitutionSupported": {
|
|
928
1252
|
"type": "boolean",
|
|
929
|
-
"description": "Host honors `NodeModule.fallbackModel` substitution per RFC 0031
|
|
1253
|
+
"description": "Host honors `NodeModule.fallbackModel` substitution per RFC 0031 \u00a7B step 3. When `false` or absent, hosts MUST refuse to dispatch (step 4) on any unmet capability \u2014 they MUST NOT attempt fallback even when the field is declared on the NodeModule. Recursive fallback is NOT permitted (RFC 0031 \u00a7\"Unresolved questions\" #3)."
|
|
930
1254
|
}
|
|
931
1255
|
}
|
|
932
1256
|
},
|
|
933
1257
|
"providerUsage": {
|
|
934
1258
|
"type": "object",
|
|
935
|
-
"description": "RFC 0026. Hosts that emit `provider.usage` events after every LLM provider invocation per RFC 0026
|
|
1259
|
+
"description": "RFC 0026. Hosts that emit `provider.usage` events after every LLM provider invocation per RFC 0026 \u00a7B. The event carries per-call token counts in the durable event log; cost rollup remains in `RunSnapshot.metrics.openwopCost`. Old hosts ignore.",
|
|
936
1260
|
"properties": {
|
|
937
|
-
"supported": {
|
|
938
|
-
|
|
939
|
-
|
|
1261
|
+
"supported": {
|
|
1262
|
+
"type": "boolean",
|
|
1263
|
+
"description": "Host emits one `provider.usage` event per LLM provider call."
|
|
1264
|
+
},
|
|
1265
|
+
"costEstimates": {
|
|
1266
|
+
"type": "boolean",
|
|
1267
|
+
"description": "When true, the host includes `costEstimateUsd` on `provider.usage` events using its internal rate table. When false/absent, only token counts are emitted."
|
|
1268
|
+
},
|
|
1269
|
+
"currency": {
|
|
1270
|
+
"type": "string",
|
|
1271
|
+
"pattern": "^[A-Z]{3}$",
|
|
1272
|
+
"description": "Default ISO 4217 currency for `costEstimateUsd` values. When absent, USD is assumed."
|
|
1273
|
+
}
|
|
940
1274
|
},
|
|
941
|
-
"required": [
|
|
1275
|
+
"required": [
|
|
1276
|
+
"supported"
|
|
1277
|
+
],
|
|
942
1278
|
"additionalProperties": false
|
|
943
1279
|
},
|
|
944
1280
|
"aiProviders": {
|
|
@@ -947,67 +1283,107 @@
|
|
|
947
1283
|
"properties": {
|
|
948
1284
|
"supported": {
|
|
949
1285
|
"type": "array",
|
|
950
|
-
"items": {
|
|
1286
|
+
"items": {
|
|
1287
|
+
"type": "string",
|
|
1288
|
+
"minLength": 1
|
|
1289
|
+
},
|
|
951
1290
|
"uniqueItems": true,
|
|
952
|
-
"description": "Provider ids the host's AI-proxy can route to. Conventional ids (RFC 0067
|
|
1291
|
+
"description": "Provider ids the host's AI-proxy can route to. Conventional ids (RFC 0067 \u00a7C recommended vocabulary \u2014 advisory, not a closed set): `anthropic`, `openai`, `gemini`, `vertex`, `bedrock`, `mistral`, `cohere`, `openrouter`, `litellm`, `together`, `huggingface`, `qwen`, `ollama`, `vllm`. Hosts MAY add vendor-prefixed extensions; clients MUST tolerate unknown ids."
|
|
953
1292
|
},
|
|
954
1293
|
"byok": {
|
|
955
1294
|
"type": "array",
|
|
956
|
-
"items": {
|
|
1295
|
+
"items": {
|
|
1296
|
+
"type": "string",
|
|
1297
|
+
"minLength": 1
|
|
1298
|
+
},
|
|
957
1299
|
"uniqueItems": true,
|
|
958
|
-
"description": "Subset of `supported` for which BYOK is permitted. Empty array
|
|
1300
|
+
"description": "Subset of `supported` for which BYOK is permitted. Empty array \u2192 all calls use platform-managed keys; non-empty \u2192 clients MAY pass `ai.credentialRef` in `RunOptions.configurable` for matching providers."
|
|
959
1301
|
},
|
|
960
1302
|
"selfHosted": {
|
|
961
1303
|
"type": "array",
|
|
962
|
-
"items": {
|
|
1304
|
+
"items": {
|
|
1305
|
+
"type": "string",
|
|
1306
|
+
"minLength": 1
|
|
1307
|
+
},
|
|
963
1308
|
"uniqueItems": true,
|
|
964
|
-
"description": "RFC 0108. Subset of `supported` whose entries are operator- or tenant-configured OpenAI-compatible endpoints (e.g. an Ollama / vLLM / LM Studio / any `/v1/chat/completions`-compatible server), as opposed to a host-managed connection to a known public vendor. Each entry MUST also appear in `supported`. An entry MAY also appear in `byok` (the endpoint requires a client/tenant-supplied key) or be absent from it (the endpoint needs no key, e.g. a default Ollama). The provider id is an OPAQUE label chosen by the host; it MUST NOT encode the endpoint's network location (scheme, host, port, path, or base-URL) per RFC 0108
|
|
1309
|
+
"description": "RFC 0108. Subset of `supported` whose entries are operator- or tenant-configured OpenAI-compatible endpoints (e.g. an Ollama / vLLM / LM Studio / any `/v1/chat/completions`-compatible server), as opposed to a host-managed connection to a known public vendor. Each entry MUST also appear in `supported`. An entry MAY also appear in `byok` (the endpoint requires a client/tenant-supplied key) or be absent from it (the endpoint needs no key, e.g. a default Ollama). The provider id is an OPAQUE label chosen by the host; it MUST NOT encode the endpoint's network location (scheme, host, port, path, or base-URL) per RFC 0108 \u00a7A.3, and the endpoint location MUST NOT be disclosed on any wire surface (see the `self-hosted-endpoint-no-disclosure` SECURITY invariant). A client MUST NOT infer model capabilities from a `selfHosted` id (RFC 0108 \u00a7B); the only authoritative capability sources are `modelCapabilities.advertised[]` (RFC 0031) and `aiProviders.input.modalities` (RFC 0091)."
|
|
965
1310
|
},
|
|
966
1311
|
"speechSynthesis": {
|
|
967
1312
|
"const": "supported",
|
|
968
|
-
"description": "RFC 0105. When present (value MUST be the string `\"supported\"`), the host exposes `ctx.callSpeechSynthesizer({ text, voiceId, mimeType?, format?, languageCode?, ... })` returning a binary audio asset (host-served `url` OR inline `base64` + `mimeType`), paralleling `aiProviders.imageGeneration`. Absent
|
|
1313
|
+
"description": "RFC 0105. When present (value MUST be the string `\"supported\"`), the host exposes `ctx.callSpeechSynthesizer({ text, voiceId, mimeType?, format?, languageCode?, ... })` returning a binary audio asset (host-served `url` OR inline `base64` + `mimeType`), paralleling `aiProviders.imageGeneration`. Absent \u21d2 no TTS; a call MUST be rejected with `speech_synthesis_unsupported` (never a no-op). Voices are referenced by an opaque host-resolved `voiceId`; the spec does NOT enumerate voices. TTS provider ids are advertised via the existing `aiProviders.supported[]` (the call's `provider?` MUST be a member); there is no `speechSynthesis` sub-field for providers. Per-host model/voice routing is a host choice."
|
|
969
1314
|
},
|
|
970
1315
|
"input": {
|
|
971
1316
|
"type": "object",
|
|
972
1317
|
"additionalProperties": false,
|
|
973
|
-
"description": "RFC 0091. Multimodal PERCEPTION input on `ctx.callAI`
|
|
1318
|
+
"description": "RFC 0091. Multimodal PERCEPTION input on `ctx.callAI` \u2014 the modalities a `callAI` message ContentPart may carry as model INPUT. Absent \u21d2 text-only (today's behavior); a `string` message content is always valid. Distinct from `imageGeneration` (output) and the `ai-envelope.md` media emission types (output).",
|
|
974
1319
|
"properties": {
|
|
975
1320
|
"modalities": {
|
|
976
1321
|
"type": "array",
|
|
977
1322
|
"uniqueItems": true,
|
|
978
|
-
"items": {
|
|
1323
|
+
"items": {
|
|
1324
|
+
"type": "string",
|
|
1325
|
+
"enum": [
|
|
1326
|
+
"text",
|
|
1327
|
+
"image",
|
|
1328
|
+
"audio",
|
|
1329
|
+
"document"
|
|
1330
|
+
]
|
|
1331
|
+
},
|
|
979
1332
|
"description": "Input modalities the host's `callAI` accepts as ContentParts. `text` is implicit even when omitted. A ContentPart whose `type` is not advertised here MUST be rejected with `unsupported_modality` (never silently dropped)."
|
|
980
1333
|
},
|
|
981
|
-
"maxBytesPerPart": {
|
|
1334
|
+
"maxBytesPerPart": {
|
|
1335
|
+
"type": "integer",
|
|
1336
|
+
"minimum": 1,
|
|
1337
|
+
"description": "Optional host cap on a single inline (`data`) or `mediaRef` part."
|
|
1338
|
+
}
|
|
982
1339
|
}
|
|
983
1340
|
},
|
|
984
1341
|
"authModes": {
|
|
985
1342
|
"type": "object",
|
|
986
|
-
"description": "RFC 0067 (`Active`), extended by RFC 0121 (`Active`). Optional per-provider advertisement of HOW the host expects a provider's credential to be supplied. Keys are provider ids appearing in `supported`; values are the auth modes the host honors for that provider. Absent
|
|
1343
|
+
"description": "RFC 0067 (`Active`), extended by RFC 0121 (`Active`). Optional per-provider advertisement of HOW the host expects a provider's credential to be supplied. Keys are provider ids appearing in `supported`; values are the auth modes the host honors for that provider. Absent \u21d2 no advertisement: a provider in `byok` defaults to `apiKey` semantics (client passes `ai.credentialRef`); a provider in `supported` but not in `byok` defaults to `none` (platform-managed). This map only DESCRIBES the supply mechanism \u2014 `oauth-pkce`/`oauth-device` flow mechanics compose RFC 0047 `host.oauth` and resolve credentials by `ref` (RFC 0046), never on `ai.credentialRef`. A provider with `apiKey` MUST appear in `byok`; a provider whose modes are exactly `[\"none\"]` MUST NOT appear in `byok`. `subscription` (RFC 0121) advertises that a provider credential may be supplied by reusing the caller's existing personal, non-metered consumer subscription (e.g. Claude Pro/Max, ChatGPT Plus) rather than a metered API key; a `subscription` provider MUST appear in `byok`, is referenced by `ref` (RFC 0046) like the `oauth-*` modes (never on `ai.credentialRef`), and its credential MUST bind at `host.credentials` `scope:\"user\"` \u2014 never tenant/workspace-shared (SECURITY invariant `subscription-credential-user-scope-only`). Consumers MUST ignore an auth mode they don't recognize rather than reject the discovery doc.",
|
|
987
1344
|
"additionalProperties": {
|
|
988
1345
|
"type": "array",
|
|
989
1346
|
"minItems": 1,
|
|
990
1347
|
"uniqueItems": true,
|
|
991
1348
|
"items": {
|
|
992
1349
|
"type": "string",
|
|
993
|
-
"enum": [
|
|
1350
|
+
"enum": [
|
|
1351
|
+
"apiKey",
|
|
1352
|
+
"oauth-pkce",
|
|
1353
|
+
"oauth-device",
|
|
1354
|
+
"none",
|
|
1355
|
+
"subscription"
|
|
1356
|
+
]
|
|
994
1357
|
}
|
|
995
1358
|
}
|
|
996
1359
|
},
|
|
997
1360
|
"policies": {
|
|
998
1361
|
"type": "object",
|
|
999
|
-
"description": "Optional v1 host-side policy enforcement modes for per-provider gating. Omitted
|
|
1000
|
-
"required": [
|
|
1362
|
+
"description": "Optional v1 host-side policy enforcement modes for per-provider gating. Omitted \u2192 no enforcement; clients see only `optional` semantics. When present, MUST declare `modes` \u2014 an empty `{}` is not a valid third state. See `capabilities.md` \u00a7`aiProviders.policies`.",
|
|
1363
|
+
"required": [
|
|
1364
|
+
"modes"
|
|
1365
|
+
],
|
|
1001
1366
|
"properties": {
|
|
1002
1367
|
"modes": {
|
|
1003
1368
|
"type": "array",
|
|
1004
|
-
"items": {
|
|
1369
|
+
"items": {
|
|
1370
|
+
"type": "string",
|
|
1371
|
+
"enum": [
|
|
1372
|
+
"disabled",
|
|
1373
|
+
"optional",
|
|
1374
|
+
"required",
|
|
1375
|
+
"restricted"
|
|
1376
|
+
]
|
|
1377
|
+
},
|
|
1005
1378
|
"uniqueItems": true,
|
|
1006
1379
|
"description": "Subset of policy modes this host can enforce. `disabled` = provider may not be used; `optional` = no restriction (default); `required` = BYOK required; `restricted` = model must match the policy's `allowedModels` glob list. Hosts MAY support a subset; clients MUST tolerate any subset."
|
|
1007
1380
|
},
|
|
1008
1381
|
"scopes": {
|
|
1009
1382
|
"type": "array",
|
|
1010
|
-
"items": {
|
|
1383
|
+
"items": {
|
|
1384
|
+
"type": "string",
|
|
1385
|
+
"minLength": 1
|
|
1386
|
+
},
|
|
1011
1387
|
"uniqueItems": true,
|
|
1012
1388
|
"description": "Resolution layers the host evaluates. Conventional ids: `workspace`, `project`, `canvas-type`. Precedence is host-defined and SHOULD be documented per-deployment."
|
|
1013
1389
|
},
|
|
@@ -1023,12 +1399,12 @@
|
|
|
1023
1399
|
"type": "integer",
|
|
1024
1400
|
"minimum": 0,
|
|
1025
1401
|
"default": 262144,
|
|
1026
|
-
"description": "RFC 0055
|
|
1402
|
+
"description": "RFC 0055 \u00a7C rule 2 \u2014 optional cap (bytes) on inline base64 in `media.*` envelope payloads. A `media.{image,audio,file}` asset above this size MUST be served by a tenant-scoped `url` reference rather than inlined (bounds event-log + replay-payload size). Default 256 KiB (262144) when absent. A host MAY set 0 to force URL references for all emitted media."
|
|
1027
1403
|
},
|
|
1028
1404
|
"realtimeVoice": {
|
|
1029
1405
|
"type": "object",
|
|
1030
1406
|
"additionalProperties": false,
|
|
1031
|
-
"description": "RFC 0106. Optional real-time voice profile. Absent
|
|
1407
|
+
"description": "RFC 0106. Optional real-time voice profile. Absent \u21d2 no live voice (a call to `ctx.callTranscriber` MUST be rejected with `transcription_unsupported`, and `stream:true` on `ctx.callSpeechSynthesizer` with `streaming_unsupported`). `ctx.callTranscriber` resolves a `Promise` at `turn_commit` with the settled final transcript and emits the interim/final/endpoint signals as `voice.*` run-events on the durable event log (the single canonical record); the streaming synthesis arm resolves a `Promise` at completion and announces clause-boundary chunks as `voice.synthesis_chunk` metadata run-events (bytes by `streamRef`/`url`, not inlined past the host cap).",
|
|
1032
1408
|
"properties": {
|
|
1033
1409
|
"transcription": {
|
|
1034
1410
|
"const": "streaming",
|
|
@@ -1039,7 +1415,10 @@
|
|
|
1039
1415
|
"description": "When present (value MUST be `\"streaming\"`), the RFC 0105 `ctx.callSpeechSynthesizer` request honors `stream: true` (chunked synthesis). REQUIRES `aiProviders.speechSynthesis: \"supported\"` (enforced by the if/then closure on `aiProviders`)."
|
|
1040
1416
|
},
|
|
1041
1417
|
"turnDetection": {
|
|
1042
|
-
"enum": [
|
|
1418
|
+
"enum": [
|
|
1419
|
+
"vad",
|
|
1420
|
+
"semantic"
|
|
1421
|
+
],
|
|
1043
1422
|
"description": "Endpointing sophistication. `vad` = silence-threshold endpointing only; `semantic` = a turn detector that emits `voice.endpoint_candidate` distinct from `voice.turn_commit`. Requires `transcription`."
|
|
1044
1423
|
},
|
|
1045
1424
|
"bargeIn": {
|
|
@@ -1048,14 +1427,18 @@
|
|
|
1048
1427
|
}
|
|
1049
1428
|
},
|
|
1050
1429
|
"dependentRequired": {
|
|
1051
|
-
"turnDetection": [
|
|
1052
|
-
|
|
1430
|
+
"turnDetection": [
|
|
1431
|
+
"transcription"
|
|
1432
|
+
],
|
|
1433
|
+
"bargeIn": [
|
|
1434
|
+
"transcription"
|
|
1435
|
+
]
|
|
1053
1436
|
}
|
|
1054
1437
|
},
|
|
1055
1438
|
"promptPrefixCache": {
|
|
1056
1439
|
"type": "object",
|
|
1057
1440
|
"additionalProperties": false,
|
|
1058
|
-
"description": "RFC 0116. Host honors the AI-envelope `generate` request's optional `cachePrefixId` as a provider-cache routing hint
|
|
1441
|
+
"description": "RFC 0116. Host honors the AI-envelope `generate` request's optional `cachePrefixId` as a provider-cache routing hint \u2014 tenant-namespaced (SECURITY invariant `prompt-prefix-cache-cross-tenant-isolation`), secret-free, and replay-invariant (a cache hit/miss MUST NOT change the recorded envelope or `provider.usage.inputTokens`/`outputTokens`). Absent \u21d2 a host MUST ignore `cachePrefixId` (no error, no behavior change). PROVIDER-SCOPED: prefix caching is provider-specific (e.g. Anthropic ephemeral), so this is NOT a universal claim \u2014 see `providers`.",
|
|
1059
1442
|
"properties": {
|
|
1060
1443
|
"supported": {
|
|
1061
1444
|
"type": "boolean",
|
|
@@ -1063,26 +1446,42 @@
|
|
|
1063
1446
|
},
|
|
1064
1447
|
"providers": {
|
|
1065
1448
|
"type": "array",
|
|
1066
|
-
"items": {
|
|
1449
|
+
"items": {
|
|
1450
|
+
"type": "string",
|
|
1451
|
+
"minLength": 1
|
|
1452
|
+
},
|
|
1067
1453
|
"uniqueItems": true,
|
|
1068
|
-
"description": "RFC 0116. The subset of `aiProviders.supported[]` for which the host honors `cachePrefixId` (prefix caching is provider-specific). A request whose routed provider is NOT in this list MUST have `cachePrefixId` ignored. Absent
|
|
1454
|
+
"description": "RFC 0116. The subset of `aiProviders.supported[]` for which the host honors `cachePrefixId` (prefix caching is provider-specific). A request whose routed provider is NOT in this list MUST have `cachePrefixId` ignored. Absent \u21d2 host-defined per-provider routing; NOT a universal claim across providers."
|
|
1069
1455
|
}
|
|
1070
1456
|
},
|
|
1071
|
-
"required": [
|
|
1457
|
+
"required": [
|
|
1458
|
+
"supported"
|
|
1459
|
+
]
|
|
1072
1460
|
}
|
|
1073
1461
|
},
|
|
1074
1462
|
"additionalProperties": false,
|
|
1075
1463
|
"allOf": [
|
|
1076
1464
|
{
|
|
1077
|
-
"$comment": "RFC 0106
|
|
1465
|
+
"$comment": "RFC 0106 \u00a7A closure: realtimeVoice.synthesis (streaming TTS) requires the whole-file TTS surface aiProviders.speechSynthesis to be advertised.",
|
|
1078
1466
|
"if": {
|
|
1079
1467
|
"type": "object",
|
|
1080
|
-
"required": [
|
|
1468
|
+
"required": [
|
|
1469
|
+
"realtimeVoice"
|
|
1470
|
+
],
|
|
1081
1471
|
"properties": {
|
|
1082
|
-
"realtimeVoice": {
|
|
1472
|
+
"realtimeVoice": {
|
|
1473
|
+
"type": "object",
|
|
1474
|
+
"required": [
|
|
1475
|
+
"synthesis"
|
|
1476
|
+
]
|
|
1477
|
+
}
|
|
1083
1478
|
}
|
|
1084
1479
|
},
|
|
1085
|
-
"then": {
|
|
1480
|
+
"then": {
|
|
1481
|
+
"required": [
|
|
1482
|
+
"speechSynthesis"
|
|
1483
|
+
]
|
|
1484
|
+
}
|
|
1086
1485
|
}
|
|
1087
1486
|
]
|
|
1088
1487
|
},
|
|
@@ -1092,7 +1491,10 @@
|
|
|
1092
1491
|
"properties": {
|
|
1093
1492
|
"mockProviders": {
|
|
1094
1493
|
"type": "array",
|
|
1095
|
-
"items": {
|
|
1494
|
+
"items": {
|
|
1495
|
+
"type": "string",
|
|
1496
|
+
"minLength": 1
|
|
1497
|
+
},
|
|
1096
1498
|
"uniqueItems": true,
|
|
1097
1499
|
"description": "Mock-provider IDs this server recognizes via `RunOptions.configurable.mockProvider.id`. Servers claiming OpenWOP v1.0 conformance MUST include `stream-text`. Other canonical providers (`tool-calls`, `error`, `usage-only`) are recommended. Implementations MAY add their own (vendor-prefixed)."
|
|
1098
1500
|
},
|
|
@@ -1105,10 +1507,21 @@
|
|
|
1105
1507
|
"forceEngineVersionRange": {
|
|
1106
1508
|
"type": "object",
|
|
1107
1509
|
"description": "Range of engine versions the server can be forced into via the `X-Force-Engine-Version` request header (test-keys-only). Used by the conformance suite to verify forward-compat fold-best-effort across the version-negotiation matrix. Closes F5.",
|
|
1108
|
-
"required": [
|
|
1510
|
+
"required": [
|
|
1511
|
+
"min",
|
|
1512
|
+
"max"
|
|
1513
|
+
],
|
|
1109
1514
|
"properties": {
|
|
1110
|
-
"min": {
|
|
1111
|
-
|
|
1515
|
+
"min": {
|
|
1516
|
+
"type": "integer",
|
|
1517
|
+
"minimum": 0,
|
|
1518
|
+
"description": "Lowest forceable engine version. Typically (current - 1) so back-compat is exercised."
|
|
1519
|
+
},
|
|
1520
|
+
"max": {
|
|
1521
|
+
"type": "integer",
|
|
1522
|
+
"minimum": 0,
|
|
1523
|
+
"description": "Highest forceable engine version. Typically (current + 1) so forward-compat is exercised."
|
|
1524
|
+
}
|
|
1112
1525
|
},
|
|
1113
1526
|
"additionalProperties": false
|
|
1114
1527
|
}
|
|
@@ -1121,19 +1534,22 @@
|
|
|
1121
1534
|
"properties": {
|
|
1122
1535
|
"mockAgent": {
|
|
1123
1536
|
"type": "boolean",
|
|
1124
|
-
"description": "RFC 0023
|
|
1537
|
+
"description": "RFC 0023 \u00a7B.2. When `true`, the host has registered the `core.conformance.mock-agent` typeId. The scenarios `agentReasoningEvents.test.ts` and `agentConfidenceEscalation.test.ts` rely on the typeId being reachable. Hosts that register the typeId only for workflow ids matching the conformance fixture prefix (`conformance-*`) and refuse it for other tenants MAY still advertise `true` \u2014 the advertisement says only that the typeId is reachable from the conformance suite, not that it is reachable from arbitrary workflows."
|
|
1125
1538
|
},
|
|
1126
1539
|
"certificationBundleUrl": {
|
|
1127
1540
|
"type": "string",
|
|
1128
1541
|
"format": "uri",
|
|
1129
|
-
"description": "OPTIONAL (RFC 0089). URL of the host's most recent conformance certification bundle (`conformance-certification-bundle.schema.json`)
|
|
1542
|
+
"description": "OPTIONAL (RFC 0089). URL of the host's most recent conformance certification bundle (`conformance-certification-bundle.schema.json`) \u2014 a machine-readable attestation binding this host's claimed profiles to the reproducible run that substantiates them. Omitting it is fully conformant; clients MUST tolerate its absence."
|
|
1130
1543
|
}
|
|
1131
1544
|
},
|
|
1132
1545
|
"additionalProperties": false
|
|
1133
1546
|
},
|
|
1134
1547
|
"fixtures": {
|
|
1135
1548
|
"type": "array",
|
|
1136
|
-
"items": {
|
|
1549
|
+
"items": {
|
|
1550
|
+
"type": "string",
|
|
1551
|
+
"minLength": 1
|
|
1552
|
+
},
|
|
1137
1553
|
"uniqueItems": true,
|
|
1138
1554
|
"description": "Optional v1 fixture workflow IDs the host has seeded. The conformance suite uses this list to decide which fixture-dependent scenarios run vs. skip. Each ID matches a stub at `node_modules/@openwop/openwop-conformance/fixtures/{id}.json`. Hosts MAY advertise vendor-prefixed IDs; clients MUST tolerate unknown IDs. Empty array or absent means the host advertises no fixtures."
|
|
1139
1555
|
},
|
|
@@ -1153,7 +1569,17 @@
|
|
|
1153
1569
|
"type": "array",
|
|
1154
1570
|
"items": {
|
|
1155
1571
|
"type": "string",
|
|
1156
|
-
"enum": [
|
|
1572
|
+
"enum": [
|
|
1573
|
+
"reasoning",
|
|
1574
|
+
"tool-using",
|
|
1575
|
+
"chat",
|
|
1576
|
+
"code",
|
|
1577
|
+
"vision",
|
|
1578
|
+
"multimodal",
|
|
1579
|
+
"embedding",
|
|
1580
|
+
"classification",
|
|
1581
|
+
"retrieval"
|
|
1582
|
+
]
|
|
1157
1583
|
},
|
|
1158
1584
|
"uniqueItems": true,
|
|
1159
1585
|
"description": "Optional list of `AgentRef.modelClass` values this host supports for hosted agents (Phase 2). Pack manifests whose `modelClass` is not in this list MUST refuse install with `unsupported_model_class`."
|
|
@@ -1164,15 +1590,22 @@
|
|
|
1164
1590
|
},
|
|
1165
1591
|
"memoryBackends": {
|
|
1166
1592
|
"type": "array",
|
|
1167
|
-
"items": {
|
|
1593
|
+
"items": {
|
|
1594
|
+
"type": "string",
|
|
1595
|
+
"enum": [
|
|
1596
|
+
"long-term"
|
|
1597
|
+
]
|
|
1598
|
+
},
|
|
1168
1599
|
"uniqueItems": true,
|
|
1169
1600
|
"description": "Optional list of memory backends (Phase 3). `long-term` means the host implements `ExecutionHost.memory` against a durable store with the SR-1 redaction invariant intact end-to-end. Hosts that don't wire `MemoryAdapter` omit this field."
|
|
1170
1601
|
},
|
|
1171
1602
|
"memoryConsolidation": {
|
|
1172
1603
|
"type": "object",
|
|
1173
|
-
"description": "RFC 0068 (`Draft`). Background reconciliation of LONG-TERM memory (merge/dedup/supersede/strengthen)
|
|
1604
|
+
"description": "RFC 0068 (`Draft`). Background reconciliation of LONG-TERM memory (merge/dedup/supersede/strengthen) \u2014 distinct from RFC 0062 token-budgeted distillation of TRANSACTIONAL memory. A host advertising this emits `agent.memory.consolidated` (content-free) after a consolidation pass. Requires `agents.memoryBackends` to include `long-term`. SR-1 carry-forward + CTI-1 (RFC 0004) hold across the pass. Hosts that omit this block do not consolidate; the conformance scenarios skip cleanly.",
|
|
1174
1605
|
"additionalProperties": false,
|
|
1175
|
-
"required": [
|
|
1606
|
+
"required": [
|
|
1607
|
+
"supported"
|
|
1608
|
+
],
|
|
1176
1609
|
"properties": {
|
|
1177
1610
|
"supported": {
|
|
1178
1611
|
"type": "boolean",
|
|
@@ -1180,16 +1613,22 @@
|
|
|
1180
1613
|
},
|
|
1181
1614
|
"schedule": {
|
|
1182
1615
|
"type": "string",
|
|
1183
|
-
"enum": [
|
|
1616
|
+
"enum": [
|
|
1617
|
+
"host-managed",
|
|
1618
|
+
"scheduled",
|
|
1619
|
+
"on-demand"
|
|
1620
|
+
],
|
|
1184
1621
|
"description": "How a consolidation pass is initiated. `host-managed`: a host-internal cadence clients do not control (default when absent and supported:true). `scheduled`: bound to a `capabilities.scheduling` (RFC 0052) trigger. `on-demand`: the host runs a pass when explicitly requested. A host MAY honor more than one path but advertises the primary."
|
|
1185
1622
|
}
|
|
1186
1623
|
}
|
|
1187
1624
|
},
|
|
1188
1625
|
"commitments": {
|
|
1189
1626
|
"type": "object",
|
|
1190
|
-
"description": "RFC 0068 (`Draft`). Inferred STANDING commitments
|
|
1627
|
+
"description": "RFC 0068 (`Draft`). Inferred STANDING commitments \u2014 durable, memory-derived intentions the host promotes into a time- or predicate-gated arm that fires a run later, without a fresh user turn. When an arm fires the host emits `commitment.fired` (content-free \u2014 the intention text lives in SR-1-redacted memory). Composes RFC 0052 (time arms) / RFC 0060 (predicate arms) for the fire substrate. Hosts that omit this block do not infer commitments; the conformance scenario skips cleanly.",
|
|
1191
1628
|
"additionalProperties": false,
|
|
1192
|
-
"required": [
|
|
1629
|
+
"required": [
|
|
1630
|
+
"supported"
|
|
1631
|
+
],
|
|
1193
1632
|
"properties": {
|
|
1194
1633
|
"supported": {
|
|
1195
1634
|
"type": "boolean",
|
|
@@ -1197,9 +1636,15 @@
|
|
|
1197
1636
|
},
|
|
1198
1637
|
"fireConditions": {
|
|
1199
1638
|
"type": "array",
|
|
1200
|
-
"items": {
|
|
1639
|
+
"items": {
|
|
1640
|
+
"type": "string",
|
|
1641
|
+
"enum": [
|
|
1642
|
+
"time",
|
|
1643
|
+
"predicate"
|
|
1644
|
+
]
|
|
1645
|
+
},
|
|
1201
1646
|
"uniqueItems": true,
|
|
1202
|
-
"description": "Which fire-condition kinds the host supports. `time` composes RFC 0052 scheduling; `predicate` composes RFC 0060 heartbeat. Absent
|
|
1647
|
+
"description": "Which fire-condition kinds the host supports. `time` composes RFC 0052 scheduling; `predicate` composes RFC 0060 heartbeat. Absent \u21d2 `['time']`."
|
|
1203
1648
|
}
|
|
1204
1649
|
}
|
|
1205
1650
|
},
|
|
@@ -1213,58 +1658,74 @@
|
|
|
1213
1658
|
},
|
|
1214
1659
|
"manifestRuntime": {
|
|
1215
1660
|
"type": "object",
|
|
1216
|
-
"description": "RFC 0070. Agent-manifest runtime floor
|
|
1661
|
+
"description": "RFC 0070. Agent-manifest runtime floor \u2014 the minimal tier that makes a published agent pack (RFC 0003) runnable. When `supported: true`, the host implements RFC 0003 `installAgents`: it loads each installed pack's `agents[]` into an in-process AgentRegistry, resolves `systemPromptRef` + `handoff.*SchemaRef` from the tarball at install (RFC 0003 \u00a7C/\u00a7D), and can DISPATCH a manifest agent on the existing `core.dispatch`/orchestrator loop (RFC 0007/0037/0061). Does NOT imply swarm/consensus (`host.agentRuntime`), long-term memory (`agents.memoryBackends`), or crews beyond `agents.dispatch`. A host advertising `host.agentRuntime: supported` is treated as also satisfying this flag (RFC 0070 \u00a7B). Hosts that omit this block do not instantiate manifest agents (today's default).",
|
|
1217
1662
|
"additionalProperties": false,
|
|
1218
|
-
"required": [
|
|
1663
|
+
"required": [
|
|
1664
|
+
"supported"
|
|
1665
|
+
],
|
|
1219
1666
|
"properties": {
|
|
1220
1667
|
"supported": {
|
|
1221
1668
|
"type": "boolean",
|
|
1222
|
-
"description": "REQUIRED when the block is present. When `true`, the host loads + dispatches pack-declared manifest agents. A host with `supported: true` MUST enforce each dispatched agent's `toolAllowlist` (RFC 0002
|
|
1669
|
+
"description": "REQUIRED when the block is present. When `true`, the host loads + dispatches pack-declared manifest agents. A host with `supported: true` MUST enforce each dispatched agent's `toolAllowlist` (RFC 0002 \u00a7A14) and MUST NOT leak BYOK plaintext into `agent.*` events or handoff payloads (SR-1)."
|
|
1223
1670
|
},
|
|
1224
1671
|
"handoffValidation": {
|
|
1225
1672
|
"type": "boolean",
|
|
1226
1673
|
"default": false,
|
|
1227
|
-
"description": "When `true`, the host validates inbound task payloads against the agent's `handoff.taskSchemaRef` before dispatch and outbound results against `handoff.returnSchemaRef` before persistence (RFC 0003
|
|
1674
|
+
"description": "When `true`, the host validates inbound task payloads against the agent's `handoff.taskSchemaRef` before dispatch and outbound results against `handoff.returnSchemaRef` before persistence (RFC 0003 \u00a7D). When `false`/absent, manifests carrying `handoff` schemas are dispatched with opaque payloads."
|
|
1228
1675
|
},
|
|
1229
1676
|
"installScope": {
|
|
1230
1677
|
"type": "string",
|
|
1231
|
-
"enum": [
|
|
1678
|
+
"enum": [
|
|
1679
|
+
"host",
|
|
1680
|
+
"tenant"
|
|
1681
|
+
],
|
|
1232
1682
|
"default": "host",
|
|
1233
|
-
"description": "RFC 0074. Scope at which manifest agents are installed/approved and therefore enumerated by GET /v1/agents. 'host' (default): a single host-global inventory; the endpoint returns the same set for every caller (RFC 0072's original behavior). 'tenant': agents are installed per tenant
|
|
1683
|
+
"description": "RFC 0074. Scope at which manifest agents are installed/approved and therefore enumerated by GET /v1/agents. 'host' (default): a single host-global inventory; the endpoint returns the same set for every caller (RFC 0072's original behavior). 'tenant': agents are installed per tenant\u00b7workspace (RFC 0048 owner triple); GET /v1/agents returns ONLY the agents available to the authenticated principal's workspace, and an unapproved/unknown agent 404s \u2014 the surface never discloses another tenant's inventory. Does not change dispatch (RFC 0072 \u00a7B, owner-triple-scoped POST /v1/runs) or any floor safety guarantee (toolAllowlist/systemPromptRef/SR-1 stay mandatory regardless of scope)."
|
|
1234
1684
|
}
|
|
1235
1685
|
}
|
|
1236
1686
|
},
|
|
1237
1687
|
"liveRuntime": {
|
|
1238
1688
|
"type": "object",
|
|
1239
|
-
"description": "RFC 0077. The host executes manifest agents against LIVE models and tools (not the deterministic RFC 0070 sample floor) per the normative AgentManifest
|
|
1689
|
+
"description": "RFC 0077. The host executes manifest agents against LIVE models and tools (not the deterministic RFC 0070 sample floor) per the normative AgentManifest\u2192live-run mapping (`multi-agent-execution.md` \u00a7\"Live manifest dispatch\"), and emits the `agent.invocation.started`/`agent.invocation.completed` content-free bracket around the existing `agent.*` family. REQUIRES `agents.manifestRuntime.supported: true` \u2014 `liveRuntime` is a strict superset of the floor. The floor's mandatory safety guarantees (toolAllowlist enforcement, handoff inbound validation, tenant scoping, untrusted-model-output handling, fail-closed per-tool authorization) stay unconditional under `liveRuntime`. Hosts that omit this block run the floor only; the behavioral conformance scenarios skip cleanly.",
|
|
1240
1690
|
"additionalProperties": false,
|
|
1241
|
-
"required": [
|
|
1691
|
+
"required": [
|
|
1692
|
+
"supported"
|
|
1693
|
+
],
|
|
1242
1694
|
"properties": {
|
|
1243
1695
|
"supported": {
|
|
1244
1696
|
"type": "boolean",
|
|
1245
|
-
"description": "REQUIRED when present. When `true`, the host performs live manifest dispatch per the
|
|
1697
|
+
"description": "REQUIRED when present. When `true`, the host performs live manifest dispatch per the \u00a7B mapping and emits the `agent.invocation.*` bracket. Gated on `agents.manifestRuntime.supported: true`."
|
|
1246
1698
|
},
|
|
1247
1699
|
"structuredOutput": {
|
|
1248
1700
|
"type": "boolean",
|
|
1249
|
-
"description": "When `true`, the host validates the terminal result against the agent's `handoff.returnSchemaRef` and fails the run with a structured-output error on a non-conforming result rather than shipping it. Absent
|
|
1701
|
+
"description": "When `true`, the host validates the terminal result against the agent's `handoff.returnSchemaRef` and fails the run with a structured-output error on a non-conforming result rather than shipping it. Absent \u21d2 `false` (runs live but does not enforce `returnSchemaRef`)."
|
|
1250
1702
|
},
|
|
1251
1703
|
"confidenceEscalation": {
|
|
1252
1704
|
"type": "boolean",
|
|
1253
|
-
"description": "When `true`, the host honors `AgentManifest.confidence.defaultThreshold` and triggers the RFC 0002
|
|
1705
|
+
"description": "When `true`, the host honors `AgentManifest.confidence.defaultThreshold` and triggers the RFC 0002 \u00a7F escalation contract when an `agent.decided` confidence falls below the effective threshold, rather than silently accepting the decision. Absent \u21d2 `false`."
|
|
1254
1706
|
},
|
|
1255
1707
|
"sources": {
|
|
1256
1708
|
"type": "array",
|
|
1257
1709
|
"uniqueItems": true,
|
|
1258
|
-
"items": {
|
|
1259
|
-
|
|
1710
|
+
"items": {
|
|
1711
|
+
"type": "string",
|
|
1712
|
+
"enum": [
|
|
1713
|
+
"workflow-node",
|
|
1714
|
+
"run-api",
|
|
1715
|
+
"chat-mention"
|
|
1716
|
+
]
|
|
1717
|
+
},
|
|
1718
|
+
"description": "Which invocation entry points the host exposes for live manifest dispatch. `workflow-node`: an agent step inside a workflow run (RFC 0072 \u00a7B); `run-api`: an agent as the root of POST /v1/runs; `chat-mention`: a chat @agent invocation mapped onto the run surface. Enum membership is NOT mandatory \u2014 a host with no chat surface simply omits `chat-mention`. Absent \u21d2 `['workflow-node']` (the RFC 0072 \u00a7B normative path). All advertised sources MUST emit the identical `agent.invocation.*` + `agent.*` event family."
|
|
1260
1719
|
}
|
|
1261
1720
|
}
|
|
1262
1721
|
},
|
|
1263
1722
|
"evalSuite": {
|
|
1264
1723
|
"type": "object",
|
|
1265
|
-
"description": "RFC 0081. The host runs portable `agent-eval-suite.schema.json` suites as eval runs (a `mode: \"eval\"` projection over POST /v1/runs, RFC 0081
|
|
1724
|
+
"description": "RFC 0081. The host runs portable `agent-eval-suite.schema.json` suites as eval runs (a `mode: \"eval\"` projection over POST /v1/runs, RFC 0081 \u00a7B), emits the `eval.started`/`eval.scored`/`eval.completed` content-free family, and terminates with an `eval-summary.schema.json` scorecard. Composes RFC 0026 (per-task cost), RFC 0054 (regression baseline diff), RFC 0056 (human override of an auto-score). Hosts that omit this block reject `mode: \"eval\"` with 501; the behavioral conformance scenario soft-skips. The summary + events are content-free (SECURITY invariant `eval-summary-no-content-leak`).",
|
|
1266
1725
|
"additionalProperties": false,
|
|
1267
|
-
"required": [
|
|
1726
|
+
"required": [
|
|
1727
|
+
"supported"
|
|
1728
|
+
],
|
|
1268
1729
|
"properties": {
|
|
1269
1730
|
"supported": {
|
|
1270
1731
|
"type": "boolean",
|
|
@@ -1273,13 +1734,22 @@
|
|
|
1273
1734
|
"modes": {
|
|
1274
1735
|
"type": "array",
|
|
1275
1736
|
"uniqueItems": true,
|
|
1276
|
-
"items": {
|
|
1277
|
-
|
|
1737
|
+
"items": {
|
|
1738
|
+
"type": "string",
|
|
1739
|
+
"enum": [
|
|
1740
|
+
"golden",
|
|
1741
|
+
"rubric",
|
|
1742
|
+
"adversarial",
|
|
1743
|
+
"regression",
|
|
1744
|
+
"live-shadow"
|
|
1745
|
+
]
|
|
1746
|
+
},
|
|
1747
|
+
"description": "Which eval modes the host actually implements (RFC 0081 \u00a7D closed vocabulary). Truthful advertisement (RFC 0031): a host advertises ONLY the modes it gates on; a suite requesting an unadvertised mode is rejected at run-create with `400 validation_error`. Absent \u21d2 no modes (the host advertises `supported` but gates nothing \u2014 effectively shape-only)."
|
|
1278
1748
|
},
|
|
1279
1749
|
"maxTasksPerSuite": {
|
|
1280
1750
|
"type": "integer",
|
|
1281
1751
|
"minimum": 1,
|
|
1282
|
-
"description": "MAY. Host ceiling on tasks per suite; a suite exceeding it is rejected at run-create (the RFC 0058
|
|
1752
|
+
"description": "MAY. Host ceiling on tasks per suite; a suite exceeding it is rejected at run-create (the RFC 0058 \u00a7A clamp pattern)."
|
|
1283
1753
|
},
|
|
1284
1754
|
"maxCostUsdPerSuite": {
|
|
1285
1755
|
"type": "number",
|
|
@@ -1290,9 +1760,11 @@
|
|
|
1290
1760
|
},
|
|
1291
1761
|
"deployment": {
|
|
1292
1762
|
"type": "object",
|
|
1293
|
-
"description": "RFC 0082. The host implements an agent deployment lifecycle: per-(agentId, version) deployment records with the seven-state machine (draft/test/staged/active/paused/deprecated/rolled-back), named-channel binding (`agentId@channel` / `@latest` resolved + pinned per-(run, agentId, channel) at first resolution per
|
|
1763
|
+
"description": "RFC 0082. The host implements an agent deployment lifecycle: per-(agentId, version) deployment records with the seven-state machine (draft/test/staged/active/paused/deprecated/rolled-back), named-channel binding (`agentId@channel` / `@latest` resolved + pinned per-(run, agentId, channel) at first resolution per \u00a7B), optional canary traffic-split, a rollback pointer, the content-free `deployment.*` audit events, and the `POST /v1/agents/{agentId}/deployments` promotion contract composing RFC 0049 (`deploy:*` fail-closed scopes) + RFC 0051 (approvalGate) + RFC 0081 (`requiredEval`). Hosts that omit this block reject a `channel`-bearing `AgentRef` with `validation_error` and 501 the deployment endpoint. The promotion endpoint + behavioral lifecycle scenario + reference-host store land at Active \u2192 Accepted.",
|
|
1294
1764
|
"additionalProperties": false,
|
|
1295
|
-
"required": [
|
|
1765
|
+
"required": [
|
|
1766
|
+
"supported"
|
|
1767
|
+
],
|
|
1296
1768
|
"properties": {
|
|
1297
1769
|
"supported": {
|
|
1298
1770
|
"type": "boolean",
|
|
@@ -1301,30 +1773,46 @@
|
|
|
1301
1773
|
"channels": {
|
|
1302
1774
|
"type": "array",
|
|
1303
1775
|
"uniqueItems": true,
|
|
1304
|
-
"items": {
|
|
1776
|
+
"items": {
|
|
1777
|
+
"type": "string",
|
|
1778
|
+
"minLength": 1
|
|
1779
|
+
},
|
|
1305
1780
|
"description": "The named channels the host resolves (e.g. `[\"stable\", \"canary\", \"latest\"]`). Truthful advertisement (RFC 0031): a `channel` not in this list resolves to no version and fails the run with `no_active_deployment`."
|
|
1306
1781
|
},
|
|
1307
1782
|
"canary": {
|
|
1308
1783
|
"type": "boolean",
|
|
1309
|
-
"description": "When `true`, the host implements canary traffic-split (a per-run
|
|
1784
|
+
"description": "When `true`, the host implements canary traffic-split (a per-run \u00a7B draw assigns the run to one of the channel's active versions by `canaryPercent`). When `false`/absent, the host MUST reject any `canaryPercent < 100`."
|
|
1310
1785
|
},
|
|
1311
1786
|
"rollback": {
|
|
1312
1787
|
"type": "boolean",
|
|
1313
|
-
"description": "When `true`, the host implements the `rollbackPointer` recovery path (active
|
|
1788
|
+
"description": "When `true`, the host implements the `rollbackPointer` recovery path (active\u2192rolled-back restoring a prior version to active)."
|
|
1314
1789
|
},
|
|
1315
1790
|
"states": {
|
|
1316
1791
|
"type": "array",
|
|
1317
1792
|
"uniqueItems": true,
|
|
1318
|
-
"items": {
|
|
1793
|
+
"items": {
|
|
1794
|
+
"type": "string",
|
|
1795
|
+
"enum": [
|
|
1796
|
+
"draft",
|
|
1797
|
+
"test",
|
|
1798
|
+
"staged",
|
|
1799
|
+
"active",
|
|
1800
|
+
"paused",
|
|
1801
|
+
"deprecated",
|
|
1802
|
+
"rolled-back"
|
|
1803
|
+
]
|
|
1804
|
+
},
|
|
1319
1805
|
"description": "The subset of the seven lifecycle states the host implements. Truthful advertisement (RFC 0031): the host MUST reject a transition into a state not advertised here."
|
|
1320
1806
|
}
|
|
1321
1807
|
}
|
|
1322
1808
|
},
|
|
1323
1809
|
"roster": {
|
|
1324
1810
|
"type": "object",
|
|
1325
|
-
"description": "RFC 0086. The host maintains a standing agent roster: named, tenant-scoped agent INSTANCES (the 'digital-twin employee') that reference a manifest/deployment and own a workflow portfolio, discoverable via GET /v1/agents/roster, with trigger-fired portfolio runs attributed to the member via the content-free `roster.run.initiated` event. REQUIRES `agents.manifestRuntime.supported: true` (a roster entry instantiates a manifest agent). Triggers compose RFC 0052 (schedule) + RFC 0083 (durable work-item bridge)
|
|
1811
|
+
"description": "RFC 0086. The host maintains a standing agent roster: named, tenant-scoped agent INSTANCES (the 'digital-twin employee') that reference a manifest/deployment and own a workflow portfolio, discoverable via GET /v1/agents/roster, with trigger-fired portfolio runs attributed to the member via the content-free `roster.run.initiated` event. REQUIRES `agents.manifestRuntime.supported: true` (a roster entry instantiates a manifest agent). Triggers compose RFC 0052 (schedule) + RFC 0083 (durable work-item bridge) \u2014 no new WorkflowTrigger.type; the concrete work surface (a Kanban board) stays a host/vendor extension (\u00a7E). Hosts that omit this block do not maintain a roster (the roster reads 501). The roster-management endpoints + behavioral attribution scenario + reference-host store land at Active \u2192 Accepted.",
|
|
1326
1812
|
"additionalProperties": false,
|
|
1327
|
-
"required": [
|
|
1813
|
+
"required": [
|
|
1814
|
+
"supported"
|
|
1815
|
+
],
|
|
1328
1816
|
"properties": {
|
|
1329
1817
|
"supported": {
|
|
1330
1818
|
"type": "boolean",
|
|
@@ -1332,30 +1820,41 @@
|
|
|
1332
1820
|
},
|
|
1333
1821
|
"installScope": {
|
|
1334
1822
|
"type": "string",
|
|
1335
|
-
"enum": [
|
|
1823
|
+
"enum": [
|
|
1824
|
+
"host",
|
|
1825
|
+
"tenant"
|
|
1826
|
+
],
|
|
1336
1827
|
"description": "RFC 0074 carry-forward. `host`: a single global roster. `tenant`: roster entries are scoped per owner triple; GET /v1/agents/roster returns only the caller's entries and a cross-tenant entry 404s. MUST equal `agents.manifestRuntime.installScope` (a roster cannot be host-global while its manifests are tenant-scoped, or vice-versa)."
|
|
1337
1828
|
},
|
|
1338
1829
|
"portfolioTriggerSources": {
|
|
1339
1830
|
"type": "array",
|
|
1340
1831
|
"uniqueItems": true,
|
|
1341
|
-
"items": {
|
|
1832
|
+
"items": {
|
|
1833
|
+
"type": "string",
|
|
1834
|
+
"minLength": 1
|
|
1835
|
+
},
|
|
1342
1836
|
"description": "Which RFC 0052/0083 trigger sources fire portfolio runs on this host (e.g. `[\"schedule\", \"queue\", \"webhook\"]`). Truthful advertisement (RFC 0031): a source not listed does not fire portfolios here."
|
|
1343
1837
|
}
|
|
1344
1838
|
}
|
|
1345
1839
|
},
|
|
1346
1840
|
"orgChart": {
|
|
1347
1841
|
"type": "object",
|
|
1348
|
-
"description": "RFC 0087. The host maintains a tenant-scoped, DESCRIPTIVE org-chart over RFC 0086 roster members: departments + roles with acyclic `reportsTo` edges + a derived responsibility roll-up, discoverable via GET /v1/agents/org-chart. The load-bearing guarantee (
|
|
1842
|
+
"description": "RFC 0087. The host maintains a tenant-scoped, DESCRIPTIVE org-chart over RFC 0086 roster members: departments + roles with acyclic `reportsTo` edges + a derived responsibility roll-up, discoverable via GET /v1/agents/org-chart. The load-bearing guarantee (\u00a7B `org-position-no-authority-escalation`): an org edge confers NO authority \u2014 it MUST NOT widen `toolAllowlist` (RFC 0002 \u00a7A14), grant an RBAC scope (RFC 0049), or bypass an approval gate (RFC 0051); org position MUST NOT be an authorization input. The schema carries no authority-bearing field, and a conformant host MUST NOT derive authority from position out-of-band. REQUIRES `agents.roster.supported: true` (the chart's members are roster entries). Hosts that omit this block have no org-chart surface (the read 501s). The org-chart-management endpoints + behavioral non-authority scenario + reference-host store land at Active \u2192 Accepted.",
|
|
1349
1843
|
"additionalProperties": false,
|
|
1350
|
-
"required": [
|
|
1844
|
+
"required": [
|
|
1845
|
+
"supported"
|
|
1846
|
+
],
|
|
1351
1847
|
"properties": {
|
|
1352
1848
|
"supported": {
|
|
1353
1849
|
"type": "boolean",
|
|
1354
|
-
"description": "REQUIRED when present. When `true`, the host serves the tenant-scoped org-chart + the responsibility roll-up. The
|
|
1850
|
+
"description": "REQUIRED when present. When `true`, the host serves the tenant-scoped org-chart + the responsibility roll-up. The \u00a7B non-authority guarantee holds at every `installScope` \u2014 it is never gated, weakened, or opt-out."
|
|
1355
1851
|
},
|
|
1356
1852
|
"installScope": {
|
|
1357
1853
|
"type": "string",
|
|
1358
|
-
"enum": [
|
|
1854
|
+
"enum": [
|
|
1855
|
+
"host",
|
|
1856
|
+
"tenant"
|
|
1857
|
+
],
|
|
1359
1858
|
"description": "RFC 0074 carry-forward. `host`: a single global chart. `tenant`: charts are scoped per owner triple; GET /v1/agents/org-chart returns only the caller's chart. SHOULD equal `agents.roster.installScope` (the members are roster entries)."
|
|
1360
1859
|
},
|
|
1361
1860
|
"departmentNesting": {
|
|
@@ -1364,14 +1863,14 @@
|
|
|
1364
1863
|
},
|
|
1365
1864
|
"responsibilityView": {
|
|
1366
1865
|
"type": "boolean",
|
|
1367
|
-
"description": "When `true`, the host computes the
|
|
1866
|
+
"description": "When `true`, the host computes the \u00a7D responsibility roll-up (the union of a department's members' RFC 0086 portfolios) on GET /v1/agents/org-chart/{departmentId}."
|
|
1368
1867
|
}
|
|
1369
1868
|
}
|
|
1370
1869
|
},
|
|
1371
1870
|
"dispatchMapping": {
|
|
1372
1871
|
"type": "boolean",
|
|
1373
1872
|
"default": false,
|
|
1374
|
-
"description": "Phase 6.1 (RFC 0022
|
|
1873
|
+
"description": "Phase 6.1 (RFC 0022 \u00a7A). When `true`, host honors `inputMapping` / `outputMapping` / `perWorkerInputMappings` / `perWorkerOutputMappings` on `DispatchConfig` \u2014 building child inputs from parent variables before dispatch and harvesting child variables into parent variables on completion. Implies (but does NOT require) `agents.dispatch: true`. Hosts that set `agents.dispatch: true` but omit / `false` this flag MUST refuse workflows that carry non-empty mapping fields at registration with `validation_error` + `details.requiredCapability: 'agents.dispatchMapping'`."
|
|
1375
1874
|
},
|
|
1376
1875
|
"reasoning": {
|
|
1377
1876
|
"type": "object",
|
|
@@ -1379,7 +1878,11 @@
|
|
|
1379
1878
|
"properties": {
|
|
1380
1879
|
"verbosity": {
|
|
1381
1880
|
"type": "string",
|
|
1382
|
-
"enum": [
|
|
1881
|
+
"enum": [
|
|
1882
|
+
"summary",
|
|
1883
|
+
"full",
|
|
1884
|
+
"off"
|
|
1885
|
+
],
|
|
1383
1886
|
"description": "Default reasoning verbosity for `agent.reasoned` events when the run does not override via `RunOptions.configurable.reasoningVerbosity`."
|
|
1384
1887
|
},
|
|
1385
1888
|
"tokenLimit": {
|
|
@@ -1398,17 +1901,28 @@
|
|
|
1398
1901
|
"subRunAttestation": {
|
|
1399
1902
|
"type": "boolean",
|
|
1400
1903
|
"default": false,
|
|
1401
|
-
"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`
|
|
1904
|
+
"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` \u21d2 no merge). Reuses RFC 0051's `approval` kind + RFC 0049 scopes for `principalScope` \u2014 no new interrupt kind, event type, or error code. Hosts that omit / `false` this flag treat `outputAttestation` as inert (blind merge, today's behavior)."
|
|
1402
1905
|
},
|
|
1403
1906
|
"proposals": {
|
|
1404
1907
|
"type": "object",
|
|
1405
|
-
"description": "RFC 0096 (`Active`). Reviewable learning
|
|
1908
|
+
"description": "RFC 0096 (`Active`). Reviewable learning \u2014 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 \u2014 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.",
|
|
1406
1909
|
"additionalProperties": false,
|
|
1407
|
-
"required": [
|
|
1910
|
+
"required": [
|
|
1911
|
+
"artifactKinds",
|
|
1912
|
+
"activation"
|
|
1913
|
+
],
|
|
1408
1914
|
"properties": {
|
|
1409
1915
|
"artifactKinds": {
|
|
1410
1916
|
"type": "array",
|
|
1411
|
-
"items": {
|
|
1917
|
+
"items": {
|
|
1918
|
+
"type": "string",
|
|
1919
|
+
"enum": [
|
|
1920
|
+
"agent-pack",
|
|
1921
|
+
"workflow-chain-pack",
|
|
1922
|
+
"prompt-template",
|
|
1923
|
+
"automation"
|
|
1924
|
+
]
|
|
1925
|
+
},
|
|
1412
1926
|
"uniqueItems": true,
|
|
1413
1927
|
"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)."
|
|
1414
1928
|
},
|
|
@@ -1419,25 +1933,42 @@
|
|
|
1419
1933
|
},
|
|
1420
1934
|
"activation": {
|
|
1421
1935
|
"type": "string",
|
|
1422
|
-
"enum": [
|
|
1936
|
+
"enum": [
|
|
1937
|
+
"approval-gate",
|
|
1938
|
+
"direct-rbac"
|
|
1939
|
+
],
|
|
1423
1940
|
"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."
|
|
1424
1941
|
}
|
|
1425
1942
|
}
|
|
1426
1943
|
},
|
|
1427
1944
|
"goals": {
|
|
1428
1945
|
"type": "object",
|
|
1429
|
-
"description": "RFC 0097 (`Active`). Standing goals
|
|
1946
|
+
"description": "RFC 0097 (`Active`). Standing goals \u2014 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 \u2014 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.",
|
|
1430
1947
|
"additionalProperties": false,
|
|
1431
|
-
"required": [
|
|
1948
|
+
"required": [
|
|
1949
|
+
"judge",
|
|
1950
|
+
"continuation"
|
|
1951
|
+
],
|
|
1432
1952
|
"properties": {
|
|
1433
1953
|
"judge": {
|
|
1434
1954
|
"type": "string",
|
|
1435
|
-
"enum": [
|
|
1955
|
+
"enum": [
|
|
1956
|
+
"verifier",
|
|
1957
|
+
"host"
|
|
1958
|
+
],
|
|
1436
1959
|
"description": "`verifier`: completion is an RFC 0090 verifier verdict. `host`: an opaque host evaluator."
|
|
1437
1960
|
},
|
|
1438
1961
|
"continuation": {
|
|
1439
1962
|
"type": "array",
|
|
1440
|
-
"items": {
|
|
1963
|
+
"items": {
|
|
1964
|
+
"type": "string",
|
|
1965
|
+
"enum": [
|
|
1966
|
+
"schedule",
|
|
1967
|
+
"commitment",
|
|
1968
|
+
"heartbeat",
|
|
1969
|
+
"manual"
|
|
1970
|
+
]
|
|
1971
|
+
},
|
|
1441
1972
|
"uniqueItems": true,
|
|
1442
1973
|
"description": "How a goal re-engages work between judge checks. `schedule` (RFC 0052), `commitment` (RFC 0068), `heartbeat` (RFC 0060), `manual`."
|
|
1443
1974
|
},
|
|
@@ -1457,7 +1988,7 @@
|
|
|
1457
1988
|
"properties": {
|
|
1458
1989
|
"supported": {
|
|
1459
1990
|
"type": "boolean",
|
|
1460
|
-
"description": "When `true`, host implements the four-operation MemoryAdapter contract (`list`, `get`, `put`, `delete`) per RFC 0004
|
|
1991
|
+
"description": "When `true`, host implements the four-operation MemoryAdapter contract (`list`, `get`, `put`, `delete`) per RFC 0004 \u00a7A."
|
|
1461
1992
|
},
|
|
1462
1993
|
"maxEntrySizeBytes": {
|
|
1463
1994
|
"type": "integer",
|
|
@@ -1466,21 +1997,27 @@
|
|
|
1466
1997
|
},
|
|
1467
1998
|
"ttlSupported": {
|
|
1468
1999
|
"type": "boolean",
|
|
1469
|
-
"description": "When `true`, host honors `expiresAt` per RFC 0004
|
|
2000
|
+
"description": "When `true`, host honors `expiresAt` per RFC 0004 \u00a7E."
|
|
1470
2001
|
},
|
|
1471
2002
|
"compaction": {
|
|
1472
2003
|
"type": "object",
|
|
1473
2004
|
"description": "RFC 0012 Memory Compaction Profile (Accepted 2026-05-15). Hosts that distill many short-lived MemoryEntry rows into fewer long-lived ones MAY advertise here; advertising implies the SR-1 carry-forward invariant (`SECURITY/invariants.yaml` row `memory-compaction-sr-1-carry-forward`).",
|
|
1474
|
-
"required": [
|
|
2005
|
+
"required": [
|
|
2006
|
+
"supported"
|
|
2007
|
+
],
|
|
1475
2008
|
"properties": {
|
|
1476
2009
|
"supported": {
|
|
1477
2010
|
"type": "boolean",
|
|
1478
|
-
"description": "REQUIRED when the sub-block is present. When `true`, host performs compaction over `longTerm` memory and emits the `memory.compacted` event per `observability.md`
|
|
2011
|
+
"description": "REQUIRED when the sub-block is present. When `true`, host performs compaction over `longTerm` memory and emits the `memory.compacted` event per `observability.md` \u00a7Canonical event vocabulary."
|
|
1479
2012
|
},
|
|
1480
2013
|
"trigger": {
|
|
1481
2014
|
"type": "string",
|
|
1482
|
-
"enum": [
|
|
1483
|
-
|
|
2015
|
+
"enum": [
|
|
2016
|
+
"host-managed",
|
|
2017
|
+
"client-requested",
|
|
2018
|
+
"both"
|
|
2019
|
+
],
|
|
2020
|
+
"description": "REQUIRED when `supported: true` per RFC 0012 \u00a7A (enforced via the `if/then` clause). `host-managed` runs on a host-internal schedule clients do not control. `client-requested` and `both` are reserved enum values; v1.x normates only `host-managed`."
|
|
1484
2021
|
},
|
|
1485
2022
|
"maxInputEntries": {
|
|
1486
2023
|
"type": "integer",
|
|
@@ -1490,37 +2027,74 @@
|
|
|
1490
2027
|
"maxOutputBytes": {
|
|
1491
2028
|
"type": "integer",
|
|
1492
2029
|
"minimum": 0,
|
|
1493
|
-
"description": "Informational ceiling on the distilled entry size. SHOULD be
|
|
2030
|
+
"description": "Informational ceiling on the distilled entry size. SHOULD be \u2264 `memory.maxEntrySizeBytes`."
|
|
1494
2031
|
}
|
|
1495
2032
|
},
|
|
1496
2033
|
"additionalProperties": false,
|
|
1497
|
-
"if": {
|
|
1498
|
-
|
|
2034
|
+
"if": {
|
|
2035
|
+
"properties": {
|
|
2036
|
+
"supported": {
|
|
2037
|
+
"const": true
|
|
2038
|
+
}
|
|
2039
|
+
},
|
|
2040
|
+
"required": [
|
|
2041
|
+
"supported"
|
|
2042
|
+
]
|
|
2043
|
+
},
|
|
2044
|
+
"then": {
|
|
2045
|
+
"required": [
|
|
2046
|
+
"supported",
|
|
2047
|
+
"trigger"
|
|
2048
|
+
]
|
|
2049
|
+
}
|
|
1499
2050
|
},
|
|
1500
2051
|
"distillation": {
|
|
1501
2052
|
"type": "object",
|
|
1502
|
-
"description": "RFC 0062 (`Active`). Scheduled, token-budgeted background compaction
|
|
1503
|
-
"required": [
|
|
2053
|
+
"description": "RFC 0062 (`Active`). Scheduled, token-budgeted background compaction \u2014 the 'dream' pattern \u2014 built on compaction (RFC 0012) + scheduling (RFC 0052) + the workspace index (RFC 0059). A distillation run IS a compaction run with a mandatory token budget, an optional schedule, and a retrieval index wrapped around it; it reuses the `memory.compacted` event (extended with the additive optional `distillation` sub-object) rather than a parallel `memory.distilled` event. SR-1 carry-forward (RFC 0012 \u00a7D) holds \u2014 a distilled archive MUST NOT re-expose a redacted secret. Hosts that omit this block keep plain on-demand compaction (RFC 0012) or no memory.",
|
|
2054
|
+
"required": [
|
|
2055
|
+
"supported"
|
|
2056
|
+
],
|
|
1504
2057
|
"additionalProperties": false,
|
|
1505
|
-
"properties": {
|
|
1506
|
-
"supported": { "type": "boolean", "description": "REQUIRED when the sub-block is present. When `true`, host honors the `distillation.tokenBudget` reserved run-option key, runs budgeted distillation over `longTerm` memory, writes a stable archive, and emits `memory.compacted` with the `distillation` sub-object." },
|
|
1507
|
-
"maxTokenBudget": { "type": "integer", "minimum": 1, "description": "Largest per-run distillation token budget the host honors. A supplied `distillation.tokenBudget` is clamped to this; absent ⇒ the host defaults to this." },
|
|
1508
|
-
"scheduled": { "type": "boolean", "description": "When `true`, host can initiate distillation on a schedule (requires `capabilities.scheduling`, RFC 0052). Distillation MAY also run on-demand without scheduling." },
|
|
1509
|
-
"indexEmitted": { "type": "boolean", "description": "When `true`, host writes a retrievable memory-index manifest (`MEMORY-INDEX.json`, a workspace file per RFC 0059) after distillation; updating it emits `workspace.updated`." },
|
|
1510
|
-
"tokenizerName": { "type": "string", "description": "Identifier of the tokenizer the budget is counted against (e.g. `claude`, `gpt-4`). The budget is best-effort-honest per this tokenizer (±10% conformance tolerance), not byte-exact." },
|
|
1511
|
-
"archiveRetention": { "type": "string", "description": "ISO-8601 duration (e.g. `P30D`) the distilled archives persist before GC. Recursive distillation (distilling prior archives) is allowed; each level re-checks SR-1." }
|
|
1512
|
-
}
|
|
1513
|
-
},
|
|
1514
|
-
"attribution": {
|
|
1515
|
-
"type": "object",
|
|
1516
|
-
"description": "RFC 0057 Memory write-attribution. Hosts that emit per-node memory provenance on the run event log MAY advertise here. Advertising `emitsWriteEvents: true` commits the host to emit a `memory.written` RunEvent for every memory write a run makes (identifiers only, never content), and implies the SECURITY invariants `memory-attribution-no-content` + `memory-attribution-tenant-scoped`.",
|
|
1517
|
-
"required": ["supported"],
|
|
1518
2058
|
"properties": {
|
|
1519
2059
|
"supported": {
|
|
1520
|
-
"
|
|
1521
|
-
"description": "REQUIRED when the sub-block is present.
|
|
2060
|
+
"type": "boolean",
|
|
2061
|
+
"description": "REQUIRED when the sub-block is present. When `true`, host honors the `distillation.tokenBudget` reserved run-option key, runs budgeted distillation over `longTerm` memory, writes a stable archive, and emits `memory.compacted` with the `distillation` sub-object."
|
|
1522
2062
|
},
|
|
1523
|
-
"
|
|
2063
|
+
"maxTokenBudget": {
|
|
2064
|
+
"type": "integer",
|
|
2065
|
+
"minimum": 1,
|
|
2066
|
+
"description": "Largest per-run distillation token budget the host honors. A supplied `distillation.tokenBudget` is clamped to this; absent \u21d2 the host defaults to this."
|
|
2067
|
+
},
|
|
2068
|
+
"scheduled": {
|
|
2069
|
+
"type": "boolean",
|
|
2070
|
+
"description": "When `true`, host can initiate distillation on a schedule (requires `capabilities.scheduling`, RFC 0052). Distillation MAY also run on-demand without scheduling."
|
|
2071
|
+
},
|
|
2072
|
+
"indexEmitted": {
|
|
2073
|
+
"type": "boolean",
|
|
2074
|
+
"description": "When `true`, host writes a retrievable memory-index manifest (`MEMORY-INDEX.json`, a workspace file per RFC 0059) after distillation; updating it emits `workspace.updated`."
|
|
2075
|
+
},
|
|
2076
|
+
"tokenizerName": {
|
|
2077
|
+
"type": "string",
|
|
2078
|
+
"description": "Identifier of the tokenizer the budget is counted against (e.g. `claude`, `gpt-4`). The budget is best-effort-honest per this tokenizer (\u00b110% conformance tolerance), not byte-exact."
|
|
2079
|
+
},
|
|
2080
|
+
"archiveRetention": {
|
|
2081
|
+
"type": "string",
|
|
2082
|
+
"description": "ISO-8601 duration (e.g. `P30D`) the distilled archives persist before GC. Recursive distillation (distilling prior archives) is allowed; each level re-checks SR-1."
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
},
|
|
2086
|
+
"attribution": {
|
|
2087
|
+
"type": "object",
|
|
2088
|
+
"description": "RFC 0057 Memory write-attribution. Hosts that emit per-node memory provenance on the run event log MAY advertise here. Advertising `emitsWriteEvents: true` commits the host to emit a `memory.written` RunEvent for every memory write a run makes (identifiers only, never content), and implies the SECURITY invariants `memory-attribution-no-content` + `memory-attribution-tenant-scoped`.",
|
|
2089
|
+
"required": [
|
|
2090
|
+
"supported"
|
|
2091
|
+
],
|
|
2092
|
+
"properties": {
|
|
2093
|
+
"supported": {
|
|
2094
|
+
"const": true,
|
|
2095
|
+
"description": "REQUIRED when the sub-block is present. The block is omitted entirely by hosts that do not support write attribution."
|
|
2096
|
+
},
|
|
2097
|
+
"emitsWriteEvents": {
|
|
1524
2098
|
"type": "boolean",
|
|
1525
2099
|
"description": "When `true`, the host emits `memory.written` (per `run-event-payloads.schema.json#/$defs/memoryWritten`) for every memory write during a run. When `false` or absent, consumers MUST tolerate the event never appearing."
|
|
1526
2100
|
}
|
|
@@ -1529,47 +2103,88 @@
|
|
|
1529
2103
|
},
|
|
1530
2104
|
"writable": {
|
|
1531
2105
|
"type": "boolean",
|
|
1532
|
-
"description": "RFC 0080
|
|
2106
|
+
"description": "RFC 0080 \u00a7A (`write` dimension). Absent \u21d2 the host implements the full RFC 0004 four-operation MemoryAdapter (`put`/`delete` available \u2014 i.e. writable), the back-compatible default. A read-only host (`get`/`list` only) MUST set `writable: false` so a consumer can distinguish a read-only store from a read/write one. Only meaningful when `supported: true`."
|
|
1533
2107
|
},
|
|
1534
2108
|
"search": {
|
|
1535
2109
|
"type": "object",
|
|
1536
|
-
"description": "RFC 0080
|
|
1537
|
-
"required": [
|
|
2110
|
+
"description": "RFC 0080 \u00a7A (`search` dimension) \u2014 NEW optional. Semantic or filtered query beyond the RFC 0004 `list` enumeration. Absent \u21d2 only `list`/`get` retrieval is advertised. The query path itself stays the host-internal MemoryAdapter (RFC 0080 \u00a7B \u2014 no portable `GET /v1/memory` at v1.x).",
|
|
2111
|
+
"required": [
|
|
2112
|
+
"supported"
|
|
2113
|
+
],
|
|
1538
2114
|
"additionalProperties": false,
|
|
1539
2115
|
"properties": {
|
|
1540
|
-
"supported": {
|
|
2116
|
+
"supported": {
|
|
2117
|
+
"type": "boolean",
|
|
2118
|
+
"description": "REQUIRED when the sub-block is present. When `true`, the host supports memory query beyond `list` (semantic and/or filter modes per `modes`)."
|
|
2119
|
+
},
|
|
1541
2120
|
"modes": {
|
|
1542
2121
|
"type": "array",
|
|
1543
|
-
"items": {
|
|
2122
|
+
"items": {
|
|
2123
|
+
"type": "string",
|
|
2124
|
+
"enum": [
|
|
2125
|
+
"semantic",
|
|
2126
|
+
"filter"
|
|
2127
|
+
]
|
|
2128
|
+
},
|
|
1544
2129
|
"uniqueItems": true,
|
|
1545
|
-
"description": "The query modes the host supports. `semantic` = embedding/similarity retrieval; `filter` = structured predicate query over entry metadata. Omitted
|
|
2130
|
+
"description": "The query modes the host supports. `semantic` = embedding/similarity retrieval; `filter` = structured predicate query over entry metadata. Omitted \u21d2 unspecified mode (the host supports some query beyond `list`)."
|
|
1546
2131
|
}
|
|
1547
2132
|
}
|
|
1548
2133
|
},
|
|
1549
2134
|
"retention": {
|
|
1550
2135
|
"type": "object",
|
|
1551
|
-
"description": "RFC 0080
|
|
2136
|
+
"description": "RFC 0080 \u00a7A (`retention/forget` dimension) \u2014 NEW optional. TTL expiry (`agent-memory.md \u00a7TTL`) and/or an explicit forget operation. Absent \u21d2 no TTL beyond `ttlSupported` and no forget operation advertised. `forget` is a host-managed mutation OUTSIDE the replay envelope (RFC 0080 \u00a7UQ3 / `replay.md` \u00a7Recorded-fact events \u2014 a replay re-reads the log-recorded snapshot, not live memory).",
|
|
1552
2137
|
"additionalProperties": false,
|
|
1553
2138
|
"properties": {
|
|
1554
|
-
"ttl": {
|
|
1555
|
-
|
|
2139
|
+
"ttl": {
|
|
2140
|
+
"type": "boolean",
|
|
2141
|
+
"description": "When `true`, memory entries expire per `expiresAt` (the `ttlSupported` semantics surfaced as a named retention dimension)."
|
|
2142
|
+
},
|
|
2143
|
+
"forget": {
|
|
2144
|
+
"type": "boolean",
|
|
2145
|
+
"description": "When `true`, the host supports a tenant-scoped delete-by-subject forget operation (composes the CTI-1 cross-tenant invariant \u2014 a forget MUST NOT cross tenant boundaries)."
|
|
2146
|
+
}
|
|
1556
2147
|
}
|
|
1557
2148
|
},
|
|
1558
2149
|
"injectionBudget": {
|
|
1559
2150
|
"type": "object",
|
|
1560
|
-
"description": "RFC 0113 (`Active`). The host honors `MemoryListOptions.tokenBudget`
|
|
2151
|
+
"description": "RFC 0113 (`Active`). The host honors `MemoryListOptions.tokenBudget` \u2014 a token-denominated bound on a single injection read (the live read that feeds a turn), distinct from RFC 0062 distillation's background-compaction budget. Advertising it commits the host to return a token-bounded prefix of the ranked entry list (over-budget single entry omitted, never truncated mid-entry) over the SR-1-redacted, CTI-1-single-tenant result set. Relevance ranking is NOT advertised here \u2014 `rank:'relevance'` delegates to the existing `memory.search` semantic mode (RFC 0080), so there is exactly one relevance surface in the corpus. Hosts that omit this block do not honor `tokenBudget` (a supplied `tokenBudget` is ignored, today's `limit`/`tag` behavior).",
|
|
1561
2152
|
"additionalProperties": false,
|
|
1562
|
-
"required": [
|
|
2153
|
+
"required": [
|
|
2154
|
+
"supported"
|
|
2155
|
+
],
|
|
1563
2156
|
"properties": {
|
|
1564
|
-
"supported": {
|
|
2157
|
+
"supported": {
|
|
2158
|
+
"type": "boolean",
|
|
2159
|
+
"description": "REQUIRED when the sub-block is present. When `true`, the host honors `MemoryListOptions.tokenBudget` per `agent-memory.md` \u00a7\"Injection budget\"."
|
|
2160
|
+
},
|
|
1565
2161
|
"tokenCounter": {
|
|
1566
2162
|
"type": "string",
|
|
1567
|
-
"enum": [
|
|
1568
|
-
|
|
2163
|
+
"enum": [
|
|
2164
|
+
"o200k_base",
|
|
2165
|
+
"cl100k_base",
|
|
2166
|
+
"chars",
|
|
2167
|
+
"host-defined"
|
|
2168
|
+
],
|
|
2169
|
+
"description": "The unit `tokenBudget` is denominated in. REQUIRED when `injectionBudget.supported` (enforced via the `if/then` clause). `o200k_base`/`cl100k_base` are tokenizer encodings; `chars` counts UTF-8/Unicode characters of the entry `content` (a tokenizer-free unit a client can reason about directly \u2014 preferred over opaque `host-defined`); `host-defined` is an opaque host unit. The over-budget-single-entry-omitted rule applies regardless of unit. RFC 0111 aligns to these same values when it lands (0113 lands first); no shared `$ref` (decoupled)."
|
|
1569
2170
|
}
|
|
1570
2171
|
},
|
|
1571
|
-
"if": {
|
|
1572
|
-
|
|
2172
|
+
"if": {
|
|
2173
|
+
"properties": {
|
|
2174
|
+
"supported": {
|
|
2175
|
+
"const": true
|
|
2176
|
+
}
|
|
2177
|
+
},
|
|
2178
|
+
"required": [
|
|
2179
|
+
"supported"
|
|
2180
|
+
]
|
|
2181
|
+
},
|
|
2182
|
+
"then": {
|
|
2183
|
+
"required": [
|
|
2184
|
+
"supported",
|
|
2185
|
+
"tokenCounter"
|
|
2186
|
+
]
|
|
2187
|
+
}
|
|
1573
2188
|
}
|
|
1574
2189
|
},
|
|
1575
2190
|
"additionalProperties": true
|
|
@@ -1580,19 +2195,19 @@
|
|
|
1580
2195
|
},
|
|
1581
2196
|
"subWorkflow": {
|
|
1582
2197
|
"type": "object",
|
|
1583
|
-
"description": "Capability surface for `core.subWorkflow` extensions. The baseline `core.subWorkflow` contract (RFC 0007 + `node-packs.md`
|
|
2198
|
+
"description": "Capability surface for `core.subWorkflow` extensions. The baseline `core.subWorkflow` contract (RFC 0007 + `node-packs.md` \u00a7contract) is unconditional and does NOT require a capability flag; this object carries the additive extensions a host MAY support. Added by RFC 0022 \u00a7B + \u00a7C.",
|
|
1584
2199
|
"properties": {
|
|
1585
2200
|
"inputMapping": {
|
|
1586
2201
|
"type": "boolean",
|
|
1587
2202
|
"default": false,
|
|
1588
|
-
"description": "RFC 0022
|
|
2203
|
+
"description": "RFC 0022 \u00a7B. When `true`, host honors the `inputMapping` field on `core.subWorkflow` configs \u2014 seeding the child workflow's initial variable bag from `parentVariables[parentKey]` projections, overriding any matching `variables[].defaultValue` declaration on the child. When `false` or absent, hosts MUST refuse workflows that carry a non-empty `inputMapping` at registration with `validation_error` + `details.requiredCapability: 'subWorkflow.inputMapping'`. Silent ignore is NOT conformant."
|
|
1589
2204
|
}
|
|
1590
2205
|
},
|
|
1591
2206
|
"additionalProperties": false
|
|
1592
2207
|
},
|
|
1593
2208
|
"fs": {
|
|
1594
2209
|
"type": "object",
|
|
1595
|
-
"description": "RFC 0014 (`Active`). Filesystem capability
|
|
2210
|
+
"description": "RFC 0014 (`Active`). Filesystem capability \u2014 read/write/list/stat/delete inside a sandbox root. Required by the `core.openwop.files` pack. Hosts MUST resolve every input path relative to `sandboxRoot`, reject any path that escapes via `..` segments or symlinks, and enforce `maxFileSizeBytes` on write. Path-traversal rejection is normative \u2014 see `SECURITY/invariants.yaml` row `fs-path-traversal`.",
|
|
1596
2211
|
"properties": {
|
|
1597
2212
|
"supported": {
|
|
1598
2213
|
"type": "boolean",
|
|
@@ -1611,10 +2226,21 @@
|
|
|
1611
2226
|
"type": "object",
|
|
1612
2227
|
"description": "Image-processing sub-capability. Optional.",
|
|
1613
2228
|
"properties": {
|
|
1614
|
-
"supported": {
|
|
2229
|
+
"supported": {
|
|
2230
|
+
"type": "boolean"
|
|
2231
|
+
},
|
|
1615
2232
|
"formats": {
|
|
1616
2233
|
"type": "array",
|
|
1617
|
-
"items": {
|
|
2234
|
+
"items": {
|
|
2235
|
+
"type": "string",
|
|
2236
|
+
"enum": [
|
|
2237
|
+
"jpeg",
|
|
2238
|
+
"png",
|
|
2239
|
+
"webp",
|
|
2240
|
+
"avif",
|
|
2241
|
+
"gif"
|
|
2242
|
+
]
|
|
2243
|
+
}
|
|
1618
2244
|
}
|
|
1619
2245
|
},
|
|
1620
2246
|
"additionalProperties": false
|
|
@@ -1623,7 +2249,9 @@
|
|
|
1623
2249
|
"type": "object",
|
|
1624
2250
|
"description": "PDF-processing sub-capability. Optional.",
|
|
1625
2251
|
"properties": {
|
|
1626
|
-
"supported": {
|
|
2252
|
+
"supported": {
|
|
2253
|
+
"type": "boolean"
|
|
2254
|
+
}
|
|
1627
2255
|
},
|
|
1628
2256
|
"additionalProperties": false
|
|
1629
2257
|
},
|
|
@@ -1631,27 +2259,62 @@
|
|
|
1631
2259
|
"type": "object",
|
|
1632
2260
|
"description": "Network file-transport sub-capabilities. Optional.",
|
|
1633
2261
|
"properties": {
|
|
1634
|
-
"ftp": {
|
|
1635
|
-
|
|
1636
|
-
|
|
2262
|
+
"ftp": {
|
|
2263
|
+
"type": "boolean"
|
|
2264
|
+
},
|
|
2265
|
+
"sftp": {
|
|
2266
|
+
"type": "boolean"
|
|
2267
|
+
},
|
|
2268
|
+
"ssh": {
|
|
2269
|
+
"type": "boolean"
|
|
2270
|
+
}
|
|
1637
2271
|
},
|
|
1638
2272
|
"additionalProperties": false
|
|
1639
2273
|
}
|
|
1640
2274
|
},
|
|
1641
|
-
"if": {
|
|
1642
|
-
|
|
2275
|
+
"if": {
|
|
2276
|
+
"properties": {
|
|
2277
|
+
"supported": {
|
|
2278
|
+
"const": true
|
|
2279
|
+
}
|
|
2280
|
+
},
|
|
2281
|
+
"required": [
|
|
2282
|
+
"supported"
|
|
2283
|
+
]
|
|
2284
|
+
},
|
|
2285
|
+
"then": {
|
|
2286
|
+
"required": [
|
|
2287
|
+
"supported",
|
|
2288
|
+
"sandboxRoot"
|
|
2289
|
+
]
|
|
2290
|
+
},
|
|
1643
2291
|
"additionalProperties": false
|
|
1644
2292
|
},
|
|
1645
2293
|
"kvStorage": {
|
|
1646
2294
|
"type": "object",
|
|
1647
2295
|
"description": "RFC 0015 (`Active`). TTL-aware key-value store with atomic increment + compare-and-swap. Required by `core.openwop.storage` kv-* nodes. Hosts MUST partition values by tenant (`kv-cross-tenant-isolation` invariant) and atomically apply increments + CAS when those flags are advertised.",
|
|
1648
2296
|
"properties": {
|
|
1649
|
-
"supported": {
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
"
|
|
1653
|
-
|
|
1654
|
-
|
|
2297
|
+
"supported": {
|
|
2298
|
+
"type": "boolean"
|
|
2299
|
+
},
|
|
2300
|
+
"maxKeyBytes": {
|
|
2301
|
+
"type": "integer",
|
|
2302
|
+
"minimum": 0
|
|
2303
|
+
},
|
|
2304
|
+
"maxValueBytes": {
|
|
2305
|
+
"type": "integer",
|
|
2306
|
+
"minimum": 0
|
|
2307
|
+
},
|
|
2308
|
+
"maxTtlSeconds": {
|
|
2309
|
+
"type": "integer",
|
|
2310
|
+
"minimum": 0
|
|
2311
|
+
},
|
|
2312
|
+
"atomicIncrement": {
|
|
2313
|
+
"type": "boolean"
|
|
2314
|
+
},
|
|
2315
|
+
"compareAndSwap": {
|
|
2316
|
+
"type": "boolean"
|
|
2317
|
+
}
|
|
1655
2318
|
},
|
|
1656
2319
|
"additionalProperties": false
|
|
1657
2320
|
},
|
|
@@ -1659,29 +2322,62 @@
|
|
|
1659
2322
|
"type": "object",
|
|
1660
2323
|
"description": "RFC 0016 (`Active`). Structured-record store with user-defined schemas. Sibling to kvStorage. Cross-tenant isolation enforced (mirrors RFC 0015 invariant).",
|
|
1661
2324
|
"properties": {
|
|
1662
|
-
"supported": {
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
"
|
|
1666
|
-
|
|
2325
|
+
"supported": {
|
|
2326
|
+
"type": "boolean"
|
|
2327
|
+
},
|
|
2328
|
+
"maxRowsPerTable": {
|
|
2329
|
+
"type": "integer",
|
|
2330
|
+
"minimum": 0
|
|
2331
|
+
},
|
|
2332
|
+
"maxColumnsPerRow": {
|
|
2333
|
+
"type": "integer",
|
|
2334
|
+
"minimum": 0
|
|
2335
|
+
},
|
|
2336
|
+
"indexable": {
|
|
2337
|
+
"type": "boolean"
|
|
2338
|
+
},
|
|
2339
|
+
"fullTextSearch": {
|
|
2340
|
+
"type": "boolean"
|
|
2341
|
+
}
|
|
1667
2342
|
},
|
|
1668
2343
|
"additionalProperties": false
|
|
1669
2344
|
},
|
|
1670
2345
|
"queueBus": {
|
|
1671
2346
|
"type": "object",
|
|
1672
|
-
"description": "RFC 0017 (`Active`). Inbound queue + stream capability
|
|
2347
|
+
"description": "RFC 0017 (`Active`). Inbound queue + stream capability \u2014 publish, consume (trigger), ack/nack/dead-letter. Cross-tenant message isolation invariant (`queue-cross-tenant-isolation`). Sibling to host.messaging (which is outbound-egress-only).",
|
|
1673
2348
|
"properties": {
|
|
1674
|
-
"supported": {
|
|
2349
|
+
"supported": {
|
|
2350
|
+
"type": "boolean"
|
|
2351
|
+
},
|
|
1675
2352
|
"backends": {
|
|
1676
2353
|
"type": "array",
|
|
1677
|
-
"items": {
|
|
2354
|
+
"items": {
|
|
2355
|
+
"type": "string",
|
|
2356
|
+
"enum": [
|
|
2357
|
+
"rabbitmq",
|
|
2358
|
+
"kafka",
|
|
2359
|
+
"sqs",
|
|
2360
|
+
"sns",
|
|
2361
|
+
"pubsub",
|
|
2362
|
+
"mqtt",
|
|
2363
|
+
"nats",
|
|
2364
|
+
"redis-streams",
|
|
2365
|
+
"in-memory"
|
|
2366
|
+
]
|
|
2367
|
+
}
|
|
2368
|
+
},
|
|
2369
|
+
"deadLetterSupported": {
|
|
2370
|
+
"type": "boolean"
|
|
1678
2371
|
},
|
|
1679
|
-
"deadLetterSupported": { "type": "boolean" },
|
|
1680
2372
|
"stream": {
|
|
1681
2373
|
"type": "object",
|
|
1682
2374
|
"properties": {
|
|
1683
|
-
"supported": {
|
|
1684
|
-
|
|
2375
|
+
"supported": {
|
|
2376
|
+
"type": "boolean"
|
|
2377
|
+
},
|
|
2378
|
+
"fromBeginning": {
|
|
2379
|
+
"type": "boolean"
|
|
2380
|
+
}
|
|
1685
2381
|
},
|
|
1686
2382
|
"additionalProperties": false
|
|
1687
2383
|
}
|
|
@@ -1690,112 +2386,260 @@
|
|
|
1690
2386
|
},
|
|
1691
2387
|
"scheduling": {
|
|
1692
2388
|
"type": "object",
|
|
1693
|
-
"description": "RFC 0052 (`Draft`). Time-based run initiation behind the `schedule` trigger
|
|
1694
|
-
"required": [
|
|
2389
|
+
"description": "RFC 0052 (`Draft`). Time-based run initiation behind the `schedule` trigger \u2014 gives the trigger a portable, durable, once-per-tick execution contract. Composes with `queueBus` (RFC 0017) where the host backs scheduling with a queue; orthogonal to the in-DAG `core.control.delay` primitive (which delays a node mid-run, not run initiation).",
|
|
2390
|
+
"required": [
|
|
2391
|
+
"supported"
|
|
2392
|
+
],
|
|
1695
2393
|
"properties": {
|
|
1696
|
-
"supported": {
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
"
|
|
1700
|
-
|
|
2394
|
+
"supported": {
|
|
2395
|
+
"type": "boolean"
|
|
2396
|
+
},
|
|
2397
|
+
"cron": {
|
|
2398
|
+
"type": "boolean",
|
|
2399
|
+
"description": "Host honors cron-expression schedules."
|
|
2400
|
+
},
|
|
2401
|
+
"delayed": {
|
|
2402
|
+
"type": "boolean",
|
|
2403
|
+
"description": "Host honors one-shot delayed execution."
|
|
2404
|
+
},
|
|
2405
|
+
"calendar": {
|
|
2406
|
+
"type": "boolean",
|
|
2407
|
+
"description": "Host honors calendar-reference schedules."
|
|
2408
|
+
},
|
|
2409
|
+
"maxFutureHorizon": {
|
|
2410
|
+
"type": "string",
|
|
2411
|
+
"description": "ISO-8601 duration (e.g. `P90D`); the farthest-future a run may be scheduled. Schedules beyond it MUST be rejected with `schedule_horizon_exceeded`."
|
|
2412
|
+
}
|
|
1701
2413
|
},
|
|
1702
2414
|
"additionalProperties": false
|
|
1703
2415
|
},
|
|
1704
2416
|
"heartbeat": {
|
|
1705
2417
|
"type": "object",
|
|
1706
2418
|
"description": "RFC 0060 (`Draft`). System-managed, predicate-gated polling: a short-interval, runtime-bounded evaluation of an idempotent predicate that emits state-change events and conditionally enqueues a run, rather than re-running an agent blindly. Composes with `scheduling` (RFC 0052) for the once-per-tick interval substrate; the controlled, request-shaped exception to openwop's poll-free design (`positioning.md`).",
|
|
1707
|
-
"required": [
|
|
2419
|
+
"required": [
|
|
2420
|
+
"supported"
|
|
2421
|
+
],
|
|
1708
2422
|
"properties": {
|
|
1709
|
-
"supported": {
|
|
1710
|
-
|
|
1711
|
-
|
|
2423
|
+
"supported": {
|
|
2424
|
+
"type": "boolean"
|
|
2425
|
+
},
|
|
2426
|
+
"minIntervalSec": {
|
|
2427
|
+
"type": "integer",
|
|
2428
|
+
"minimum": 1,
|
|
2429
|
+
"description": "Smallest interval the host honors; requests below it clamp up."
|
|
2430
|
+
},
|
|
2431
|
+
"maxRuntimeMs": {
|
|
2432
|
+
"type": "integer",
|
|
2433
|
+
"minimum": 1,
|
|
2434
|
+
"description": "Per-tick predicate-evaluation budget; bounded above by `capabilities.limits.maxRunDurationMs` (RFC 0058) as the hard ceiling. Over-budget evaluation is terminated and reported as `heartbeat.evaluated { status: 'timeout' }`."
|
|
2435
|
+
}
|
|
1712
2436
|
},
|
|
1713
2437
|
"additionalProperties": false
|
|
1714
2438
|
},
|
|
1715
2439
|
"toolHooks": {
|
|
1716
2440
|
"type": "object",
|
|
1717
|
-
"description": "RFC 0064 (`Active`)
|
|
1718
|
-
"required": [
|
|
2441
|
+
"description": "RFC 0064 (`Active`) \u2014 sibling of `heartbeat`. Per-tool authorization + rate limiting + content-free tool-call audit fields, layered on the existing `agent.toolCalled` / `agent.toolReturned` events (RFC 0002). Generalizes the MCP-specific bridges across transports (mcp / http / native). Reuses RFC 0049's `forbidden` error + `authorization-fail-closed` invariant and the existing `rate_limited` error \u2014 no new event type, error code, or invariant.",
|
|
2442
|
+
"required": [
|
|
2443
|
+
"supported"
|
|
2444
|
+
],
|
|
1719
2445
|
"additionalProperties": false,
|
|
1720
2446
|
"properties": {
|
|
1721
|
-
"supported": {
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
"
|
|
2447
|
+
"supported": {
|
|
2448
|
+
"type": "boolean"
|
|
2449
|
+
},
|
|
2450
|
+
"prePostEvents": {
|
|
2451
|
+
"type": "boolean",
|
|
2452
|
+
"description": "Host populates `argsHash`/`principal`/`transport` on `agent.toolCalled` + `status`/`durationMs` on `agent.toolReturned` for every external tool call."
|
|
2453
|
+
},
|
|
2454
|
+
"perToolAuthorization": {
|
|
2455
|
+
"type": "boolean",
|
|
2456
|
+
"description": "Host enforces per-tool scopes against the run principal (RFC 0049), fail-closed; a lacked-or-unevaluable scope yields `agent.toolReturned { status: 'forbidden' }` + a `forbidden` (403) error and the tool is never invoked."
|
|
2457
|
+
},
|
|
2458
|
+
"perToolRateLimit": {
|
|
2459
|
+
"type": "boolean",
|
|
2460
|
+
"description": "Host applies a per-`(principal, tool)` token-bucket rate limit; exhaustion yields `agent.toolReturned { status: 'rate_limited' }` + a `rate_limited` (429) error."
|
|
2461
|
+
}
|
|
1725
2462
|
}
|
|
1726
2463
|
},
|
|
1727
2464
|
"toolCatalog": {
|
|
1728
2465
|
"type": "object",
|
|
1729
|
-
"description": "RFC 0078 (`Active`). The host exposes a read-only projection of its tool surfaces (node-pack / workflow / MCP / connector / host-extension) at `GET /v1/tools` + `GET /v1/tools/{toolId}`, returning `ToolDescriptor` records (`tool-descriptor.schema.json`). Optional; hosts that omit it expose no catalog (today's behavior) and the conformance scenarios skip cleanly. Read-only
|
|
1730
|
-
"required": [
|
|
2466
|
+
"description": "RFC 0078 (`Active`). The host exposes a read-only projection of its tool surfaces (node-pack / workflow / MCP / connector / host-extension) at `GET /v1/tools` + `GET /v1/tools/{toolId}`, returning `ToolDescriptor` records (`tool-descriptor.schema.json`). Optional; hosts that omit it expose no catalog (today's behavior) and the conformance scenarios skip cleanly. Read-only \u2014 the catalog never mutates tools; tool invocation stays on the existing surfaces (agent dispatch, `core.dispatch`, MCP). The listing is authorization-scoped + non-disclosing (RFC 0074 pattern).",
|
|
2467
|
+
"required": [
|
|
2468
|
+
"supported"
|
|
2469
|
+
],
|
|
1731
2470
|
"additionalProperties": false,
|
|
1732
2471
|
"properties": {
|
|
1733
|
-
"supported": {
|
|
2472
|
+
"supported": {
|
|
2473
|
+
"type": "boolean",
|
|
2474
|
+
"description": "REQUIRED when present. `true` \u21d2 `GET /v1/tools` + `GET /v1/tools/{toolId}` are served per RFC 0078 \u00a7B."
|
|
2475
|
+
},
|
|
1734
2476
|
"sources": {
|
|
1735
2477
|
"type": "array",
|
|
1736
2478
|
"uniqueItems": true,
|
|
1737
|
-
"items": {
|
|
1738
|
-
|
|
2479
|
+
"items": {
|
|
2480
|
+
"type": "string",
|
|
2481
|
+
"enum": [
|
|
2482
|
+
"node-pack",
|
|
2483
|
+
"workflow",
|
|
2484
|
+
"mcp",
|
|
2485
|
+
"connector",
|
|
2486
|
+
"host-extension"
|
|
2487
|
+
]
|
|
2488
|
+
},
|
|
2489
|
+
"description": "Which tool sources the catalog projects. A host advertises only the sources it actually surfaces; a consumer MUST tolerate any subset. Absent \u21d2 all sources the host implements."
|
|
2490
|
+
},
|
|
2491
|
+
"sessionLifecycle": {
|
|
2492
|
+
"type": "boolean",
|
|
2493
|
+
"description": "`true` \u21d2 the host emits the RFC 0078 \u00a7D tool-session lifecycle events (`tool.session.opened`/`tool.session.closed`, content-free) bracketing the existing RFC 0064 `agent.toolCalled`/`agent.toolReturned` call events for multi-step interactions. Absent \u21d2 `false` (single-shot tool calls only)."
|
|
1739
2494
|
},
|
|
1740
|
-
"
|
|
1741
|
-
|
|
2495
|
+
"compactView": {
|
|
2496
|
+
"type": "boolean",
|
|
2497
|
+
"description": "RFC 0112. `true` \u21d2 the host honors `GET /v1/tools?view=compact` + `GET /v1/tools/{toolId}?view=compact`, returning the `{ tools: CompactToolDescriptor[] }` projection (`compact-tool-descriptor.schema.json`): the heavy descriptor fields (`outputSchema`/`auth`/`egress`/`approval`/`replayPolicy`/`costHint`/`latencyHint`) are dropped and any `inputSchema` is bounded to the compact structural subset. The compact `tools[]` carries the same `toolId` set as the standard view for the same principal. Absent \u21d2 the host treats `view=compact` as an unknown query param (standard view)."
|
|
2498
|
+
}
|
|
1742
2499
|
}
|
|
1743
2500
|
},
|
|
1744
2501
|
"httpClient": {
|
|
1745
2502
|
"type": "object",
|
|
1746
|
-
"description": "Host outbound-HTTP surface. The host's HTTP-client node egress (e.g. `core.http.request`) MUST be SSRF-guarded (`ssrfGuard: true`) with a positive `maxResponseBodyBytes` cap
|
|
1747
|
-
"required": [
|
|
2503
|
+
"description": "Host outbound-HTTP surface. The host's HTTP-client node egress (e.g. `core.http.request`) MUST be SSRF-guarded (`ssrfGuard: true`) with a positive `maxResponseBodyBytes` cap \u2014 the `http-client-ssrf-guard` protocol invariant. RFC 0076 \u00a7B adds the OPTIONAL `safeFetch` sub-capability: a host-mediated `ctx.http.safeFetch(url, init?)` exposed to pack runtime code, backed by the SAME SSRF guard (resolve\u2192pin\u2192connect, metadata-endpoint blocklist, DNS-rebinding defeat) so packs need not reach for raw DNS/sockets. See `host-capabilities.md` \u00a7host.http.",
|
|
2504
|
+
"required": [
|
|
2505
|
+
"supported"
|
|
2506
|
+
],
|
|
1748
2507
|
"additionalProperties": false,
|
|
1749
2508
|
"properties": {
|
|
1750
|
-
"supported": {
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
"
|
|
1754
|
-
|
|
2509
|
+
"supported": {
|
|
2510
|
+
"type": "boolean"
|
|
2511
|
+
},
|
|
2512
|
+
"ssrfGuard": {
|
|
2513
|
+
"type": "boolean",
|
|
2514
|
+
"description": "Host rejects egress to loopback / RFC 1918 / link-local / cloud-metadata addresses (resolve\u2192pin\u2192connect). MUST be `true` when `supported` (the `http-client-ssrf-guard` invariant)."
|
|
2515
|
+
},
|
|
2516
|
+
"maxResponseBodyBytes": {
|
|
2517
|
+
"type": "integer",
|
|
2518
|
+
"minimum": 1,
|
|
2519
|
+
"description": "Positive ceiling on a response body the host will buffer. Reused by `safeFetch`."
|
|
2520
|
+
},
|
|
2521
|
+
"requestTimeoutMs": {
|
|
2522
|
+
"type": "integer",
|
|
2523
|
+
"minimum": 1,
|
|
2524
|
+
"description": "Host-enforced per-request wall-clock timeout (also applies to `safeFetch`)."
|
|
2525
|
+
},
|
|
2526
|
+
"methods": {
|
|
2527
|
+
"type": "array",
|
|
2528
|
+
"items": {
|
|
2529
|
+
"type": "string"
|
|
2530
|
+
},
|
|
2531
|
+
"description": "HTTP methods the client surface accepts (e.g. `GET`, `POST`)."
|
|
2532
|
+
},
|
|
1755
2533
|
"safeFetch": {
|
|
1756
2534
|
"type": "object",
|
|
1757
|
-
"description": "RFC 0076
|
|
1758
|
-
"required": [
|
|
2535
|
+
"description": "RFC 0076 \u00a7B. Host-provided `ctx.http.safeFetch(url, init?)` for pack runtime code \u2014 the pack-facing exposure of the SSRF-guarded client. When advertised, the host MUST apply the \u00a7host.http SSRF defense + clamps (incl. refusing `Connection: upgrade`), and \u2014 when `toolHooks.prePostEvents` is also advertised \u2014 MUST emit the `agent.toolCalled`/`agent.toolReturned` pair (`transport: 'http'`) for each call. A pack that uses `safeFetch` need not declare `net.dns` in `runtime.requires` (the host owns resolution; RFC 0076 \u00a7A).",
|
|
2536
|
+
"required": [
|
|
2537
|
+
"supported"
|
|
2538
|
+
],
|
|
1759
2539
|
"additionalProperties": false,
|
|
1760
2540
|
"properties": {
|
|
1761
|
-
"supported": {
|
|
2541
|
+
"supported": {
|
|
2542
|
+
"type": "boolean"
|
|
2543
|
+
}
|
|
1762
2544
|
}
|
|
1763
2545
|
},
|
|
1764
2546
|
"egressPolicy": {
|
|
1765
2547
|
"type": "object",
|
|
1766
2548
|
"additionalProperties": false,
|
|
1767
|
-
"description": "RFC 0079. The host evaluates credential provenance (`credential-provenance.schema.json`) + the audience-binding MUST (
|
|
1768
|
-
"required": [
|
|
2549
|
+
"description": "RFC 0079. The host evaluates credential provenance (`credential-provenance.schema.json`) + the audience-binding MUST (\u00a7C) on credentialed egress and emits `egress.decided` (\u00a7B). Requires `httpClient.safeFetch` (the egress mechanism). Absent \u21d2 the host does not perform provenance binding (the RFC 0076 \u00a7B SSRF guard still applies); the conformance behavioral scenarios skip cleanly. Closes the credential\u2194destination-binding question RFC 0076 \u00a7B parked.",
|
|
2550
|
+
"required": [
|
|
2551
|
+
"supported"
|
|
2552
|
+
],
|
|
1769
2553
|
"properties": {
|
|
1770
|
-
"supported": {
|
|
1771
|
-
|
|
2554
|
+
"supported": {
|
|
2555
|
+
"type": "boolean",
|
|
2556
|
+
"description": "REQUIRED when present. `true` \u21d2 the \u00a7C audience-binding MUST is enforced + `egress.decided` is emitted."
|
|
2557
|
+
},
|
|
2558
|
+
"decisions": {
|
|
2559
|
+
"type": "array",
|
|
2560
|
+
"uniqueItems": true,
|
|
2561
|
+
"items": {
|
|
2562
|
+
"type": "string",
|
|
2563
|
+
"enum": [
|
|
2564
|
+
"allowed",
|
|
2565
|
+
"denied",
|
|
2566
|
+
"downgraded",
|
|
2567
|
+
"approval-required"
|
|
2568
|
+
]
|
|
2569
|
+
},
|
|
2570
|
+
"description": "MAY \u2014 which decision outcomes the host implements. Absent \u21d2 at least `allowed` + `denied`."
|
|
2571
|
+
}
|
|
1772
2572
|
}
|
|
1773
2573
|
}
|
|
1774
2574
|
}
|
|
1775
2575
|
},
|
|
1776
2576
|
"artifactTypes": {
|
|
1777
2577
|
"type": "object",
|
|
1778
|
-
"description": "RFC 0071, amended by RFC 0075; declared by RFC 0144. Host artifact-type surface
|
|
2578
|
+
"description": "RFC 0071, amended by RFC 0075; declared by RFC 0144. Host artifact-type surface \u2014 an advertisement (no `ctx.artifactTypes.*` method) that changes how the host treats the artifact references already on the wire (`nodes[].artifact.typeId`, `WorkflowNode.artifactType`, `artifact.created.artifactType`). Carries the corpus's only emission MUST: a host advertising `store: true` MUST persist registered artifacts and emit `artifact.created`. See `host-capabilities.md` \u00a7host.artifactTypes and `artifact-type-packs.md` \u00a7\"Host capability\". The discovery key is the PLAIN family name at the document root (RFC 0137 G16); `host.artifactTypes` is the capability IDENTIFIER used in pack `peerDependencies`, not this key.",
|
|
1779
2579
|
"additionalProperties": false,
|
|
1780
2580
|
"properties": {
|
|
1781
|
-
"supported": {
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2581
|
+
"supported": {
|
|
2582
|
+
"type": "boolean",
|
|
2583
|
+
"description": "Host honors registered artifact types \u2014 validates an artifact whose type is registered (pack-installed or host-native) against that type's schema before emitting `artifact.created`, setting `registered: true` + `registrationSource`. Unregistered types stay accepted unvalidated with `registered: false`."
|
|
2584
|
+
},
|
|
2585
|
+
"store": {
|
|
2586
|
+
"type": "boolean",
|
|
2587
|
+
"description": "`true` \u21d2 the host persists artifacts of registered types AND emits `artifact.created`. Advertising this is a commitment to emit; RFC 0142 leg B is the witness."
|
|
2588
|
+
},
|
|
2589
|
+
"render": {
|
|
2590
|
+
"type": "boolean",
|
|
2591
|
+
"description": "Advisory \u2014 the spec defines no rendering surface. A host advertising `false` for a type it can `store` MUST still accept and store the artifact and MUST NOT fail the run for lack of a renderer (the store-without-render negotiation guarantee)."
|
|
2592
|
+
},
|
|
2593
|
+
"export": {
|
|
2594
|
+
"type": "array",
|
|
2595
|
+
"items": {
|
|
2596
|
+
"type": "string"
|
|
2597
|
+
},
|
|
2598
|
+
"description": "Export-format identifiers the host can materialize, drawn from declared `exportFormats`. Advisory."
|
|
2599
|
+
},
|
|
1785
2600
|
"types": {
|
|
1786
2601
|
"type": "object",
|
|
1787
|
-
"description": "RFC 0075 per-type facets, keyed by `artifactTypeId`. Each entry overrides the global object for that type; the global object is the fallback for any type not listed (absent
|
|
2602
|
+
"description": "RFC 0075 per-type facets, keyed by `artifactTypeId`. Each entry overrides the global object for that type; the global object is the fallback for any type not listed (absent \u21d2 host-global semantics; any facet absent \u21d2 the global default \u2014 additive).",
|
|
1788
2603
|
"additionalProperties": {
|
|
1789
2604
|
"type": "object",
|
|
1790
2605
|
"additionalProperties": false,
|
|
1791
2606
|
"properties": {
|
|
1792
|
-
"validated": {
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
"
|
|
1797
|
-
|
|
1798
|
-
|
|
2607
|
+
"validated": {
|
|
2608
|
+
"type": "boolean",
|
|
2609
|
+
"description": "The runtime validation guarantee \u2014 `true` \u21d2 the host validates this type before emit, so emits `registered: true`. Decoupled from `schemaVersions`, which is a version DECLARATION only."
|
|
2610
|
+
},
|
|
2611
|
+
"validation": {
|
|
2612
|
+
"type": "string",
|
|
2613
|
+
"enum": [
|
|
2614
|
+
"open",
|
|
2615
|
+
"closed"
|
|
2616
|
+
],
|
|
2617
|
+
"description": "Mirrors `ArtifactType.validation`, surfacing schema strictness in discovery so a consumer needn't fetch the schema. Default `\"open\"` per `COMPATIBILITY.md` \u00a72.1."
|
|
2618
|
+
},
|
|
2619
|
+
"schemaVersion": {
|
|
2620
|
+
"type": "integer",
|
|
2621
|
+
"minimum": 0
|
|
2622
|
+
},
|
|
2623
|
+
"registrationSource": {
|
|
2624
|
+
"type": "string",
|
|
2625
|
+
"enum": [
|
|
2626
|
+
"pack",
|
|
2627
|
+
"host"
|
|
2628
|
+
],
|
|
2629
|
+
"description": "RFC 0145. Provenance of this registered type: `pack` (an installed artifact-type pack backs it) or `host` (host-native, validated against a host-known schema with no pack). Mirrors `artifact.created.registrationSource` and MUST match what the host would emit for this type \u2014 the two surfaces MUST NOT disagree. OPTIONAL; absent \u21d2 unspecified provenance, NOT a default of `pack`. Discloses which \u00a7\"Schema distribution\" regime applies: serving the canonical schema URL is a MUST for host-registered (no-pack) types and only a SHOULD for pack-backed ones, and nothing else in the advert reveals which. A host MUST NOT infer this from the identifier's shape \u2014 `vendor.*` is a registry namespace, not an installation claim."
|
|
2630
|
+
},
|
|
2631
|
+
"store": {
|
|
2632
|
+
"type": "boolean"
|
|
2633
|
+
},
|
|
2634
|
+
"render": {
|
|
2635
|
+
"type": "boolean"
|
|
2636
|
+
},
|
|
2637
|
+
"export": {
|
|
2638
|
+
"type": "array",
|
|
2639
|
+
"items": {
|
|
2640
|
+
"type": "string"
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
1799
2643
|
}
|
|
1800
2644
|
}
|
|
1801
2645
|
}
|
|
@@ -1803,177 +2647,461 @@
|
|
|
1803
2647
|
},
|
|
1804
2648
|
"forms": {
|
|
1805
2649
|
"type": "object",
|
|
1806
|
-
"description": "RFC 0137; declared by RFC 0144. Host form-content-pack surface
|
|
2650
|
+
"description": "RFC 0137; declared by RFC 0144. Host form-content-pack surface \u2014 like `artifactTypes` it adds no `ctx.forms.*` method; it advertises that the host resolves registered form templates from installed `kind: \"form-content\"` packs and instantiates them through its own normal create path. See `host-capabilities.md` \u00a7host.forms and `form-content-packs.md`. The discovery key is the PLAIN family name at the document root (RFC 0137 G16); a host may additionally carry a deprecated dotted `\"host.forms\"` mirror during migration \u2014 root `additionalProperties` stays `true` so that document remains valid.",
|
|
1807
2651
|
"additionalProperties": false,
|
|
1808
2652
|
"properties": {
|
|
1809
|
-
"contentPacks": {
|
|
2653
|
+
"contentPacks": {
|
|
2654
|
+
"type": "boolean",
|
|
2655
|
+
"description": "`true` \u21d2 the host instantiates registered form templates. Normative consequences (`form-content-packs.md` \u00a7\"Instantiation\"): create through the SAME path a hand-authored form uses; degrade an unrecognized field type to a plain text input rather than failing; keep the instantiated form fully editable; execute nothing from the pack; sanitize/validate/authorize submissions exactly as hand-typed input. Pack-authored strings are UNTRUSTED and MUST propagate `meta.contentTrust: \"untrusted\"` into interpolated prompt segments (invariant `form-content-pack-string-trust-boundary`) \u2014 a signature proves authorship, not content safety."
|
|
2656
|
+
}
|
|
1810
2657
|
}
|
|
1811
2658
|
},
|
|
1812
2659
|
"aiEnvelope": {
|
|
1813
2660
|
"type": "object",
|
|
1814
|
-
"description": "Declared by RFC 0144. Host typed-envelope generation surface (`ctx.aiEnvelope.generate`), routing the call through the host's BYOK provider layer. Opinionated about envelope shape, unlike the lower-level `aiProviders` capability which returns raw model output. See `host-capabilities.md`
|
|
2661
|
+
"description": "Declared by RFC 0144. Host typed-envelope generation surface (`ctx.aiEnvelope.generate`), routing the call through the host's BYOK provider layer. Opinionated about envelope shape, unlike the lower-level `aiProviders` capability which returns raw model output. See `host-capabilities.md` \u00a7host.aiEnvelope and `ai-envelope.md`.",
|
|
1815
2662
|
"additionalProperties": false,
|
|
1816
2663
|
"properties": {
|
|
1817
|
-
"supported": {
|
|
1818
|
-
|
|
2664
|
+
"supported": {
|
|
2665
|
+
"type": "boolean",
|
|
2666
|
+
"description": "`true` \u21d2 `ctx.aiEnvelope.generate` is exposed. Absent/`false` \u21d2 packs binding this surface fail with `host_capability_missing`."
|
|
2667
|
+
},
|
|
2668
|
+
"await": {
|
|
2669
|
+
"type": "boolean",
|
|
2670
|
+
"description": "`true` \u21d2 `ctx.aiEnvelope.await` is ALSO exposed. `generate` is required whenever the family is advertised; `await` is required only when this sub-flag is."
|
|
2671
|
+
}
|
|
1819
2672
|
}
|
|
1820
2673
|
},
|
|
1821
2674
|
"promptLibrary": {
|
|
1822
2675
|
"type": "object",
|
|
1823
|
-
"description": "Declared by RFC 0144. Host prompt-lookup surface (`ctx.promptLibrary.get`), returning a prompt pinned to a specific version so replay stays deterministic. Consumed by `core.ai.callPrompt`. See `host-capabilities.md`
|
|
2676
|
+
"description": "Declared by RFC 0144. Host prompt-lookup surface (`ctx.promptLibrary.get`), returning a prompt pinned to a specific version so replay stays deterministic. Consumed by `core.ai.callPrompt`. See `host-capabilities.md` \u00a7host.promptLibrary.",
|
|
1824
2677
|
"additionalProperties": false,
|
|
1825
2678
|
"properties": {
|
|
1826
|
-
"supported": {
|
|
2679
|
+
"supported": {
|
|
2680
|
+
"type": "boolean",
|
|
2681
|
+
"description": "`true` \u21d2 `ctx.promptLibrary.get(promptId)` resolves a `{ promptId, systemPrompt, version, envelopeType? }` record. The returned `version` MUST pin the prompt text for replay."
|
|
2682
|
+
}
|
|
1827
2683
|
}
|
|
1828
2684
|
},
|
|
1829
2685
|
"agentRuntime": {
|
|
1830
2686
|
"type": "object",
|
|
1831
|
-
"description": "Declared by RFC 0144. The heavyweight swarm/consensus SUPERSET of the agent surface
|
|
2687
|
+
"description": "Declared by RFC 0144. The heavyweight swarm/consensus SUPERSET of the agent surface \u2014 spawn, delegate, consensus, message-send, skill-invoke, swarm-execute over RFC 0002/0003/0007 primitives. Advertising it IMPLIES `agents.manifestRuntime` (RFC 0070 \u00a7B), since `spawn({ manifestId })` instantiates a manifest agent; hosts needing only single-agent or crew dispatch advertise that floor and omit this family. Per-tool authorization, rate limiting, and the content-free tool-call audit trail live in the top-level `toolHooks` block, NOT under this family. See `host-capabilities.md` \u00a7host.agentRuntime.",
|
|
1832
2688
|
"additionalProperties": false,
|
|
1833
2689
|
"properties": {
|
|
1834
|
-
"supported": {
|
|
2690
|
+
"supported": {
|
|
2691
|
+
"type": "boolean",
|
|
2692
|
+
"description": "`true` \u21d2 `ctx.agentRuntime.*` is exposed AND `agents.manifestRuntime` is implied (RFC 0070 \u00a7B). A multi-tenant host additionally advertises `agents.manifestRuntime.installScope: 'tenant'` (RFC 0074) so `GET /v1/agents` scopes to the caller's owner triple."
|
|
2693
|
+
}
|
|
1835
2694
|
}
|
|
1836
2695
|
},
|
|
1837
2696
|
"deadLetter": {
|
|
1838
2697
|
"type": "object",
|
|
1839
2698
|
"description": "RFC 0053 (`Draft`). Run-level dead-letter sink for terminally-failed runs/nodes. On retry exhaustion (RFC 0009), the run is routed to a durable, inspectable sink and a `run.dead_lettered` event is emitted; dead-lettered runs remain fork-eligible (RFC 0011) for the retention window. Distinct from `queueBus.deadLetterSupported`, which dead-letters transport *messages*, not *runs*.",
|
|
1840
|
-
"required": [
|
|
2699
|
+
"required": [
|
|
2700
|
+
"supported"
|
|
2701
|
+
],
|
|
1841
2702
|
"properties": {
|
|
1842
|
-
"supported": {
|
|
1843
|
-
|
|
2703
|
+
"supported": {
|
|
2704
|
+
"type": "boolean"
|
|
2705
|
+
},
|
|
2706
|
+
"retentionDays": {
|
|
2707
|
+
"type": "integer",
|
|
2708
|
+
"minimum": 1,
|
|
2709
|
+
"description": "Days a dead-lettered run is retained for inspection/fork before purge."
|
|
2710
|
+
}
|
|
1844
2711
|
},
|
|
1845
2712
|
"additionalProperties": false
|
|
1846
2713
|
},
|
|
1847
2714
|
"webhooks": {
|
|
1848
2715
|
"type": "object",
|
|
1849
|
-
"description": "Webhook delivery surface (`webhooks.md`). The base contract is best-effort (5s per-attempt timeout, a circuit breaker, no durable retry). RFC 0083 adds the OPTIONAL `durable` mode: when `true`, webhook delivery participates in the trigger-bridge durable model (subscription states + retry policy + dead-letter on exhaustion) instead of the best-effort circuit-breaker-then-drop. Absent `durable`
|
|
2716
|
+
"description": "Webhook delivery surface (`webhooks.md`). The base contract is best-effort (5s per-attempt timeout, a circuit breaker, no durable retry). RFC 0083 adds the OPTIONAL `durable` mode: when `true`, webhook delivery participates in the trigger-bridge durable model (subscription states + retry policy + dead-letter on exhaustion) instead of the best-effort circuit-breaker-then-drop. Absent `durable` \u21d2 the best-effort default, explicitly unchanged.",
|
|
1850
2717
|
"additionalProperties": true,
|
|
1851
2718
|
"properties": {
|
|
1852
|
-
"supported": {
|
|
1853
|
-
|
|
1854
|
-
|
|
2719
|
+
"supported": {
|
|
2720
|
+
"type": "boolean",
|
|
2721
|
+
"description": "Host serves the `webhooks.md` signed-delivery surface."
|
|
2722
|
+
},
|
|
2723
|
+
"signatureAlgorithms": {
|
|
2724
|
+
"type": "array",
|
|
2725
|
+
"items": {
|
|
2726
|
+
"type": "string"
|
|
2727
|
+
},
|
|
2728
|
+
"uniqueItems": true,
|
|
2729
|
+
"description": "HMAC signature algorithm ids the host supports (e.g. `v1`)."
|
|
2730
|
+
},
|
|
2731
|
+
"durable": {
|
|
2732
|
+
"type": "boolean",
|
|
2733
|
+
"description": "RFC 0083 \u00a7A \u2014 OPTIONAL opt-in. `true` \u21d2 webhook delivery is durable (a trigger-bridge source); absent/`false` \u21d2 the best-effort `webhooks.md` contract, unchanged. The best-effort default is NOT relaxed."
|
|
2734
|
+
}
|
|
1855
2735
|
}
|
|
1856
2736
|
},
|
|
1857
2737
|
"triggerBridge": {
|
|
1858
2738
|
"type": "object",
|
|
1859
|
-
"description": "RFC 0083 (`Active`). Composes the existing scheduling (RFC 0052), dead-letter (RFC 0053), queue-bus (RFC 0017), webhook, and cross-host-causation (RFC 0040) primitives into one uniform durable inbound-work contract: standardized subscription states + a delivery-attempt/dedup/retry model + trigger
|
|
1860
|
-
"required": [
|
|
2739
|
+
"description": "RFC 0083 (`Active`). Composes the existing scheduling (RFC 0052), dead-letter (RFC 0053), queue-bus (RFC 0017), webhook, and cross-host-causation (RFC 0040) primitives into one uniform durable inbound-work contract: standardized subscription states + a delivery-attempt/dedup/retry model + trigger\u2192run causation. Backs the derived `openwop-trigger-bridge` profile. Channels (Slack/email/SMS) stay vendor extensions (\u00a7E) \u2014 only their bridge into a run is uniform. Hosts that omit it have no uniform trigger contract (today's behavior); the conformance behavioral scenarios skip cleanly.",
|
|
2740
|
+
"required": [
|
|
2741
|
+
"supported"
|
|
2742
|
+
],
|
|
1861
2743
|
"additionalProperties": false,
|
|
1862
2744
|
"properties": {
|
|
1863
|
-
"supported": {
|
|
1864
|
-
|
|
1865
|
-
|
|
2745
|
+
"supported": {
|
|
2746
|
+
"type": "boolean",
|
|
2747
|
+
"description": "REQUIRED when present. `true` \u21d2 the host implements the \u00a7B state machine + \u00a7C delivery model + emits the two `trigger.*` events."
|
|
2748
|
+
},
|
|
2749
|
+
"subscriptionStates": {
|
|
2750
|
+
"type": "array",
|
|
2751
|
+
"uniqueItems": true,
|
|
2752
|
+
"items": {
|
|
2753
|
+
"type": "string",
|
|
2754
|
+
"enum": [
|
|
2755
|
+
"active",
|
|
2756
|
+
"paused",
|
|
2757
|
+
"failed",
|
|
2758
|
+
"dead-lettered"
|
|
2759
|
+
]
|
|
2760
|
+
},
|
|
2761
|
+
"description": "The subscription states the host implements (the \u00a7B four-state vocabulary). Absent \u21d2 at least `active` + `dead-lettered`."
|
|
2762
|
+
},
|
|
2763
|
+
"dedup": {
|
|
2764
|
+
"type": "boolean",
|
|
2765
|
+
"description": "`true` \u21d2 the host de-duplicates inbound events by `dedupKey` within the retention window (\u00a7C-1; at-least-once becomes effectively-once)."
|
|
2766
|
+
},
|
|
1866
2767
|
"retryPolicy": {
|
|
1867
2768
|
"type": "object",
|
|
1868
2769
|
"additionalProperties": false,
|
|
1869
|
-
"description": "The host's default delivery retry policy (
|
|
2770
|
+
"description": "The host's default delivery retry policy (\u00a7C-2).",
|
|
1870
2771
|
"properties": {
|
|
1871
|
-
"maxAttempts": {
|
|
1872
|
-
|
|
2772
|
+
"maxAttempts": {
|
|
2773
|
+
"type": "integer",
|
|
2774
|
+
"minimum": 1,
|
|
2775
|
+
"description": "Max delivery attempts before dead-lettering."
|
|
2776
|
+
},
|
|
2777
|
+
"backoff": {
|
|
2778
|
+
"type": "string",
|
|
2779
|
+
"enum": [
|
|
2780
|
+
"none",
|
|
2781
|
+
"fixed",
|
|
2782
|
+
"exponential"
|
|
2783
|
+
],
|
|
2784
|
+
"description": "Backoff strategy between attempts."
|
|
2785
|
+
}
|
|
1873
2786
|
}
|
|
1874
2787
|
},
|
|
1875
|
-
"sources": {
|
|
2788
|
+
"sources": {
|
|
2789
|
+
"type": "array",
|
|
2790
|
+
"uniqueItems": true,
|
|
2791
|
+
"items": {
|
|
2792
|
+
"type": "string",
|
|
2793
|
+
"enum": [
|
|
2794
|
+
"webhook",
|
|
2795
|
+
"schedule",
|
|
2796
|
+
"queue",
|
|
2797
|
+
"email",
|
|
2798
|
+
"form",
|
|
2799
|
+
"stream",
|
|
2800
|
+
"change"
|
|
2801
|
+
]
|
|
2802
|
+
},
|
|
2803
|
+
"description": "Which trigger sources bridge uniformly. A source listed here MUST have a registerable `TriggerSubscription` driven through the four-state machine AND emit the two `trigger.*` events for that source \u2014 the list MUST NOT over-claim a source the host has as a feature but does not wire as a durable trigger subscription. A consumer MUST tolerate any subset."
|
|
2804
|
+
},
|
|
1876
2805
|
"ingestion": {
|
|
1877
2806
|
"type": "object",
|
|
1878
2807
|
"additionalProperties": false,
|
|
1879
|
-
"description": "RFC 0099
|
|
2808
|
+
"description": "RFC 0099 \u00a7F.3 (additive). External-event ingestion advertisement \u2014 which of `sources[]` the host actually ingests from EXTERNALLY-originated events (`webhook`/`email`/`form`/`stream`/`change`), normalizing each to a `TriggerEvent` (`trigger-event.schema.json`) and starting a run. Absent \u21d2 the host does NOT externally-ingest (today's behavior \u2014 schedule/queue only). A source in `externalSources[]` MUST actually accept an external event, normalize it, and start a run \u2014 over-claiming is a dishonest advertisement. A consumer MUST tolerate any subset.",
|
|
1880
2809
|
"properties": {
|
|
1881
|
-
"externalSources": {
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
2810
|
+
"externalSources": {
|
|
2811
|
+
"type": "array",
|
|
2812
|
+
"uniqueItems": true,
|
|
2813
|
+
"items": {
|
|
2814
|
+
"type": "string",
|
|
2815
|
+
"enum": [
|
|
2816
|
+
"webhook",
|
|
2817
|
+
"email",
|
|
2818
|
+
"form",
|
|
2819
|
+
"stream",
|
|
2820
|
+
"change"
|
|
2821
|
+
]
|
|
2822
|
+
},
|
|
2823
|
+
"description": "Which of `sources[]` are EXTERNALLY ingested per RFC 0099 (`stream`/`change` per RFC 0127). The honesty gate \u2014 each MUST normalize to a `TriggerEvent` and start a run."
|
|
2824
|
+
},
|
|
2825
|
+
"maxBodyBytes": {
|
|
2826
|
+
"type": "integer",
|
|
2827
|
+
"minimum": 1,
|
|
2828
|
+
"description": "Inbound body cap (webhook body / email / form), reusing the RFC 0076 \u00a7B response-cap discipline."
|
|
2829
|
+
},
|
|
2830
|
+
"verification": {
|
|
2831
|
+
"type": "array",
|
|
2832
|
+
"uniqueItems": true,
|
|
2833
|
+
"items": {
|
|
2834
|
+
"type": "string",
|
|
2835
|
+
"enum": [
|
|
2836
|
+
"webhook-signature",
|
|
2837
|
+
"email-dmarc",
|
|
2838
|
+
"form-origin"
|
|
2839
|
+
]
|
|
2840
|
+
},
|
|
2841
|
+
"description": "Which source-authenticity checks the host performs. An advertised check MUST actually be performed (RFC 0099 \u00a7F.3 / UQ1)."
|
|
2842
|
+
},
|
|
2843
|
+
"registrationEndpoint": {
|
|
2844
|
+
"type": "boolean",
|
|
2845
|
+
"description": "`true` \u21d2 the host serves `POST /v1/trigger-subscriptions` (RFC 0099 \u00a7F.2) for portable external-event subscription creation."
|
|
2846
|
+
}
|
|
1885
2847
|
}
|
|
1886
2848
|
}
|
|
1887
2849
|
}
|
|
1888
2850
|
},
|
|
1889
|
-
"a2a": {
|
|
1890
|
-
"type": "object",
|
|
1891
|
-
"additionalProperties": false,
|
|
1892
|
-
"description": "RFC 0100 (`Active`). The host exposes itself as an A2A (Agent2Agent) agent. `supported: true` alone
|
|
1893
|
-
"required": [
|
|
1894
|
-
|
|
1895
|
-
"
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
"
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
2851
|
+
"a2a": {
|
|
2852
|
+
"type": "object",
|
|
2853
|
+
"additionalProperties": false,
|
|
2854
|
+
"description": "RFC 0100 (`Active`). The host exposes itself as an A2A (Agent2Agent) agent. `supported: true` alone \u21d2 the SYNCHRONOUS `message/send` \u2192 poll `tasks/get` round-trip already specified by `a2a-integration.md` (today's behavior \u2014 no regression). The optional `streaming`/`pushNotifications`/`durableTasks` flags gate the RFC 0100 async/durable additions (resubscribe re-attach, push config, persisted `A2ATaskState` so `tasks/get` returns live state after disconnect). Absent block \u21d2 no A2A advertisement.",
|
|
2855
|
+
"required": [
|
|
2856
|
+
"supported",
|
|
2857
|
+
"agentCardUrl"
|
|
2858
|
+
],
|
|
2859
|
+
"properties": {
|
|
2860
|
+
"supported": {
|
|
2861
|
+
"type": "boolean",
|
|
2862
|
+
"description": "Host exposes itself as an A2A agent."
|
|
2863
|
+
},
|
|
2864
|
+
"agentCardUrl": {
|
|
2865
|
+
"type": "string",
|
|
2866
|
+
"format": "uri",
|
|
2867
|
+
"description": "The A2A 0.3 well-known agent card URL (`/.well-known/agent-card.json`)."
|
|
2868
|
+
},
|
|
2869
|
+
"streaming": {
|
|
2870
|
+
"type": "boolean",
|
|
2871
|
+
"description": "Host supports `message/stream` + `tasks/resubscribe` (A2A `capabilities.streaming`). Gates the RFC 0100 \u00a73 resubscribe re-attach."
|
|
2872
|
+
},
|
|
2873
|
+
"pushNotifications": {
|
|
2874
|
+
"type": "boolean",
|
|
2875
|
+
"description": "Host supports A2A push-notification config (A2A `capabilities.push_notifications`). Gates the RFC 0100 \u00a74 push contract; a caller-supplied `pushConfig.url` is SSRF-validated (`a2a-push-egress-ssrf`)."
|
|
2876
|
+
},
|
|
2877
|
+
"durableTasks": {
|
|
2878
|
+
"type": "boolean",
|
|
2879
|
+
"description": "RFC 0100 \u00a72. Host PERSISTS the projected Task (`A2ATaskState`) per backing run; `tasks/get` returns live state after disconnect. Absent/false \u21d2 synchronous round-trip only."
|
|
2880
|
+
},
|
|
2881
|
+
"protocolVersions": {
|
|
2882
|
+
"type": "array",
|
|
2883
|
+
"minItems": 1,
|
|
2884
|
+
"uniqueItems": true,
|
|
2885
|
+
"items": {
|
|
2886
|
+
"type": "string",
|
|
2887
|
+
"pattern": "^[0-9]+\\.[0-9]+$"
|
|
2888
|
+
},
|
|
2889
|
+
"description": "RFC 0152 \u00a7A \u2014 every A2A protocol version this host speaks, newest-preferred first by convention. An A2A-capable host MUST advertise a non-empty array. `supported: true` WITHOUT versions is deprecated and CANNOT substantiate a current-A2A claim: it says the host speaks some A2A, which is not a fact a peer can negotiate against."
|
|
2890
|
+
},
|
|
2891
|
+
"preferredVersion": {
|
|
2892
|
+
"type": "string",
|
|
2893
|
+
"pattern": "^[0-9]+\\.[0-9]+$",
|
|
2894
|
+
"description": "RFC 0152 \u00a7A \u2014 MUST be present in `protocolVersions`. New hosts SHOULD prefer `1.0`."
|
|
2895
|
+
},
|
|
2896
|
+
"profiles": {
|
|
2897
|
+
"type": "array",
|
|
2898
|
+
"uniqueItems": true,
|
|
2899
|
+
"items": {
|
|
2900
|
+
"type": "string",
|
|
2901
|
+
"pattern": "^a2a-[0-9]+\\.[0-9]+(-legacy)?$"
|
|
2902
|
+
},
|
|
2903
|
+
"description": "RFC 0152 \u00a7A \u2014 named composition profiles, e.g. `a2a-1.0`, `a2a-0.3-legacy`. A legacy-only host advertises only the `-legacy` profile, which makes the deprecation explicit and time-boundable rather than implicit in a bare `supported: true`."
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
},
|
|
1902
2907
|
"budget": {
|
|
1903
2908
|
"type": "object",
|
|
1904
|
-
"description": "RFC 0084 (`Active`). Enforceable per-run SPEND governance
|
|
1905
|
-
"required": [
|
|
2909
|
+
"description": "RFC 0084 (`Active`). Enforceable per-run SPEND governance \u2014 the reserved `budget` run-options key (`budget-policy.schema.json`), the content-free `budget.{reserved,consumed,threshold.crossed,exhausted}` events, and hard-stop enforcement via `cap.breached{kind:\"budget-*\"}`. Orthogonal to RFC 0058 (which owns wall-time + loop-iterations via `limits.maxRunDurationMs`/`maxLoopIterations`); they share only the `cap.breached` overflow event. Hosts that omit it perform no spend enforcement (today's behavior); the conformance behavioral scenarios skip cleanly.",
|
|
2910
|
+
"required": [
|
|
2911
|
+
"supported"
|
|
2912
|
+
],
|
|
1906
2913
|
"additionalProperties": false,
|
|
1907
2914
|
"properties": {
|
|
1908
|
-
"supported": {
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
2915
|
+
"supported": {
|
|
2916
|
+
"type": "boolean",
|
|
2917
|
+
"description": "REQUIRED when present. `true` \u21d2 the host resolves the `budget` policy, emits the `budget.*` events, and (when `enforce: \"hard\"`) stops the run on exhaustion."
|
|
2918
|
+
},
|
|
2919
|
+
"dimensions": {
|
|
2920
|
+
"type": "array",
|
|
2921
|
+
"uniqueItems": true,
|
|
2922
|
+
"items": {
|
|
2923
|
+
"type": "string",
|
|
2924
|
+
"enum": [
|
|
2925
|
+
"tokens",
|
|
2926
|
+
"cost",
|
|
2927
|
+
"toolCalls",
|
|
2928
|
+
"retries",
|
|
2929
|
+
"model"
|
|
2930
|
+
]
|
|
2931
|
+
},
|
|
2932
|
+
"description": "Which budget dimensions the host actually enforces (truthful \u2014 advertise only what it honors). A consumer MUST tolerate any subset."
|
|
2933
|
+
},
|
|
2934
|
+
"enforce": {
|
|
2935
|
+
"type": "string",
|
|
2936
|
+
"enum": [
|
|
2937
|
+
"hard",
|
|
2938
|
+
"advisory"
|
|
2939
|
+
],
|
|
2940
|
+
"description": "`hard`: exhaustion emits `cap.breached` + stops the run. `advisory`: emits the events but MUST NOT stop the run (honest advertisement of observe-only)."
|
|
2941
|
+
},
|
|
2942
|
+
"scopes": {
|
|
2943
|
+
"type": "array",
|
|
2944
|
+
"uniqueItems": true,
|
|
2945
|
+
"items": {
|
|
2946
|
+
"type": "string",
|
|
2947
|
+
"enum": [
|
|
2948
|
+
"run",
|
|
2949
|
+
"workflow",
|
|
2950
|
+
"agent",
|
|
2951
|
+
"project"
|
|
2952
|
+
]
|
|
2953
|
+
},
|
|
2954
|
+
"description": "Which budget scopes the host honors (\u00a7B). Absent \u21d2 at least `run`."
|
|
2955
|
+
}
|
|
1912
2956
|
}
|
|
1913
2957
|
},
|
|
1914
2958
|
"nondeterminismPolicy": {
|
|
1915
2959
|
"type": "object",
|
|
1916
|
-
"description": "RFC 0085. A host that does NOT support replay/fork (`replay.supported`) MAY instead DECLARE that it is honestly nondeterministic
|
|
1917
|
-
"required": [
|
|
2960
|
+
"description": "RFC 0085. A host that does NOT support replay/fork (`replay.supported`) MAY instead DECLARE that it is honestly nondeterministic \u2014 satisfying the `openwop-agent-platform` floor's replay-OR-policy term (`agent-platform-profile.md` \u00a7B) without claiming a replay capability it lacks. Absent \u21d2 the floor's replay term must be met by `replay.supported`.",
|
|
2961
|
+
"required": [
|
|
2962
|
+
"declared"
|
|
2963
|
+
],
|
|
1918
2964
|
"additionalProperties": false,
|
|
1919
2965
|
"properties": {
|
|
1920
|
-
"declared": {
|
|
2966
|
+
"declared": {
|
|
2967
|
+
"type": "boolean",
|
|
2968
|
+
"description": "When `true`, the host documents its nondeterminism (it does not guarantee deterministic replay). A bare flag for v1.x (RFC 0085 \u00a7UQ2); a structured per-source policy is a future refinement."
|
|
2969
|
+
}
|
|
1921
2970
|
}
|
|
1922
2971
|
},
|
|
1923
2972
|
"workspace": {
|
|
1924
2973
|
"type": "object",
|
|
1925
|
-
"description": "RFC 0059 (`Active`). Versioned, tenant
|
|
1926
|
-
"required": [
|
|
2974
|
+
"description": "RFC 0059 (`Active`). Versioned, tenant\u00b7workspace-scoped ground-truth file store (the `host.workspace` capability). Scopes to the RFC 0048 owner triple. Atomic, optimistically-concurrent writes (`If-Match` ETag); a read snapshot is exposed to every run at `run.started` (deterministic for replay). Complements the transactional `MemoryAdapter` (RFC 0004) with a durable, path-addressable file layer. Endpoints (`/v1/host/workspace/files[/{path}]`) are gated on `supported: true`; unsupported hosts return `501 capability_not_provided`. SECURITY invariants `workspace-cross-tenant-isolation` (WCT-1) + the WSR-1 secret-redaction MUST land with their conformance tests at implementation (RFC 0059 \u00a7E).",
|
|
2975
|
+
"required": [
|
|
2976
|
+
"supported"
|
|
2977
|
+
],
|
|
1927
2978
|
"properties": {
|
|
1928
|
-
"supported": {
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
"
|
|
2979
|
+
"supported": {
|
|
2980
|
+
"type": "boolean",
|
|
2981
|
+
"description": "Host implements the RFC 0059 workspace file store + endpoints + `workspace.updated` event."
|
|
2982
|
+
},
|
|
2983
|
+
"versioned": {
|
|
2984
|
+
"type": "boolean",
|
|
2985
|
+
"description": "Each write bumps a monotonic `version`; prior versions are retrievable via `GET \u2026/files/{path}?version=N`. Latest-version retrieval is the MUST regardless; history is best-effort up to `maxVersions`."
|
|
2986
|
+
},
|
|
2987
|
+
"maxFileBytes": {
|
|
2988
|
+
"type": "integer",
|
|
2989
|
+
"minimum": 1,
|
|
2990
|
+
"description": "Per-file byte ceiling; writes beyond it return `workspace_too_large`."
|
|
2991
|
+
},
|
|
2992
|
+
"maxFiles": {
|
|
2993
|
+
"type": "integer",
|
|
2994
|
+
"minimum": 1,
|
|
2995
|
+
"description": "Per-workspace file-count ceiling."
|
|
2996
|
+
},
|
|
2997
|
+
"maxVersions": {
|
|
2998
|
+
"type": "integer",
|
|
2999
|
+
"minimum": 1,
|
|
3000
|
+
"description": "When `versioned: true`, the number of historical versions a host advertises it will retain (history best-effort beyond the mandatory latest)."
|
|
3001
|
+
}
|
|
1933
3002
|
},
|
|
1934
3003
|
"additionalProperties": false
|
|
1935
3004
|
},
|
|
1936
3005
|
"uiPlugins": {
|
|
1937
3006
|
"type": "object",
|
|
1938
|
-
"description": "RFC 0117 (`Active`; amended by RFC 0119). Host loads SIGNED, SANDBOXED front-end plugin packs (`kind: \"frontend-plugin\"`)
|
|
1939
|
-
"required": [
|
|
3007
|
+
"description": "RFC 0117 (`Active`; amended by RFC 0119). Host loads SIGNED, SANDBOXED front-end plugin packs (`kind: \"frontend-plugin\"`) \u2014 canvas editors, custom artifact viewers, settings panels \u2014 in an ORIGIN/EXECUTION-ISOLATED sandbox (mechanism named by `isolation`: cross-origin iframe by default, or wasm/process/container/vm) and talks to them over the closed `ui-plugin/1` host-RPC boundary. The wire owns the boundary (isolation + RPC allowlist + manifest), NOT a renderer. Gated on `supported: true`; a host that does not advertise it rejects `kind: \"frontend-plugin\"` packs at registration and renders no plugin surface (graceful degradation to RFC 0071 host rendering). SECURITY invariants `frontend-plugin-isolation` / `frontend-plugin-egress` / `frontend-plugin-rpc-allowlist` / `frontend-plugin-no-byok` (RFC 0117 \u00a7Security).",
|
|
3008
|
+
"required": [
|
|
3009
|
+
"supported"
|
|
3010
|
+
],
|
|
1940
3011
|
"properties": {
|
|
1941
|
-
"supported": {
|
|
3012
|
+
"supported": {
|
|
3013
|
+
"type": "boolean",
|
|
3014
|
+
"description": "Host loads `kind: \"frontend-plugin\"` packs in an origin/execution-isolated sandbox (mechanism per `isolation`) and serves the `ui-plugin/1` host-RPC boundary."
|
|
3015
|
+
},
|
|
1942
3016
|
"isolation": {
|
|
1943
3017
|
"type": "string",
|
|
1944
3018
|
"anyOf": [
|
|
1945
|
-
{
|
|
1946
|
-
|
|
3019
|
+
{
|
|
3020
|
+
"enum": [
|
|
3021
|
+
"cross-origin-iframe",
|
|
3022
|
+
"wasm",
|
|
3023
|
+
"process",
|
|
3024
|
+
"container",
|
|
3025
|
+
"vm"
|
|
3026
|
+
]
|
|
3027
|
+
},
|
|
3028
|
+
{
|
|
3029
|
+
"pattern": "^x-host-[a-z0-9-]+-[a-z0-9-]+$"
|
|
3030
|
+
}
|
|
1947
3031
|
],
|
|
1948
3032
|
"default": "cross-origin-iframe",
|
|
1949
|
-
"description": "RFC 0117 (amended by RFC 0119). The categorical isolation model the host enforces for plugin bytes. `cross-origin-iframe` = a distinct-origin sandboxed browser frame (the browser default;
|
|
3033
|
+
"description": "RFC 0117 (amended by RFC 0119). The categorical isolation model the host enforces for plugin bytes. `cross-origin-iframe` = a distinct-origin sandboxed browser frame (the browser default; \u00a7Isolation). `wasm`/`process`/`container`/`vm` mirror `sandbox.isolationModel` (RFC 0035) for non-browser hosts that enforce the SAME isolation property. Vendor-specific models advertise `^x-host-<host>-<key>$` per `host-extensions.md`. ALL values denote the SAME mandatory property (`frontend-plugin-isolation`): plugin bytes execute in a boundary with no access to the host's execution context / DOM / origin-storage / credentials, deny-egress by default, and all host interaction mediated by the closed `ui-plugin/1` RPC. The field names the MECHANISM, never relaxes the property. In-process / same-origin / module-federation loading is a protocol-tier MUST NOT regardless of the advertised value."
|
|
1950
3034
|
},
|
|
1951
3035
|
"surfaces": {
|
|
1952
3036
|
"type": "array",
|
|
1953
|
-
"description": "Plugin surfaces this host renders. A pack's `uiPlugins[].surface` not in this set is installable-but-inert (
|
|
1954
|
-
"items": {
|
|
3037
|
+
"description": "Plugin surfaces this host renders. A pack's `uiPlugins[].surface` not in this set is installable-but-inert (\u00a7Degradation). `canvas-preview` (RFC 0130) mounts inside a host-owned canvas editor.",
|
|
3038
|
+
"items": {
|
|
3039
|
+
"type": "string",
|
|
3040
|
+
"enum": [
|
|
3041
|
+
"artifact-viewer",
|
|
3042
|
+
"route",
|
|
3043
|
+
"settings-panel",
|
|
3044
|
+
"canvas-preview"
|
|
3045
|
+
]
|
|
3046
|
+
},
|
|
1955
3047
|
"uniqueItems": true
|
|
1956
3048
|
},
|
|
1957
3049
|
"hostApi": {
|
|
1958
3050
|
"type": "array",
|
|
1959
|
-
"description": "The `ui-plugin/1` host-RPC methods this host honors. A plugin call to a method not in this set (regardless of the plugin's declared `hostApi`) MUST be rejected with `method_not_allowed` (`frontend-plugin-rpc-allowlist`). A host advertising `artifact.write` MUST enforce the `version`-token optimistic concurrency (RFC 0117
|
|
1960
|
-
"items": {
|
|
3051
|
+
"description": "The `ui-plugin/1` host-RPC methods this host honors. A plugin call to a method not in this set (regardless of the plugin's declared `hostApi`) MUST be rejected with `method_not_allowed` (`frontend-plugin-rpc-allowlist`). A host advertising `artifact.write` MUST enforce the `version`-token optimistic concurrency (RFC 0117 \u00a7Concurrency).",
|
|
3052
|
+
"items": {
|
|
3053
|
+
"type": "string",
|
|
3054
|
+
"enum": [
|
|
3055
|
+
"artifact.read",
|
|
3056
|
+
"artifact.write",
|
|
3057
|
+
"host.toast",
|
|
3058
|
+
"host.navigate",
|
|
3059
|
+
"host.announce"
|
|
3060
|
+
]
|
|
3061
|
+
},
|
|
1961
3062
|
"uniqueItems": true
|
|
1962
3063
|
},
|
|
1963
|
-
"maxEntryBytes": {
|
|
3064
|
+
"maxEntryBytes": {
|
|
3065
|
+
"type": "integer",
|
|
3066
|
+
"minimum": 1,
|
|
3067
|
+
"description": "Per-plugin entry-bundle byte ceiling the host will load."
|
|
3068
|
+
}
|
|
1964
3069
|
},
|
|
1965
3070
|
"additionalProperties": false
|
|
1966
3071
|
},
|
|
1967
3072
|
"sql": {
|
|
1968
3073
|
"type": "object",
|
|
1969
|
-
"description": "RFC 0018 (`Active`). SQL database adapter with parametric-only enforcement. Hosts MUST reject non-parametric queries that inline user input (`sql-parametric-only` invariant
|
|
3074
|
+
"description": "RFC 0018 (`Active`). SQL database adapter with parametric-only enforcement. Hosts MUST reject non-parametric queries that inline user input (`sql-parametric-only` invariant \u2014 guards against SQL injection across every workflow).",
|
|
1970
3075
|
"properties": {
|
|
1971
|
-
"supported": {
|
|
1972
|
-
|
|
1973
|
-
|
|
3076
|
+
"supported": {
|
|
3077
|
+
"type": "boolean"
|
|
3078
|
+
},
|
|
3079
|
+
"datasources": {
|
|
3080
|
+
"type": "array",
|
|
3081
|
+
"items": {
|
|
3082
|
+
"type": "object",
|
|
3083
|
+
"additionalProperties": true
|
|
3084
|
+
}
|
|
3085
|
+
},
|
|
3086
|
+
"transactions": {
|
|
3087
|
+
"type": "boolean"
|
|
3088
|
+
},
|
|
1974
3089
|
"drivers": {
|
|
1975
3090
|
"type": "array",
|
|
1976
|
-
"items": {
|
|
3091
|
+
"items": {
|
|
3092
|
+
"type": "string",
|
|
3093
|
+
"enum": [
|
|
3094
|
+
"postgres",
|
|
3095
|
+
"mysql",
|
|
3096
|
+
"mariadb",
|
|
3097
|
+
"sqlite",
|
|
3098
|
+
"mssql",
|
|
3099
|
+
"clickhouse",
|
|
3100
|
+
"snowflake",
|
|
3101
|
+
"bigquery",
|
|
3102
|
+
"duckdb"
|
|
3103
|
+
]
|
|
3104
|
+
}
|
|
1977
3105
|
}
|
|
1978
3106
|
},
|
|
1979
3107
|
"additionalProperties": false
|
|
@@ -1982,9 +3110,24 @@
|
|
|
1982
3110
|
"type": "object",
|
|
1983
3111
|
"description": "RFC 0018 (`Active`). MongoDB-shape document store adapter.",
|
|
1984
3112
|
"properties": {
|
|
1985
|
-
"supported": {
|
|
1986
|
-
|
|
1987
|
-
|
|
3113
|
+
"supported": {
|
|
3114
|
+
"type": "boolean"
|
|
3115
|
+
},
|
|
3116
|
+
"datasources": {
|
|
3117
|
+
"type": "array"
|
|
3118
|
+
},
|
|
3119
|
+
"drivers": {
|
|
3120
|
+
"type": "array",
|
|
3121
|
+
"items": {
|
|
3122
|
+
"type": "string",
|
|
3123
|
+
"enum": [
|
|
3124
|
+
"mongodb",
|
|
3125
|
+
"dynamodb",
|
|
3126
|
+
"cosmosdb",
|
|
3127
|
+
"firestore"
|
|
3128
|
+
]
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
1988
3131
|
},
|
|
1989
3132
|
"additionalProperties": false
|
|
1990
3133
|
},
|
|
@@ -1992,11 +3135,29 @@
|
|
|
1992
3135
|
"type": "object",
|
|
1993
3136
|
"description": "RFC 0018 (`Active`). Vector-DB capability for k-NN search.",
|
|
1994
3137
|
"properties": {
|
|
1995
|
-
"supported": {
|
|
1996
|
-
|
|
3138
|
+
"supported": {
|
|
3139
|
+
"type": "boolean"
|
|
3140
|
+
},
|
|
3141
|
+
"collections": {
|
|
3142
|
+
"type": "array"
|
|
3143
|
+
},
|
|
1997
3144
|
"backends": {
|
|
1998
3145
|
"type": "array",
|
|
1999
|
-
"items": {
|
|
3146
|
+
"items": {
|
|
3147
|
+
"type": "string",
|
|
3148
|
+
"enum": [
|
|
3149
|
+
"pinecone",
|
|
3150
|
+
"qdrant",
|
|
3151
|
+
"weaviate",
|
|
3152
|
+
"milvus",
|
|
3153
|
+
"pgvector",
|
|
3154
|
+
"redis",
|
|
3155
|
+
"mongodb-atlas",
|
|
3156
|
+
"chroma",
|
|
3157
|
+
"azure-ai-search",
|
|
3158
|
+
"in-memory"
|
|
3159
|
+
]
|
|
3160
|
+
}
|
|
2000
3161
|
}
|
|
2001
3162
|
},
|
|
2002
3163
|
"additionalProperties": false
|
|
@@ -2005,11 +3166,24 @@
|
|
|
2005
3166
|
"type": "object",
|
|
2006
3167
|
"description": "RFC 0018 (`Active`). Full-text search index adapter.",
|
|
2007
3168
|
"properties": {
|
|
2008
|
-
"supported": {
|
|
2009
|
-
|
|
3169
|
+
"supported": {
|
|
3170
|
+
"type": "boolean"
|
|
3171
|
+
},
|
|
3172
|
+
"indexes": {
|
|
3173
|
+
"type": "array"
|
|
3174
|
+
},
|
|
2010
3175
|
"backends": {
|
|
2011
3176
|
"type": "array",
|
|
2012
|
-
"items": {
|
|
3177
|
+
"items": {
|
|
3178
|
+
"type": "string",
|
|
3179
|
+
"enum": [
|
|
3180
|
+
"elasticsearch",
|
|
3181
|
+
"opensearch",
|
|
3182
|
+
"meilisearch",
|
|
3183
|
+
"typesense",
|
|
3184
|
+
"algolia"
|
|
3185
|
+
]
|
|
3186
|
+
}
|
|
2013
3187
|
}
|
|
2014
3188
|
},
|
|
2015
3189
|
"additionalProperties": false
|
|
@@ -2018,26 +3192,43 @@
|
|
|
2018
3192
|
"type": "object",
|
|
2019
3193
|
"description": "RFC 0019 (`Active`). Binary artifact store with presigned URLs. Per-bucket tenant isolation. Presigned URLs MUST expire at the advertised TTL.",
|
|
2020
3194
|
"properties": {
|
|
2021
|
-
"supported": {
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
"
|
|
3195
|
+
"supported": {
|
|
3196
|
+
"type": "boolean"
|
|
3197
|
+
},
|
|
3198
|
+
"buckets": {
|
|
3199
|
+
"type": "array"
|
|
3200
|
+
},
|
|
3201
|
+
"presignSupported": {
|
|
3202
|
+
"type": "boolean"
|
|
3203
|
+
},
|
|
3204
|
+
"maxObjectBytes": {
|
|
3205
|
+
"type": "integer",
|
|
3206
|
+
"minimum": 0
|
|
3207
|
+
}
|
|
2025
3208
|
},
|
|
2026
3209
|
"additionalProperties": false
|
|
2027
3210
|
},
|
|
2028
3211
|
"cache": {
|
|
2029
3212
|
"type": "object",
|
|
2030
|
-
"description": "RFC 0019 (`Active`). TTL cache for HTTP / AI response memoization. Per-tenant scoping; TTL drift
|
|
3213
|
+
"description": "RFC 0019 (`Active`). TTL cache for HTTP / AI response memoization. Per-tenant scoping; TTL drift \u2264 1s.",
|
|
2031
3214
|
"properties": {
|
|
2032
|
-
"supported": {
|
|
2033
|
-
|
|
2034
|
-
|
|
3215
|
+
"supported": {
|
|
3216
|
+
"type": "boolean"
|
|
3217
|
+
},
|
|
3218
|
+
"maxValueBytes": {
|
|
3219
|
+
"type": "integer",
|
|
3220
|
+
"minimum": 0
|
|
3221
|
+
},
|
|
3222
|
+
"maxTtlSeconds": {
|
|
3223
|
+
"type": "integer",
|
|
3224
|
+
"minimum": 0
|
|
3225
|
+
}
|
|
2035
3226
|
},
|
|
2036
3227
|
"additionalProperties": false
|
|
2037
3228
|
},
|
|
2038
3229
|
"workflowChainPacks": {
|
|
2039
3230
|
"type": "object",
|
|
2040
|
-
"description": "RFC 0013 (Phase 1, `Draft`). When `supported: true`, the host's workflow editor implements workflow-chain pack expansion per `workflow-chain-packs.md`
|
|
3231
|
+
"description": "RFC 0013 (Phase 1, `Draft`). When `supported: true`, the host's workflow editor implements workflow-chain pack expansion per `workflow-chain-packs.md` \u2014 author drops a chain tile, host resolves the pack, prompts for `parameters`, substitutes `{{params.<name>}}` placeholders, rewrites node ids, splices the resulting DAG into the parent workflow. Hosts that don't implement expansion omit this block (or set `supported: false`); conformance scenarios under `conformance/src/scenarios/workflow-chain-*.test.ts` skip cleanly against those hosts.",
|
|
2041
3232
|
"properties": {
|
|
2042
3233
|
"supported": {
|
|
2043
3234
|
"type": "boolean",
|
|
@@ -2045,23 +3236,25 @@
|
|
|
2045
3236
|
},
|
|
2046
3237
|
"deferredParameters": {
|
|
2047
3238
|
"type": "object",
|
|
2048
|
-
"description": "RFC 0124 (WCP4, `Active`). OPTIONAL. When `supported: true`, the host offers a capability-gated deferred-parameter expansion mode in ADDITION to expansion-time substitution (which remains the default and floor): at drop time it materializes the chain's `parameters` into top-level workflow `variables[]` (author value as `defaultValue`) and rewrites `{{params.<name>}}` into a spec'd runtime binding (PromptTemplate `{{varName}}` with `source:\"variable\"`, or a variable-sourced PortValue), so chain parameters stay overridable per run via `configurable` while the persisted definition keeps ZERO `{{params.*}}` tokens. A parameter marked `x-openwop-sensitive` MUST be deferred or the expansion fail-closed (`sensitive_param_not_deferrable`, 422)
|
|
3239
|
+
"description": "RFC 0124 (WCP4, `Active`). OPTIONAL. When `supported: true`, the host offers a capability-gated deferred-parameter expansion mode in ADDITION to expansion-time substitution (which remains the default and floor): at drop time it materializes the chain's `parameters` into top-level workflow `variables[]` (author value as `defaultValue`) and rewrites `{{params.<name>}}` into a spec'd runtime binding (PromptTemplate `{{varName}}` with `source:\"variable\"`, or a variable-sourced PortValue), so chain parameters stay overridable per run via `configurable` while the persisted definition keeps ZERO `{{params.*}}` tokens. A parameter marked `x-openwop-sensitive` MUST be deferred or the expansion fail-closed (`sensitive_param_not_deferrable`, 422) \u2014 never frozen into persisted `config`. Omission (or `supported:false`) signals the host does NOT offer deferred mode. No host may advertise `supported:true` until RFC 0124 is `Accepted`. See `workflow-chain-packs.md` \u00a7\"Deferred-parameter expansion\".",
|
|
2049
3240
|
"properties": {
|
|
2050
3241
|
"supported": {
|
|
2051
3242
|
"type": "boolean",
|
|
2052
3243
|
"description": "Whether the host offers the deferred-parameter expansion mode. Requires `capabilities.prompts.supported: true` with `variable` in `prompts.variableSources` for the prompt-bearing rewrite path."
|
|
2053
3244
|
}
|
|
2054
3245
|
},
|
|
2055
|
-
"required": [
|
|
3246
|
+
"required": [
|
|
3247
|
+
"supported"
|
|
3248
|
+
],
|
|
2056
3249
|
"additionalProperties": false
|
|
2057
3250
|
},
|
|
2058
3251
|
"hostExpansionSeam": {
|
|
2059
3252
|
"type": "boolean",
|
|
2060
|
-
"description": "RFC 0013 erratum (2026-07-05). OPTIONAL. A **conformance-only test seam** advertisement (category: test harness, cf. `observability.testSeams`
|
|
3253
|
+
"description": "RFC 0013 erratum (2026-07-05). OPTIONAL. A **conformance-only test seam** advertisement (category: test harness, cf. `observability.testSeams` \u2014 NOT a product capability): when `true`, the host serves `POST /v1/host/sample/workflow-chain:expand` returning the `vendor.openwop.workflow-chain-sample` v1.0.0 expansion that `conformance/src/scenarios/workflow-chain-host-expansion.test.ts` asserts against. Absent/`false` \u21d2 that live-host expansion scenario soft-skips; the semantic `workflowChainPacks.supported` claim is witnessed by the server-free `workflow-chain-expansion.test.ts` legs. This flag is DISTINCT from `deferredParameters` (RFC 0124), which is witnessed through its own `POST /v1/host/sample/chain/deferred-expand` seam \u2014 so a host MAY advertise `supported` / `deferredParameters.supported` without standing up the RFC 0013 sample-pack seam it was never handed a published fixture for. Advertising `supported:true` no longer conscripts a host into the RFC 0013 host-expansion scenario."
|
|
2061
3254
|
},
|
|
2062
3255
|
"subChains": {
|
|
2063
3256
|
"type": "object",
|
|
2064
|
-
"description": "RFC 0133 (workflow-chain composition, `Accepted`). OPTIONAL. When `supported: true`, the host's `POST
|
|
3257
|
+
"description": "RFC 0133 (workflow-chain composition, `Accepted`). OPTIONAL. When `supported: true`, the host's `POST \u2026/workflows/from-chain` implements RUNTIME sub-chain composition per `workflow-chain-packs.md` \u00a7\"Sub-chain composition (RFC 0133)\": for each `config.subChainRef` reachable from a parent chain, it resolves the referenced chain (sibling or external), recursively expands + co-registers it as its own owned workflow (deterministic TENANT-SCOPED id from `(tenantId, childChainId, version)` \u2014 two tenants never collide on the global registry, a shared child registers once across parents in a tenant, a repeat instantiation converges), rewrites the referencing node's `subChainRef` \u2192 the minted child `config.workflowId`, and dispatches the child as a child run (`core.subWorkflow` / `core.dispatch` child-run); the `from-chain` response carries `{ workflowId, subChainWorkflowIds[], nodeCount }`. Bounded by a cycle check (`sub_chain_cycle`) + a depth cap (`sub_chain_max_depth_exceeded`). A host that does NOT advertise this block MUST refuse a `subChains`-bearing chain at author/instantiate time with `sub_chain_unsupported` (422) \u2014 it never silently flattens. `producedVariables` (RFC 0133 \u00a72) needs NO flag: it is pure variable emission under the base `workflowChainPacks.supported`. Conformance scenarios `chain-subchain-fanout.test.ts` + `chain-subchain-unsupported-refused.test.ts` gate on this flag; the server-free `chain-subchain-sibling` / `chain-subchain-cycle-rejected` / `chain-produced-var-roundtrip` legs run unconditionally against the reference library.",
|
|
2065
3258
|
"properties": {
|
|
2066
3259
|
"supported": {
|
|
2067
3260
|
"type": "boolean",
|
|
@@ -2071,49 +3264,61 @@
|
|
|
2071
3264
|
"type": "integer",
|
|
2072
3265
|
"minimum": 1,
|
|
2073
3266
|
"default": 8,
|
|
2074
|
-
"description": "RFC 0133
|
|
3267
|
+
"description": "RFC 0133 \u00a71.3 (resolves UQ3). RECOMMENDED default 8. The maximum sub-chain nesting depth the host co-expands; exceeding it fails closed with the DISTINCT code `sub_chain_max_depth_exceeded` (the DoS depth backstop, alongside the `sub_chain_cycle` self-composition check \u2014 SECURITY `sub-chain-expansion-bounded`)."
|
|
2075
3268
|
}
|
|
2076
3269
|
},
|
|
2077
|
-
"required": [
|
|
3270
|
+
"required": [
|
|
3271
|
+
"supported"
|
|
3272
|
+
],
|
|
2078
3273
|
"additionalProperties": false
|
|
2079
3274
|
}
|
|
2080
3275
|
},
|
|
2081
|
-
"required": [
|
|
3276
|
+
"required": [
|
|
3277
|
+
"supported"
|
|
3278
|
+
],
|
|
2082
3279
|
"additionalProperties": false
|
|
2083
3280
|
},
|
|
2084
3281
|
"packs": {
|
|
2085
3282
|
"type": "object",
|
|
2086
|
-
"description": "RFC 0025 (`Active`). Pack-registry surface advertisement. The baseline `/v1/packs/*` read surface (per `spec/v1/node-packs.md`
|
|
3283
|
+
"description": "RFC 0025 (`Active`). Pack-registry surface advertisement. The baseline `/v1/packs/*` read surface (per `spec/v1/node-packs.md` \u00a7\"Registry HTTP API\") is unconditional for hosts that ship a pack catalog and does NOT require a capability flag; this object carries optional sub-blocks (currently the test-mode mirror namespace). Hosts that don't expose any optional pack-registry sub-block MAY omit this block entirely.",
|
|
2087
3284
|
"properties": {
|
|
2088
3285
|
"testMode": {
|
|
2089
3286
|
"type": "object",
|
|
2090
|
-
"description": "RFC 0025
|
|
3287
|
+
"description": "RFC 0025 \u00a7A. Optional `/v1/packs-test/*` mirror surface that exposes the production publish/get/delete/sig contract against an isolated catalog. Lets the conformance suite (`pack-registry-publish.test.ts`) exercise the documented 19-code publish error catalog without `packs:publish` scope on the real registry. Hosts that advertise `supported: true` MUST honor the \u00a7C isolation guarantees and MUST surface the same error envelopes and HTTP statuses as the production `/v1/packs/*` surface.",
|
|
2091
3288
|
"properties": {
|
|
2092
3289
|
"supported": {
|
|
2093
3290
|
"type": "boolean",
|
|
2094
|
-
"description": "Host exposes `/v1/packs-test/*` per RFC 0025
|
|
3291
|
+
"description": "Host exposes `/v1/packs-test/*` per RFC 0025 \u00a7B. When `true`, the conformance suite drives publish-error-catalog assertions through the test namespace; when `false` or absent, the 26 scenarios in `pack-registry-publish.test.ts` soft-skip cleanly."
|
|
2095
3292
|
},
|
|
2096
3293
|
"isolated": {
|
|
2097
3294
|
"type": "boolean",
|
|
2098
|
-
"description": "RFC 0025
|
|
3295
|
+
"description": "RFC 0025 \u00a7C point 1. MUST be `true` when `supported` is `true` \u2014 guarantees the test catalog is persisted distinctly from the production catalog and that a pack PUT'd via `/v1/packs-test/*` MUST NOT appear in `/v1/packs/*` listings."
|
|
2099
3296
|
},
|
|
2100
3297
|
"catalogResetEndpoint": {
|
|
2101
3298
|
"type": "string",
|
|
2102
|
-
"description": "RFC 0025
|
|
3299
|
+
"description": "RFC 0025 \u00a7C point 4. Optional URL path (e.g. `/v1/packs-test/reset`) that clears the entire test catalog. When advertised, conformance-suite teardown SHOULD call it; the endpoint MUST be idempotent. Hosts MAY omit; in that case the suite leaves disposable timestamped pack names in place and relies on the next host restart to clear in-memory state.",
|
|
2103
3300
|
"pattern": "^/"
|
|
2104
3301
|
},
|
|
2105
3302
|
"scopes": {
|
|
2106
3303
|
"type": "array",
|
|
2107
3304
|
"items": {
|
|
2108
3305
|
"type": "string",
|
|
2109
|
-
"enum": [
|
|
3306
|
+
"enum": [
|
|
3307
|
+
"core",
|
|
3308
|
+
"vendor",
|
|
3309
|
+
"community",
|
|
3310
|
+
"private",
|
|
3311
|
+
"local"
|
|
3312
|
+
]
|
|
2110
3313
|
},
|
|
2111
3314
|
"uniqueItems": true,
|
|
2112
3315
|
"minItems": 1,
|
|
2113
|
-
"description": "RFC 0025
|
|
3316
|
+
"description": "RFC 0025 \u00a7A. Which namespace scopes the test catalog accepts in pack names. Public test catalogs SHOULD refuse `private` and `local` (matching the production-registry rule for `packs.openwop.dev`); private dev catalogs MAY accept all five. When omitted, the test catalog defaults to the same scope set as the production namespace it mirrors."
|
|
2114
3317
|
}
|
|
2115
3318
|
},
|
|
2116
|
-
"required": [
|
|
3319
|
+
"required": [
|
|
3320
|
+
"supported"
|
|
3321
|
+
],
|
|
2117
3322
|
"additionalProperties": false
|
|
2118
3323
|
}
|
|
2119
3324
|
},
|
|
@@ -2121,107 +3326,227 @@
|
|
|
2121
3326
|
},
|
|
2122
3327
|
"mcp": {
|
|
2123
3328
|
"type": "object",
|
|
2124
|
-
"description": "RFC 0020 (`Active`). MCP (Model Context Protocol) composition surface. The client half is consumed implicitly via `host.mcp` host-surface; this block adds the optional server half
|
|
3329
|
+
"description": "RFC 0020 (`Active`). MCP (Model Context Protocol) composition surface. The client half is consumed implicitly via `host.mcp` host-surface; this block adds the optional server half \u2014 workflow exposed AS an MCP server with bidirectional sampling/elicitation bridges.",
|
|
2125
3330
|
"properties": {
|
|
2126
|
-
"supported": {
|
|
3331
|
+
"supported": {
|
|
3332
|
+
"type": "boolean",
|
|
3333
|
+
"description": "Host advertises a client-side MCP surface (ctx.mcp.*). See spec/v1/mcp-integration.md."
|
|
3334
|
+
},
|
|
2127
3335
|
"serverMount": {
|
|
2128
3336
|
"type": "object",
|
|
2129
3337
|
"description": "Server-side MCP composition (workflow IS an MCP server). When supported, the host mounts an MCP endpoint and routes inbound tools/call, resources/read, prompts/get into workflows. Inbound MUST be treated as `trustBoundary: 'untrusted'`.",
|
|
2130
3338
|
"properties": {
|
|
2131
|
-
"supported": {
|
|
3339
|
+
"supported": {
|
|
3340
|
+
"type": "boolean"
|
|
3341
|
+
},
|
|
2132
3342
|
"transports": {
|
|
2133
3343
|
"type": "array",
|
|
2134
|
-
"items": {
|
|
3344
|
+
"items": {
|
|
3345
|
+
"type": "string",
|
|
3346
|
+
"enum": [
|
|
3347
|
+
"stdio",
|
|
3348
|
+
"streamable-http"
|
|
3349
|
+
]
|
|
3350
|
+
}
|
|
2135
3351
|
},
|
|
2136
|
-
"samplingBridge": {
|
|
2137
|
-
|
|
3352
|
+
"samplingBridge": {
|
|
3353
|
+
"type": "boolean",
|
|
3354
|
+
"description": "Inbound sampling/createMessage bridges to the workflow's ctx.callAI."
|
|
3355
|
+
},
|
|
3356
|
+
"elicitationBridge": {
|
|
3357
|
+
"type": "boolean",
|
|
3358
|
+
"description": "Inbound elicitation/create bridges to ctx.suspend."
|
|
3359
|
+
}
|
|
2138
3360
|
},
|
|
2139
3361
|
"additionalProperties": false
|
|
3362
|
+
},
|
|
3363
|
+
"protocolVersions": {
|
|
3364
|
+
"type": "array",
|
|
3365
|
+
"minItems": 1,
|
|
3366
|
+
"uniqueItems": true,
|
|
3367
|
+
"items": {
|
|
3368
|
+
"type": "string",
|
|
3369
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
|
|
3370
|
+
},
|
|
3371
|
+
"description": "RFC 0153 \u00a7A \u2014 MCP revisions in MCP's own date form, exactly. The pattern is date-shaped rather than free string because MCP versions ARE dates: accepting `latest` or `2026-7-28` would make two hosts disagree about which revision they share while both validating."
|
|
3372
|
+
},
|
|
3373
|
+
"preferredVersion": {
|
|
3374
|
+
"type": "string",
|
|
3375
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$",
|
|
3376
|
+
"description": "RFC 0153 \u00a7A \u2014 MUST be present in `protocolVersions`."
|
|
3377
|
+
},
|
|
3378
|
+
"profiles": {
|
|
3379
|
+
"type": "array",
|
|
3380
|
+
"uniqueItems": true,
|
|
3381
|
+
"items": {
|
|
3382
|
+
"type": "string",
|
|
3383
|
+
"pattern": "^mcp-[0-9]{4}-[0-9]{2}-[0-9]{2}(-legacy)?$"
|
|
3384
|
+
},
|
|
3385
|
+
"description": "RFC 0153 \u00a7A \u2014 named composition profiles. Unqualified `supported: true` is deprecated and cannot substantiate a current-MCP claim."
|
|
3386
|
+
},
|
|
3387
|
+
"features": {
|
|
3388
|
+
"type": "array",
|
|
3389
|
+
"uniqueItems": true,
|
|
3390
|
+
"items": {
|
|
3391
|
+
"enum": [
|
|
3392
|
+
"server-discover",
|
|
3393
|
+
"mrtr",
|
|
3394
|
+
"cacheable-lists",
|
|
3395
|
+
"extensions"
|
|
3396
|
+
]
|
|
3397
|
+
},
|
|
3398
|
+
"description": "RFC 0153 \u00a7A \u2014 closed feature set for the current revision. Closed rather than open because an unrecognized feature name is indistinguishable from a typo, and a peer that silently ignores one negotiates a capability neither side has."
|
|
2140
3399
|
}
|
|
2141
3400
|
},
|
|
2142
3401
|
"additionalProperties": false
|
|
2143
3402
|
},
|
|
2144
3403
|
"sandbox": {
|
|
2145
3404
|
"type": "object",
|
|
2146
|
-
"description": "RFC 0035
|
|
3405
|
+
"description": "RFC 0035 \u2014 Sandbox execution contract for pack-loaded typeIds. Hosts that advertise execute pack-loaded code inside an isolation boundary meeting the 8 failure-mode invariants in spec/v1/host-capabilities.md \u00a7'Sandbox execution contract'. Absent block = host does NOT sandbox pack-loaded code and MUST refuse to load any pack whose manifest declares `peerDependencies.host.sandbox: required`.",
|
|
2147
3406
|
"additionalProperties": false,
|
|
2148
|
-
"required": [
|
|
3407
|
+
"required": [
|
|
3408
|
+
"supported",
|
|
3409
|
+
"isolationModel"
|
|
3410
|
+
],
|
|
2149
3411
|
"properties": {
|
|
2150
3412
|
"supported": {
|
|
2151
3413
|
"type": "boolean",
|
|
2152
|
-
"description": "Host enforces the 8 sandbox failure-mode invariants per spec/v1/host-capabilities.md
|
|
3414
|
+
"description": "Host enforces the 8 sandbox failure-mode invariants per spec/v1/host-capabilities.md \u00a7'Sandbox execution contract'. When false, host MUST refuse to load packs declaring required sandbox isolation."
|
|
2153
3415
|
},
|
|
2154
3416
|
"isolationModel": {
|
|
2155
3417
|
"type": "string",
|
|
2156
3418
|
"anyOf": [
|
|
2157
|
-
{
|
|
2158
|
-
|
|
3419
|
+
{
|
|
3420
|
+
"enum": [
|
|
3421
|
+
"wasm",
|
|
3422
|
+
"process",
|
|
3423
|
+
"container",
|
|
3424
|
+
"vm"
|
|
3425
|
+
]
|
|
3426
|
+
},
|
|
3427
|
+
{
|
|
3428
|
+
"pattern": "^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$"
|
|
3429
|
+
}
|
|
2159
3430
|
],
|
|
2160
|
-
"description": "Categorical isolation model. `wasm` = WebAssembly sandbox with explicit host imports (e.g., Wasmtime, Wasmer). `process` = OS process boundary with restricted syscalls (e.g., gVisor, seccomp, Landlock). `container` = container runtime boundary (e.g., Firecracker microVM). `vm` = full VM. Vendor-specific isolation models advertise `^x-host-<host>-<key>$` per spec/v1/host-extensions.md
|
|
3431
|
+
"description": "Categorical isolation model. `wasm` = WebAssembly sandbox with explicit host imports (e.g., Wasmtime, Wasmer). `process` = OS process boundary with restricted syscalls (e.g., gVisor, seccomp, Landlock). `container` = container runtime boundary (e.g., Firecracker microVM). `vm` = full VM. Vendor-specific isolation models advertise `^x-host-<host>-<key>$` per spec/v1/host-extensions.md \u00a7'Canonical prefixes'; documentation lives at the host's discovery doc."
|
|
2161
3432
|
},
|
|
2162
3433
|
"allowedHostCalls": {
|
|
2163
3434
|
"type": "array",
|
|
2164
|
-
"items": {
|
|
3435
|
+
"items": {
|
|
3436
|
+
"type": "string"
|
|
3437
|
+
},
|
|
2165
3438
|
"description": "Whitelist of host-call surfaces sandboxed code MAY invoke. Identifiers from the spec-reserved `host.*` capability set or `^x-host-<host>-<key>$` extension namespace. Empty array = pure compute only (no host I/O). Conformance verifies the sandbox refuses unlisted calls (`sandbox_capability_denied`)."
|
|
2166
3439
|
},
|
|
2167
3440
|
"memoryLimitBytes": {
|
|
2168
3441
|
"type": "integer",
|
|
2169
3442
|
"minimum": 1048576,
|
|
2170
|
-
"description": "Per-invocation memory cap (
|
|
3443
|
+
"description": "Per-invocation memory cap (\u2265 1 MiB). Host MUST enforce; exceeding fails the node with `sandbox_memory_exceeded`."
|
|
2171
3444
|
},
|
|
2172
3445
|
"wallClockLimitMs": {
|
|
2173
3446
|
"type": "integer",
|
|
2174
3447
|
"minimum": 100,
|
|
2175
|
-
"description": "Per-invocation wall-clock cap (
|
|
3448
|
+
"description": "Per-invocation wall-clock cap (\u2265 100 ms). Host MUST enforce; exceeding fails the node with `sandbox_timeout`."
|
|
3449
|
+
}
|
|
3450
|
+
}
|
|
3451
|
+
},
|
|
3452
|
+
"compensation": {
|
|
3453
|
+
"type": "object",
|
|
3454
|
+
"description": "RFC 0151 \u00a7A \u2014 generic compensation (Saga) contract. OPTIONAL; absent means the host offers no generic compensation contract, NOT that it never compensates \u2014 a workflow can always model an inverse action as an ordinary node. What this advertises is that the HOST orders, persists, and retries the unwind, so a client can rely on it rather than hand-rolling one. Compensation is a second effect, not an undo: it can fail, can be partially applied, and can itself require approval, which is why the profile is security-tier high (RFC 0147 R9).",
|
|
3455
|
+
"additionalProperties": false,
|
|
3456
|
+
"required": [
|
|
3457
|
+
"supported"
|
|
3458
|
+
],
|
|
3459
|
+
"properties": {
|
|
3460
|
+
"supported": {
|
|
3461
|
+
"type": "boolean"
|
|
3462
|
+
},
|
|
3463
|
+
"profileVersion": {
|
|
3464
|
+
"type": "string",
|
|
3465
|
+
"pattern": "^[1-9][0-9]*$",
|
|
3466
|
+
"description": "RFC 0151. Participates in the inverse-action identity, so a profile bump cannot silently collide with identities minted under the previous ordering rules."
|
|
3467
|
+
},
|
|
3468
|
+
"orderingModels": {
|
|
3469
|
+
"type": "array",
|
|
3470
|
+
"minItems": 1,
|
|
3471
|
+
"uniqueItems": true,
|
|
3472
|
+
"items": {
|
|
3473
|
+
"enum": [
|
|
3474
|
+
"reverse-completion",
|
|
3475
|
+
"dependency-graph"
|
|
3476
|
+
]
|
|
3477
|
+
},
|
|
3478
|
+
"description": "RFC 0151 \u00a7A. A host that advertises compensation MUST implement `reverse-completion` and MAY additionally implement `dependency-graph`. `dependency-graph` MUST be a DAG and preserve reverse dependency order."
|
|
3479
|
+
},
|
|
3480
|
+
"manualIntervention": {
|
|
3481
|
+
"type": "boolean",
|
|
3482
|
+
"description": "RFC 0151 \u00a7C \u2014 the host can record `manual-intervention-required` rather than silently abandoning an unwind. Cancelling the parent MUST NOT abandon an active compensation: it continues, pauses for authorized intervention, or records this state."
|
|
2176
3483
|
}
|
|
2177
3484
|
}
|
|
2178
3485
|
},
|
|
2179
3486
|
"idempotency": {
|
|
2180
3487
|
"type": "object",
|
|
2181
|
-
"description": "RFC 0036
|
|
3488
|
+
"description": "RFC 0036 \u2014 Multi-region idempotency contract. Optional v1 advertisement. The existing `crossRegion: 'single-region'|'best-effort'|'strict'` categorical claim lives under `capabilities.idempotency.crossRegion` per spec/v1/idempotency.md \u00a7'Multi-region idempotency (annex)'. The `multiRegion` sub-block here gives a granular advertisement that hosts SHOULD pair with the categorical `crossRegion` claim.",
|
|
2182
3489
|
"additionalProperties": true,
|
|
2183
3490
|
"properties": {
|
|
3491
|
+
"supported": {
|
|
3492
|
+
"type": "boolean",
|
|
3493
|
+
"description": "Whether the host implements the idempotency contract. Used in `spec/v1/idempotency.md`'s own capability example and throughout the corpus, but UNDECLARED until 2026-08-13 \u2014 it validated only because this family carries `additionalProperties: true`, which meant a typo such as `suported` was accepted silently and a consumer reading it saw nothing advertised. Declaring it does not close the family; it makes the field a contract rather than a convention."
|
|
3494
|
+
},
|
|
2184
3495
|
"multiRegion": {
|
|
2185
3496
|
"type": "object",
|
|
2186
3497
|
"additionalProperties": false,
|
|
2187
|
-
"required": [
|
|
3498
|
+
"required": [
|
|
3499
|
+
"supported"
|
|
3500
|
+
],
|
|
2188
3501
|
"properties": {
|
|
2189
3502
|
"supported": {
|
|
2190
3503
|
"type": "boolean",
|
|
2191
|
-
"description": "Host implements cross-region idempotency reconciliation per spec/v1/idempotency.md
|
|
3504
|
+
"description": "Host implements cross-region idempotency reconciliation per spec/v1/idempotency.md \u00a7'Multi-region reconciliation'. When `true`, an Idempotency-Key write succeeding in region A is read-visible in region B within `replicationLagBoundMs + safetyMargin`."
|
|
2192
3505
|
},
|
|
2193
3506
|
"replicationLagBoundMs": {
|
|
2194
3507
|
"type": "integer",
|
|
2195
3508
|
"minimum": 0,
|
|
2196
3509
|
"maximum": 60000,
|
|
2197
|
-
"description": "Conservative upper bound on cross-region replication lag (
|
|
3510
|
+
"description": "Conservative upper bound on cross-region replication lag (\u2264 60s ceiling chosen to keep operator advertisement honest; production cross-region deployments typically run < 10s). Conformance asserts read-visibility after the bound."
|
|
2198
3511
|
},
|
|
2199
3512
|
"partitionRecoveryStrategy": {
|
|
2200
3513
|
"type": "string",
|
|
2201
3514
|
"anyOf": [
|
|
2202
|
-
{
|
|
2203
|
-
|
|
3515
|
+
{
|
|
3516
|
+
"enum": [
|
|
3517
|
+
"lexicographic-min-run-id"
|
|
3518
|
+
]
|
|
3519
|
+
},
|
|
3520
|
+
{
|
|
3521
|
+
"pattern": "^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$"
|
|
3522
|
+
}
|
|
2204
3523
|
],
|
|
2205
|
-
"description": "
|
|
3524
|
+
"description": "RFC 0150 \u00a7D \u2014 deterministic resolution rule for conflicting idempotency-key records after a partition heals. `lexicographic-min-run-id` is the rule spec/v1/idempotency.md \u00a7'Guarantees under partition' MUSTs: the lower runId wins, deterministic without coordination. Vendor strategies use `^x-host-<host>-<key>$` and MUST still satisfy the reproducible-survivor requirement. The time-ordered `last-writer-wins` / `first-writer-wins` values were REMOVED as a safety-fix: under a partition there is no shared clock, so both regions believe they wrote last, which cannot satisfy the annex MUST that re-running the same conflict input produces the same survivor \u2014 and both select a different survivor than the lex-min rule the same document requires. Resolving a RECORD never authorizes an EFFECT; see `crossRegion`."
|
|
2206
3525
|
}
|
|
2207
3526
|
}
|
|
2208
3527
|
},
|
|
2209
3528
|
"crossRegion": {
|
|
2210
3529
|
"type": "string",
|
|
2211
|
-
"enum": [
|
|
2212
|
-
|
|
3530
|
+
"enum": [
|
|
3531
|
+
"single-region",
|
|
3532
|
+
"reconciled-records",
|
|
3533
|
+
"fenced-effects"
|
|
3534
|
+
],
|
|
3535
|
+
"description": "RFC 0036, revised by RFC 0150 \u00a7D \u2014 categorical multi-region idempotency posture (the canonical conformance-checked surface per spec/v1/idempotency.md \u00a7'Multi-region idempotency (annex)'). The ladder is about EFFECTS, not replication latency. `single-region`: the host runs in one region and makes no cross-region claim (it MAY still implement the convergence resolver, demonstrable via the multi-region simulator seam). `reconciled-records`: cross-region reconciliation converges eventually under the annex's lex-min(runId) rule, and external effects MAY remain at-least-once \u2014 converging on which RECORD survives says nothing about how many times an effect was issued. `fenced-effects`: records converge AND every external effect is either fenced by a monotonic token from a linearizable ownership service or issued to a provider that guarantees duplicate suppression. When `reconciled-records` or `fenced-effects`, the host MUST emit the `openwop.idempotency.cross_region_conflicts_total` operator metric. The `multiRegion` sub-block above is the optional granular companion. REMOVED as a safety-fix: `best-effort` (renamed to `reconciled-records`, which states the effect caveat the old name hid) and `strict`, which promised only that read-visibility was bounded by `multiRegion.replicationLagBoundMs` \u2014 a LATENCY claim occupying the top slot of a ladder implementers read as effect safety. A host replicating synchronously at 0 ms can still issue duplicate effects from two regions, because knowing what the other region wrote is not being authorized to act. That latency bound already has its own field, so no information is lost."
|
|
2213
3536
|
}
|
|
2214
3537
|
}
|
|
2215
3538
|
},
|
|
2216
3539
|
"eventLog": {
|
|
2217
3540
|
"type": "object",
|
|
2218
|
-
"description": "RFC 0036
|
|
3541
|
+
"description": "RFC 0036 \u2014 Event-log multi-engine advertisement. Optional v1.",
|
|
2219
3542
|
"additionalProperties": false,
|
|
2220
3543
|
"properties": {
|
|
2221
3544
|
"crossEngineOrdering": {
|
|
2222
3545
|
"type": "object",
|
|
2223
3546
|
"additionalProperties": false,
|
|
2224
|
-
"required": [
|
|
3547
|
+
"required": [
|
|
3548
|
+
"supported"
|
|
3549
|
+
],
|
|
2225
3550
|
"properties": {
|
|
2226
3551
|
"supported": {
|
|
2227
3552
|
"type": "boolean",
|
|
@@ -2229,7 +3554,11 @@
|
|
|
2229
3554
|
},
|
|
2230
3555
|
"orderingModel": {
|
|
2231
3556
|
"type": "string",
|
|
2232
|
-
"enum": [
|
|
3557
|
+
"enum": [
|
|
3558
|
+
"lamport",
|
|
3559
|
+
"vector-clock",
|
|
3560
|
+
"global-sequencer"
|
|
3561
|
+
],
|
|
2233
3562
|
"description": "Mechanism the host uses to derive the total order. `lamport` = Lamport timestamps on each append. `vector-clock` = per-engine vector counters merged at read. `global-sequencer` = single sequencer assigns monotonic seq numbers (the Postgres reference host's posture)."
|
|
2234
3563
|
}
|
|
2235
3564
|
}
|
|
@@ -2242,12 +3571,26 @@
|
|
|
2242
3571
|
"properties": {
|
|
2243
3572
|
"defaultMode": {
|
|
2244
3573
|
"type": "string",
|
|
2245
|
-
"enum": [
|
|
2246
|
-
|
|
3574
|
+
"enum": [
|
|
3575
|
+
"mask",
|
|
3576
|
+
"omit",
|
|
3577
|
+
"hash",
|
|
3578
|
+
"passthrough"
|
|
3579
|
+
],
|
|
3580
|
+
"description": "Server's default masking mode for fields marked sensitive. `mask` (default): replace with `\"[REDACTED]\"`. `omit`: drop the field entirely. `hash`: replace with `\"sha256:<hex>\"` for audit-only equality. `passthrough`: record as-is (NOT recommended for production). Workflow authors MAY override per-workflow via `metadata.complianceConfig.maskingMode`. See observability.md \u00a7Privacy classification."
|
|
2247
3581
|
},
|
|
2248
3582
|
"supportedClasses": {
|
|
2249
3583
|
"type": "array",
|
|
2250
|
-
"items": {
|
|
3584
|
+
"items": {
|
|
3585
|
+
"type": "string",
|
|
3586
|
+
"enum": [
|
|
3587
|
+
"public",
|
|
3588
|
+
"pii",
|
|
3589
|
+
"phi",
|
|
3590
|
+
"pci",
|
|
3591
|
+
"regulated"
|
|
3592
|
+
]
|
|
3593
|
+
},
|
|
2251
3594
|
"uniqueItems": true,
|
|
2252
3595
|
"description": "Compliance classes this server applies special handling for. A server MAY accept all five classes but only enforce stricter retention on a subset; this field declares the operational reality so workflow authors can choose a server appropriately."
|
|
2253
3596
|
}
|
|
@@ -2257,7 +3600,9 @@
|
|
|
2257
3600
|
"production": {
|
|
2258
3601
|
"type": "object",
|
|
2259
3602
|
"description": "Production-profile advertisement (see production-profile.md). Optional in v1; absence means the host does not claim the openwop-production profile. When `supported: true`, the host claims every MUST in production-profile.md and conformance scenarios gated on this block MUST run. Landed by RFC 0009.",
|
|
2260
|
-
"required": [
|
|
3603
|
+
"required": [
|
|
3604
|
+
"supported"
|
|
3605
|
+
],
|
|
2261
3606
|
"properties": {
|
|
2262
3607
|
"supported": {
|
|
2263
3608
|
"type": "boolean",
|
|
@@ -2265,11 +3610,11 @@
|
|
|
2265
3610
|
},
|
|
2266
3611
|
"backpressure": {
|
|
2267
3612
|
"type": "object",
|
|
2268
|
-
"description": "Backpressure envelope advertisement (production-profile.md
|
|
3613
|
+
"description": "Backpressure envelope advertisement (production-profile.md \u00a7Backpressure).",
|
|
2269
3614
|
"properties": {
|
|
2270
3615
|
"supported": {
|
|
2271
3616
|
"type": "boolean",
|
|
2272
|
-
"description": "Host returns 503 + Retry-After + canonical envelope under load per production-profile.md
|
|
3617
|
+
"description": "Host returns 503 + Retry-After + canonical envelope under load per production-profile.md \u00a7Backpressure."
|
|
2273
3618
|
},
|
|
2274
3619
|
"inflightCap": {
|
|
2275
3620
|
"type": "integer",
|
|
@@ -2280,14 +3625,14 @@
|
|
|
2280
3625
|
"type": "integer",
|
|
2281
3626
|
"minimum": 0,
|
|
2282
3627
|
"maximum": 86400,
|
|
2283
|
-
"description": "Optional advertised Retry-After value in seconds the host returns on 503. When present, MUST equal both the `Retry-After` header and the `details.retryAfter` body field per production-profile.md. Upper bound 86400 (24h)
|
|
3628
|
+
"description": "Optional advertised Retry-After value in seconds the host returns on 503. When present, MUST equal both the `Retry-After` header and the `details.retryAfter` body field per production-profile.md. Upper bound 86400 (24h) \u2014 values beyond that are operationally indistinguishable from 'permanently denied'. Hosts needing longer holds SHOULD omit `Retry-After` entirely (RFC 0009 Q#2)."
|
|
2284
3629
|
}
|
|
2285
3630
|
},
|
|
2286
3631
|
"additionalProperties": false
|
|
2287
3632
|
},
|
|
2288
3633
|
"retention": {
|
|
2289
3634
|
"type": "object",
|
|
2290
|
-
"description": "Event-retention advertisement (production-profile.md
|
|
3635
|
+
"description": "Event-retention advertisement (production-profile.md \u00a7\"Event retention\").",
|
|
2291
3636
|
"properties": {
|
|
2292
3637
|
"supported": {
|
|
2293
3638
|
"type": "boolean",
|
|
@@ -2296,18 +3641,18 @@
|
|
|
2296
3641
|
"minWindowSeconds": {
|
|
2297
3642
|
"type": "integer",
|
|
2298
3643
|
"minimum": 604800,
|
|
2299
|
-
"description": "Documented minimum retention window in seconds. Per production-profile.md
|
|
3644
|
+
"description": "Documented minimum retention window in seconds. Per production-profile.md \u00a7\"Event retention\", MUST be \u2265 604800 (7 days) for public hosts; development-only hosts MAY advertise a smaller window but MUST NOT claim `supported: true` while doing so."
|
|
2300
3645
|
},
|
|
2301
3646
|
"testForceExpire": {
|
|
2302
3647
|
"type": "boolean",
|
|
2303
|
-
"description": "Host exposes a test-only force-expire hook the conformance suite can call (URL/method supplied via `OPENWOP_TEST_FORCE_EXPIRE_URL` / `OPENWOP_TEST_FORCE_EXPIRE_METHOD` env vars). When `false`, the production-retention-expiry scenario asserts only the 410/404 envelope shape on an operator-supplied already-expired run id (via `OPENWOP_TEST_EXPIRED_RUN_ID`); otherwise it soft-skips. RFC 0009 unresolved question #1
|
|
3648
|
+
"description": "Host exposes a test-only force-expire hook the conformance suite can call (URL/method supplied via `OPENWOP_TEST_FORCE_EXPIRE_URL` / `OPENWOP_TEST_FORCE_EXPIRE_METHOD` env vars). When `false`, the production-retention-expiry scenario asserts only the 410/404 envelope shape on an operator-supplied already-expired run id (via `OPENWOP_TEST_EXPIRED_RUN_ID`); otherwise it soft-skips. RFC 0009 unresolved question #1 \u2014 endpoint normation is deferred."
|
|
2304
3649
|
}
|
|
2305
3650
|
},
|
|
2306
3651
|
"additionalProperties": false
|
|
2307
3652
|
},
|
|
2308
3653
|
"debugBundle": {
|
|
2309
3654
|
"type": "object",
|
|
2310
|
-
"description": "Debug-bundle truncation advertisement (production-profile.md
|
|
3655
|
+
"description": "Debug-bundle truncation advertisement (production-profile.md \u00a7\"Debug bundle behavior\"). Stricter than the existing `capabilities.debugBundle.supported` advertised per debug-bundle.md \u2014 this block adds the production-profile MUSTs (truncation metadata, redaction).",
|
|
2311
3656
|
"properties": {
|
|
2312
3657
|
"supported": {
|
|
2313
3658
|
"type": "boolean",
|
|
@@ -2315,7 +3660,7 @@
|
|
|
2315
3660
|
},
|
|
2316
3661
|
"truncationMetadata": {
|
|
2317
3662
|
"type": "boolean",
|
|
2318
|
-
"description": "When `true`, host surfaces `truncated: true` + non-empty `truncatedReason` per debug-bundle.md
|
|
3663
|
+
"description": "When `true`, host surfaces `truncated: true` + non-empty `truncatedReason` per debug-bundle.md \u00a7\"Bundle size limits\" when caps are reached."
|
|
2319
3664
|
}
|
|
2320
3665
|
},
|
|
2321
3666
|
"additionalProperties": false
|
|
@@ -2329,13 +3674,16 @@
|
|
|
2329
3674
|
"properties": {
|
|
2330
3675
|
"profiles": {
|
|
2331
3676
|
"type": "array",
|
|
2332
|
-
"items": {
|
|
3677
|
+
"items": {
|
|
3678
|
+
"type": "string",
|
|
3679
|
+
"minLength": 1
|
|
3680
|
+
},
|
|
2333
3681
|
"uniqueItems": true,
|
|
2334
|
-
"description": "Auth profiles the host claims. Canonical ids: `openwop-audit-log-integrity` (auth-profiles.md
|
|
3682
|
+
"description": "Auth profiles the host claims. Canonical ids: `openwop-audit-log-integrity` (auth-profiles.md \u00a7Audit-log integrity), `openwop-auth-api-key-rotation`, `openwop-auth-oauth2-client-credentials`, `openwop-auth-oidc-user-bearer`, `openwop-auth-mtls`, `openwop-auth-saml` + `openwop-auth-scim` + `openwop-auth-ldap` (RFC 0050 enterprise identity). Clients SHOULD tolerate unknown profile ids."
|
|
2335
3683
|
},
|
|
2336
3684
|
"rotation": {
|
|
2337
3685
|
"type": "object",
|
|
2338
|
-
"description": "API-key rotation advertisement (auth-profiles.md
|
|
3686
|
+
"description": "API-key rotation advertisement (auth-profiles.md \u00a7`openwop-auth-api-key-rotation`).",
|
|
2339
3687
|
"properties": {
|
|
2340
3688
|
"supported": {
|
|
2341
3689
|
"type": "boolean",
|
|
@@ -2344,16 +3692,18 @@
|
|
|
2344
3692
|
"minGraceSeconds": {
|
|
2345
3693
|
"type": "integer",
|
|
2346
3694
|
"minimum": 0,
|
|
2347
|
-
"description": "Minimum rotation grace window in seconds. auth-profiles.md SHOULDs production-profile hosts to
|
|
3695
|
+
"description": "Minimum rotation grace window in seconds. auth-profiles.md SHOULDs production-profile hosts to \u2265 86400 (24h). The conformance scenario tolerates any non-negative value but warns in behavior mode when < 86400."
|
|
2348
3696
|
}
|
|
2349
3697
|
},
|
|
2350
3698
|
"additionalProperties": false
|
|
2351
3699
|
},
|
|
2352
3700
|
"oauth2": {
|
|
2353
3701
|
"type": "object",
|
|
2354
|
-
"description": "OAuth2 client-credentials advertisement (auth-profiles.md
|
|
3702
|
+
"description": "OAuth2 client-credentials advertisement (auth-profiles.md \u00a7`openwop-auth-oauth2-client-credentials`).",
|
|
2355
3703
|
"properties": {
|
|
2356
|
-
"supported": {
|
|
3704
|
+
"supported": {
|
|
3705
|
+
"type": "boolean"
|
|
3706
|
+
},
|
|
2357
3707
|
"issuer": {
|
|
2358
3708
|
"type": "string",
|
|
2359
3709
|
"format": "uri",
|
|
@@ -2365,7 +3715,10 @@
|
|
|
2365
3715
|
},
|
|
2366
3716
|
"supportedAlgorithms": {
|
|
2367
3717
|
"type": "array",
|
|
2368
|
-
"items": {
|
|
3718
|
+
"items": {
|
|
3719
|
+
"type": "string",
|
|
3720
|
+
"minLength": 1
|
|
3721
|
+
},
|
|
2369
3722
|
"uniqueItems": true,
|
|
2370
3723
|
"description": "JWS signing algorithms the host accepts (canonical: RS256, ES256). Hosts MUST reject tokens signed with algorithms outside this list."
|
|
2371
3724
|
}
|
|
@@ -2374,12 +3727,17 @@
|
|
|
2374
3727
|
},
|
|
2375
3728
|
"oidc": {
|
|
2376
3729
|
"type": "object",
|
|
2377
|
-
"description": "OIDC user-bearer advertisement (auth-profiles.md
|
|
3730
|
+
"description": "OIDC user-bearer advertisement (auth-profiles.md \u00a7`openwop-auth-oidc-user-bearer`).",
|
|
2378
3731
|
"properties": {
|
|
2379
|
-
"supported": {
|
|
3732
|
+
"supported": {
|
|
3733
|
+
"type": "boolean"
|
|
3734
|
+
},
|
|
2380
3735
|
"issuers": {
|
|
2381
3736
|
"type": "array",
|
|
2382
|
-
"items": {
|
|
3737
|
+
"items": {
|
|
3738
|
+
"type": "string",
|
|
3739
|
+
"format": "uri"
|
|
3740
|
+
},
|
|
2383
3741
|
"minItems": 1,
|
|
2384
3742
|
"uniqueItems": true,
|
|
2385
3743
|
"description": "Trusted OIDC issuer URLs. The host accepts tokens whose `iss` claim matches any entry."
|
|
@@ -2390,8 +3748,12 @@
|
|
|
2390
3748
|
},
|
|
2391
3749
|
"supportedScopeMapping": {
|
|
2392
3750
|
"type": "string",
|
|
2393
|
-
"enum": [
|
|
2394
|
-
|
|
3751
|
+
"enum": [
|
|
3752
|
+
"group-claim",
|
|
3753
|
+
"scope-claim",
|
|
3754
|
+
"host-acl"
|
|
3755
|
+
],
|
|
3756
|
+
"description": "How the host derives openwop scopes from the OIDC token. `group-claim`: from `groups` claim via host config. `scope-claim`: from `scope` claim directly. `host-acl`: from a host-side mapping table (sub \u2192 scope)."
|
|
2395
3757
|
},
|
|
2396
3758
|
"introspectionIntervalSeconds": {
|
|
2397
3759
|
"type": "integer",
|
|
@@ -2403,20 +3765,82 @@
|
|
|
2403
3765
|
},
|
|
2404
3766
|
"mtls": {
|
|
2405
3767
|
"type": "object",
|
|
2406
|
-
"description": "mTLS advertisement (auth-profiles.md
|
|
3768
|
+
"description": "mTLS advertisement (auth-profiles.md \u00a7`openwop-auth-mtls`).",
|
|
2407
3769
|
"properties": {
|
|
2408
|
-
"supported": {
|
|
3770
|
+
"supported": {
|
|
3771
|
+
"type": "boolean"
|
|
3772
|
+
},
|
|
2409
3773
|
"required": {
|
|
2410
3774
|
"type": "boolean",
|
|
2411
3775
|
"description": "When `true`, the host rejects bearer-only requests (mTLS required for all authenticated calls). When `false`, mTLS is optional and complements bearer auth."
|
|
2412
3776
|
},
|
|
2413
3777
|
"subjectMapping": {
|
|
2414
3778
|
"type": "string",
|
|
2415
|
-
"enum": [
|
|
3779
|
+
"enum": [
|
|
3780
|
+
"cn",
|
|
3781
|
+
"san-dns",
|
|
3782
|
+
"san-uri"
|
|
3783
|
+
],
|
|
2416
3784
|
"description": "How the host derives the transport principal from the client certificate. `cn`: subject CN. `san-dns`: subjectAltName DNS entry. `san-uri`: subjectAltName URI entry."
|
|
2417
3785
|
}
|
|
2418
3786
|
},
|
|
2419
3787
|
"additionalProperties": false
|
|
3788
|
+
},
|
|
3789
|
+
"workloadIdentity": {
|
|
3790
|
+
"type": "object",
|
|
3791
|
+
"description": "RFC 0154 \u00a7A \u2014 workload identity profile `openwop-workload-identity-v1`. A host that advertises this cryptographically verifies the presented workload identity, binds it to the request, and resolves it to an OpenWOP principal BEFORE authorization. Unresolvable identity fails closed. **Identity is not authorization** (RFC 0147 R12): proving which workload called says nothing about what it may do, and treating the two as one is the confused-deputy shape this profile exists to prevent \u2014 tenant, audience, and policy MUST still be re-evaluated at every boundary.",
|
|
3792
|
+
"additionalProperties": false,
|
|
3793
|
+
"required": [
|
|
3794
|
+
"supported"
|
|
3795
|
+
],
|
|
3796
|
+
"properties": {
|
|
3797
|
+
"supported": {
|
|
3798
|
+
"type": "boolean"
|
|
3799
|
+
},
|
|
3800
|
+
"schemes": {
|
|
3801
|
+
"type": "array",
|
|
3802
|
+
"minItems": 1,
|
|
3803
|
+
"uniqueItems": true,
|
|
3804
|
+
"items": {
|
|
3805
|
+
"enum": [
|
|
3806
|
+
"spiffe",
|
|
3807
|
+
"mtls-san",
|
|
3808
|
+
"cloud-subject",
|
|
3809
|
+
"oauth-client"
|
|
3810
|
+
]
|
|
3811
|
+
},
|
|
3812
|
+
"description": "RFC 0154 \u00a7A \u2014 closed set of identity schemes the host verifies. Closed because an unrecognized scheme is a verification path nobody implemented, and accepting the NAME without the verification is precisely the failure the profile prevents."
|
|
3813
|
+
},
|
|
3814
|
+
"senderConstraint": {
|
|
3815
|
+
"type": "array",
|
|
3816
|
+
"uniqueItems": true,
|
|
3817
|
+
"items": {
|
|
3818
|
+
"enum": [
|
|
3819
|
+
"mtls",
|
|
3820
|
+
"dpop"
|
|
3821
|
+
]
|
|
3822
|
+
},
|
|
3823
|
+
"description": "RFC 0154 \u00a7A \u2014 proof-of-possession mechanisms. Without a sender constraint a bearer credential is replayable by anyone who observes it, so a host advertising workload identity WITHOUT one is asserting who called, not that the caller held the key."
|
|
3824
|
+
},
|
|
3825
|
+
"delegation": {
|
|
3826
|
+
"type": "object",
|
|
3827
|
+
"description": "RFC 0154 \u00a7B \u2014 delegated actor chains, advertised SEPARATELY from \u00a7A identity resolution. A host can verify workload identity without implementing delegation, and forcing one flag to cover both would make a \u00a7A-only host choose between advertising a capability it does not have and advertising nothing at all. That is the same overclaim-or-silence bind RFC 0155 \u00a7A names for `openwop-core`, and per-section advertisement is how it is avoided: `supported` means \u00a7A resolution, `delegation.supported` means \u00a7B chain verification, and a conformance run gates each section on its own flag.",
|
|
3828
|
+
"additionalProperties": false,
|
|
3829
|
+
"required": [
|
|
3830
|
+
"supported"
|
|
3831
|
+
],
|
|
3832
|
+
"properties": {
|
|
3833
|
+
"supported": {
|
|
3834
|
+
"type": "boolean"
|
|
3835
|
+
},
|
|
3836
|
+
"maxChainDepth": {
|
|
3837
|
+
"type": "integer",
|
|
3838
|
+
"minimum": 1,
|
|
3839
|
+
"description": "RFC 0154 \u00a7B \u2014 bounded chain length. Unbounded delegation is unbounded authority laundering: each hop is another party the host is trusting transitively."
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
2420
3844
|
}
|
|
2421
3845
|
},
|
|
2422
3846
|
"additionalProperties": true
|
|
@@ -2427,7 +3851,7 @@
|
|
|
2427
3851
|
"properties": {
|
|
2428
3852
|
"authScoped": {
|
|
2429
3853
|
"type": "object",
|
|
2430
|
-
"description": "Auth-scoped discovery advertisement (capabilities-change-detection.md
|
|
3854
|
+
"description": "Auth-scoped discovery advertisement (capabilities-change-detection.md \u00a7\"Scoped capability views\"). Hosts that return a different payload when called with Authorization than when called anonymously declare it here. The authenticated view MUST still satisfy the base capabilities.schema.json shape per the spec annex.",
|
|
2431
3855
|
"properties": {
|
|
2432
3856
|
"supported": {
|
|
2433
3857
|
"type": "boolean",
|
|
@@ -2435,7 +3859,10 @@
|
|
|
2435
3859
|
},
|
|
2436
3860
|
"mode": {
|
|
2437
3861
|
"type": "string",
|
|
2438
|
-
"enum": [
|
|
3862
|
+
"enum": [
|
|
3863
|
+
"same-endpoint",
|
|
3864
|
+
"extension-endpoint"
|
|
3865
|
+
],
|
|
2439
3866
|
"description": "How the host exposes the auth-scoped view. `same-endpoint`: the canonical /.well-known/openwop returns a narrowed/enriched view when authenticated. `extension-endpoint`: a separate host route carries the scoped view (path advertised via `endpointPath`). Hosts using the third pattern from the spec annex (documentation pointer in the public payload) MAY omit this field."
|
|
2440
3867
|
},
|
|
2441
3868
|
"endpointPath": {
|
|
@@ -2477,9 +3904,13 @@
|
|
|
2477
3904
|
},
|
|
2478
3905
|
"content": {
|
|
2479
3906
|
"type": "object",
|
|
2480
|
-
"description": "RFC 0103 (spec/v1/localized-content.md). Localized authored content (pages
|
|
3907
|
+
"description": "RFC 0103 (spec/v1/localized-content.md). Localized authored content (pages \u2192 sections) advertisement. Reuses the i18n annex's Accept-Language/Content-Language negotiation; it does NOT redeclare negotiation. Requires `i18n.supported: true`. `baseLocale` MUST equal `capabilities.i18n.defaultLocale`; `({baseLocale} \u222a supportedLocales)` MUST be a subset of `capabilities.i18n.supportedLocales`; `baseLocale` MUST NOT appear in `supportedLocales`. Hosts that omit this block serve no content surface; the conformance scenarios skip cleanly.",
|
|
2481
3908
|
"additionalProperties": false,
|
|
2482
|
-
"required": [
|
|
3909
|
+
"required": [
|
|
3910
|
+
"supported",
|
|
3911
|
+
"baseLocale",
|
|
3912
|
+
"supportedLocales"
|
|
3913
|
+
],
|
|
2483
3914
|
"properties": {
|
|
2484
3915
|
"supported": {
|
|
2485
3916
|
"type": "boolean",
|
|
@@ -2497,13 +3928,13 @@
|
|
|
2497
3928
|
"type": "string",
|
|
2498
3929
|
"pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8}){0,3}$"
|
|
2499
3930
|
},
|
|
2500
|
-
"description": "BCP 47 tags the host has authored content translations for. MUST NOT contain `baseLocale`; `({baseLocale}
|
|
3931
|
+
"description": "BCP 47 tags the host has authored content translations for. MUST NOT contain `baseLocale`; `({baseLocale} \u222a supportedLocales)` MUST be a subset of `i18n.supportedLocales`."
|
|
2501
3932
|
}
|
|
2502
3933
|
}
|
|
2503
3934
|
},
|
|
2504
3935
|
"portability": {
|
|
2505
3936
|
"type": "object",
|
|
2506
|
-
"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
|
|
3937
|
+
"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 \u2014 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.",
|
|
2507
3938
|
"additionalProperties": false,
|
|
2508
3939
|
"properties": {
|
|
2509
3940
|
"export": {
|
|
@@ -2518,7 +3949,18 @@
|
|
|
2518
3949
|
},
|
|
2519
3950
|
"kinds": {
|
|
2520
3951
|
"type": "array",
|
|
2521
|
-
"items": {
|
|
3952
|
+
"items": {
|
|
3953
|
+
"type": "string",
|
|
3954
|
+
"enum": [
|
|
3955
|
+
"agent",
|
|
3956
|
+
"pack",
|
|
3957
|
+
"prompt-template",
|
|
3958
|
+
"connection-ref",
|
|
3959
|
+
"schedule",
|
|
3960
|
+
"roster",
|
|
3961
|
+
"org-chart"
|
|
3962
|
+
]
|
|
3963
|
+
},
|
|
2522
3964
|
"uniqueItems": true,
|
|
2523
3965
|
"description": "Estate kinds this host can export/import."
|
|
2524
3966
|
},
|
|
@@ -2528,8 +3970,26 @@
|
|
|
2528
3970
|
"description": "Import supports a no-write plan preview (`POST /import?dryRun=true`). MUST be true if `import` is true."
|
|
2529
3971
|
}
|
|
2530
3972
|
},
|
|
2531
|
-
"if": {
|
|
2532
|
-
|
|
3973
|
+
"if": {
|
|
3974
|
+
"properties": {
|
|
3975
|
+
"import": {
|
|
3976
|
+
"const": true
|
|
3977
|
+
}
|
|
3978
|
+
},
|
|
3979
|
+
"required": [
|
|
3980
|
+
"import"
|
|
3981
|
+
]
|
|
3982
|
+
},
|
|
3983
|
+
"then": {
|
|
3984
|
+
"properties": {
|
|
3985
|
+
"dryRun": {
|
|
3986
|
+
"const": true
|
|
3987
|
+
}
|
|
3988
|
+
},
|
|
3989
|
+
"required": [
|
|
3990
|
+
"dryRun"
|
|
3991
|
+
]
|
|
3992
|
+
}
|
|
2533
3993
|
},
|
|
2534
3994
|
"interrupt": {
|
|
2535
3995
|
"type": "object",
|
|
@@ -2539,17 +3999,32 @@
|
|
|
2539
3999
|
"approverRouting": {
|
|
2540
4000
|
"type": "object",
|
|
2541
4001
|
"additionalProperties": false,
|
|
2542
|
-
"required": [
|
|
4002
|
+
"required": [
|
|
4003
|
+
"supported"
|
|
4004
|
+
],
|
|
2543
4005
|
"description": "RFC 0104. When `supported: true`, the host surfaces the OPTIONAL, ADVISORY `approverGroupRefs` / `approverRoleRefs` / `audience` fields on the approval InterruptPayload unchanged, resolves the ref kinds it advertises against its own identity/RBAC, ENFORCES eligibility at resolve time (the refs stay advisory metadata for clients; enforcement is host-side), and SHOULD route notifications to the resolved union. Refs are opaque to the engine and snapshotted at decision time for deterministic replay. Hosts that omit this block (or set `supported: false`) ignore the fields and remain conformant. Advertise only what the host actually resolves (`refKinds`) and honors (`audience`).",
|
|
2544
4006
|
"properties": {
|
|
2545
|
-
"supported": {
|
|
4007
|
+
"supported": {
|
|
4008
|
+
"type": "boolean",
|
|
4009
|
+
"description": "Host honors the RFC 0104 approver-routing fields."
|
|
4010
|
+
},
|
|
2546
4011
|
"refKinds": {
|
|
2547
4012
|
"type": "array",
|
|
2548
|
-
"items": {
|
|
4013
|
+
"items": {
|
|
4014
|
+
"type": "string",
|
|
4015
|
+
"enum": [
|
|
4016
|
+
"group",
|
|
4017
|
+
"role"
|
|
4018
|
+
]
|
|
4019
|
+
},
|
|
2549
4020
|
"uniqueItems": true,
|
|
2550
|
-
"description": "Which approver ref kinds the host actually resolves. `group`
|
|
4021
|
+
"description": "Which approver ref kinds the host actually resolves. `group` \u21d2 honors `approverGroupRefs`; `role` \u21d2 honors `approverRoleRefs`. Absent \u21d2 the host resolves neither (advisory-only passthrough). Capability honesty: advertise only the kinds the host's resolver supports."
|
|
2551
4022
|
},
|
|
2552
|
-
"audience": {
|
|
4023
|
+
"audience": {
|
|
4024
|
+
"type": "boolean",
|
|
4025
|
+
"default": false,
|
|
4026
|
+
"description": "Host honors the `audience` notification-targeting override. Absent/`false` \u21d2 the host notifies the resolved eligible union and ignores `audience`."
|
|
4027
|
+
}
|
|
2553
4028
|
}
|
|
2554
4029
|
}
|
|
2555
4030
|
}
|
|
@@ -2557,7 +4032,7 @@
|
|
|
2557
4032
|
"restTransport": {
|
|
2558
4033
|
"type": "object",
|
|
2559
4034
|
"additionalProperties": false,
|
|
2560
|
-
"description": "RFC 0115 (`Active`). Conditional-GET + Content-Encoding negotiation on run reads (`GET /v1/runs/{runId}`). Optional. Distinct from the file-egress `fileHandling.transport` (ftp/sftp/ssh) sub-capability
|
|
4035
|
+
"description": "RFC 0115 (`Active`). Conditional-GET + Content-Encoding negotiation on run reads (`GET /v1/runs/{runId}`). Optional. Distinct from the file-egress `fileHandling.transport` (ftp/sftp/ssh) sub-capability \u2014 this advertises HTTP-layer poll economy on the run-read REST surface.",
|
|
2561
4036
|
"properties": {
|
|
2562
4037
|
"conditionalRunGet": {
|
|
2563
4038
|
"type": "boolean",
|
|
@@ -2565,15 +4040,22 @@
|
|
|
2565
4040
|
},
|
|
2566
4041
|
"contentEncodings": {
|
|
2567
4042
|
"type": "array",
|
|
2568
|
-
"items": {
|
|
2569
|
-
|
|
4043
|
+
"items": {
|
|
4044
|
+
"type": "string",
|
|
4045
|
+
"enum": [
|
|
4046
|
+
"gzip",
|
|
4047
|
+
"br",
|
|
4048
|
+
"zstd"
|
|
4049
|
+
]
|
|
4050
|
+
},
|
|
4051
|
+
"description": "RFC 0115. Content-Encoding values the host will negotiate on run reads (advertisement of standard-HTTP behavior). `gzip` is the baseline; `br`/`zstd` are OPTIONAL \u2014 the host advertises only the subset it can actually serve. For each advertised value the decoded body MUST be byte-identical to the identity body."
|
|
2570
4052
|
}
|
|
2571
4053
|
}
|
|
2572
4054
|
},
|
|
2573
4055
|
"a2uiSurface": {
|
|
2574
4056
|
"type": "object",
|
|
2575
4057
|
"additionalProperties": false,
|
|
2576
|
-
"description": "RFC 0114 (`Active`). Host-side TRANSPORT features over the recorded `ui.a2ui-surface` envelope (RFC 0102). A transport optimization, NOT an envelope-payload kind
|
|
4058
|
+
"description": "RFC 0114 (`Active`). Host-side TRANSPORT features over the recorded `ui.a2ui-surface` envelope (RFC 0102). A transport optimization, NOT an envelope-payload kind \u2014 the recorded envelope stays the full surface. Optional.",
|
|
2577
4059
|
"properties": {
|
|
2578
4060
|
"deltaTransport": {
|
|
2579
4061
|
"type": "boolean",
|