@openwop/openwop-conformance 1.73.0 → 1.99.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 +2028 -563
- 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 +80 -5
- 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 +215 -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,16 +4,21 @@
|
|
|
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]*)$"
|
|
13
18
|
},
|
|
14
19
|
"contractProvenance": {
|
|
15
20
|
"type": "object",
|
|
16
|
-
"description": "RFC 0146 (`Active`). Which corpus revision this host's contract handling corresponds to
|
|
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.",
|
|
17
22
|
"properties": {
|
|
18
23
|
"suiteVersion": {
|
|
19
24
|
"type": "string",
|
|
@@ -22,7 +27,7 @@
|
|
|
22
27
|
},
|
|
23
28
|
"corpusCommit": {
|
|
24
29
|
"type": "string",
|
|
25
|
-
"description": "Full 40-character commit SHA of the openwop repository. A vendor build identifier does NOT belong here
|
|
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.",
|
|
26
31
|
"pattern": "^[0-9a-f]{40}$"
|
|
27
32
|
}
|
|
28
33
|
},
|
|
@@ -30,17 +35,27 @@
|
|
|
30
35
|
},
|
|
31
36
|
"supportedEnvelopes": {
|
|
32
37
|
"type": "array",
|
|
33
|
-
"items": {
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"minLength": 1
|
|
41
|
+
},
|
|
34
42
|
"description": "Envelope `type` strings the engine recognizes (e.g., `prd.create`, `theme.create`, `tasks.create`, `clarification.request`)."
|
|
35
43
|
},
|
|
36
44
|
"schemaVersions": {
|
|
37
45
|
"type": "object",
|
|
38
|
-
"additionalProperties": {
|
|
46
|
+
"additionalProperties": {
|
|
47
|
+
"type": "integer",
|
|
48
|
+
"minimum": 0
|
|
49
|
+
},
|
|
39
50
|
"description": "Active schema version per envelope type (e.g., `{ \"prd.create\": 2 }`)."
|
|
40
51
|
},
|
|
41
52
|
"limits": {
|
|
42
53
|
"type": "object",
|
|
43
|
-
"required": [
|
|
54
|
+
"required": [
|
|
55
|
+
"clarificationRounds",
|
|
56
|
+
"schemaRounds",
|
|
57
|
+
"envelopesPerTurn"
|
|
58
|
+
],
|
|
44
59
|
"properties": {
|
|
45
60
|
"clarificationRounds": {
|
|
46
61
|
"type": "integer",
|
|
@@ -85,21 +100,26 @@
|
|
|
85
100
|
"maxRequestBodyBytes": {
|
|
86
101
|
"type": "integer",
|
|
87
102
|
"minimum": 1,
|
|
88
|
-
"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."
|
|
89
104
|
}
|
|
90
105
|
},
|
|
91
106
|
"additionalProperties": false,
|
|
92
|
-
"description": "Hard limits enforced by the engine. See capabilities.md
|
|
107
|
+
"description": "Hard limits enforced by the engine. See capabilities.md \u00a73."
|
|
93
108
|
},
|
|
94
109
|
"envelopeStrictness": {
|
|
95
110
|
"type": "string",
|
|
96
|
-
"enum": [
|
|
97
|
-
|
|
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."
|
|
98
116
|
},
|
|
99
117
|
"envelopeContracts": {
|
|
100
118
|
"type": "object",
|
|
101
|
-
"description": "AI Envelope contract-gating advertisement per `spec/v1/ai-envelope.md`
|
|
102
|
-
"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
|
+
],
|
|
103
123
|
"properties": {
|
|
104
124
|
"advertised": {
|
|
105
125
|
"type": "boolean",
|
|
@@ -110,36 +130,48 @@
|
|
|
110
130
|
},
|
|
111
131
|
"envelopes": {
|
|
112
132
|
"type": "object",
|
|
113
|
-
"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\".",
|
|
114
134
|
"additionalProperties": true,
|
|
115
135
|
"properties": {
|
|
116
136
|
"reasoning": {
|
|
117
137
|
"type": "object",
|
|
118
|
-
"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).",
|
|
119
139
|
"additionalProperties": false,
|
|
120
|
-
"required": [
|
|
140
|
+
"required": [
|
|
141
|
+
"supported"
|
|
142
|
+
],
|
|
121
143
|
"properties": {
|
|
122
144
|
"supported": {
|
|
123
145
|
"type": "boolean",
|
|
124
|
-
"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."
|
|
125
147
|
},
|
|
126
148
|
"promptDirective": {
|
|
127
149
|
"type": "string",
|
|
128
|
-
"enum": [
|
|
129
|
-
|
|
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."
|
|
130
156
|
}
|
|
131
157
|
}
|
|
132
158
|
},
|
|
133
159
|
"tierOneSubsetCompliance": {
|
|
134
160
|
"type": "string",
|
|
135
|
-
"enum": [
|
|
136
|
-
|
|
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."
|
|
137
167
|
},
|
|
138
168
|
"reliability": {
|
|
139
169
|
"type": "object",
|
|
140
170
|
"additionalProperties": false,
|
|
141
|
-
"required": [
|
|
142
|
-
|
|
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.",
|
|
143
175
|
"properties": {
|
|
144
176
|
"supported": {
|
|
145
177
|
"type": "boolean",
|
|
@@ -165,23 +197,25 @@
|
|
|
165
197
|
"type": "integer",
|
|
166
198
|
"minimum": 1,
|
|
167
199
|
"maximum": 16,
|
|
168
|
-
"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."
|
|
169
201
|
},
|
|
170
202
|
"completion": {
|
|
171
203
|
"type": "object",
|
|
172
204
|
"additionalProperties": false,
|
|
173
|
-
"required": [
|
|
174
|
-
|
|
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?",
|
|
175
209
|
"properties": {
|
|
176
210
|
"distinguishesTruncation": {
|
|
177
211
|
"type": "boolean",
|
|
178
|
-
"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."
|
|
179
213
|
},
|
|
180
214
|
"truncationBudgetMultiplier": {
|
|
181
215
|
"type": "number",
|
|
182
216
|
"minimum": 1,
|
|
183
217
|
"maximum": 8,
|
|
184
|
-
"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."
|
|
185
219
|
}
|
|
186
220
|
}
|
|
187
221
|
}
|
|
@@ -191,26 +225,38 @@
|
|
|
191
225
|
},
|
|
192
226
|
"prompts": {
|
|
193
227
|
"type": "object",
|
|
194
|
-
"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
|
|
195
|
-
"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
|
+
],
|
|
196
232
|
"properties": {
|
|
197
233
|
"supported": {
|
|
198
234
|
"type": "boolean",
|
|
199
|
-
"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."
|
|
200
236
|
},
|
|
201
237
|
"endpointsSupported": {
|
|
202
238
|
"type": "boolean",
|
|
203
|
-
"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)."
|
|
204
240
|
},
|
|
205
241
|
"templateKinds": {
|
|
206
242
|
"type": "array",
|
|
207
|
-
"items": {
|
|
243
|
+
"items": {
|
|
244
|
+
"$ref": "./prompt-kind.schema.json"
|
|
245
|
+
},
|
|
208
246
|
"uniqueItems": true,
|
|
209
|
-
"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."
|
|
210
248
|
},
|
|
211
249
|
"variableSources": {
|
|
212
250
|
"type": "array",
|
|
213
|
-
"items": {
|
|
251
|
+
"items": {
|
|
252
|
+
"type": "string",
|
|
253
|
+
"enum": [
|
|
254
|
+
"input",
|
|
255
|
+
"variable",
|
|
256
|
+
"secret",
|
|
257
|
+
"context"
|
|
258
|
+
]
|
|
259
|
+
},
|
|
214
260
|
"uniqueItems": true,
|
|
215
261
|
"description": "Subset of PromptVariable.source values the host supports. `secret` SHOULD only appear when `capabilities.secrets.supported` is also true."
|
|
216
262
|
},
|
|
@@ -222,21 +268,25 @@
|
|
|
222
268
|
},
|
|
223
269
|
"observability": {
|
|
224
270
|
"type": "string",
|
|
225
|
-
"enum": [
|
|
271
|
+
"enum": [
|
|
272
|
+
"off",
|
|
273
|
+
"hashed",
|
|
274
|
+
"full"
|
|
275
|
+
],
|
|
226
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`."
|
|
227
277
|
},
|
|
228
278
|
"packsSupported": {
|
|
229
279
|
"type": "boolean",
|
|
230
|
-
"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."
|
|
231
281
|
},
|
|
232
282
|
"mutableLibrary": {
|
|
233
283
|
"type": "boolean",
|
|
234
|
-
"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."
|
|
235
285
|
},
|
|
236
286
|
"library": {
|
|
237
287
|
"type": "object",
|
|
238
288
|
"additionalProperties": false,
|
|
239
|
-
"description": "RFC 0028
|
|
289
|
+
"description": "RFC 0028 \u00a7C. Per-library configuration knobs that influence how clients call the prompt surface.",
|
|
240
290
|
"properties": {
|
|
241
291
|
"id": {
|
|
242
292
|
"type": "string",
|
|
@@ -257,17 +307,25 @@
|
|
|
257
307
|
"defaults": {
|
|
258
308
|
"type": "object",
|
|
259
309
|
"additionalProperties": false,
|
|
260
|
-
"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.",
|
|
261
311
|
"properties": {
|
|
262
|
-
"system": {
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
"
|
|
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
|
+
}
|
|
266
324
|
}
|
|
267
325
|
},
|
|
268
326
|
"agentBindings": {
|
|
269
327
|
"type": "boolean",
|
|
270
|
-
"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."
|
|
271
329
|
}
|
|
272
330
|
},
|
|
273
331
|
"additionalProperties": false
|
|
@@ -280,9 +338,15 @@
|
|
|
280
338
|
"type": "object",
|
|
281
339
|
"description": "Optional v1 server identity (name + version + vendor).",
|
|
282
340
|
"properties": {
|
|
283
|
-
"name": {
|
|
284
|
-
|
|
285
|
-
|
|
341
|
+
"name": {
|
|
342
|
+
"type": "string"
|
|
343
|
+
},
|
|
344
|
+
"version": {
|
|
345
|
+
"type": "string"
|
|
346
|
+
},
|
|
347
|
+
"vendor": {
|
|
348
|
+
"type": "string"
|
|
349
|
+
}
|
|
286
350
|
},
|
|
287
351
|
"additionalProperties": false
|
|
288
352
|
},
|
|
@@ -298,17 +362,29 @@
|
|
|
298
362
|
},
|
|
299
363
|
"supportedTransports": {
|
|
300
364
|
"type": "array",
|
|
301
|
-
"items": {
|
|
365
|
+
"items": {
|
|
366
|
+
"type": "string",
|
|
367
|
+
"enum": [
|
|
368
|
+
"rest",
|
|
369
|
+
"mcp",
|
|
370
|
+
"a2a",
|
|
371
|
+
"grpc"
|
|
372
|
+
]
|
|
373
|
+
},
|
|
302
374
|
"description": "Optional v1 transport advertisement. REST is required whether or not this field is present."
|
|
303
375
|
},
|
|
304
376
|
"grpc": {
|
|
305
377
|
"type": "object",
|
|
306
|
-
"description": "RFC 0094
|
|
307
|
-
"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
|
+
],
|
|
308
384
|
"properties": {
|
|
309
385
|
"supported": {
|
|
310
386
|
"type": "boolean",
|
|
311
|
-
"description": "Toggle
|
|
387
|
+
"description": "Toggle \u2014 `true` when the gRPC surface is live."
|
|
312
388
|
},
|
|
313
389
|
"endpoint": {
|
|
314
390
|
"type": "string",
|
|
@@ -319,11 +395,15 @@
|
|
|
319
395
|
"service": {
|
|
320
396
|
"type": "string",
|
|
321
397
|
"const": "openwop.v1.Engine",
|
|
322
|
-
"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\"."
|
|
323
399
|
},
|
|
324
400
|
"tls": {
|
|
325
401
|
"type": "string",
|
|
326
|
-
"enum": [
|
|
402
|
+
"enum": [
|
|
403
|
+
"required",
|
|
404
|
+
"optional",
|
|
405
|
+
"disabled"
|
|
406
|
+
],
|
|
327
407
|
"description": "TLS posture. Production hosts MUST set `\"required\"`."
|
|
328
408
|
}
|
|
329
409
|
},
|
|
@@ -331,16 +411,18 @@
|
|
|
331
411
|
},
|
|
332
412
|
"configurable": {
|
|
333
413
|
"type": "object",
|
|
334
|
-
"description": "Optional v1 per-run overlay schema
|
|
414
|
+
"description": "Optional v1 per-run overlay schema \u2014 what `RunOptions.configurable` keys this server honors."
|
|
335
415
|
},
|
|
336
416
|
"nodePackRuntimes": {
|
|
337
417
|
"type": "object",
|
|
338
|
-
"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.",
|
|
339
419
|
"properties": {
|
|
340
420
|
"wasm": {
|
|
341
421
|
"type": "object",
|
|
342
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).",
|
|
343
|
-
"required": [
|
|
423
|
+
"required": [
|
|
424
|
+
"supported"
|
|
425
|
+
],
|
|
344
426
|
"properties": {
|
|
345
427
|
"supported": {
|
|
346
428
|
"type": "boolean",
|
|
@@ -354,13 +436,13 @@
|
|
|
354
436
|
},
|
|
355
437
|
"uniqueItems": true,
|
|
356
438
|
"minItems": 1,
|
|
357
|
-
"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."
|
|
358
440
|
},
|
|
359
441
|
"maxMemoryBytes": {
|
|
360
442
|
"type": "integer",
|
|
361
443
|
"minimum": 1048576,
|
|
362
444
|
"maximum": 8589934592,
|
|
363
|
-
"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\"`."
|
|
364
446
|
},
|
|
365
447
|
"loadedPacks": {
|
|
366
448
|
"type": "array",
|
|
@@ -369,7 +451,7 @@
|
|
|
369
451
|
"minLength": 1
|
|
370
452
|
},
|
|
371
453
|
"uniqueItems": true,
|
|
372
|
-
"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)."
|
|
373
455
|
}
|
|
374
456
|
},
|
|
375
457
|
"additionalProperties": true
|
|
@@ -378,7 +460,9 @@
|
|
|
378
460
|
"type": "object",
|
|
379
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`.",
|
|
380
462
|
"properties": {
|
|
381
|
-
"supported": {
|
|
463
|
+
"supported": {
|
|
464
|
+
"type": "boolean"
|
|
465
|
+
}
|
|
382
466
|
},
|
|
383
467
|
"additionalProperties": true
|
|
384
468
|
}
|
|
@@ -397,7 +481,11 @@
|
|
|
397
481
|
"type": "array",
|
|
398
482
|
"items": {
|
|
399
483
|
"type": "string",
|
|
400
|
-
"enum": [
|
|
484
|
+
"enum": [
|
|
485
|
+
"http/json",
|
|
486
|
+
"http/protobuf",
|
|
487
|
+
"grpc"
|
|
488
|
+
]
|
|
401
489
|
},
|
|
402
490
|
"uniqueItems": true,
|
|
403
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."
|
|
@@ -408,7 +496,7 @@
|
|
|
408
496
|
"testSeams": {
|
|
409
497
|
"type": "object",
|
|
410
498
|
"additionalProperties": false,
|
|
411
|
-
"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.",
|
|
412
500
|
"properties": {
|
|
413
501
|
"otelScrape": {
|
|
414
502
|
"type": "boolean",
|
|
@@ -430,7 +518,9 @@
|
|
|
430
518
|
"secrets": {
|
|
431
519
|
"type": "object",
|
|
432
520
|
"description": "Optional v1 secret/credential resolution advertisement. Clients gate BYOK flows on this. Hosts that don't store credentials return `supported: false`.",
|
|
433
|
-
"required": [
|
|
521
|
+
"required": [
|
|
522
|
+
"supported"
|
|
523
|
+
],
|
|
434
524
|
"properties": {
|
|
435
525
|
"supported": {
|
|
436
526
|
"type": "boolean",
|
|
@@ -440,14 +530,21 @@
|
|
|
440
530
|
"type": "array",
|
|
441
531
|
"items": {
|
|
442
532
|
"type": "string",
|
|
443
|
-
"enum": [
|
|
533
|
+
"enum": [
|
|
534
|
+
"tenant",
|
|
535
|
+
"user",
|
|
536
|
+
"run",
|
|
537
|
+
"workspace"
|
|
538
|
+
]
|
|
444
539
|
},
|
|
445
540
|
"uniqueItems": true,
|
|
446
|
-
"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."
|
|
447
542
|
},
|
|
448
543
|
"resolution": {
|
|
449
544
|
"type": "string",
|
|
450
|
-
"enum": [
|
|
545
|
+
"enum": [
|
|
546
|
+
"host-managed"
|
|
547
|
+
],
|
|
451
548
|
"description": "Resolution mode. v1.x supports only `host-managed` (clients reference stored secrets via opaque ids); reserved for future modes."
|
|
452
549
|
}
|
|
453
550
|
},
|
|
@@ -455,8 +552,10 @@
|
|
|
455
552
|
},
|
|
456
553
|
"connections": {
|
|
457
554
|
"type": "object",
|
|
458
|
-
"description": "RFC 0095 (`Draft`). Connection packs
|
|
459
|
-
"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
|
+
],
|
|
460
559
|
"properties": {
|
|
461
560
|
"supported": {
|
|
462
561
|
"type": "boolean",
|
|
@@ -464,7 +563,7 @@
|
|
|
464
563
|
},
|
|
465
564
|
"packsSupported": {
|
|
466
565
|
"type": "boolean",
|
|
467
|
-
"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."
|
|
468
567
|
}
|
|
469
568
|
},
|
|
470
569
|
"additionalProperties": false
|
|
@@ -472,8 +571,10 @@
|
|
|
472
571
|
"selfHostedRunner": {
|
|
473
572
|
"type": "object",
|
|
474
573
|
"additionalProperties": false,
|
|
475
|
-
"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
|
|
476
|
-
"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
|
+
],
|
|
477
578
|
"properties": {
|
|
478
579
|
"supported": {
|
|
479
580
|
"type": "boolean",
|
|
@@ -481,21 +582,29 @@
|
|
|
481
582
|
},
|
|
482
583
|
"dispatchKinds": {
|
|
483
584
|
"type": "array",
|
|
484
|
-
"items": {
|
|
585
|
+
"items": {
|
|
586
|
+
"type": "string",
|
|
587
|
+
"enum": [
|
|
588
|
+
"model",
|
|
589
|
+
"tool"
|
|
590
|
+
]
|
|
591
|
+
},
|
|
485
592
|
"uniqueItems": true,
|
|
486
|
-
"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."
|
|
487
594
|
}
|
|
488
595
|
}
|
|
489
596
|
},
|
|
490
597
|
"purposePropagation": {
|
|
491
598
|
"type": "object",
|
|
492
599
|
"additionalProperties": false,
|
|
493
|
-
"description": "RFC 0128 (`Active`). Purpose-propagation
|
|
494
|
-
"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
|
+
],
|
|
495
604
|
"properties": {
|
|
496
605
|
"supported": {
|
|
497
606
|
"type": "boolean",
|
|
498
|
-
"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)."
|
|
499
608
|
},
|
|
500
609
|
"propagatesOnward": {
|
|
501
610
|
"type": "boolean",
|
|
@@ -506,44 +615,63 @@
|
|
|
506
615
|
"dataResidency": {
|
|
507
616
|
"type": "object",
|
|
508
617
|
"additionalProperties": false,
|
|
509
|
-
"description": "RFC 0129 (`Active`). Data-residency
|
|
510
|
-
"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
|
+
],
|
|
511
623
|
"properties": {
|
|
512
624
|
"supported": {
|
|
513
625
|
"const": true,
|
|
514
|
-
"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."
|
|
515
627
|
},
|
|
516
628
|
"regions": {
|
|
517
629
|
"type": "array",
|
|
518
|
-
"items": {
|
|
630
|
+
"items": {
|
|
631
|
+
"type": "string",
|
|
632
|
+
"minLength": 1
|
|
633
|
+
},
|
|
519
634
|
"uniqueItems": true,
|
|
520
|
-
"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`."
|
|
521
636
|
}
|
|
522
637
|
}
|
|
523
638
|
},
|
|
524
639
|
"anonymousActor": {
|
|
525
640
|
"type": "object",
|
|
526
641
|
"additionalProperties": false,
|
|
527
|
-
"description": "RFC 0132 (`Active`). Anonymous-actor authorization for public agent surfaces
|
|
528
|
-
"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
|
+
],
|
|
529
647
|
"properties": {
|
|
530
648
|
"supported": {
|
|
531
649
|
"const": true,
|
|
532
|
-
"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`)."
|
|
533
651
|
},
|
|
534
652
|
"tiers": {
|
|
535
653
|
"type": "array",
|
|
536
654
|
"minItems": 1,
|
|
537
655
|
"uniqueItems": true,
|
|
538
|
-
"items": {
|
|
539
|
-
|
|
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."
|
|
540
663
|
},
|
|
541
664
|
"writeEgressControls": {
|
|
542
665
|
"type": "array",
|
|
543
666
|
"minItems": 1,
|
|
544
667
|
"uniqueItems": true,
|
|
545
|
-
"items": {
|
|
546
|
-
|
|
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."
|
|
547
675
|
},
|
|
548
676
|
"failClosed": {
|
|
549
677
|
"const": true,
|
|
@@ -552,20 +680,40 @@
|
|
|
552
680
|
},
|
|
553
681
|
"allOf": [
|
|
554
682
|
{
|
|
555
|
-
"$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).",
|
|
556
684
|
"if": {
|
|
557
|
-
"properties": {
|
|
558
|
-
|
|
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
|
+
]
|
|
559
700
|
},
|
|
560
|
-
"
|
|
561
|
-
|
|
701
|
+
"else": {
|
|
702
|
+
"not": {
|
|
703
|
+
"required": [
|
|
704
|
+
"writeEgressControls"
|
|
705
|
+
]
|
|
706
|
+
}
|
|
707
|
+
}
|
|
562
708
|
}
|
|
563
709
|
]
|
|
564
710
|
},
|
|
565
711
|
"credentials": {
|
|
566
712
|
"type": "object",
|
|
567
|
-
"description": "RFC 0046 (`Draft`). Portable credential resolution + lifecycle contract
|
|
568
|
-
"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
|
+
],
|
|
569
717
|
"properties": {
|
|
570
718
|
"supported": {
|
|
571
719
|
"type": "boolean",
|
|
@@ -573,7 +721,14 @@
|
|
|
573
721
|
},
|
|
574
722
|
"scopes": {
|
|
575
723
|
"type": "array",
|
|
576
|
-
"items": {
|
|
724
|
+
"items": {
|
|
725
|
+
"type": "string",
|
|
726
|
+
"enum": [
|
|
727
|
+
"user",
|
|
728
|
+
"workspace",
|
|
729
|
+
"tenant"
|
|
730
|
+
]
|
|
731
|
+
},
|
|
577
732
|
"uniqueItems": true,
|
|
578
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."
|
|
579
734
|
},
|
|
@@ -583,7 +738,10 @@
|
|
|
583
738
|
},
|
|
584
739
|
"rotation": {
|
|
585
740
|
"type": "string",
|
|
586
|
-
"enum": [
|
|
741
|
+
"enum": [
|
|
742
|
+
"none",
|
|
743
|
+
"two-key-overlap"
|
|
744
|
+
],
|
|
587
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."
|
|
588
746
|
},
|
|
589
747
|
"sharing": {
|
|
@@ -595,8 +753,10 @@
|
|
|
595
753
|
},
|
|
596
754
|
"feedback": {
|
|
597
755
|
"type": "object",
|
|
598
|
-
"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
|
|
599
|
-
"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
|
+
],
|
|
600
760
|
"properties": {
|
|
601
761
|
"supported": {
|
|
602
762
|
"type": "boolean",
|
|
@@ -604,13 +764,28 @@
|
|
|
604
764
|
},
|
|
605
765
|
"targets": {
|
|
606
766
|
"type": "array",
|
|
607
|
-
"items": {
|
|
767
|
+
"items": {
|
|
768
|
+
"type": "string",
|
|
769
|
+
"enum": [
|
|
770
|
+
"run",
|
|
771
|
+
"event",
|
|
772
|
+
"node"
|
|
773
|
+
]
|
|
774
|
+
},
|
|
608
775
|
"uniqueItems": true,
|
|
609
776
|
"description": "Which annotation-target granularities the host accepts. Absent = `run` only."
|
|
610
777
|
},
|
|
611
778
|
"signals": {
|
|
612
779
|
"type": "array",
|
|
613
|
-
"items": {
|
|
780
|
+
"items": {
|
|
781
|
+
"type": "string",
|
|
782
|
+
"enum": [
|
|
783
|
+
"rating",
|
|
784
|
+
"correction",
|
|
785
|
+
"label",
|
|
786
|
+
"flag"
|
|
787
|
+
]
|
|
788
|
+
},
|
|
614
789
|
"uniqueItems": true,
|
|
615
790
|
"description": "Which signal kinds the host accepts. Absent = all four."
|
|
616
791
|
}
|
|
@@ -619,7 +794,7 @@
|
|
|
619
794
|
},
|
|
620
795
|
"replay": {
|
|
621
796
|
"type": "object",
|
|
622
|
-
"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.",
|
|
623
798
|
"properties": {
|
|
624
799
|
"supported": {
|
|
625
800
|
"type": "boolean",
|
|
@@ -627,7 +802,13 @@
|
|
|
627
802
|
},
|
|
628
803
|
"modes": {
|
|
629
804
|
"type": "array",
|
|
630
|
-
"items": {
|
|
805
|
+
"items": {
|
|
806
|
+
"type": "string",
|
|
807
|
+
"enum": [
|
|
808
|
+
"replay",
|
|
809
|
+
"branch"
|
|
810
|
+
]
|
|
811
|
+
},
|
|
631
812
|
"uniqueItems": true,
|
|
632
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."
|
|
633
814
|
},
|
|
@@ -641,28 +822,43 @@
|
|
|
641
822
|
"windowSeconds": {
|
|
642
823
|
"type": "integer",
|
|
643
824
|
"minimum": 0,
|
|
644
|
-
"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."
|
|
645
826
|
}
|
|
646
827
|
},
|
|
647
828
|
"description": "OPTIONAL retention metadata."
|
|
648
829
|
},
|
|
649
830
|
"sideEffectSuppression": {
|
|
650
831
|
"type": "string",
|
|
651
|
-
"enum": [
|
|
832
|
+
"enum": [
|
|
833
|
+
"recorded-outcome",
|
|
834
|
+
"none"
|
|
835
|
+
],
|
|
652
836
|
"default": "none",
|
|
653
|
-
"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."
|
|
654
838
|
}
|
|
655
839
|
}
|
|
656
840
|
},
|
|
657
841
|
"oauth": {
|
|
658
842
|
"type": "object",
|
|
659
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).",
|
|
660
|
-
"required": [
|
|
844
|
+
"required": [
|
|
845
|
+
"supported"
|
|
846
|
+
],
|
|
661
847
|
"properties": {
|
|
662
|
-
"supported": {
|
|
848
|
+
"supported": {
|
|
849
|
+
"type": "boolean",
|
|
850
|
+
"description": "Host implements the host.oauth third-party token acquisition + refresh contract."
|
|
851
|
+
},
|
|
663
852
|
"grants": {
|
|
664
853
|
"type": "array",
|
|
665
|
-
"items": {
|
|
854
|
+
"items": {
|
|
855
|
+
"type": "string",
|
|
856
|
+
"enum": [
|
|
857
|
+
"authorization_code",
|
|
858
|
+
"client_credentials",
|
|
859
|
+
"refresh_token"
|
|
860
|
+
]
|
|
861
|
+
},
|
|
666
862
|
"uniqueItems": true,
|
|
667
863
|
"description": "OAuth 2.0 grant types the host performs on a node's behalf."
|
|
668
864
|
},
|
|
@@ -671,12 +867,32 @@
|
|
|
671
867
|
"description": "Provider catalog the host can acquire tokens for. A connector node's `auth.provider` MUST match an `id` here.",
|
|
672
868
|
"items": {
|
|
673
869
|
"type": "object",
|
|
674
|
-
"required": [
|
|
870
|
+
"required": [
|
|
871
|
+
"id"
|
|
872
|
+
],
|
|
675
873
|
"properties": {
|
|
676
|
-
"id": {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
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
|
+
}
|
|
680
896
|
},
|
|
681
897
|
"additionalProperties": false
|
|
682
898
|
}
|
|
@@ -687,19 +903,40 @@
|
|
|
687
903
|
"authorization": {
|
|
688
904
|
"type": "object",
|
|
689
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`).",
|
|
690
|
-
"required": [
|
|
906
|
+
"required": [
|
|
907
|
+
"supported"
|
|
908
|
+
],
|
|
691
909
|
"properties": {
|
|
692
|
-
"supported": {
|
|
693
|
-
|
|
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
|
+
},
|
|
694
918
|
"roles": {
|
|
695
919
|
"type": "array",
|
|
696
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.",
|
|
697
921
|
"items": {
|
|
698
922
|
"type": "object",
|
|
699
|
-
"required": [
|
|
923
|
+
"required": [
|
|
924
|
+
"role",
|
|
925
|
+
"scopes"
|
|
926
|
+
],
|
|
700
927
|
"properties": {
|
|
701
|
-
"role": {
|
|
702
|
-
|
|
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
|
+
}
|
|
703
940
|
},
|
|
704
941
|
"additionalProperties": false
|
|
705
942
|
}
|
|
@@ -709,14 +946,19 @@
|
|
|
709
946
|
},
|
|
710
947
|
"runtimeCapabilities": {
|
|
711
948
|
"type": "array",
|
|
712
|
-
"items": {
|
|
949
|
+
"items": {
|
|
950
|
+
"type": "string",
|
|
951
|
+
"minLength": 1
|
|
952
|
+
},
|
|
713
953
|
"uniqueItems": true,
|
|
714
|
-
"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\"."
|
|
715
955
|
},
|
|
716
956
|
"multiPartyConversation": {
|
|
717
957
|
"type": "object",
|
|
718
|
-
"description": "RFC 0101
|
|
719
|
-
"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
|
+
],
|
|
720
962
|
"additionalProperties": false,
|
|
721
963
|
"properties": {
|
|
722
964
|
"supported": {
|
|
@@ -726,14 +968,16 @@
|
|
|
726
968
|
"maxParticipants": {
|
|
727
969
|
"type": "integer",
|
|
728
970
|
"minimum": 2,
|
|
729
|
-
"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."
|
|
730
972
|
}
|
|
731
973
|
}
|
|
732
974
|
},
|
|
733
975
|
"conversationTurnModelProvenance": {
|
|
734
976
|
"type": "object",
|
|
735
|
-
"description": "RFC 0109
|
|
736
|
-
"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
|
+
],
|
|
737
981
|
"additionalProperties": false,
|
|
738
982
|
"properties": {
|
|
739
983
|
"supported": {
|
|
@@ -744,8 +988,10 @@
|
|
|
744
988
|
},
|
|
745
989
|
"channelPresence": {
|
|
746
990
|
"type": "object",
|
|
747
|
-
"description": "RFC 0110
|
|
748
|
-
"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
|
+
],
|
|
749
995
|
"additionalProperties": false,
|
|
750
996
|
"properties": {
|
|
751
997
|
"supported": {
|
|
@@ -756,78 +1002,111 @@
|
|
|
756
1002
|
},
|
|
757
1003
|
"multiAgent": {
|
|
758
1004
|
"type": "object",
|
|
759
|
-
"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.",
|
|
760
1006
|
"additionalProperties": false,
|
|
761
1007
|
"properties": {
|
|
762
1008
|
"executionModel": {
|
|
763
1009
|
"type": "object",
|
|
764
1010
|
"additionalProperties": false,
|
|
765
|
-
"required": [
|
|
1011
|
+
"required": [
|
|
1012
|
+
"supported",
|
|
1013
|
+
"version"
|
|
1014
|
+
],
|
|
766
1015
|
"if": {
|
|
767
|
-
"properties": {
|
|
768
|
-
|
|
1016
|
+
"properties": {
|
|
1017
|
+
"tier": {
|
|
1018
|
+
"const": "experimental"
|
|
1019
|
+
}
|
|
1020
|
+
},
|
|
1021
|
+
"required": [
|
|
1022
|
+
"tier"
|
|
1023
|
+
]
|
|
769
1024
|
},
|
|
770
1025
|
"then": {
|
|
771
|
-
"required": [
|
|
1026
|
+
"required": [
|
|
1027
|
+
"experimentalUntil"
|
|
1028
|
+
]
|
|
772
1029
|
},
|
|
773
1030
|
"properties": {
|
|
774
1031
|
"supported": {
|
|
775
1032
|
"type": "boolean",
|
|
776
|
-
"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."
|
|
777
1034
|
},
|
|
778
1035
|
"tier": {
|
|
779
1036
|
"type": "string",
|
|
780
|
-
"enum": [
|
|
1037
|
+
"enum": [
|
|
1038
|
+
"stable",
|
|
1039
|
+
"experimental"
|
|
1040
|
+
],
|
|
781
1041
|
"default": "stable",
|
|
782
|
-
"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`."
|
|
783
1043
|
},
|
|
784
1044
|
"experimentalUntil": {
|
|
785
1045
|
"type": "string",
|
|
786
1046
|
"format": "date",
|
|
787
1047
|
"pattern": "^\\d{4}-\\d{2}-\\d{2}$",
|
|
788
|
-
"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)."
|
|
789
1049
|
},
|
|
790
1050
|
"version": {
|
|
791
1051
|
"type": "integer",
|
|
792
1052
|
"minimum": 1,
|
|
793
1053
|
"maximum": 6,
|
|
794
|
-
"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."
|
|
795
1055
|
},
|
|
796
1056
|
"verifier": {
|
|
797
1057
|
"type": "object",
|
|
798
1058
|
"additionalProperties": false,
|
|
799
|
-
"required": [
|
|
800
|
-
|
|
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.",
|
|
801
1063
|
"properties": {
|
|
802
|
-
"supported": {
|
|
803
|
-
|
|
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
|
+
}
|
|
804
1072
|
}
|
|
805
1073
|
},
|
|
806
1074
|
"confidenceEscalationFloor": {
|
|
807
1075
|
"type": "number",
|
|
808
1076
|
"minimum": 0.5,
|
|
809
1077
|
"maximum": 1.0,
|
|
810
|
-
"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`."
|
|
811
1079
|
},
|
|
812
1080
|
"confidenceEscalationInterruptKind": {
|
|
813
1081
|
"type": "string",
|
|
814
1082
|
"anyOf": [
|
|
815
|
-
{
|
|
816
|
-
|
|
817
|
-
|
|
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
|
+
}
|
|
818
1092
|
],
|
|
819
|
-
"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."
|
|
820
1094
|
},
|
|
821
1095
|
"crossChildMemoryConcurrency": {
|
|
822
1096
|
"type": "string",
|
|
823
|
-
"enum": [
|
|
824
|
-
|
|
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)."
|
|
825
1102
|
},
|
|
826
1103
|
"crossHostCausation": {
|
|
827
1104
|
"type": "object",
|
|
828
|
-
"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`.",
|
|
829
1106
|
"additionalProperties": false,
|
|
830
|
-
"required": [
|
|
1107
|
+
"required": [
|
|
1108
|
+
"supported"
|
|
1109
|
+
],
|
|
831
1110
|
"properties": {
|
|
832
1111
|
"supported": {
|
|
833
1112
|
"type": "boolean",
|
|
@@ -840,15 +1119,17 @@
|
|
|
840
1119
|
},
|
|
841
1120
|
"ancestryEndpointSupported": {
|
|
842
1121
|
"type": "boolean",
|
|
843
|
-
"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."
|
|
844
1123
|
}
|
|
845
1124
|
}
|
|
846
1125
|
},
|
|
847
1126
|
"replayDeterminism": {
|
|
848
1127
|
"type": "object",
|
|
849
|
-
"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`.",
|
|
850
1129
|
"additionalProperties": false,
|
|
851
|
-
"required": [
|
|
1130
|
+
"required": [
|
|
1131
|
+
"supported"
|
|
1132
|
+
],
|
|
852
1133
|
"properties": {
|
|
853
1134
|
"supported": {
|
|
854
1135
|
"type": "boolean",
|
|
@@ -857,45 +1138,56 @@
|
|
|
857
1138
|
"llmCacheKeyRecipe": {
|
|
858
1139
|
"type": "string",
|
|
859
1140
|
"anyOf": [
|
|
860
|
-
{
|
|
861
|
-
|
|
1141
|
+
{
|
|
1142
|
+
"const": "spec-rfc-0041"
|
|
1143
|
+
},
|
|
1144
|
+
{
|
|
1145
|
+
"pattern": "^x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*$"
|
|
1146
|
+
}
|
|
862
1147
|
],
|
|
863
|
-
"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."
|
|
864
1149
|
},
|
|
865
1150
|
"refusalDivergenceEmission": {
|
|
866
1151
|
"type": "boolean",
|
|
867
|
-
"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`."
|
|
868
1153
|
}
|
|
869
1154
|
}
|
|
870
1155
|
},
|
|
871
1156
|
"statefulResume": {
|
|
872
1157
|
"type": "boolean",
|
|
873
|
-
"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`."
|
|
874
1159
|
},
|
|
875
1160
|
"transcriptWindow": {
|
|
876
1161
|
"type": "integer",
|
|
877
1162
|
"minimum": 1,
|
|
878
|
-
"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."
|
|
879
1164
|
},
|
|
880
1165
|
"contextBudget": {
|
|
881
1166
|
"type": "object",
|
|
882
|
-
"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)\".",
|
|
883
1168
|
"additionalProperties": false,
|
|
884
1169
|
"properties": {
|
|
885
1170
|
"transcriptTokenBudget": {
|
|
886
1171
|
"type": "integer",
|
|
887
1172
|
"minimum": 1,
|
|
888
|
-
"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)."
|
|
889
1174
|
},
|
|
890
1175
|
"tokenCounter": {
|
|
891
1176
|
"type": "string",
|
|
892
|
-
"enum": [
|
|
893
|
-
|
|
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)."
|
|
894
1184
|
},
|
|
895
1185
|
"summarization": {
|
|
896
1186
|
"type": "object",
|
|
897
1187
|
"additionalProperties": false,
|
|
898
|
-
"required": [
|
|
1188
|
+
"required": [
|
|
1189
|
+
"supported"
|
|
1190
|
+
],
|
|
899
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).",
|
|
900
1192
|
"properties": {
|
|
901
1193
|
"supported": {
|
|
@@ -904,19 +1196,32 @@
|
|
|
904
1196
|
},
|
|
905
1197
|
"strategy": {
|
|
906
1198
|
"type": "string",
|
|
907
|
-
"enum": [
|
|
908
|
-
|
|
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."
|
|
909
1205
|
},
|
|
910
1206
|
"keepLastTurns": {
|
|
911
1207
|
"type": "integer",
|
|
912
1208
|
"minimum": 0,
|
|
913
|
-
"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."
|
|
914
1210
|
}
|
|
915
1211
|
}
|
|
916
1212
|
}
|
|
917
1213
|
},
|
|
918
|
-
"if": {
|
|
919
|
-
|
|
1214
|
+
"if": {
|
|
1215
|
+
"required": [
|
|
1216
|
+
"transcriptTokenBudget"
|
|
1217
|
+
]
|
|
1218
|
+
},
|
|
1219
|
+
"then": {
|
|
1220
|
+
"required": [
|
|
1221
|
+
"transcriptTokenBudget",
|
|
1222
|
+
"tokenCounter"
|
|
1223
|
+
]
|
|
1224
|
+
}
|
|
920
1225
|
}
|
|
921
1226
|
}
|
|
922
1227
|
}
|
|
@@ -924,13 +1229,15 @@
|
|
|
924
1229
|
},
|
|
925
1230
|
"modelCapabilities": {
|
|
926
1231
|
"type": "object",
|
|
927
|
-
"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.",
|
|
928
1233
|
"additionalProperties": false,
|
|
929
|
-
"required": [
|
|
1234
|
+
"required": [
|
|
1235
|
+
"supported"
|
|
1236
|
+
],
|
|
930
1237
|
"properties": {
|
|
931
1238
|
"supported": {
|
|
932
1239
|
"type": "boolean",
|
|
933
|
-
"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."
|
|
934
1241
|
},
|
|
935
1242
|
"advertised": {
|
|
936
1243
|
"type": "array",
|
|
@@ -939,23 +1246,35 @@
|
|
|
939
1246
|
"pattern": "^([a-z][a-z0-9-]*|x-host-[a-z][a-z0-9-]*-[a-z][a-z0-9-]*)$"
|
|
940
1247
|
},
|
|
941
1248
|
"uniqueItems": true,
|
|
942
|
-
"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>-`."
|
|
943
1250
|
},
|
|
944
1251
|
"substitutionSupported": {
|
|
945
1252
|
"type": "boolean",
|
|
946
|
-
"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)."
|
|
947
1254
|
}
|
|
948
1255
|
}
|
|
949
1256
|
},
|
|
950
1257
|
"providerUsage": {
|
|
951
1258
|
"type": "object",
|
|
952
|
-
"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.",
|
|
953
1260
|
"properties": {
|
|
954
|
-
"supported": {
|
|
955
|
-
|
|
956
|
-
|
|
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
|
+
}
|
|
957
1274
|
},
|
|
958
|
-
"required": [
|
|
1275
|
+
"required": [
|
|
1276
|
+
"supported"
|
|
1277
|
+
],
|
|
959
1278
|
"additionalProperties": false
|
|
960
1279
|
},
|
|
961
1280
|
"aiProviders": {
|
|
@@ -964,67 +1283,107 @@
|
|
|
964
1283
|
"properties": {
|
|
965
1284
|
"supported": {
|
|
966
1285
|
"type": "array",
|
|
967
|
-
"items": {
|
|
1286
|
+
"items": {
|
|
1287
|
+
"type": "string",
|
|
1288
|
+
"minLength": 1
|
|
1289
|
+
},
|
|
968
1290
|
"uniqueItems": true,
|
|
969
|
-
"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."
|
|
970
1292
|
},
|
|
971
1293
|
"byok": {
|
|
972
1294
|
"type": "array",
|
|
973
|
-
"items": {
|
|
1295
|
+
"items": {
|
|
1296
|
+
"type": "string",
|
|
1297
|
+
"minLength": 1
|
|
1298
|
+
},
|
|
974
1299
|
"uniqueItems": true,
|
|
975
|
-
"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."
|
|
976
1301
|
},
|
|
977
1302
|
"selfHosted": {
|
|
978
1303
|
"type": "array",
|
|
979
|
-
"items": {
|
|
1304
|
+
"items": {
|
|
1305
|
+
"type": "string",
|
|
1306
|
+
"minLength": 1
|
|
1307
|
+
},
|
|
980
1308
|
"uniqueItems": true,
|
|
981
|
-
"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)."
|
|
982
1310
|
},
|
|
983
1311
|
"speechSynthesis": {
|
|
984
1312
|
"const": "supported",
|
|
985
|
-
"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."
|
|
986
1314
|
},
|
|
987
1315
|
"input": {
|
|
988
1316
|
"type": "object",
|
|
989
1317
|
"additionalProperties": false,
|
|
990
|
-
"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).",
|
|
991
1319
|
"properties": {
|
|
992
1320
|
"modalities": {
|
|
993
1321
|
"type": "array",
|
|
994
1322
|
"uniqueItems": true,
|
|
995
|
-
"items": {
|
|
1323
|
+
"items": {
|
|
1324
|
+
"type": "string",
|
|
1325
|
+
"enum": [
|
|
1326
|
+
"text",
|
|
1327
|
+
"image",
|
|
1328
|
+
"audio",
|
|
1329
|
+
"document"
|
|
1330
|
+
]
|
|
1331
|
+
},
|
|
996
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)."
|
|
997
1333
|
},
|
|
998
|
-
"maxBytesPerPart": {
|
|
1334
|
+
"maxBytesPerPart": {
|
|
1335
|
+
"type": "integer",
|
|
1336
|
+
"minimum": 1,
|
|
1337
|
+
"description": "Optional host cap on a single inline (`data`) or `mediaRef` part."
|
|
1338
|
+
}
|
|
999
1339
|
}
|
|
1000
1340
|
},
|
|
1001
1341
|
"authModes": {
|
|
1002
1342
|
"type": "object",
|
|
1003
|
-
"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.",
|
|
1004
1344
|
"additionalProperties": {
|
|
1005
1345
|
"type": "array",
|
|
1006
1346
|
"minItems": 1,
|
|
1007
1347
|
"uniqueItems": true,
|
|
1008
1348
|
"items": {
|
|
1009
1349
|
"type": "string",
|
|
1010
|
-
"enum": [
|
|
1350
|
+
"enum": [
|
|
1351
|
+
"apiKey",
|
|
1352
|
+
"oauth-pkce",
|
|
1353
|
+
"oauth-device",
|
|
1354
|
+
"none",
|
|
1355
|
+
"subscription"
|
|
1356
|
+
]
|
|
1011
1357
|
}
|
|
1012
1358
|
}
|
|
1013
1359
|
},
|
|
1014
1360
|
"policies": {
|
|
1015
1361
|
"type": "object",
|
|
1016
|
-
"description": "Optional v1 host-side policy enforcement modes for per-provider gating. Omitted
|
|
1017
|
-
"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
|
+
],
|
|
1018
1366
|
"properties": {
|
|
1019
1367
|
"modes": {
|
|
1020
1368
|
"type": "array",
|
|
1021
|
-
"items": {
|
|
1369
|
+
"items": {
|
|
1370
|
+
"type": "string",
|
|
1371
|
+
"enum": [
|
|
1372
|
+
"disabled",
|
|
1373
|
+
"optional",
|
|
1374
|
+
"required",
|
|
1375
|
+
"restricted"
|
|
1376
|
+
]
|
|
1377
|
+
},
|
|
1022
1378
|
"uniqueItems": true,
|
|
1023
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."
|
|
1024
1380
|
},
|
|
1025
1381
|
"scopes": {
|
|
1026
1382
|
"type": "array",
|
|
1027
|
-
"items": {
|
|
1383
|
+
"items": {
|
|
1384
|
+
"type": "string",
|
|
1385
|
+
"minLength": 1
|
|
1386
|
+
},
|
|
1028
1387
|
"uniqueItems": true,
|
|
1029
1388
|
"description": "Resolution layers the host evaluates. Conventional ids: `workspace`, `project`, `canvas-type`. Precedence is host-defined and SHOULD be documented per-deployment."
|
|
1030
1389
|
},
|
|
@@ -1040,12 +1399,12 @@
|
|
|
1040
1399
|
"type": "integer",
|
|
1041
1400
|
"minimum": 0,
|
|
1042
1401
|
"default": 262144,
|
|
1043
|
-
"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."
|
|
1044
1403
|
},
|
|
1045
1404
|
"realtimeVoice": {
|
|
1046
1405
|
"type": "object",
|
|
1047
1406
|
"additionalProperties": false,
|
|
1048
|
-
"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).",
|
|
1049
1408
|
"properties": {
|
|
1050
1409
|
"transcription": {
|
|
1051
1410
|
"const": "streaming",
|
|
@@ -1056,7 +1415,10 @@
|
|
|
1056
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`)."
|
|
1057
1416
|
},
|
|
1058
1417
|
"turnDetection": {
|
|
1059
|
-
"enum": [
|
|
1418
|
+
"enum": [
|
|
1419
|
+
"vad",
|
|
1420
|
+
"semantic"
|
|
1421
|
+
],
|
|
1060
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`."
|
|
1061
1423
|
},
|
|
1062
1424
|
"bargeIn": {
|
|
@@ -1065,14 +1427,18 @@
|
|
|
1065
1427
|
}
|
|
1066
1428
|
},
|
|
1067
1429
|
"dependentRequired": {
|
|
1068
|
-
"turnDetection": [
|
|
1069
|
-
|
|
1430
|
+
"turnDetection": [
|
|
1431
|
+
"transcription"
|
|
1432
|
+
],
|
|
1433
|
+
"bargeIn": [
|
|
1434
|
+
"transcription"
|
|
1435
|
+
]
|
|
1070
1436
|
}
|
|
1071
1437
|
},
|
|
1072
1438
|
"promptPrefixCache": {
|
|
1073
1439
|
"type": "object",
|
|
1074
1440
|
"additionalProperties": false,
|
|
1075
|
-
"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`.",
|
|
1076
1442
|
"properties": {
|
|
1077
1443
|
"supported": {
|
|
1078
1444
|
"type": "boolean",
|
|
@@ -1080,26 +1446,42 @@
|
|
|
1080
1446
|
},
|
|
1081
1447
|
"providers": {
|
|
1082
1448
|
"type": "array",
|
|
1083
|
-
"items": {
|
|
1449
|
+
"items": {
|
|
1450
|
+
"type": "string",
|
|
1451
|
+
"minLength": 1
|
|
1452
|
+
},
|
|
1084
1453
|
"uniqueItems": true,
|
|
1085
|
-
"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."
|
|
1086
1455
|
}
|
|
1087
1456
|
},
|
|
1088
|
-
"required": [
|
|
1457
|
+
"required": [
|
|
1458
|
+
"supported"
|
|
1459
|
+
]
|
|
1089
1460
|
}
|
|
1090
1461
|
},
|
|
1091
1462
|
"additionalProperties": false,
|
|
1092
1463
|
"allOf": [
|
|
1093
1464
|
{
|
|
1094
|
-
"$comment": "RFC 0106
|
|
1465
|
+
"$comment": "RFC 0106 \u00a7A closure: realtimeVoice.synthesis (streaming TTS) requires the whole-file TTS surface aiProviders.speechSynthesis to be advertised.",
|
|
1095
1466
|
"if": {
|
|
1096
1467
|
"type": "object",
|
|
1097
|
-
"required": [
|
|
1468
|
+
"required": [
|
|
1469
|
+
"realtimeVoice"
|
|
1470
|
+
],
|
|
1098
1471
|
"properties": {
|
|
1099
|
-
"realtimeVoice": {
|
|
1472
|
+
"realtimeVoice": {
|
|
1473
|
+
"type": "object",
|
|
1474
|
+
"required": [
|
|
1475
|
+
"synthesis"
|
|
1476
|
+
]
|
|
1477
|
+
}
|
|
1100
1478
|
}
|
|
1101
1479
|
},
|
|
1102
|
-
"then": {
|
|
1480
|
+
"then": {
|
|
1481
|
+
"required": [
|
|
1482
|
+
"speechSynthesis"
|
|
1483
|
+
]
|
|
1484
|
+
}
|
|
1103
1485
|
}
|
|
1104
1486
|
]
|
|
1105
1487
|
},
|
|
@@ -1109,7 +1491,10 @@
|
|
|
1109
1491
|
"properties": {
|
|
1110
1492
|
"mockProviders": {
|
|
1111
1493
|
"type": "array",
|
|
1112
|
-
"items": {
|
|
1494
|
+
"items": {
|
|
1495
|
+
"type": "string",
|
|
1496
|
+
"minLength": 1
|
|
1497
|
+
},
|
|
1113
1498
|
"uniqueItems": true,
|
|
1114
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)."
|
|
1115
1500
|
},
|
|
@@ -1122,10 +1507,21 @@
|
|
|
1122
1507
|
"forceEngineVersionRange": {
|
|
1123
1508
|
"type": "object",
|
|
1124
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.",
|
|
1125
|
-
"required": [
|
|
1510
|
+
"required": [
|
|
1511
|
+
"min",
|
|
1512
|
+
"max"
|
|
1513
|
+
],
|
|
1126
1514
|
"properties": {
|
|
1127
|
-
"min": {
|
|
1128
|
-
|
|
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
|
+
}
|
|
1129
1525
|
},
|
|
1130
1526
|
"additionalProperties": false
|
|
1131
1527
|
}
|
|
@@ -1138,19 +1534,22 @@
|
|
|
1138
1534
|
"properties": {
|
|
1139
1535
|
"mockAgent": {
|
|
1140
1536
|
"type": "boolean",
|
|
1141
|
-
"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."
|
|
1142
1538
|
},
|
|
1143
1539
|
"certificationBundleUrl": {
|
|
1144
1540
|
"type": "string",
|
|
1145
1541
|
"format": "uri",
|
|
1146
|
-
"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."
|
|
1147
1543
|
}
|
|
1148
1544
|
},
|
|
1149
1545
|
"additionalProperties": false
|
|
1150
1546
|
},
|
|
1151
1547
|
"fixtures": {
|
|
1152
1548
|
"type": "array",
|
|
1153
|
-
"items": {
|
|
1549
|
+
"items": {
|
|
1550
|
+
"type": "string",
|
|
1551
|
+
"minLength": 1
|
|
1552
|
+
},
|
|
1154
1553
|
"uniqueItems": true,
|
|
1155
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."
|
|
1156
1555
|
},
|
|
@@ -1170,7 +1569,17 @@
|
|
|
1170
1569
|
"type": "array",
|
|
1171
1570
|
"items": {
|
|
1172
1571
|
"type": "string",
|
|
1173
|
-
"enum": [
|
|
1572
|
+
"enum": [
|
|
1573
|
+
"reasoning",
|
|
1574
|
+
"tool-using",
|
|
1575
|
+
"chat",
|
|
1576
|
+
"code",
|
|
1577
|
+
"vision",
|
|
1578
|
+
"multimodal",
|
|
1579
|
+
"embedding",
|
|
1580
|
+
"classification",
|
|
1581
|
+
"retrieval"
|
|
1582
|
+
]
|
|
1174
1583
|
},
|
|
1175
1584
|
"uniqueItems": true,
|
|
1176
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`."
|
|
@@ -1181,15 +1590,22 @@
|
|
|
1181
1590
|
},
|
|
1182
1591
|
"memoryBackends": {
|
|
1183
1592
|
"type": "array",
|
|
1184
|
-
"items": {
|
|
1593
|
+
"items": {
|
|
1594
|
+
"type": "string",
|
|
1595
|
+
"enum": [
|
|
1596
|
+
"long-term"
|
|
1597
|
+
]
|
|
1598
|
+
},
|
|
1185
1599
|
"uniqueItems": true,
|
|
1186
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."
|
|
1187
1601
|
},
|
|
1188
1602
|
"memoryConsolidation": {
|
|
1189
1603
|
"type": "object",
|
|
1190
|
-
"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.",
|
|
1191
1605
|
"additionalProperties": false,
|
|
1192
|
-
"required": [
|
|
1606
|
+
"required": [
|
|
1607
|
+
"supported"
|
|
1608
|
+
],
|
|
1193
1609
|
"properties": {
|
|
1194
1610
|
"supported": {
|
|
1195
1611
|
"type": "boolean",
|
|
@@ -1197,16 +1613,22 @@
|
|
|
1197
1613
|
},
|
|
1198
1614
|
"schedule": {
|
|
1199
1615
|
"type": "string",
|
|
1200
|
-
"enum": [
|
|
1616
|
+
"enum": [
|
|
1617
|
+
"host-managed",
|
|
1618
|
+
"scheduled",
|
|
1619
|
+
"on-demand"
|
|
1620
|
+
],
|
|
1201
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."
|
|
1202
1622
|
}
|
|
1203
1623
|
}
|
|
1204
1624
|
},
|
|
1205
1625
|
"commitments": {
|
|
1206
1626
|
"type": "object",
|
|
1207
|
-
"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.",
|
|
1208
1628
|
"additionalProperties": false,
|
|
1209
|
-
"required": [
|
|
1629
|
+
"required": [
|
|
1630
|
+
"supported"
|
|
1631
|
+
],
|
|
1210
1632
|
"properties": {
|
|
1211
1633
|
"supported": {
|
|
1212
1634
|
"type": "boolean",
|
|
@@ -1214,9 +1636,15 @@
|
|
|
1214
1636
|
},
|
|
1215
1637
|
"fireConditions": {
|
|
1216
1638
|
"type": "array",
|
|
1217
|
-
"items": {
|
|
1639
|
+
"items": {
|
|
1640
|
+
"type": "string",
|
|
1641
|
+
"enum": [
|
|
1642
|
+
"time",
|
|
1643
|
+
"predicate"
|
|
1644
|
+
]
|
|
1645
|
+
},
|
|
1218
1646
|
"uniqueItems": true,
|
|
1219
|
-
"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']`."
|
|
1220
1648
|
}
|
|
1221
1649
|
}
|
|
1222
1650
|
},
|
|
@@ -1230,58 +1658,74 @@
|
|
|
1230
1658
|
},
|
|
1231
1659
|
"manifestRuntime": {
|
|
1232
1660
|
"type": "object",
|
|
1233
|
-
"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).",
|
|
1234
1662
|
"additionalProperties": false,
|
|
1235
|
-
"required": [
|
|
1663
|
+
"required": [
|
|
1664
|
+
"supported"
|
|
1665
|
+
],
|
|
1236
1666
|
"properties": {
|
|
1237
1667
|
"supported": {
|
|
1238
1668
|
"type": "boolean",
|
|
1239
|
-
"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)."
|
|
1240
1670
|
},
|
|
1241
1671
|
"handoffValidation": {
|
|
1242
1672
|
"type": "boolean",
|
|
1243
1673
|
"default": false,
|
|
1244
|
-
"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."
|
|
1245
1675
|
},
|
|
1246
1676
|
"installScope": {
|
|
1247
1677
|
"type": "string",
|
|
1248
|
-
"enum": [
|
|
1678
|
+
"enum": [
|
|
1679
|
+
"host",
|
|
1680
|
+
"tenant"
|
|
1681
|
+
],
|
|
1249
1682
|
"default": "host",
|
|
1250
|
-
"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)."
|
|
1251
1684
|
}
|
|
1252
1685
|
}
|
|
1253
1686
|
},
|
|
1254
1687
|
"liveRuntime": {
|
|
1255
1688
|
"type": "object",
|
|
1256
|
-
"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.",
|
|
1257
1690
|
"additionalProperties": false,
|
|
1258
|
-
"required": [
|
|
1691
|
+
"required": [
|
|
1692
|
+
"supported"
|
|
1693
|
+
],
|
|
1259
1694
|
"properties": {
|
|
1260
1695
|
"supported": {
|
|
1261
1696
|
"type": "boolean",
|
|
1262
|
-
"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`."
|
|
1263
1698
|
},
|
|
1264
1699
|
"structuredOutput": {
|
|
1265
1700
|
"type": "boolean",
|
|
1266
|
-
"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`)."
|
|
1267
1702
|
},
|
|
1268
1703
|
"confidenceEscalation": {
|
|
1269
1704
|
"type": "boolean",
|
|
1270
|
-
"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`."
|
|
1271
1706
|
},
|
|
1272
1707
|
"sources": {
|
|
1273
1708
|
"type": "array",
|
|
1274
1709
|
"uniqueItems": true,
|
|
1275
|
-
"items": {
|
|
1276
|
-
|
|
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."
|
|
1277
1719
|
}
|
|
1278
1720
|
}
|
|
1279
1721
|
},
|
|
1280
1722
|
"evalSuite": {
|
|
1281
1723
|
"type": "object",
|
|
1282
|
-
"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`).",
|
|
1283
1725
|
"additionalProperties": false,
|
|
1284
|
-
"required": [
|
|
1726
|
+
"required": [
|
|
1727
|
+
"supported"
|
|
1728
|
+
],
|
|
1285
1729
|
"properties": {
|
|
1286
1730
|
"supported": {
|
|
1287
1731
|
"type": "boolean",
|
|
@@ -1290,13 +1734,22 @@
|
|
|
1290
1734
|
"modes": {
|
|
1291
1735
|
"type": "array",
|
|
1292
1736
|
"uniqueItems": true,
|
|
1293
|
-
"items": {
|
|
1294
|
-
|
|
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)."
|
|
1295
1748
|
},
|
|
1296
1749
|
"maxTasksPerSuite": {
|
|
1297
1750
|
"type": "integer",
|
|
1298
1751
|
"minimum": 1,
|
|
1299
|
-
"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)."
|
|
1300
1753
|
},
|
|
1301
1754
|
"maxCostUsdPerSuite": {
|
|
1302
1755
|
"type": "number",
|
|
@@ -1307,9 +1760,11 @@
|
|
|
1307
1760
|
},
|
|
1308
1761
|
"deployment": {
|
|
1309
1762
|
"type": "object",
|
|
1310
|
-
"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.",
|
|
1311
1764
|
"additionalProperties": false,
|
|
1312
|
-
"required": [
|
|
1765
|
+
"required": [
|
|
1766
|
+
"supported"
|
|
1767
|
+
],
|
|
1313
1768
|
"properties": {
|
|
1314
1769
|
"supported": {
|
|
1315
1770
|
"type": "boolean",
|
|
@@ -1318,30 +1773,46 @@
|
|
|
1318
1773
|
"channels": {
|
|
1319
1774
|
"type": "array",
|
|
1320
1775
|
"uniqueItems": true,
|
|
1321
|
-
"items": {
|
|
1776
|
+
"items": {
|
|
1777
|
+
"type": "string",
|
|
1778
|
+
"minLength": 1
|
|
1779
|
+
},
|
|
1322
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`."
|
|
1323
1781
|
},
|
|
1324
1782
|
"canary": {
|
|
1325
1783
|
"type": "boolean",
|
|
1326
|
-
"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`."
|
|
1327
1785
|
},
|
|
1328
1786
|
"rollback": {
|
|
1329
1787
|
"type": "boolean",
|
|
1330
|
-
"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)."
|
|
1331
1789
|
},
|
|
1332
1790
|
"states": {
|
|
1333
1791
|
"type": "array",
|
|
1334
1792
|
"uniqueItems": true,
|
|
1335
|
-
"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
|
+
},
|
|
1336
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."
|
|
1337
1806
|
}
|
|
1338
1807
|
}
|
|
1339
1808
|
},
|
|
1340
1809
|
"roster": {
|
|
1341
1810
|
"type": "object",
|
|
1342
|
-
"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.",
|
|
1343
1812
|
"additionalProperties": false,
|
|
1344
|
-
"required": [
|
|
1813
|
+
"required": [
|
|
1814
|
+
"supported"
|
|
1815
|
+
],
|
|
1345
1816
|
"properties": {
|
|
1346
1817
|
"supported": {
|
|
1347
1818
|
"type": "boolean",
|
|
@@ -1349,30 +1820,41 @@
|
|
|
1349
1820
|
},
|
|
1350
1821
|
"installScope": {
|
|
1351
1822
|
"type": "string",
|
|
1352
|
-
"enum": [
|
|
1823
|
+
"enum": [
|
|
1824
|
+
"host",
|
|
1825
|
+
"tenant"
|
|
1826
|
+
],
|
|
1353
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)."
|
|
1354
1828
|
},
|
|
1355
1829
|
"portfolioTriggerSources": {
|
|
1356
1830
|
"type": "array",
|
|
1357
1831
|
"uniqueItems": true,
|
|
1358
|
-
"items": {
|
|
1832
|
+
"items": {
|
|
1833
|
+
"type": "string",
|
|
1834
|
+
"minLength": 1
|
|
1835
|
+
},
|
|
1359
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."
|
|
1360
1837
|
}
|
|
1361
1838
|
}
|
|
1362
1839
|
},
|
|
1363
1840
|
"orgChart": {
|
|
1364
1841
|
"type": "object",
|
|
1365
|
-
"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.",
|
|
1366
1843
|
"additionalProperties": false,
|
|
1367
|
-
"required": [
|
|
1844
|
+
"required": [
|
|
1845
|
+
"supported"
|
|
1846
|
+
],
|
|
1368
1847
|
"properties": {
|
|
1369
1848
|
"supported": {
|
|
1370
1849
|
"type": "boolean",
|
|
1371
|
-
"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."
|
|
1372
1851
|
},
|
|
1373
1852
|
"installScope": {
|
|
1374
1853
|
"type": "string",
|
|
1375
|
-
"enum": [
|
|
1854
|
+
"enum": [
|
|
1855
|
+
"host",
|
|
1856
|
+
"tenant"
|
|
1857
|
+
],
|
|
1376
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)."
|
|
1377
1859
|
},
|
|
1378
1860
|
"departmentNesting": {
|
|
@@ -1381,14 +1863,14 @@
|
|
|
1381
1863
|
},
|
|
1382
1864
|
"responsibilityView": {
|
|
1383
1865
|
"type": "boolean",
|
|
1384
|
-
"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}."
|
|
1385
1867
|
}
|
|
1386
1868
|
}
|
|
1387
1869
|
},
|
|
1388
1870
|
"dispatchMapping": {
|
|
1389
1871
|
"type": "boolean",
|
|
1390
1872
|
"default": false,
|
|
1391
|
-
"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'`."
|
|
1392
1874
|
},
|
|
1393
1875
|
"reasoning": {
|
|
1394
1876
|
"type": "object",
|
|
@@ -1396,7 +1878,11 @@
|
|
|
1396
1878
|
"properties": {
|
|
1397
1879
|
"verbosity": {
|
|
1398
1880
|
"type": "string",
|
|
1399
|
-
"enum": [
|
|
1881
|
+
"enum": [
|
|
1882
|
+
"summary",
|
|
1883
|
+
"full",
|
|
1884
|
+
"off"
|
|
1885
|
+
],
|
|
1400
1886
|
"description": "Default reasoning verbosity for `agent.reasoned` events when the run does not override via `RunOptions.configurable.reasoningVerbosity`."
|
|
1401
1887
|
},
|
|
1402
1888
|
"tokenLimit": {
|
|
@@ -1415,17 +1901,28 @@
|
|
|
1415
1901
|
"subRunAttestation": {
|
|
1416
1902
|
"type": "boolean",
|
|
1417
1903
|
"default": false,
|
|
1418
|
-
"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)."
|
|
1419
1905
|
},
|
|
1420
1906
|
"proposals": {
|
|
1421
1907
|
"type": "object",
|
|
1422
|
-
"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.",
|
|
1423
1909
|
"additionalProperties": false,
|
|
1424
|
-
"required": [
|
|
1910
|
+
"required": [
|
|
1911
|
+
"artifactKinds",
|
|
1912
|
+
"activation"
|
|
1913
|
+
],
|
|
1425
1914
|
"properties": {
|
|
1426
1915
|
"artifactKinds": {
|
|
1427
1916
|
"type": "array",
|
|
1428
|
-
"items": {
|
|
1917
|
+
"items": {
|
|
1918
|
+
"type": "string",
|
|
1919
|
+
"enum": [
|
|
1920
|
+
"agent-pack",
|
|
1921
|
+
"workflow-chain-pack",
|
|
1922
|
+
"prompt-template",
|
|
1923
|
+
"automation"
|
|
1924
|
+
]
|
|
1925
|
+
},
|
|
1429
1926
|
"uniqueItems": true,
|
|
1430
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)."
|
|
1431
1928
|
},
|
|
@@ -1436,25 +1933,42 @@
|
|
|
1436
1933
|
},
|
|
1437
1934
|
"activation": {
|
|
1438
1935
|
"type": "string",
|
|
1439
|
-
"enum": [
|
|
1936
|
+
"enum": [
|
|
1937
|
+
"approval-gate",
|
|
1938
|
+
"direct-rbac"
|
|
1939
|
+
],
|
|
1440
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."
|
|
1441
1941
|
}
|
|
1442
1942
|
}
|
|
1443
1943
|
},
|
|
1444
1944
|
"goals": {
|
|
1445
1945
|
"type": "object",
|
|
1446
|
-
"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.",
|
|
1447
1947
|
"additionalProperties": false,
|
|
1448
|
-
"required": [
|
|
1948
|
+
"required": [
|
|
1949
|
+
"judge",
|
|
1950
|
+
"continuation"
|
|
1951
|
+
],
|
|
1449
1952
|
"properties": {
|
|
1450
1953
|
"judge": {
|
|
1451
1954
|
"type": "string",
|
|
1452
|
-
"enum": [
|
|
1955
|
+
"enum": [
|
|
1956
|
+
"verifier",
|
|
1957
|
+
"host"
|
|
1958
|
+
],
|
|
1453
1959
|
"description": "`verifier`: completion is an RFC 0090 verifier verdict. `host`: an opaque host evaluator."
|
|
1454
1960
|
},
|
|
1455
1961
|
"continuation": {
|
|
1456
1962
|
"type": "array",
|
|
1457
|
-
"items": {
|
|
1963
|
+
"items": {
|
|
1964
|
+
"type": "string",
|
|
1965
|
+
"enum": [
|
|
1966
|
+
"schedule",
|
|
1967
|
+
"commitment",
|
|
1968
|
+
"heartbeat",
|
|
1969
|
+
"manual"
|
|
1970
|
+
]
|
|
1971
|
+
},
|
|
1458
1972
|
"uniqueItems": true,
|
|
1459
1973
|
"description": "How a goal re-engages work between judge checks. `schedule` (RFC 0052), `commitment` (RFC 0068), `heartbeat` (RFC 0060), `manual`."
|
|
1460
1974
|
},
|
|
@@ -1474,7 +1988,7 @@
|
|
|
1474
1988
|
"properties": {
|
|
1475
1989
|
"supported": {
|
|
1476
1990
|
"type": "boolean",
|
|
1477
|
-
"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."
|
|
1478
1992
|
},
|
|
1479
1993
|
"maxEntrySizeBytes": {
|
|
1480
1994
|
"type": "integer",
|
|
@@ -1483,21 +1997,27 @@
|
|
|
1483
1997
|
},
|
|
1484
1998
|
"ttlSupported": {
|
|
1485
1999
|
"type": "boolean",
|
|
1486
|
-
"description": "When `true`, host honors `expiresAt` per RFC 0004
|
|
2000
|
+
"description": "When `true`, host honors `expiresAt` per RFC 0004 \u00a7E."
|
|
1487
2001
|
},
|
|
1488
2002
|
"compaction": {
|
|
1489
2003
|
"type": "object",
|
|
1490
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`).",
|
|
1491
|
-
"required": [
|
|
2005
|
+
"required": [
|
|
2006
|
+
"supported"
|
|
2007
|
+
],
|
|
1492
2008
|
"properties": {
|
|
1493
2009
|
"supported": {
|
|
1494
2010
|
"type": "boolean",
|
|
1495
|
-
"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."
|
|
1496
2012
|
},
|
|
1497
2013
|
"trigger": {
|
|
1498
2014
|
"type": "string",
|
|
1499
|
-
"enum": [
|
|
1500
|
-
|
|
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`."
|
|
1501
2021
|
},
|
|
1502
2022
|
"maxInputEntries": {
|
|
1503
2023
|
"type": "integer",
|
|
@@ -1507,31 +2027,68 @@
|
|
|
1507
2027
|
"maxOutputBytes": {
|
|
1508
2028
|
"type": "integer",
|
|
1509
2029
|
"minimum": 0,
|
|
1510
|
-
"description": "Informational ceiling on the distilled entry size. SHOULD be
|
|
2030
|
+
"description": "Informational ceiling on the distilled entry size. SHOULD be \u2264 `memory.maxEntrySizeBytes`."
|
|
1511
2031
|
}
|
|
1512
2032
|
},
|
|
1513
2033
|
"additionalProperties": false,
|
|
1514
|
-
"if": {
|
|
1515
|
-
|
|
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
|
+
}
|
|
1516
2050
|
},
|
|
1517
2051
|
"distillation": {
|
|
1518
2052
|
"type": "object",
|
|
1519
|
-
"description": "RFC 0062 (`Active`). Scheduled, token-budgeted background compaction
|
|
1520
|
-
"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
|
+
],
|
|
1521
2057
|
"additionalProperties": false,
|
|
1522
2058
|
"properties": {
|
|
1523
|
-
"supported": {
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
"
|
|
1528
|
-
|
|
2059
|
+
"supported": {
|
|
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."
|
|
2062
|
+
},
|
|
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
|
+
}
|
|
1529
2084
|
}
|
|
1530
2085
|
},
|
|
1531
2086
|
"attribution": {
|
|
1532
2087
|
"type": "object",
|
|
1533
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`.",
|
|
1534
|
-
"required": [
|
|
2089
|
+
"required": [
|
|
2090
|
+
"supported"
|
|
2091
|
+
],
|
|
1535
2092
|
"properties": {
|
|
1536
2093
|
"supported": {
|
|
1537
2094
|
"const": true,
|
|
@@ -1546,47 +2103,88 @@
|
|
|
1546
2103
|
},
|
|
1547
2104
|
"writable": {
|
|
1548
2105
|
"type": "boolean",
|
|
1549
|
-
"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`."
|
|
1550
2107
|
},
|
|
1551
2108
|
"search": {
|
|
1552
2109
|
"type": "object",
|
|
1553
|
-
"description": "RFC 0080
|
|
1554
|
-
"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
|
+
],
|
|
1555
2114
|
"additionalProperties": false,
|
|
1556
2115
|
"properties": {
|
|
1557
|
-
"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
|
+
},
|
|
1558
2120
|
"modes": {
|
|
1559
2121
|
"type": "array",
|
|
1560
|
-
"items": {
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
2122
|
+
"items": {
|
|
2123
|
+
"type": "string",
|
|
2124
|
+
"enum": [
|
|
2125
|
+
"semantic",
|
|
2126
|
+
"filter"
|
|
2127
|
+
]
|
|
2128
|
+
},
|
|
2129
|
+
"uniqueItems": true,
|
|
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`)."
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
1565
2133
|
},
|
|
1566
2134
|
"retention": {
|
|
1567
2135
|
"type": "object",
|
|
1568
|
-
"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).",
|
|
1569
2137
|
"additionalProperties": false,
|
|
1570
2138
|
"properties": {
|
|
1571
|
-
"ttl": {
|
|
1572
|
-
|
|
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
|
+
}
|
|
1573
2147
|
}
|
|
1574
2148
|
},
|
|
1575
2149
|
"injectionBudget": {
|
|
1576
2150
|
"type": "object",
|
|
1577
|
-
"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).",
|
|
1578
2152
|
"additionalProperties": false,
|
|
1579
|
-
"required": [
|
|
2153
|
+
"required": [
|
|
2154
|
+
"supported"
|
|
2155
|
+
],
|
|
1580
2156
|
"properties": {
|
|
1581
|
-
"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
|
+
},
|
|
1582
2161
|
"tokenCounter": {
|
|
1583
2162
|
"type": "string",
|
|
1584
|
-
"enum": [
|
|
1585
|
-
|
|
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)."
|
|
1586
2170
|
}
|
|
1587
2171
|
},
|
|
1588
|
-
"if": {
|
|
1589
|
-
|
|
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
|
+
}
|
|
1590
2188
|
}
|
|
1591
2189
|
},
|
|
1592
2190
|
"additionalProperties": true
|
|
@@ -1597,19 +2195,19 @@
|
|
|
1597
2195
|
},
|
|
1598
2196
|
"subWorkflow": {
|
|
1599
2197
|
"type": "object",
|
|
1600
|
-
"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.",
|
|
1601
2199
|
"properties": {
|
|
1602
2200
|
"inputMapping": {
|
|
1603
2201
|
"type": "boolean",
|
|
1604
2202
|
"default": false,
|
|
1605
|
-
"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."
|
|
1606
2204
|
}
|
|
1607
2205
|
},
|
|
1608
2206
|
"additionalProperties": false
|
|
1609
2207
|
},
|
|
1610
2208
|
"fs": {
|
|
1611
2209
|
"type": "object",
|
|
1612
|
-
"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`.",
|
|
1613
2211
|
"properties": {
|
|
1614
2212
|
"supported": {
|
|
1615
2213
|
"type": "boolean",
|
|
@@ -1628,10 +2226,21 @@
|
|
|
1628
2226
|
"type": "object",
|
|
1629
2227
|
"description": "Image-processing sub-capability. Optional.",
|
|
1630
2228
|
"properties": {
|
|
1631
|
-
"supported": {
|
|
2229
|
+
"supported": {
|
|
2230
|
+
"type": "boolean"
|
|
2231
|
+
},
|
|
1632
2232
|
"formats": {
|
|
1633
2233
|
"type": "array",
|
|
1634
|
-
"items": {
|
|
2234
|
+
"items": {
|
|
2235
|
+
"type": "string",
|
|
2236
|
+
"enum": [
|
|
2237
|
+
"jpeg",
|
|
2238
|
+
"png",
|
|
2239
|
+
"webp",
|
|
2240
|
+
"avif",
|
|
2241
|
+
"gif"
|
|
2242
|
+
]
|
|
2243
|
+
}
|
|
1635
2244
|
}
|
|
1636
2245
|
},
|
|
1637
2246
|
"additionalProperties": false
|
|
@@ -1640,7 +2249,9 @@
|
|
|
1640
2249
|
"type": "object",
|
|
1641
2250
|
"description": "PDF-processing sub-capability. Optional.",
|
|
1642
2251
|
"properties": {
|
|
1643
|
-
"supported": {
|
|
2252
|
+
"supported": {
|
|
2253
|
+
"type": "boolean"
|
|
2254
|
+
}
|
|
1644
2255
|
},
|
|
1645
2256
|
"additionalProperties": false
|
|
1646
2257
|
},
|
|
@@ -1648,27 +2259,62 @@
|
|
|
1648
2259
|
"type": "object",
|
|
1649
2260
|
"description": "Network file-transport sub-capabilities. Optional.",
|
|
1650
2261
|
"properties": {
|
|
1651
|
-
"ftp": {
|
|
1652
|
-
|
|
1653
|
-
|
|
2262
|
+
"ftp": {
|
|
2263
|
+
"type": "boolean"
|
|
2264
|
+
},
|
|
2265
|
+
"sftp": {
|
|
2266
|
+
"type": "boolean"
|
|
2267
|
+
},
|
|
2268
|
+
"ssh": {
|
|
2269
|
+
"type": "boolean"
|
|
2270
|
+
}
|
|
1654
2271
|
},
|
|
1655
2272
|
"additionalProperties": false
|
|
1656
2273
|
}
|
|
1657
2274
|
},
|
|
1658
|
-
"if": {
|
|
1659
|
-
|
|
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
|
+
},
|
|
1660
2291
|
"additionalProperties": false
|
|
1661
2292
|
},
|
|
1662
2293
|
"kvStorage": {
|
|
1663
2294
|
"type": "object",
|
|
1664
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.",
|
|
1665
2296
|
"properties": {
|
|
1666
|
-
"supported": {
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
"
|
|
1670
|
-
|
|
1671
|
-
|
|
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
|
+
}
|
|
1672
2318
|
},
|
|
1673
2319
|
"additionalProperties": false
|
|
1674
2320
|
},
|
|
@@ -1676,29 +2322,62 @@
|
|
|
1676
2322
|
"type": "object",
|
|
1677
2323
|
"description": "RFC 0016 (`Active`). Structured-record store with user-defined schemas. Sibling to kvStorage. Cross-tenant isolation enforced (mirrors RFC 0015 invariant).",
|
|
1678
2324
|
"properties": {
|
|
1679
|
-
"supported": {
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
"
|
|
1683
|
-
|
|
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
|
+
}
|
|
1684
2342
|
},
|
|
1685
2343
|
"additionalProperties": false
|
|
1686
2344
|
},
|
|
1687
2345
|
"queueBus": {
|
|
1688
2346
|
"type": "object",
|
|
1689
|
-
"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).",
|
|
1690
2348
|
"properties": {
|
|
1691
|
-
"supported": {
|
|
2349
|
+
"supported": {
|
|
2350
|
+
"type": "boolean"
|
|
2351
|
+
},
|
|
1692
2352
|
"backends": {
|
|
1693
2353
|
"type": "array",
|
|
1694
|
-
"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"
|
|
1695
2371
|
},
|
|
1696
|
-
"deadLetterSupported": { "type": "boolean" },
|
|
1697
2372
|
"stream": {
|
|
1698
2373
|
"type": "object",
|
|
1699
2374
|
"properties": {
|
|
1700
|
-
"supported": {
|
|
1701
|
-
|
|
2375
|
+
"supported": {
|
|
2376
|
+
"type": "boolean"
|
|
2377
|
+
},
|
|
2378
|
+
"fromBeginning": {
|
|
2379
|
+
"type": "boolean"
|
|
2380
|
+
}
|
|
1702
2381
|
},
|
|
1703
2382
|
"additionalProperties": false
|
|
1704
2383
|
}
|
|
@@ -1707,112 +2386,260 @@
|
|
|
1707
2386
|
},
|
|
1708
2387
|
"scheduling": {
|
|
1709
2388
|
"type": "object",
|
|
1710
|
-
"description": "RFC 0052 (`Draft`). Time-based run initiation behind the `schedule` trigger
|
|
1711
|
-
"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
|
+
],
|
|
1712
2393
|
"properties": {
|
|
1713
|
-
"supported": {
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
"
|
|
1717
|
-
|
|
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
|
+
}
|
|
1718
2413
|
},
|
|
1719
2414
|
"additionalProperties": false
|
|
1720
2415
|
},
|
|
1721
2416
|
"heartbeat": {
|
|
1722
2417
|
"type": "object",
|
|
1723
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`).",
|
|
1724
|
-
"required": [
|
|
2419
|
+
"required": [
|
|
2420
|
+
"supported"
|
|
2421
|
+
],
|
|
1725
2422
|
"properties": {
|
|
1726
|
-
"supported": {
|
|
1727
|
-
|
|
1728
|
-
|
|
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
|
+
}
|
|
1729
2436
|
},
|
|
1730
2437
|
"additionalProperties": false
|
|
1731
2438
|
},
|
|
1732
2439
|
"toolHooks": {
|
|
1733
2440
|
"type": "object",
|
|
1734
|
-
"description": "RFC 0064 (`Active`)
|
|
1735
|
-
"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
|
+
],
|
|
1736
2445
|
"additionalProperties": false,
|
|
1737
2446
|
"properties": {
|
|
1738
|
-
"supported": {
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
"
|
|
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
|
+
}
|
|
1742
2462
|
}
|
|
1743
2463
|
},
|
|
1744
2464
|
"toolCatalog": {
|
|
1745
2465
|
"type": "object",
|
|
1746
|
-
"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
|
|
1747
|
-
"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
|
+
],
|
|
1748
2470
|
"additionalProperties": false,
|
|
1749
2471
|
"properties": {
|
|
1750
|
-
"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
|
+
},
|
|
1751
2476
|
"sources": {
|
|
1752
2477
|
"type": "array",
|
|
1753
2478
|
"uniqueItems": true,
|
|
1754
|
-
"items": {
|
|
1755
|
-
|
|
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."
|
|
1756
2490
|
},
|
|
1757
|
-
"sessionLifecycle": {
|
|
1758
|
-
|
|
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)."
|
|
2494
|
+
},
|
|
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
|
+
}
|
|
1759
2499
|
}
|
|
1760
2500
|
},
|
|
1761
2501
|
"httpClient": {
|
|
1762
2502
|
"type": "object",
|
|
1763
|
-
"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
|
|
1764
|
-
"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
|
+
],
|
|
1765
2507
|
"additionalProperties": false,
|
|
1766
2508
|
"properties": {
|
|
1767
|
-
"supported": {
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
"
|
|
1771
|
-
|
|
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
|
+
},
|
|
1772
2533
|
"safeFetch": {
|
|
1773
2534
|
"type": "object",
|
|
1774
|
-
"description": "RFC 0076
|
|
1775
|
-
"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
|
+
],
|
|
1776
2539
|
"additionalProperties": false,
|
|
1777
2540
|
"properties": {
|
|
1778
|
-
"supported": {
|
|
2541
|
+
"supported": {
|
|
2542
|
+
"type": "boolean"
|
|
2543
|
+
}
|
|
1779
2544
|
}
|
|
1780
2545
|
},
|
|
1781
2546
|
"egressPolicy": {
|
|
1782
2547
|
"type": "object",
|
|
1783
2548
|
"additionalProperties": false,
|
|
1784
|
-
"description": "RFC 0079. The host evaluates credential provenance (`credential-provenance.schema.json`) + the audience-binding MUST (
|
|
1785
|
-
"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
|
+
],
|
|
1786
2553
|
"properties": {
|
|
1787
|
-
"supported": {
|
|
1788
|
-
|
|
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
|
+
}
|
|
1789
2572
|
}
|
|
1790
2573
|
}
|
|
1791
2574
|
}
|
|
1792
2575
|
},
|
|
1793
2576
|
"artifactTypes": {
|
|
1794
2577
|
"type": "object",
|
|
1795
|
-
"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.",
|
|
1796
2579
|
"additionalProperties": false,
|
|
1797
2580
|
"properties": {
|
|
1798
|
-
"supported": {
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
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
|
+
},
|
|
1802
2600
|
"types": {
|
|
1803
2601
|
"type": "object",
|
|
1804
|
-
"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).",
|
|
1805
2603
|
"additionalProperties": {
|
|
1806
2604
|
"type": "object",
|
|
1807
2605
|
"additionalProperties": false,
|
|
1808
2606
|
"properties": {
|
|
1809
|
-
"validated": {
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
"
|
|
1814
|
-
|
|
1815
|
-
|
|
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
|
+
}
|
|
1816
2643
|
}
|
|
1817
2644
|
}
|
|
1818
2645
|
}
|
|
@@ -1820,85 +2647,203 @@
|
|
|
1820
2647
|
},
|
|
1821
2648
|
"forms": {
|
|
1822
2649
|
"type": "object",
|
|
1823
|
-
"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.",
|
|
1824
2651
|
"additionalProperties": false,
|
|
1825
2652
|
"properties": {
|
|
1826
|
-
"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
|
+
}
|
|
1827
2657
|
}
|
|
1828
2658
|
},
|
|
1829
2659
|
"aiEnvelope": {
|
|
1830
2660
|
"type": "object",
|
|
1831
|
-
"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`.",
|
|
1832
2662
|
"additionalProperties": false,
|
|
1833
2663
|
"properties": {
|
|
1834
|
-
"supported": {
|
|
1835
|
-
|
|
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
|
+
}
|
|
1836
2672
|
}
|
|
1837
2673
|
},
|
|
1838
2674
|
"promptLibrary": {
|
|
1839
2675
|
"type": "object",
|
|
1840
|
-
"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.",
|
|
1841
2677
|
"additionalProperties": false,
|
|
1842
2678
|
"properties": {
|
|
1843
|
-
"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
|
+
}
|
|
1844
2683
|
}
|
|
1845
2684
|
},
|
|
1846
2685
|
"agentRuntime": {
|
|
1847
2686
|
"type": "object",
|
|
1848
|
-
"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.",
|
|
1849
2688
|
"additionalProperties": false,
|
|
1850
2689
|
"properties": {
|
|
1851
|
-
"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
|
+
}
|
|
1852
2694
|
}
|
|
1853
2695
|
},
|
|
1854
2696
|
"deadLetter": {
|
|
1855
2697
|
"type": "object",
|
|
1856
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*.",
|
|
1857
|
-
"required": [
|
|
2699
|
+
"required": [
|
|
2700
|
+
"supported"
|
|
2701
|
+
],
|
|
1858
2702
|
"properties": {
|
|
1859
|
-
"supported": {
|
|
1860
|
-
|
|
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
|
+
}
|
|
1861
2711
|
},
|
|
1862
2712
|
"additionalProperties": false
|
|
1863
2713
|
},
|
|
1864
2714
|
"webhooks": {
|
|
1865
2715
|
"type": "object",
|
|
1866
|
-
"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.",
|
|
1867
2717
|
"additionalProperties": true,
|
|
1868
2718
|
"properties": {
|
|
1869
|
-
"supported": {
|
|
1870
|
-
|
|
1871
|
-
|
|
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
|
+
}
|
|
1872
2735
|
}
|
|
1873
2736
|
},
|
|
1874
2737
|
"triggerBridge": {
|
|
1875
2738
|
"type": "object",
|
|
1876
|
-
"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
|
|
1877
|
-
"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
|
+
],
|
|
1878
2743
|
"additionalProperties": false,
|
|
1879
2744
|
"properties": {
|
|
1880
|
-
"supported": {
|
|
1881
|
-
|
|
1882
|
-
|
|
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
|
+
},
|
|
1883
2767
|
"retryPolicy": {
|
|
1884
2768
|
"type": "object",
|
|
1885
2769
|
"additionalProperties": false,
|
|
1886
|
-
"description": "The host's default delivery retry policy (
|
|
2770
|
+
"description": "The host's default delivery retry policy (\u00a7C-2).",
|
|
1887
2771
|
"properties": {
|
|
1888
|
-
"maxAttempts": {
|
|
1889
|
-
|
|
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
|
+
}
|
|
1890
2786
|
}
|
|
1891
2787
|
},
|
|
1892
|
-
"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
|
+
},
|
|
1893
2805
|
"ingestion": {
|
|
1894
2806
|
"type": "object",
|
|
1895
2807
|
"additionalProperties": false,
|
|
1896
|
-
"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.",
|
|
1897
2809
|
"properties": {
|
|
1898
|
-
"externalSources": {
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
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
|
+
}
|
|
1902
2847
|
}
|
|
1903
2848
|
}
|
|
1904
2849
|
}
|
|
@@ -1906,91 +2851,257 @@
|
|
|
1906
2851
|
"a2a": {
|
|
1907
2852
|
"type": "object",
|
|
1908
2853
|
"additionalProperties": false,
|
|
1909
|
-
"description": "RFC 0100 (`Active`). The host exposes itself as an A2A (Agent2Agent) agent. `supported: true` alone
|
|
1910
|
-
"required": [
|
|
1911
|
-
|
|
1912
|
-
"
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
"
|
|
1916
|
-
|
|
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
|
+
}
|
|
1917
2905
|
}
|
|
1918
2906
|
},
|
|
1919
2907
|
"budget": {
|
|
1920
2908
|
"type": "object",
|
|
1921
|
-
"description": "RFC 0084 (`Active`). Enforceable per-run SPEND governance
|
|
1922
|
-
"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
|
+
],
|
|
1923
2913
|
"additionalProperties": false,
|
|
1924
2914
|
"properties": {
|
|
1925
|
-
"supported": {
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
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
|
+
}
|
|
1929
2956
|
}
|
|
1930
2957
|
},
|
|
1931
2958
|
"nondeterminismPolicy": {
|
|
1932
2959
|
"type": "object",
|
|
1933
|
-
"description": "RFC 0085. A host that does NOT support replay/fork (`replay.supported`) MAY instead DECLARE that it is honestly nondeterministic
|
|
1934
|
-
"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
|
+
],
|
|
1935
2964
|
"additionalProperties": false,
|
|
1936
2965
|
"properties": {
|
|
1937
|
-
"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
|
+
}
|
|
1938
2970
|
}
|
|
1939
2971
|
},
|
|
1940
2972
|
"workspace": {
|
|
1941
2973
|
"type": "object",
|
|
1942
|
-
"description": "RFC 0059 (`Active`). Versioned, tenant
|
|
1943
|
-
"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
|
+
],
|
|
1944
2978
|
"properties": {
|
|
1945
|
-
"supported": {
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
"
|
|
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
|
+
}
|
|
1950
3002
|
},
|
|
1951
3003
|
"additionalProperties": false
|
|
1952
3004
|
},
|
|
1953
3005
|
"uiPlugins": {
|
|
1954
3006
|
"type": "object",
|
|
1955
|
-
"description": "RFC 0117 (`Active`; amended by RFC 0119). Host loads SIGNED, SANDBOXED front-end plugin packs (`kind: \"frontend-plugin\"`)
|
|
1956
|
-
"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
|
+
],
|
|
1957
3011
|
"properties": {
|
|
1958
|
-
"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
|
+
},
|
|
1959
3016
|
"isolation": {
|
|
1960
3017
|
"type": "string",
|
|
1961
3018
|
"anyOf": [
|
|
1962
|
-
{
|
|
1963
|
-
|
|
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
|
+
}
|
|
1964
3031
|
],
|
|
1965
3032
|
"default": "cross-origin-iframe",
|
|
1966
|
-
"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."
|
|
1967
3034
|
},
|
|
1968
3035
|
"surfaces": {
|
|
1969
3036
|
"type": "array",
|
|
1970
|
-
"description": "Plugin surfaces this host renders. A pack's `uiPlugins[].surface` not in this set is installable-but-inert (
|
|
1971
|
-
"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
|
+
},
|
|
1972
3047
|
"uniqueItems": true
|
|
1973
3048
|
},
|
|
1974
3049
|
"hostApi": {
|
|
1975
3050
|
"type": "array",
|
|
1976
|
-
"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
|
|
1977
|
-
"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
|
+
},
|
|
1978
3062
|
"uniqueItems": true
|
|
1979
3063
|
},
|
|
1980
|
-
"maxEntryBytes": {
|
|
3064
|
+
"maxEntryBytes": {
|
|
3065
|
+
"type": "integer",
|
|
3066
|
+
"minimum": 1,
|
|
3067
|
+
"description": "Per-plugin entry-bundle byte ceiling the host will load."
|
|
3068
|
+
}
|
|
1981
3069
|
},
|
|
1982
3070
|
"additionalProperties": false
|
|
1983
3071
|
},
|
|
1984
3072
|
"sql": {
|
|
1985
3073
|
"type": "object",
|
|
1986
|
-
"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).",
|
|
1987
3075
|
"properties": {
|
|
1988
|
-
"supported": {
|
|
1989
|
-
|
|
1990
|
-
|
|
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
|
+
},
|
|
1991
3089
|
"drivers": {
|
|
1992
3090
|
"type": "array",
|
|
1993
|
-
"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
|
+
}
|
|
1994
3105
|
}
|
|
1995
3106
|
},
|
|
1996
3107
|
"additionalProperties": false
|
|
@@ -1999,9 +3110,24 @@
|
|
|
1999
3110
|
"type": "object",
|
|
2000
3111
|
"description": "RFC 0018 (`Active`). MongoDB-shape document store adapter.",
|
|
2001
3112
|
"properties": {
|
|
2002
|
-
"supported": {
|
|
2003
|
-
|
|
2004
|
-
|
|
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
|
+
}
|
|
2005
3131
|
},
|
|
2006
3132
|
"additionalProperties": false
|
|
2007
3133
|
},
|
|
@@ -2009,11 +3135,29 @@
|
|
|
2009
3135
|
"type": "object",
|
|
2010
3136
|
"description": "RFC 0018 (`Active`). Vector-DB capability for k-NN search.",
|
|
2011
3137
|
"properties": {
|
|
2012
|
-
"supported": {
|
|
2013
|
-
|
|
3138
|
+
"supported": {
|
|
3139
|
+
"type": "boolean"
|
|
3140
|
+
},
|
|
3141
|
+
"collections": {
|
|
3142
|
+
"type": "array"
|
|
3143
|
+
},
|
|
2014
3144
|
"backends": {
|
|
2015
3145
|
"type": "array",
|
|
2016
|
-
"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
|
+
}
|
|
2017
3161
|
}
|
|
2018
3162
|
},
|
|
2019
3163
|
"additionalProperties": false
|
|
@@ -2022,11 +3166,24 @@
|
|
|
2022
3166
|
"type": "object",
|
|
2023
3167
|
"description": "RFC 0018 (`Active`). Full-text search index adapter.",
|
|
2024
3168
|
"properties": {
|
|
2025
|
-
"supported": {
|
|
2026
|
-
|
|
3169
|
+
"supported": {
|
|
3170
|
+
"type": "boolean"
|
|
3171
|
+
},
|
|
3172
|
+
"indexes": {
|
|
3173
|
+
"type": "array"
|
|
3174
|
+
},
|
|
2027
3175
|
"backends": {
|
|
2028
3176
|
"type": "array",
|
|
2029
|
-
"items": {
|
|
3177
|
+
"items": {
|
|
3178
|
+
"type": "string",
|
|
3179
|
+
"enum": [
|
|
3180
|
+
"elasticsearch",
|
|
3181
|
+
"opensearch",
|
|
3182
|
+
"meilisearch",
|
|
3183
|
+
"typesense",
|
|
3184
|
+
"algolia"
|
|
3185
|
+
]
|
|
3186
|
+
}
|
|
2030
3187
|
}
|
|
2031
3188
|
},
|
|
2032
3189
|
"additionalProperties": false
|
|
@@ -2035,26 +3192,43 @@
|
|
|
2035
3192
|
"type": "object",
|
|
2036
3193
|
"description": "RFC 0019 (`Active`). Binary artifact store with presigned URLs. Per-bucket tenant isolation. Presigned URLs MUST expire at the advertised TTL.",
|
|
2037
3194
|
"properties": {
|
|
2038
|
-
"supported": {
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
"
|
|
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
|
+
}
|
|
2042
3208
|
},
|
|
2043
3209
|
"additionalProperties": false
|
|
2044
3210
|
},
|
|
2045
3211
|
"cache": {
|
|
2046
3212
|
"type": "object",
|
|
2047
|
-
"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.",
|
|
2048
3214
|
"properties": {
|
|
2049
|
-
"supported": {
|
|
2050
|
-
|
|
2051
|
-
|
|
3215
|
+
"supported": {
|
|
3216
|
+
"type": "boolean"
|
|
3217
|
+
},
|
|
3218
|
+
"maxValueBytes": {
|
|
3219
|
+
"type": "integer",
|
|
3220
|
+
"minimum": 0
|
|
3221
|
+
},
|
|
3222
|
+
"maxTtlSeconds": {
|
|
3223
|
+
"type": "integer",
|
|
3224
|
+
"minimum": 0
|
|
3225
|
+
}
|
|
2052
3226
|
},
|
|
2053
3227
|
"additionalProperties": false
|
|
2054
3228
|
},
|
|
2055
3229
|
"workflowChainPacks": {
|
|
2056
3230
|
"type": "object",
|
|
2057
|
-
"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.",
|
|
2058
3232
|
"properties": {
|
|
2059
3233
|
"supported": {
|
|
2060
3234
|
"type": "boolean",
|
|
@@ -2062,23 +3236,25 @@
|
|
|
2062
3236
|
},
|
|
2063
3237
|
"deferredParameters": {
|
|
2064
3238
|
"type": "object",
|
|
2065
|
-
"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\".",
|
|
2066
3240
|
"properties": {
|
|
2067
3241
|
"supported": {
|
|
2068
3242
|
"type": "boolean",
|
|
2069
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."
|
|
2070
3244
|
}
|
|
2071
3245
|
},
|
|
2072
|
-
"required": [
|
|
3246
|
+
"required": [
|
|
3247
|
+
"supported"
|
|
3248
|
+
],
|
|
2073
3249
|
"additionalProperties": false
|
|
2074
3250
|
},
|
|
2075
3251
|
"hostExpansionSeam": {
|
|
2076
3252
|
"type": "boolean",
|
|
2077
|
-
"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."
|
|
2078
3254
|
},
|
|
2079
3255
|
"subChains": {
|
|
2080
3256
|
"type": "object",
|
|
2081
|
-
"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.",
|
|
2082
3258
|
"properties": {
|
|
2083
3259
|
"supported": {
|
|
2084
3260
|
"type": "boolean",
|
|
@@ -2088,49 +3264,61 @@
|
|
|
2088
3264
|
"type": "integer",
|
|
2089
3265
|
"minimum": 1,
|
|
2090
3266
|
"default": 8,
|
|
2091
|
-
"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`)."
|
|
2092
3268
|
}
|
|
2093
3269
|
},
|
|
2094
|
-
"required": [
|
|
3270
|
+
"required": [
|
|
3271
|
+
"supported"
|
|
3272
|
+
],
|
|
2095
3273
|
"additionalProperties": false
|
|
2096
3274
|
}
|
|
2097
3275
|
},
|
|
2098
|
-
"required": [
|
|
3276
|
+
"required": [
|
|
3277
|
+
"supported"
|
|
3278
|
+
],
|
|
2099
3279
|
"additionalProperties": false
|
|
2100
3280
|
},
|
|
2101
3281
|
"packs": {
|
|
2102
3282
|
"type": "object",
|
|
2103
|
-
"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.",
|
|
2104
3284
|
"properties": {
|
|
2105
3285
|
"testMode": {
|
|
2106
3286
|
"type": "object",
|
|
2107
|
-
"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.",
|
|
2108
3288
|
"properties": {
|
|
2109
3289
|
"supported": {
|
|
2110
3290
|
"type": "boolean",
|
|
2111
|
-
"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."
|
|
2112
3292
|
},
|
|
2113
3293
|
"isolated": {
|
|
2114
3294
|
"type": "boolean",
|
|
2115
|
-
"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."
|
|
2116
3296
|
},
|
|
2117
3297
|
"catalogResetEndpoint": {
|
|
2118
3298
|
"type": "string",
|
|
2119
|
-
"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.",
|
|
2120
3300
|
"pattern": "^/"
|
|
2121
3301
|
},
|
|
2122
3302
|
"scopes": {
|
|
2123
3303
|
"type": "array",
|
|
2124
3304
|
"items": {
|
|
2125
3305
|
"type": "string",
|
|
2126
|
-
"enum": [
|
|
3306
|
+
"enum": [
|
|
3307
|
+
"core",
|
|
3308
|
+
"vendor",
|
|
3309
|
+
"community",
|
|
3310
|
+
"private",
|
|
3311
|
+
"local"
|
|
3312
|
+
]
|
|
2127
3313
|
},
|
|
2128
3314
|
"uniqueItems": true,
|
|
2129
3315
|
"minItems": 1,
|
|
2130
|
-
"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."
|
|
2131
3317
|
}
|
|
2132
3318
|
},
|
|
2133
|
-
"required": [
|
|
3319
|
+
"required": [
|
|
3320
|
+
"supported"
|
|
3321
|
+
],
|
|
2134
3322
|
"additionalProperties": false
|
|
2135
3323
|
}
|
|
2136
3324
|
},
|
|
@@ -2138,107 +3326,227 @@
|
|
|
2138
3326
|
},
|
|
2139
3327
|
"mcp": {
|
|
2140
3328
|
"type": "object",
|
|
2141
|
-
"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.",
|
|
2142
3330
|
"properties": {
|
|
2143
|
-
"supported": {
|
|
3331
|
+
"supported": {
|
|
3332
|
+
"type": "boolean",
|
|
3333
|
+
"description": "Host advertises a client-side MCP surface (ctx.mcp.*). See spec/v1/mcp-integration.md."
|
|
3334
|
+
},
|
|
2144
3335
|
"serverMount": {
|
|
2145
3336
|
"type": "object",
|
|
2146
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'`.",
|
|
2147
3338
|
"properties": {
|
|
2148
|
-
"supported": {
|
|
3339
|
+
"supported": {
|
|
3340
|
+
"type": "boolean"
|
|
3341
|
+
},
|
|
2149
3342
|
"transports": {
|
|
2150
3343
|
"type": "array",
|
|
2151
|
-
"items": {
|
|
3344
|
+
"items": {
|
|
3345
|
+
"type": "string",
|
|
3346
|
+
"enum": [
|
|
3347
|
+
"stdio",
|
|
3348
|
+
"streamable-http"
|
|
3349
|
+
]
|
|
3350
|
+
}
|
|
2152
3351
|
},
|
|
2153
|
-
"samplingBridge": {
|
|
2154
|
-
|
|
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
|
+
}
|
|
2155
3360
|
},
|
|
2156
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."
|
|
2157
3399
|
}
|
|
2158
3400
|
},
|
|
2159
3401
|
"additionalProperties": false
|
|
2160
3402
|
},
|
|
2161
3403
|
"sandbox": {
|
|
2162
3404
|
"type": "object",
|
|
2163
|
-
"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`.",
|
|
2164
3406
|
"additionalProperties": false,
|
|
2165
|
-
"required": [
|
|
3407
|
+
"required": [
|
|
3408
|
+
"supported",
|
|
3409
|
+
"isolationModel"
|
|
3410
|
+
],
|
|
2166
3411
|
"properties": {
|
|
2167
3412
|
"supported": {
|
|
2168
3413
|
"type": "boolean",
|
|
2169
|
-
"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."
|
|
2170
3415
|
},
|
|
2171
3416
|
"isolationModel": {
|
|
2172
3417
|
"type": "string",
|
|
2173
3418
|
"anyOf": [
|
|
2174
|
-
{
|
|
2175
|
-
|
|
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
|
+
}
|
|
2176
3430
|
],
|
|
2177
|
-
"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."
|
|
2178
3432
|
},
|
|
2179
3433
|
"allowedHostCalls": {
|
|
2180
3434
|
"type": "array",
|
|
2181
|
-
"items": {
|
|
3435
|
+
"items": {
|
|
3436
|
+
"type": "string"
|
|
3437
|
+
},
|
|
2182
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`)."
|
|
2183
3439
|
},
|
|
2184
3440
|
"memoryLimitBytes": {
|
|
2185
3441
|
"type": "integer",
|
|
2186
3442
|
"minimum": 1048576,
|
|
2187
|
-
"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`."
|
|
2188
3444
|
},
|
|
2189
3445
|
"wallClockLimitMs": {
|
|
2190
3446
|
"type": "integer",
|
|
2191
3447
|
"minimum": 100,
|
|
2192
|
-
"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."
|
|
2193
3483
|
}
|
|
2194
3484
|
}
|
|
2195
3485
|
},
|
|
2196
3486
|
"idempotency": {
|
|
2197
3487
|
"type": "object",
|
|
2198
|
-
"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.",
|
|
2199
3489
|
"additionalProperties": true,
|
|
2200
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
|
+
},
|
|
2201
3495
|
"multiRegion": {
|
|
2202
3496
|
"type": "object",
|
|
2203
3497
|
"additionalProperties": false,
|
|
2204
|
-
"required": [
|
|
3498
|
+
"required": [
|
|
3499
|
+
"supported"
|
|
3500
|
+
],
|
|
2205
3501
|
"properties": {
|
|
2206
3502
|
"supported": {
|
|
2207
3503
|
"type": "boolean",
|
|
2208
|
-
"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`."
|
|
2209
3505
|
},
|
|
2210
3506
|
"replicationLagBoundMs": {
|
|
2211
3507
|
"type": "integer",
|
|
2212
3508
|
"minimum": 0,
|
|
2213
3509
|
"maximum": 60000,
|
|
2214
|
-
"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."
|
|
2215
3511
|
},
|
|
2216
3512
|
"partitionRecoveryStrategy": {
|
|
2217
3513
|
"type": "string",
|
|
2218
3514
|
"anyOf": [
|
|
2219
|
-
{
|
|
2220
|
-
|
|
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
|
+
}
|
|
2221
3523
|
],
|
|
2222
|
-
"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`."
|
|
2223
3525
|
}
|
|
2224
3526
|
}
|
|
2225
3527
|
},
|
|
2226
3528
|
"crossRegion": {
|
|
2227
3529
|
"type": "string",
|
|
2228
|
-
"enum": [
|
|
2229
|
-
|
|
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."
|
|
2230
3536
|
}
|
|
2231
3537
|
}
|
|
2232
3538
|
},
|
|
2233
3539
|
"eventLog": {
|
|
2234
3540
|
"type": "object",
|
|
2235
|
-
"description": "RFC 0036
|
|
3541
|
+
"description": "RFC 0036 \u2014 Event-log multi-engine advertisement. Optional v1.",
|
|
2236
3542
|
"additionalProperties": false,
|
|
2237
3543
|
"properties": {
|
|
2238
3544
|
"crossEngineOrdering": {
|
|
2239
3545
|
"type": "object",
|
|
2240
3546
|
"additionalProperties": false,
|
|
2241
|
-
"required": [
|
|
3547
|
+
"required": [
|
|
3548
|
+
"supported"
|
|
3549
|
+
],
|
|
2242
3550
|
"properties": {
|
|
2243
3551
|
"supported": {
|
|
2244
3552
|
"type": "boolean",
|
|
@@ -2246,7 +3554,11 @@
|
|
|
2246
3554
|
},
|
|
2247
3555
|
"orderingModel": {
|
|
2248
3556
|
"type": "string",
|
|
2249
|
-
"enum": [
|
|
3557
|
+
"enum": [
|
|
3558
|
+
"lamport",
|
|
3559
|
+
"vector-clock",
|
|
3560
|
+
"global-sequencer"
|
|
3561
|
+
],
|
|
2250
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)."
|
|
2251
3563
|
}
|
|
2252
3564
|
}
|
|
@@ -2259,12 +3571,26 @@
|
|
|
2259
3571
|
"properties": {
|
|
2260
3572
|
"defaultMode": {
|
|
2261
3573
|
"type": "string",
|
|
2262
|
-
"enum": [
|
|
2263
|
-
|
|
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."
|
|
2264
3581
|
},
|
|
2265
3582
|
"supportedClasses": {
|
|
2266
3583
|
"type": "array",
|
|
2267
|
-
"items": {
|
|
3584
|
+
"items": {
|
|
3585
|
+
"type": "string",
|
|
3586
|
+
"enum": [
|
|
3587
|
+
"public",
|
|
3588
|
+
"pii",
|
|
3589
|
+
"phi",
|
|
3590
|
+
"pci",
|
|
3591
|
+
"regulated"
|
|
3592
|
+
]
|
|
3593
|
+
},
|
|
2268
3594
|
"uniqueItems": true,
|
|
2269
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."
|
|
2270
3596
|
}
|
|
@@ -2274,7 +3600,9 @@
|
|
|
2274
3600
|
"production": {
|
|
2275
3601
|
"type": "object",
|
|
2276
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.",
|
|
2277
|
-
"required": [
|
|
3603
|
+
"required": [
|
|
3604
|
+
"supported"
|
|
3605
|
+
],
|
|
2278
3606
|
"properties": {
|
|
2279
3607
|
"supported": {
|
|
2280
3608
|
"type": "boolean",
|
|
@@ -2282,11 +3610,11 @@
|
|
|
2282
3610
|
},
|
|
2283
3611
|
"backpressure": {
|
|
2284
3612
|
"type": "object",
|
|
2285
|
-
"description": "Backpressure envelope advertisement (production-profile.md
|
|
3613
|
+
"description": "Backpressure envelope advertisement (production-profile.md \u00a7Backpressure).",
|
|
2286
3614
|
"properties": {
|
|
2287
3615
|
"supported": {
|
|
2288
3616
|
"type": "boolean",
|
|
2289
|
-
"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."
|
|
2290
3618
|
},
|
|
2291
3619
|
"inflightCap": {
|
|
2292
3620
|
"type": "integer",
|
|
@@ -2297,14 +3625,14 @@
|
|
|
2297
3625
|
"type": "integer",
|
|
2298
3626
|
"minimum": 0,
|
|
2299
3627
|
"maximum": 86400,
|
|
2300
|
-
"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)."
|
|
2301
3629
|
}
|
|
2302
3630
|
},
|
|
2303
3631
|
"additionalProperties": false
|
|
2304
3632
|
},
|
|
2305
3633
|
"retention": {
|
|
2306
3634
|
"type": "object",
|
|
2307
|
-
"description": "Event-retention advertisement (production-profile.md
|
|
3635
|
+
"description": "Event-retention advertisement (production-profile.md \u00a7\"Event retention\").",
|
|
2308
3636
|
"properties": {
|
|
2309
3637
|
"supported": {
|
|
2310
3638
|
"type": "boolean",
|
|
@@ -2313,18 +3641,18 @@
|
|
|
2313
3641
|
"minWindowSeconds": {
|
|
2314
3642
|
"type": "integer",
|
|
2315
3643
|
"minimum": 604800,
|
|
2316
|
-
"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."
|
|
2317
3645
|
},
|
|
2318
3646
|
"testForceExpire": {
|
|
2319
3647
|
"type": "boolean",
|
|
2320
|
-
"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."
|
|
2321
3649
|
}
|
|
2322
3650
|
},
|
|
2323
3651
|
"additionalProperties": false
|
|
2324
3652
|
},
|
|
2325
3653
|
"debugBundle": {
|
|
2326
3654
|
"type": "object",
|
|
2327
|
-
"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).",
|
|
2328
3656
|
"properties": {
|
|
2329
3657
|
"supported": {
|
|
2330
3658
|
"type": "boolean",
|
|
@@ -2332,7 +3660,7 @@
|
|
|
2332
3660
|
},
|
|
2333
3661
|
"truncationMetadata": {
|
|
2334
3662
|
"type": "boolean",
|
|
2335
|
-
"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."
|
|
2336
3664
|
}
|
|
2337
3665
|
},
|
|
2338
3666
|
"additionalProperties": false
|
|
@@ -2346,13 +3674,16 @@
|
|
|
2346
3674
|
"properties": {
|
|
2347
3675
|
"profiles": {
|
|
2348
3676
|
"type": "array",
|
|
2349
|
-
"items": {
|
|
3677
|
+
"items": {
|
|
3678
|
+
"type": "string",
|
|
3679
|
+
"minLength": 1
|
|
3680
|
+
},
|
|
2350
3681
|
"uniqueItems": true,
|
|
2351
|
-
"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."
|
|
2352
3683
|
},
|
|
2353
3684
|
"rotation": {
|
|
2354
3685
|
"type": "object",
|
|
2355
|
-
"description": "API-key rotation advertisement (auth-profiles.md
|
|
3686
|
+
"description": "API-key rotation advertisement (auth-profiles.md \u00a7`openwop-auth-api-key-rotation`).",
|
|
2356
3687
|
"properties": {
|
|
2357
3688
|
"supported": {
|
|
2358
3689
|
"type": "boolean",
|
|
@@ -2361,16 +3692,18 @@
|
|
|
2361
3692
|
"minGraceSeconds": {
|
|
2362
3693
|
"type": "integer",
|
|
2363
3694
|
"minimum": 0,
|
|
2364
|
-
"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."
|
|
2365
3696
|
}
|
|
2366
3697
|
},
|
|
2367
3698
|
"additionalProperties": false
|
|
2368
3699
|
},
|
|
2369
3700
|
"oauth2": {
|
|
2370
3701
|
"type": "object",
|
|
2371
|
-
"description": "OAuth2 client-credentials advertisement (auth-profiles.md
|
|
3702
|
+
"description": "OAuth2 client-credentials advertisement (auth-profiles.md \u00a7`openwop-auth-oauth2-client-credentials`).",
|
|
2372
3703
|
"properties": {
|
|
2373
|
-
"supported": {
|
|
3704
|
+
"supported": {
|
|
3705
|
+
"type": "boolean"
|
|
3706
|
+
},
|
|
2374
3707
|
"issuer": {
|
|
2375
3708
|
"type": "string",
|
|
2376
3709
|
"format": "uri",
|
|
@@ -2382,7 +3715,10 @@
|
|
|
2382
3715
|
},
|
|
2383
3716
|
"supportedAlgorithms": {
|
|
2384
3717
|
"type": "array",
|
|
2385
|
-
"items": {
|
|
3718
|
+
"items": {
|
|
3719
|
+
"type": "string",
|
|
3720
|
+
"minLength": 1
|
|
3721
|
+
},
|
|
2386
3722
|
"uniqueItems": true,
|
|
2387
3723
|
"description": "JWS signing algorithms the host accepts (canonical: RS256, ES256). Hosts MUST reject tokens signed with algorithms outside this list."
|
|
2388
3724
|
}
|
|
@@ -2391,12 +3727,17 @@
|
|
|
2391
3727
|
},
|
|
2392
3728
|
"oidc": {
|
|
2393
3729
|
"type": "object",
|
|
2394
|
-
"description": "OIDC user-bearer advertisement (auth-profiles.md
|
|
3730
|
+
"description": "OIDC user-bearer advertisement (auth-profiles.md \u00a7`openwop-auth-oidc-user-bearer`).",
|
|
2395
3731
|
"properties": {
|
|
2396
|
-
"supported": {
|
|
3732
|
+
"supported": {
|
|
3733
|
+
"type": "boolean"
|
|
3734
|
+
},
|
|
2397
3735
|
"issuers": {
|
|
2398
3736
|
"type": "array",
|
|
2399
|
-
"items": {
|
|
3737
|
+
"items": {
|
|
3738
|
+
"type": "string",
|
|
3739
|
+
"format": "uri"
|
|
3740
|
+
},
|
|
2400
3741
|
"minItems": 1,
|
|
2401
3742
|
"uniqueItems": true,
|
|
2402
3743
|
"description": "Trusted OIDC issuer URLs. The host accepts tokens whose `iss` claim matches any entry."
|
|
@@ -2407,8 +3748,12 @@
|
|
|
2407
3748
|
},
|
|
2408
3749
|
"supportedScopeMapping": {
|
|
2409
3750
|
"type": "string",
|
|
2410
|
-
"enum": [
|
|
2411
|
-
|
|
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)."
|
|
2412
3757
|
},
|
|
2413
3758
|
"introspectionIntervalSeconds": {
|
|
2414
3759
|
"type": "integer",
|
|
@@ -2420,20 +3765,82 @@
|
|
|
2420
3765
|
},
|
|
2421
3766
|
"mtls": {
|
|
2422
3767
|
"type": "object",
|
|
2423
|
-
"description": "mTLS advertisement (auth-profiles.md
|
|
3768
|
+
"description": "mTLS advertisement (auth-profiles.md \u00a7`openwop-auth-mtls`).",
|
|
2424
3769
|
"properties": {
|
|
2425
|
-
"supported": {
|
|
3770
|
+
"supported": {
|
|
3771
|
+
"type": "boolean"
|
|
3772
|
+
},
|
|
2426
3773
|
"required": {
|
|
2427
3774
|
"type": "boolean",
|
|
2428
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."
|
|
2429
3776
|
},
|
|
2430
3777
|
"subjectMapping": {
|
|
2431
3778
|
"type": "string",
|
|
2432
|
-
"enum": [
|
|
3779
|
+
"enum": [
|
|
3780
|
+
"cn",
|
|
3781
|
+
"san-dns",
|
|
3782
|
+
"san-uri"
|
|
3783
|
+
],
|
|
2433
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."
|
|
2434
3785
|
}
|
|
2435
3786
|
},
|
|
2436
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
|
+
}
|
|
2437
3844
|
}
|
|
2438
3845
|
},
|
|
2439
3846
|
"additionalProperties": true
|
|
@@ -2444,7 +3851,7 @@
|
|
|
2444
3851
|
"properties": {
|
|
2445
3852
|
"authScoped": {
|
|
2446
3853
|
"type": "object",
|
|
2447
|
-
"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.",
|
|
2448
3855
|
"properties": {
|
|
2449
3856
|
"supported": {
|
|
2450
3857
|
"type": "boolean",
|
|
@@ -2452,7 +3859,10 @@
|
|
|
2452
3859
|
},
|
|
2453
3860
|
"mode": {
|
|
2454
3861
|
"type": "string",
|
|
2455
|
-
"enum": [
|
|
3862
|
+
"enum": [
|
|
3863
|
+
"same-endpoint",
|
|
3864
|
+
"extension-endpoint"
|
|
3865
|
+
],
|
|
2456
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."
|
|
2457
3867
|
},
|
|
2458
3868
|
"endpointPath": {
|
|
@@ -2494,9 +3904,13 @@
|
|
|
2494
3904
|
},
|
|
2495
3905
|
"content": {
|
|
2496
3906
|
"type": "object",
|
|
2497
|
-
"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.",
|
|
2498
3908
|
"additionalProperties": false,
|
|
2499
|
-
"required": [
|
|
3909
|
+
"required": [
|
|
3910
|
+
"supported",
|
|
3911
|
+
"baseLocale",
|
|
3912
|
+
"supportedLocales"
|
|
3913
|
+
],
|
|
2500
3914
|
"properties": {
|
|
2501
3915
|
"supported": {
|
|
2502
3916
|
"type": "boolean",
|
|
@@ -2514,13 +3928,13 @@
|
|
|
2514
3928
|
"type": "string",
|
|
2515
3929
|
"pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8}){0,3}$"
|
|
2516
3930
|
},
|
|
2517
|
-
"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`."
|
|
2518
3932
|
}
|
|
2519
3933
|
}
|
|
2520
3934
|
},
|
|
2521
3935
|
"portability": {
|
|
2522
3936
|
"type": "object",
|
|
2523
|
-
"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.",
|
|
2524
3938
|
"additionalProperties": false,
|
|
2525
3939
|
"properties": {
|
|
2526
3940
|
"export": {
|
|
@@ -2535,7 +3949,18 @@
|
|
|
2535
3949
|
},
|
|
2536
3950
|
"kinds": {
|
|
2537
3951
|
"type": "array",
|
|
2538
|
-
"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
|
+
},
|
|
2539
3964
|
"uniqueItems": true,
|
|
2540
3965
|
"description": "Estate kinds this host can export/import."
|
|
2541
3966
|
},
|
|
@@ -2545,8 +3970,26 @@
|
|
|
2545
3970
|
"description": "Import supports a no-write plan preview (`POST /import?dryRun=true`). MUST be true if `import` is true."
|
|
2546
3971
|
}
|
|
2547
3972
|
},
|
|
2548
|
-
"if": {
|
|
2549
|
-
|
|
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
|
+
}
|
|
2550
3993
|
},
|
|
2551
3994
|
"interrupt": {
|
|
2552
3995
|
"type": "object",
|
|
@@ -2556,17 +3999,32 @@
|
|
|
2556
3999
|
"approverRouting": {
|
|
2557
4000
|
"type": "object",
|
|
2558
4001
|
"additionalProperties": false,
|
|
2559
|
-
"required": [
|
|
4002
|
+
"required": [
|
|
4003
|
+
"supported"
|
|
4004
|
+
],
|
|
2560
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`).",
|
|
2561
4006
|
"properties": {
|
|
2562
|
-
"supported": {
|
|
4007
|
+
"supported": {
|
|
4008
|
+
"type": "boolean",
|
|
4009
|
+
"description": "Host honors the RFC 0104 approver-routing fields."
|
|
4010
|
+
},
|
|
2563
4011
|
"refKinds": {
|
|
2564
4012
|
"type": "array",
|
|
2565
|
-
"items": {
|
|
4013
|
+
"items": {
|
|
4014
|
+
"type": "string",
|
|
4015
|
+
"enum": [
|
|
4016
|
+
"group",
|
|
4017
|
+
"role"
|
|
4018
|
+
]
|
|
4019
|
+
},
|
|
2566
4020
|
"uniqueItems": true,
|
|
2567
|
-
"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."
|
|
2568
4022
|
},
|
|
2569
|
-
"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
|
+
}
|
|
2570
4028
|
}
|
|
2571
4029
|
}
|
|
2572
4030
|
}
|
|
@@ -2574,7 +4032,7 @@
|
|
|
2574
4032
|
"restTransport": {
|
|
2575
4033
|
"type": "object",
|
|
2576
4034
|
"additionalProperties": false,
|
|
2577
|
-
"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.",
|
|
2578
4036
|
"properties": {
|
|
2579
4037
|
"conditionalRunGet": {
|
|
2580
4038
|
"type": "boolean",
|
|
@@ -2582,15 +4040,22 @@
|
|
|
2582
4040
|
},
|
|
2583
4041
|
"contentEncodings": {
|
|
2584
4042
|
"type": "array",
|
|
2585
|
-
"items": {
|
|
2586
|
-
|
|
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."
|
|
2587
4052
|
}
|
|
2588
4053
|
}
|
|
2589
4054
|
},
|
|
2590
4055
|
"a2uiSurface": {
|
|
2591
4056
|
"type": "object",
|
|
2592
4057
|
"additionalProperties": false,
|
|
2593
|
-
"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.",
|
|
2594
4059
|
"properties": {
|
|
2595
4060
|
"deltaTransport": {
|
|
2596
4061
|
"type": "boolean",
|