@openwop/spec-artifacts 2.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/CORPUS-STAMP.json +234 -0
  2. package/LICENSE +201 -0
  3. package/README.md +7 -0
  4. package/api/.redocly.lint-ignore.yaml +22 -0
  5. package/api/asyncapi.yaml +834 -0
  6. package/api/grpc/openwop.proto +251 -0
  7. package/api/openapi.yaml +2693 -0
  8. package/api/redocly.yaml +23 -0
  9. package/api/seams-v2.yaml +680 -0
  10. package/api/v2/asyncapi.yaml +528 -0
  11. package/api/v2/openapi.yaml +3139 -0
  12. package/api/v2/redocly.yaml +16 -0
  13. package/package.json +10 -0
  14. package/schemas/README.md +144 -0
  15. package/schemas/a2a-task-state.schema.json +78 -0
  16. package/schemas/a2ui-surface-delta-frame.schema.json +48 -0
  17. package/schemas/agent-deployment-transition.schema.json +49 -0
  18. package/schemas/agent-deployment.schema.json +54 -0
  19. package/schemas/agent-eval-suite.schema.json +140 -0
  20. package/schemas/agent-inventory-response.schema.json +115 -0
  21. package/schemas/agent-manifest.schema.json +156 -0
  22. package/schemas/agent-org-chart.schema.json +82 -0
  23. package/schemas/agent-ref.schema.json +63 -0
  24. package/schemas/agent-roster-entry.schema.json +81 -0
  25. package/schemas/agent-roster-response.schema.json +21 -0
  26. package/schemas/ai-envelope.schema.json +134 -0
  27. package/schemas/annotation-create.schema.json +37 -0
  28. package/schemas/annotation.schema.json +56 -0
  29. package/schemas/artifact-type-pack-manifest.schema.json +244 -0
  30. package/schemas/audit-verify-result.schema.json +90 -0
  31. package/schemas/budget-policy.schema.json +18 -0
  32. package/schemas/capabilities.schema.json +4160 -0
  33. package/schemas/certification-bundle-v2.schema.json +118 -0
  34. package/schemas/channel-presence-payload.schema.json +41 -0
  35. package/schemas/channel-written-payload.schema.json +55 -0
  36. package/schemas/chat-card-pack-manifest.schema.json +253 -0
  37. package/schemas/compact-tool-descriptor.schema.json +51 -0
  38. package/schemas/compensation-policy.schema.json +64 -0
  39. package/schemas/conformance-certification-bundle.schema.json +86 -0
  40. package/schemas/connection-pack-manifest.schema.json +353 -0
  41. package/schemas/conversation-event.schema.json +168 -0
  42. package/schemas/conversation-turn.schema.json +117 -0
  43. package/schemas/core-conformance-mock-agent-config.schema.json +152 -0
  44. package/schemas/credential-provenance.schema.json +18 -0
  45. package/schemas/credential-reference.schema.json +21 -0
  46. package/schemas/debug-bundle.schema.json +196 -0
  47. package/schemas/dispatch-config.schema.json +112 -0
  48. package/schemas/envelopes/clarification.request.schema.json +52 -0
  49. package/schemas/envelopes/error.schema.json +30 -0
  50. package/schemas/envelopes/media.audio.schema.json +38 -0
  51. package/schemas/envelopes/media.file.schema.json +37 -0
  52. package/schemas/envelopes/media.image.schema.json +33 -0
  53. package/schemas/envelopes/schema.request.schema.json +26 -0
  54. package/schemas/envelopes/schema.response.schema.json +22 -0
  55. package/schemas/envelopes/ui.a2ui-surface.schema.json +154 -0
  56. package/schemas/error-envelope.schema.json +25 -0
  57. package/schemas/eval-summary.schema.json +92 -0
  58. package/schemas/export-bundle.schema.json +66 -0
  59. package/schemas/form-content-pack-manifest.schema.json +243 -0
  60. package/schemas/frontend-plugin-manifest.schema.json +109 -0
  61. package/schemas/goal.schema.json +104 -0
  62. package/schemas/heartbeat-evaluated.schema.json +14 -0
  63. package/schemas/heartbeat-state-changed.schema.json +14 -0
  64. package/schemas/localized-content-language-settings.schema.json +26 -0
  65. package/schemas/localized-content-page-response.schema.json +60 -0
  66. package/schemas/localized-content-page.schema.json +62 -0
  67. package/schemas/localized-content-section.schema.json +51 -0
  68. package/schemas/memory-entry.schema.json +36 -0
  69. package/schemas/memory-list-options.schema.json +37 -0
  70. package/schemas/node-pack-manifest.schema.json +654 -0
  71. package/schemas/orchestrator-decision.schema.json +90 -0
  72. package/schemas/org-chart-responsibility-view.schema.json +26 -0
  73. package/schemas/pack-lockfile.schema.json +108 -0
  74. package/schemas/prompt-kind.schema.json +8 -0
  75. package/schemas/prompt-pack-manifest.schema.json +117 -0
  76. package/schemas/prompt-ref.schema.json +40 -0
  77. package/schemas/prompt-template.schema.json +149 -0
  78. package/schemas/proposal.schema.json +84 -0
  79. package/schemas/registry-version-manifest.schema.json +208 -0
  80. package/schemas/residency.schema.json +16 -0
  81. package/schemas/run-ancestry-response.schema.json +54 -0
  82. package/schemas/run-diff-response.schema.json +64 -0
  83. package/schemas/run-event-payloads.schema.json +4452 -0
  84. package/schemas/run-event.schema.json +211 -0
  85. package/schemas/run-options.schema.json +80 -0
  86. package/schemas/run-orchestrator-decided-event.schema.json +20 -0
  87. package/schemas/run-snapshot.schema.json +148 -0
  88. package/schemas/security-advisory.schema.json +109 -0
  89. package/schemas/self-hosted-runner-dispatch-frame.schema.json +79 -0
  90. package/schemas/self-hosted-runner-registration.schema.json +53 -0
  91. package/schemas/self-hosted-runner-result-frame.schema.json +38 -0
  92. package/schemas/subject.schema.json +56 -0
  93. package/schemas/suspend-request.schema.json +207 -0
  94. package/schemas/tool-descriptor.schema.json +63 -0
  95. package/schemas/trigger-event.schema.json +222 -0
  96. package/schemas/trigger-subscription-registration.schema.json +67 -0
  97. package/schemas/trigger-subscription.schema.json +26 -0
  98. package/schemas/ui-plugin-message.schema.json +90 -0
  99. package/schemas/v2/a2a-task-state.schema.json +102 -0
  100. package/schemas/v2/a2ui-surface-delta-frame.schema.json +62 -0
  101. package/schemas/v2/agent-deployment-transition.schema.json +67 -0
  102. package/schemas/v2/agent-deployment.schema.json +68 -0
  103. package/schemas/v2/agent-eval-suite.schema.json +214 -0
  104. package/schemas/v2/agent-inventory-response.schema.json +172 -0
  105. package/schemas/v2/agent-manifest.schema.json +218 -0
  106. package/schemas/v2/agent-org-chart.schema.json +149 -0
  107. package/schemas/v2/agent-ref.schema.json +67 -0
  108. package/schemas/v2/agent-roster-entry.schema.json +104 -0
  109. package/schemas/v2/agent-roster-response.schema.json +27 -0
  110. package/schemas/v2/ai-envelope.schema.json +167 -0
  111. package/schemas/v2/annotation-create.schema.json +109 -0
  112. package/schemas/v2/annotation.schema.json +142 -0
  113. package/schemas/v2/artifact-type-pack-manifest.schema.json +245 -0
  114. package/schemas/v2/audit-verify-result.schema.json +110 -0
  115. package/schemas/v2/budget-policy.schema.json +61 -0
  116. package/schemas/v2/capabilities.schema.json +7644 -0
  117. package/schemas/v2/certification-bundle.schema.json +401 -0
  118. package/schemas/v2/channel-presence-payload.schema.json +60 -0
  119. package/schemas/v2/channel-written-payload.schema.json +64 -0
  120. package/schemas/v2/chat-card-pack-manifest.schema.json +254 -0
  121. package/schemas/v2/compact-tool-descriptor.schema.json +108 -0
  122. package/schemas/v2/compensation-policy.schema.json +91 -0
  123. package/schemas/v2/compensation-projection.schema.json +95 -0
  124. package/schemas/v2/configurable.schema.json +110 -0
  125. package/schemas/v2/connection-pack-manifest.schema.json +354 -0
  126. package/schemas/v2/conversation-event.schema.json +281 -0
  127. package/schemas/v2/conversation-turn.schema.json +165 -0
  128. package/schemas/v2/credential-provenance.schema.json +62 -0
  129. package/schemas/v2/credential-reference.schema.json +28 -0
  130. package/schemas/v2/debug-bundle.schema.json +312 -0
  131. package/schemas/v2/dispatch-config.schema.json +147 -0
  132. package/schemas/v2/effect-ledger-projection.schema.json +71 -0
  133. package/schemas/v2/effect-seam-manifest.schema.json +98 -0
  134. package/schemas/v2/envelopes/clarification.request.schema.json +59 -0
  135. package/schemas/v2/envelopes/error.schema.json +35 -0
  136. package/schemas/v2/envelopes/media.audio.schema.json +41 -0
  137. package/schemas/v2/envelopes/media.file.schema.json +40 -0
  138. package/schemas/v2/envelopes/media.image.schema.json +36 -0
  139. package/schemas/v2/envelopes/schema.request.schema.json +29 -0
  140. package/schemas/v2/envelopes/schema.response.schema.json +26 -0
  141. package/schemas/v2/envelopes/ui.a2ui-surface.schema.json +292 -0
  142. package/schemas/v2/error-envelope.schema.json +229 -0
  143. package/schemas/v2/eval-summary.schema.json +166 -0
  144. package/schemas/v2/export-bundle.schema.json +94 -0
  145. package/schemas/v2/form-content-pack-manifest.schema.json +241 -0
  146. package/schemas/v2/frontend-plugin-manifest.schema.json +152 -0
  147. package/schemas/v2/goal.schema.json +188 -0
  148. package/schemas/v2/heartbeat-evaluated.schema.json +34 -0
  149. package/schemas/v2/heartbeat-state-changed.schema.json +31 -0
  150. package/schemas/v2/ids.schema.json +31 -0
  151. package/schemas/v2/localized-content-language-settings.schema.json +34 -0
  152. package/schemas/v2/localized-content-page-response.schema.json +94 -0
  153. package/schemas/v2/localized-content-page.schema.json +87 -0
  154. package/schemas/v2/localized-content-section.schema.json +63 -0
  155. package/schemas/v2/memory-entry.schema.json +45 -0
  156. package/schemas/v2/memory-list-options.schema.json +41 -0
  157. package/schemas/v2/node-pack-manifest.schema.json +657 -0
  158. package/schemas/v2/orchestrator-decision.schema.json +120 -0
  159. package/schemas/v2/org-chart-responsibility-view.schema.json +36 -0
  160. package/schemas/v2/pack-lockfile.schema.json +139 -0
  161. package/schemas/v2/prompt-kind.schema.json +14 -0
  162. package/schemas/v2/prompt-pack-manifest.schema.json +118 -0
  163. package/schemas/v2/prompt-ref.schema.json +42 -0
  164. package/schemas/v2/prompt-template.schema.json +209 -0
  165. package/schemas/v2/proposal.schema.json +145 -0
  166. package/schemas/v2/registry-version-manifest.schema.json +292 -0
  167. package/schemas/v2/residency.schema.json +19 -0
  168. package/schemas/v2/run-ancestry-response.schema.json +68 -0
  169. package/schemas/v2/run-diff-response.schema.json +80 -0
  170. package/schemas/v2/run-event-payloads.schema.json +4588 -0
  171. package/schemas/v2/run-event.schema.json +324 -0
  172. package/schemas/v2/run-options.schema.json +90 -0
  173. package/schemas/v2/run-orchestrator-decided-event.schema.json +22 -0
  174. package/schemas/v2/run-snapshot.schema.json +207 -0
  175. package/schemas/v2/security-advisory.schema.json +138 -0
  176. package/schemas/v2/self-hosted-runner-dispatch-frame.schema.json +119 -0
  177. package/schemas/v2/self-hosted-runner-registration.schema.json +74 -0
  178. package/schemas/v2/self-hosted-runner-result-frame.schema.json +47 -0
  179. package/schemas/v2/subject-link.schema.json +69 -0
  180. package/schemas/v2/subject.schema.json +597 -0
  181. package/schemas/v2/suspend-request.schema.json +370 -0
  182. package/schemas/v2/tool-descriptor.schema.json +150 -0
  183. package/schemas/v2/trigger-event.schema.json +508 -0
  184. package/schemas/v2/trigger-subscription-registration.schema.json +99 -0
  185. package/schemas/v2/trigger-subscription.schema.json +79 -0
  186. package/schemas/v2/ui-plugin-message.schema.json +149 -0
  187. package/schemas/v2/workflow-chain-pack-manifest.schema.json +610 -0
  188. package/schemas/v2/workflow-definition.schema.json +864 -0
  189. package/schemas/v2/workload-identity.schema.json +115 -0
  190. package/schemas/v2/workspace-file-create.schema.json +23 -0
  191. package/schemas/v2/workspace-file.schema.json +45 -0
  192. package/schemas/workflow-chain-pack-manifest.schema.json +615 -0
  193. package/schemas/workflow-definition.schema.json +850 -0
  194. package/schemas/workload-identity.schema.json +79 -0
  195. package/schemas/workspace-file-create.schema.json +20 -0
  196. package/schemas/workspace-file.schema.json +39 -0
  197. package/spec/v1/alias-detectors.json +283 -0
  198. package/spec/v1/capability-declaration-classes.json +176 -0
  199. package/spec/v1/core-standard-manifest.json +423 -0
  200. package/spec/v1/deprecations.json +854 -0
  201. package/spec/v1/deprecations.schema.json +187 -0
  202. package/spec/v1/event-codemap.json +1089 -0
  203. package/spec/v1/event-codemap.schema.json +41 -0
  204. package/spec/v1/extensions.json +1273 -0
  205. package/spec/v1/gaps.json +14581 -0
  206. package/spec/v1/gaps.schema.json +55 -0
  207. package/spec/v1/migrations.json +1822 -0
  208. package/spec/v1/migrations.schema.json +44 -0
  209. package/spec/v1/operation-path-manifest.json +462 -0
  210. package/spec/v1/spec-gaps.json +4823 -0
  211. package/spec/v2/declaration.json +1862 -0
  212. package/spec/v2/declaration.schema.json +305 -0
  213. package/spec/v2/errors.json +837 -0
  214. package/spec/v2/event-codemap.json +1099 -0
  215. package/spec/v2/event-codemap.schema.json +114 -0
  216. package/spec/v2/ext/provider-idempotency/registry.json +6 -0
  217. package/spec/v2/facets/a2a.schema.json +51 -0
  218. package/spec/v2/facets/aiProviders.schema.json +56 -0
  219. package/spec/v2/facets/auth.schema.json +91 -0
  220. package/spec/v2/facets/heartbeat.schema.json +20 -0
  221. package/spec/v2/facets/interrupt.schema.json +29 -0
  222. package/spec/v2/facets/mcp.schema.json +81 -0
  223. package/spec/v2/facets/replay.schema.json +34 -0
  224. package/spec/v2/facets/sandbox.schema.json +31 -0
  225. package/spec/v2/facets/webhooks.schema.json +18 -0
  226. package/spec/v2/path-manifest.json +279 -0
  227. package/spec/v2/peer-dependency-aliases.json +165 -0
  228. package/spec/v2/profiles.json +45 -0
  229. package/spec/v2/release.json +6 -0
@@ -0,0 +1,864 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openwop.dev/spec/v2/workflow-definition.schema.json",
4
+ "title": "WorkflowDefinition",
5
+ "description": "DAG of typed nodes, edges, triggers, and variables that an OpenWOP host executes. Canonical OpenWOP v1 workflow-definition shape.",
6
+ "type": "object",
7
+ "required": [
8
+ "id",
9
+ "name",
10
+ "version",
11
+ "nodes",
12
+ "edges",
13
+ "triggers",
14
+ "variables",
15
+ "metadata",
16
+ "settings"
17
+ ],
18
+ "properties": {
19
+ "id": {
20
+ "type": "string",
21
+ "description": "Unique workflow identifier. Recommended format: lowercase, hyphen-separated.",
22
+ "minLength": 1,
23
+ "maxLength": 128,
24
+ "pattern": "^[a-z][a-z0-9_-]*$"
25
+ },
26
+ "name": {
27
+ "type": "string",
28
+ "minLength": 1,
29
+ "maxLength": 256
30
+ },
31
+ "description": {
32
+ "type": "string"
33
+ },
34
+ "version": {
35
+ "type": "string",
36
+ "description": "Semver-like workflow version. Tracked separately from engineVersion + eventLogSchemaVersion (see version-negotiation.md).",
37
+ "minLength": 1
38
+ },
39
+ "type": {
40
+ "type": "string",
41
+ "description": "Optional category for filtering."
42
+ },
43
+ "isActive": {
44
+ "type": "boolean"
45
+ },
46
+ "status": {
47
+ "type": "string",
48
+ "enum": [
49
+ "active",
50
+ "inactive",
51
+ "draft",
52
+ "archived"
53
+ ]
54
+ },
55
+ "tenantId": {
56
+ "$ref": "ids.schema.json#/$defs/tenantId",
57
+ "description": "Optional tenant/workspace scoping. The protocol uses the neutral term `tenantId`."
58
+ },
59
+ "scopeId": {
60
+ "type": "string",
61
+ "description": "Optional project/scope correlation. The protocol uses the neutral term `scopeId`."
62
+ },
63
+ "slug": {
64
+ "type": "string",
65
+ "description": "URL-friendly slug.",
66
+ "pattern": "^[a-z0-9][a-z0-9_-]*$"
67
+ },
68
+ "nodes": {
69
+ "type": "array",
70
+ "items": {
71
+ "$ref": "#/$defs/WorkflowNode"
72
+ },
73
+ "minItems": 1
74
+ },
75
+ "edges": {
76
+ "type": "array",
77
+ "items": {
78
+ "$ref": "#/$defs/WorkflowEdge"
79
+ }
80
+ },
81
+ "triggers": {
82
+ "type": "array",
83
+ "items": {
84
+ "$ref": "#/$defs/WorkflowTrigger"
85
+ }
86
+ },
87
+ "variables": {
88
+ "type": "array",
89
+ "items": {
90
+ "$ref": "#/$defs/WorkflowVariable"
91
+ }
92
+ },
93
+ "groups": {
94
+ "type": "array",
95
+ "items": {
96
+ "$ref": "#/$defs/NodeGroup"
97
+ },
98
+ "description": "Visual node groups (organizational only; do not affect execution)."
99
+ },
100
+ "channels": {
101
+ "description": "Optional typed state channels (see channels-and-reducers.md). When present, channel-aware mode applies.",
102
+ "type": "object",
103
+ "additionalProperties": {
104
+ "$ref": "#/$defs/ChannelDeclaration"
105
+ }
106
+ },
107
+ "configurableSchema": {
108
+ "description": "Optional JSON Schema 2020-12 declaring which RunOptions.configurable keys this workflow accepts. When present, hosts MUST validate POST /v1/runs `configurable` payloads against this schema and reject mismatches with `validation_error`. Hosts MUST surface this schema on GET /v1/workflows/{workflowId} so clients can pre-flight-validate. See run-options.md §'Per-workflow configurableSchema'. Additive in v1.1.",
109
+ "type": "object",
110
+ "additionalProperties": true
111
+ },
112
+ "defaults": {
113
+ "type": "object",
114
+ "additionalProperties": false,
115
+ "description": "RFC 0029 §B. Workflow-author-controlled per-kind fallback values that apply at resolution chain layer 3 (`workflow-defaults`) per `spec/v1/prompts.md` §\"Resolution chain (normative)\". Applied when neither the node (layer 1) nor the node's bound agent (layer 2) specifies a value for the kind. Future RFCs MAY add sibling defaults (e.g., `defaults.temperature`, `defaults.modelClass`) without colliding.",
116
+ "properties": {
117
+ "promptRefs": {
118
+ "type": "object",
119
+ "additionalProperties": false,
120
+ "description": "Per-kind PromptRef fallbacks for layer 3 of the resolution chain.",
121
+ "properties": {
122
+ "system": {
123
+ "$ref": "./prompt-ref.schema.json"
124
+ },
125
+ "user": {
126
+ "$ref": "./prompt-ref.schema.json"
127
+ },
128
+ "few-shot": {
129
+ "$ref": "./prompt-ref.schema.json"
130
+ },
131
+ "schema-hint": {
132
+ "$ref": "./prompt-ref.schema.json"
133
+ }
134
+ }
135
+ }
136
+ }
137
+ },
138
+ "metadata": {
139
+ "$ref": "#/$defs/WorkflowMetadata"
140
+ },
141
+ "settings": {
142
+ "$ref": "#/$defs/WorkflowSettings"
143
+ },
144
+ "acceptsInheritedArtifacts": {
145
+ "type": "array",
146
+ "items": {
147
+ "type": "object",
148
+ "additionalProperties": true
149
+ },
150
+ "description": "Declares which inherited artifacts this workflow accepts when run as a child of a sub-workflow."
151
+ },
152
+ "createdAt": {
153
+ "type": "string",
154
+ "format": "date-time"
155
+ },
156
+ "updatedAt": {
157
+ "type": "string",
158
+ "format": "date-time"
159
+ }
160
+ },
161
+ "additionalProperties": false,
162
+ "$defs": {
163
+ "WorkflowNode": {
164
+ "type": "object",
165
+ "required": [
166
+ "id",
167
+ "typeId",
168
+ "name",
169
+ "position",
170
+ "config",
171
+ "inputs"
172
+ ],
173
+ "properties": {
174
+ "id": {
175
+ "type": "string",
176
+ "minLength": 1,
177
+ "description": "Node identifier, unique within the workflow. Intentionally has NO `maxLength` — RFC 0013 chain expansion mints ids of the form `${chainIdSlug}_${expansionId}_${fragmentId}` where `chainIdSlug` is an unbounded reverse-DNS string, so an expanded node id can exceed any short cap. A host MUST NOT reject or truncate a node id by length (no host-imposed `maxLength` stricter than this schema)."
178
+ },
179
+ "typeId": {
180
+ "type": "string",
181
+ "description": "Canonical node type ID (e.g., 'core.ai.callPrompt', 'core.chat.approvalGate'). Reserved prefixes: 'core.*' for spec-canonical, 'vendor.<org>.*' for third-party.",
182
+ "minLength": 1,
183
+ "pattern": "^[a-z][a-zA-Z0-9._-]*$"
184
+ },
185
+ "name": {
186
+ "type": "string",
187
+ "minLength": 1
188
+ },
189
+ "position": {
190
+ "type": "object",
191
+ "required": [
192
+ "x",
193
+ "y"
194
+ ],
195
+ "properties": {
196
+ "x": {
197
+ "type": "number"
198
+ },
199
+ "y": {
200
+ "type": "number"
201
+ }
202
+ },
203
+ "additionalProperties": false
204
+ },
205
+ "config": {
206
+ "type": "object",
207
+ "description": "Node configuration (pre-execution constants). The shape is per-typeId — node-pack manifests declare each typeId's `configSchema` for install-time validation. By convention, the keys `systemPromptRef`, `userPromptRef`, and `additionalPromptRefs` MAY hold PromptRef values per `spec/v1/prompts.md` §\"PromptRef\" (RFC 0027). Hosts advertising `capabilities.prompts.supported: true` MUST resolve these keys; hosts without the capability MAY treat them as opaque strings. When both an inline body (e.g., `config.systemPrompt`) and a `*PromptRef` are present, the ref wins and the host MUST emit a `log.appended` warning with `code: \"prompt_ref_supersedes_inline\"` per RFC 0027 §C.",
208
+ "additionalProperties": true
209
+ },
210
+ "inputs": {
211
+ "type": "object",
212
+ "additionalProperties": {
213
+ "$ref": "#/$defs/PortValue"
214
+ },
215
+ "description": "Input port connections. Keys are port names; values are PortValue references."
216
+ },
217
+ "credentialsRef": {
218
+ "type": "string"
219
+ },
220
+ "settings": {
221
+ "type": "object",
222
+ "additionalProperties": true
223
+ },
224
+ "outputRole": {
225
+ "type": "string",
226
+ "enum": [
227
+ "primary",
228
+ "secondary"
229
+ ],
230
+ "description": "RFC 0065 — author hint that this terminal node's output is the workflow's primary deliverable (`primary`) or an auxiliary output (`secondary`). Advisory: hosts MUST execute the workflow identically regardless of value. Tooling MAY use the hint to pick which of N terminal nodes' outputs to surface as the run's canonical artifact. Unknown values + absent values fall back to default behavior (show all terminal outputs)."
231
+ },
232
+ "disabled": {
233
+ "type": "boolean",
234
+ "default": false
235
+ },
236
+ "notes": {
237
+ "type": "string"
238
+ },
239
+ "groupId": {
240
+ "type": "string"
241
+ },
242
+ "agent": {
243
+ "$ref": "agent-ref.schema.json",
244
+ "description": "Multi-Agent Shift Phase 1. Optional compile-time pinning of which agent executes this node. When set, the engine surfaces this AgentRef on the `RunSnapshot.agent` field while the node is active, and emits an `agent.handoff` event when control transitions from the prior node's agent (if different). Resolution at runtime: the engine MAY override via dispatch (RFC 0012 / `core.dispatch`) or orchestrator decision (RFC 0011); the node's `agent?` is the default authoring-time pin, not a hard binding."
245
+ },
246
+ "envelopeContract": {
247
+ "type": "object",
248
+ "additionalProperties": true
249
+ },
250
+ "artifactType": {
251
+ "type": "string",
252
+ "description": "Artifact type this node produces or reviews (first-class typed field — replaces the deprecated config.outputArtifactType bag entry)."
253
+ },
254
+ "cardType": {
255
+ "type": "string",
256
+ "description": "Explicit chat card type override (first-class typed field — replaces the deprecated config.chatCard bag entry)."
257
+ },
258
+ "outputSensitivity": {
259
+ "type": "object",
260
+ "additionalProperties": {
261
+ "type": "boolean"
262
+ },
263
+ "description": "Per-output-port sensitivity overrides. Map of port name → boolean. When true, the engine masks the named output value in `node.completed` event payloads. Layered on top of pack-level `nodes[].outputs[port].sensitive` declarations: workflow-level true takes precedence over pack-level false (and vice versa — last writer wins, but typically pack defaults are conservative and workflow overrides are explicit). See observability.md §Privacy classification (closes O5)."
264
+ },
265
+ "compensation": {
266
+ "type": "object",
267
+ "description": "RFC 0151 §B — the inverse action for this node. OPTIONAL and closed. `nodeTypeId` MUST resolve at registration, so an unwind cannot fail on a typo discovered only during a failure. Inputs MUST derive from RECORDED FACTS: prompt or model regeneration MUST NOT construct a compensation input during replay, because a compensation built from a re-inferred value is not the inverse of what was actually done. A host MUST reject a compensation cycle.",
268
+ "additionalProperties": false,
269
+ "required": [
270
+ "nodeTypeId"
271
+ ],
272
+ "properties": {
273
+ "nodeTypeId": {
274
+ "type": "string",
275
+ "minLength": 1,
276
+ "description": "Node type implementing the inverse action. MUST resolve at registration time."
277
+ },
278
+ "inputMapping": {
279
+ "type": "object",
280
+ "description": "Derived from recorded facts only — node outputs and run inputs already in the event log.",
281
+ "additionalProperties": true
282
+ },
283
+ "retry": {
284
+ "type": "object",
285
+ "additionalProperties": false,
286
+ "properties": {
287
+ "maxAttempts": {
288
+ "type": "integer",
289
+ "minimum": 1
290
+ },
291
+ "backoffMs": {
292
+ "type": "integer",
293
+ "minimum": 0
294
+ }
295
+ }
296
+ },
297
+ "requiresApproval": {
298
+ "type": "boolean",
299
+ "description": "RFC 0151 §C — an inverse action can itself be harmful (RFC 0147 R9), so it may be gated behind the same approval surface as a forward effect."
300
+ },
301
+ "waiveRequiresApproval": {
302
+ "type": "boolean",
303
+ "description": "RFC 0151 §B/§E (S36, 2026-08-17) — OPTIONAL. When true, ABANDONING this inverse action (§E `skip with justification` or `terminate as uncompensated`) requires an RFC 0051 approval to have resolved `approved` first — if a human must authorize RUNNING an inverse, a human must authorize deciding it will NEVER run. DEFAULT = the obligation's EFFECTIVE `requiresApproval` (after the policy's `approvalScope` escalation, §B) — NOT false — so the field is purely additive: no existing document changes meaning. Stamped onto the obligation at MINT time like `requiresApproval` (a mid-flight redefinition cannot change who had to authorize). Does NOT apply to `substitute` (still an attempt to undo; a substitution is a new planVersion whose own `requiresApproval` governs it). No policy-level counterpart: because the default inherits the effective value, an `approvalScope` escalation escalates waives with it."
304
+ }
305
+ }
306
+ },
307
+ "irreversibleEffect": {
308
+ "type": "boolean",
309
+ "description": "RFC 0151 §B (UQ4, resolved 2026-08-16) — the author states that this node's committed effect HAS NO INVERSE. OPTIONAL; absent or false means nothing (an undeclared compensator is still not implied). Mutually exclusive with `compensation`: a node declaring both is contradictory and a host MUST reject it at registration (`validation_error`). When true and the node's effect committed before an unwind starts, the plan records the node as `irreversible` (never completed) so the §D rollup caps at `partial` — a reader can no longer infer a full undo from a `completed` that quietly skipped it."
310
+ }
311
+ },
312
+ "additionalProperties": false,
313
+ "if": {
314
+ "properties": {
315
+ "irreversibleEffect": {
316
+ "const": true
317
+ }
318
+ },
319
+ "required": [
320
+ "irreversibleEffect"
321
+ ]
322
+ },
323
+ "then": {
324
+ "not": {
325
+ "required": [
326
+ "compensation"
327
+ ]
328
+ }
329
+ }
330
+ },
331
+ "WorkflowEdge": {
332
+ "type": "object",
333
+ "required": [
334
+ "id",
335
+ "sourceNodeId",
336
+ "targetNodeId"
337
+ ],
338
+ "properties": {
339
+ "id": {
340
+ "type": "string",
341
+ "minLength": 1
342
+ },
343
+ "sourceNodeId": {
344
+ "type": "string",
345
+ "minLength": 1
346
+ },
347
+ "sourceOutput": {
348
+ "type": "string",
349
+ "description": "Source output port key. Default 'output'."
350
+ },
351
+ "targetNodeId": {
352
+ "type": "string",
353
+ "minLength": 1
354
+ },
355
+ "targetInput": {
356
+ "type": "string",
357
+ "description": "Target input port key. Default 'input'."
358
+ },
359
+ "condition": {
360
+ "$ref": "#/$defs/EdgeCondition"
361
+ },
362
+ "label": {
363
+ "type": "string"
364
+ },
365
+ "triggerRule": {
366
+ "type": "string",
367
+ "enum": [
368
+ "all_success",
369
+ "any_success",
370
+ "all_complete",
371
+ "none_failed",
372
+ "any_failed"
373
+ ],
374
+ "default": "all_success"
375
+ }
376
+ },
377
+ "additionalProperties": false
378
+ },
379
+ "EdgeCondition": {
380
+ "type": "object",
381
+ "properties": {
382
+ "type": {
383
+ "type": "string",
384
+ "enum": [
385
+ "expression",
386
+ "equals",
387
+ "notEquals",
388
+ "contains",
389
+ "regex",
390
+ "truthy",
391
+ "falsy"
392
+ ],
393
+ "description": "Operator. `equals`/`notEquals`/`contains` compare `left` to `right`; `regex` matches `left` against `right`; `expression` evaluates `expression`. RFC 0134: `truthy`/`falsy` test the resolved value at `left` for JS-style truthiness and take NO `right` operand (the edge contributes iff `left` is truthy — resp. falsy/absent). `left` is required for all operators except `expression`."
394
+ },
395
+ "left": {
396
+ "type": "string",
397
+ "description": "Left operand path (e.g., 'status', 'output.approved'). Required for every operator except `expression`."
398
+ },
399
+ "right": {
400
+ "description": "Right operand value (any JSON value). Meaningless for `truthy`/`falsy` (RFC 0134) — a host MUST ignore it there, not error."
401
+ },
402
+ "expression": {
403
+ "type": "string",
404
+ "description": "Used when type='expression'."
405
+ }
406
+ },
407
+ "additionalProperties": false
408
+ },
409
+ "PortValue": {
410
+ "oneOf": [
411
+ {
412
+ "type": "object",
413
+ "required": [
414
+ "type",
415
+ "value"
416
+ ],
417
+ "properties": {
418
+ "type": {
419
+ "const": "static"
420
+ },
421
+ "value": {}
422
+ },
423
+ "additionalProperties": false
424
+ },
425
+ {
426
+ "type": "object",
427
+ "required": [
428
+ "type",
429
+ "expression"
430
+ ],
431
+ "properties": {
432
+ "type": {
433
+ "const": "expression"
434
+ },
435
+ "expression": {
436
+ "type": "string",
437
+ "minLength": 1
438
+ }
439
+ },
440
+ "additionalProperties": false
441
+ },
442
+ {
443
+ "type": "object",
444
+ "required": [
445
+ "type",
446
+ "nodeId",
447
+ "outputKey"
448
+ ],
449
+ "properties": {
450
+ "type": {
451
+ "const": "connection"
452
+ },
453
+ "nodeId": {
454
+ "$ref": "ids.schema.json#/$defs/nodeId"
455
+ },
456
+ "outputKey": {
457
+ "type": "string",
458
+ "minLength": 1
459
+ },
460
+ "optional": {
461
+ "type": "boolean",
462
+ "default": false
463
+ }
464
+ },
465
+ "additionalProperties": false
466
+ },
467
+ {
468
+ "type": "object",
469
+ "required": [
470
+ "type",
471
+ "variableName"
472
+ ],
473
+ "properties": {
474
+ "type": {
475
+ "const": "variable"
476
+ },
477
+ "variableName": {
478
+ "type": "string",
479
+ "minLength": 1
480
+ },
481
+ "optional": {
482
+ "type": "boolean",
483
+ "default": false
484
+ }
485
+ },
486
+ "additionalProperties": false
487
+ }
488
+ ]
489
+ },
490
+ "WorkflowTrigger": {
491
+ "type": "object",
492
+ "required": [
493
+ "id",
494
+ "type"
495
+ ],
496
+ "properties": {
497
+ "id": {
498
+ "type": "string",
499
+ "minLength": 1
500
+ },
501
+ "type": {
502
+ "type": "string",
503
+ "enum": [
504
+ "manual",
505
+ "schedule",
506
+ "webhook",
507
+ "event",
508
+ "artifact",
509
+ "canvas",
510
+ "envelope",
511
+ "command",
512
+ "chat-message",
513
+ "channel-write"
514
+ ],
515
+ "description": "Trigger discriminator. The `channel-write` variant fires a node when a named channel receives a write (closes C2 — reactive cross-engine pattern). Its `config` shape: `{channel: string, onlyFrom?: 'child'|'parent'|'any', debounceMs?: integer}`. See channels-and-reducers.md §Distributed reducers."
516
+ },
517
+ "name": {
518
+ "type": "string"
519
+ },
520
+ "description": {
521
+ "type": "string"
522
+ },
523
+ "config": {
524
+ "type": "object",
525
+ "additionalProperties": true
526
+ },
527
+ "enabled": {
528
+ "type": "boolean",
529
+ "default": true
530
+ },
531
+ "nodeId": {
532
+ "$ref": "ids.schema.json#/$defs/nodeId"
533
+ },
534
+ "eventType": {
535
+ "type": "string"
536
+ }
537
+ },
538
+ "additionalProperties": false
539
+ },
540
+ "WorkflowVariable": {
541
+ "type": "object",
542
+ "required": [
543
+ "name",
544
+ "type"
545
+ ],
546
+ "properties": {
547
+ "name": {
548
+ "type": "string",
549
+ "minLength": 1
550
+ },
551
+ "type": {
552
+ "type": "string",
553
+ "enum": [
554
+ "string",
555
+ "number",
556
+ "boolean",
557
+ "object",
558
+ "array"
559
+ ]
560
+ },
561
+ "description": {
562
+ "type": "string"
563
+ },
564
+ "required": {
565
+ "type": "boolean",
566
+ "default": false
567
+ },
568
+ "defaultValue": {},
569
+ "sensitive": {
570
+ "type": "boolean",
571
+ "default": false,
572
+ "description": "When true, the engine masks this variable's value in persisted `variable.changed` events, `state.snapshot` projections, and `RunSnapshot.variables`. Reads inside NodeModule executors work normally; only persistence + external surfaces mask. See observability.md §Privacy classification (closes O5)."
573
+ },
574
+ "format": {
575
+ "type": "string",
576
+ "minLength": 1,
577
+ "description": "RFC 0136 (`Active`). ADVISORY presentational hint for a `type: \"string\"` variable, drawn from the JSON-Schema format vocabulary (`email`, `uri`, `date`, `date-time`, `time`, `duration` are the v1 recognised set). Hosts SHOULD use it to choose an input affordance (e.g. an email keyboard). It is NOT a validation contract: a host MUST NOT reject a run, refuse a variable write, or fail validation because a value does not match, and MUST NOT assume a value matches when reading it. DELIBERATELY NOT AN ENUM — an unrecognised value MUST round-trip and degrade to plain text rather than error (RFC 0136 requirement 2), which an enum would turn into a hard validation failure on a client-submitted (closed) shape. Ignored when `type` is not `\"string\"`. Orthogonal to `sensitive`: masking hides the VALUE on server-emitted surfaces, `format` describes the FIELD in the definition, so the two compose with no interaction."
578
+ }
579
+ },
580
+ "additionalProperties": false
581
+ },
582
+ "NodeGroup": {
583
+ "type": "object",
584
+ "required": [
585
+ "id",
586
+ "name",
587
+ "nodeIds",
588
+ "position",
589
+ "size"
590
+ ],
591
+ "properties": {
592
+ "id": {
593
+ "type": "string",
594
+ "minLength": 1
595
+ },
596
+ "name": {
597
+ "type": "string",
598
+ "minLength": 1
599
+ },
600
+ "color": {
601
+ "type": "string"
602
+ },
603
+ "collapsed": {
604
+ "type": "boolean",
605
+ "default": false
606
+ },
607
+ "nodeIds": {
608
+ "type": "array",
609
+ "items": {
610
+ "type": "string"
611
+ }
612
+ },
613
+ "position": {
614
+ "type": "object",
615
+ "required": [
616
+ "x",
617
+ "y"
618
+ ],
619
+ "properties": {
620
+ "x": {
621
+ "type": "number"
622
+ },
623
+ "y": {
624
+ "type": "number"
625
+ }
626
+ },
627
+ "additionalProperties": false
628
+ },
629
+ "size": {
630
+ "type": "object",
631
+ "required": [
632
+ "width",
633
+ "height"
634
+ ],
635
+ "properties": {
636
+ "width": {
637
+ "type": "number"
638
+ },
639
+ "height": {
640
+ "type": "number"
641
+ }
642
+ },
643
+ "additionalProperties": false
644
+ }
645
+ },
646
+ "additionalProperties": false
647
+ },
648
+ "ChannelDeclaration": {
649
+ "type": "object",
650
+ "required": [
651
+ "reducer"
652
+ ],
653
+ "properties": {
654
+ "reducer": {
655
+ "type": "string",
656
+ "description": "Canonical names: 'replace', 'append', 'merge', 'counter', 'votes', 'feedback', 'message' (Multi-Agent Shift Phase 1 — append-only + idempotent on `messageId`). Custom reducers MUST use 'vendor.<org>.<name>'.",
657
+ "pattern": "^(replace|append|merge|counter|votes|feedback|message|vendor\\.[a-z][a-z0-9_-]*\\.[a-z][a-z0-9_-]*)$"
658
+ },
659
+ "schema": {
660
+ "type": "object",
661
+ "additionalProperties": true
662
+ },
663
+ "default": {},
664
+ "maxSize": {
665
+ "type": "integer",
666
+ "minimum": 1
667
+ },
668
+ "ttlMs": {
669
+ "type": "integer",
670
+ "minimum": 1,
671
+ "maximum": 31536000000,
672
+ "description": "Optional entry-age TTL in milliseconds (closes C3). Applies to `append` / `votes` / `feedback` reducers; ignored on others. Engine drops entries older than this age (lazy: on read or next write). Range: 1..1 year. Replay-safe — uses original event timestamps for comparison. See channels-and-reducers.md §Channel TTL."
673
+ },
674
+ "options": {
675
+ "type": "object",
676
+ "additionalProperties": true
677
+ },
678
+ "access": {
679
+ "$ref": "#/$defs/ChannelAccess"
680
+ },
681
+ "schemaVersion": {
682
+ "type": "integer",
683
+ "minimum": 1,
684
+ "default": 1,
685
+ "description": "Integer version of the current `schema`. Increments whenever the channel author edits `schema`. Each `channel.written` event records this version at write time. (closes C4)"
686
+ },
687
+ "compatibleWith": {
688
+ "type": "array",
689
+ "items": {
690
+ "type": "integer",
691
+ "minimum": 1
692
+ },
693
+ "uniqueItems": true,
694
+ "description": "Older schema versions whose persisted writes are forward-readable under the CURRENT schema. The engine validates each old write against the current schema during fold; pass = include, fail = hard error `channel_schema_breaking_change`. Empty/omitted = no backward compat (any older write trips the breaking-change error). For breaking edits, authors create a new channel name + a copy node — see channels-and-reducers.md §Channel schema migration."
695
+ },
696
+ "sensitive": {
697
+ "type": "boolean",
698
+ "default": false,
699
+ "description": "When true, the engine masks `channel.written` event payloads' `value` field. The reduced channel state in `RunSnapshot.channels` is also masked when read via the REST surface. See observability.md §Privacy classification (closes O5)."
700
+ }
701
+ },
702
+ "additionalProperties": false
703
+ },
704
+ "ChannelAccess": {
705
+ "description": "Per-channel access control. See channels-and-reducers.md §Channel access control (closes C1). Three forms: 'public' (no restriction; same as omitting), 'private' (lockdown shorthand — equivalent to {readers: [], writers: []}), or an explicit {readers?, writers?} object where each side is independently scoped (omitted = open, present = strict allowlist).",
706
+ "oneOf": [
707
+ {
708
+ "const": "public"
709
+ },
710
+ {
711
+ "const": "private"
712
+ },
713
+ {
714
+ "type": "object",
715
+ "properties": {
716
+ "readers": {
717
+ "$ref": "#/$defs/ChannelAccessList"
718
+ },
719
+ "writers": {
720
+ "$ref": "#/$defs/ChannelAccessList"
721
+ }
722
+ },
723
+ "additionalProperties": false
724
+ }
725
+ ]
726
+ },
727
+ "ChannelAccessList": {
728
+ "type": "array",
729
+ "description": "Allowlist entries. Each item matches against the requesting node's `nodeId` (exact) OR `typeId` (wildcard). Wildcard format: dotted prefix + '*' (e.g., 'core.ai.*'). Bare '*' matches any node.",
730
+ "items": {
731
+ "type": "string",
732
+ "minLength": 1,
733
+ "maxLength": 256,
734
+ "pattern": "^([a-z][a-zA-Z0-9._-]*\\*?|\\*)$"
735
+ },
736
+ "uniqueItems": true,
737
+ "maxItems": 256
738
+ },
739
+ "WorkflowMetadata": {
740
+ "type": "object",
741
+ "properties": {
742
+ "createdBy": {
743
+ "type": "string"
744
+ },
745
+ "createdAt": {
746
+ "type": "string",
747
+ "format": "date-time"
748
+ },
749
+ "updatedBy": {
750
+ "type": "string"
751
+ },
752
+ "updatedAt": {
753
+ "type": "string",
754
+ "format": "date-time"
755
+ },
756
+ "tags": {
757
+ "type": "array",
758
+ "items": {
759
+ "type": "string",
760
+ "minLength": 1,
761
+ "maxLength": 256
762
+ },
763
+ "maxItems": 100
764
+ },
765
+ "category": {
766
+ "type": "string"
767
+ },
768
+ "author": {
769
+ "type": "string"
770
+ },
771
+ "codeVersion": {
772
+ "type": "string"
773
+ },
774
+ "customizedAt": {
775
+ "type": "string",
776
+ "format": "date-time"
777
+ },
778
+ "customizedBy": {
779
+ "type": "string"
780
+ },
781
+ "forkedFrom": {
782
+ "type": "string",
783
+ "description": "ID of platform template this was forked from."
784
+ },
785
+ "clonedFrom": {
786
+ "type": "string",
787
+ "description": "ID of workflow this was cloned from (project clone, not template fork)."
788
+ },
789
+ "clonedAt": {
790
+ "type": "string",
791
+ "format": "date-time"
792
+ },
793
+ "customProperties": {
794
+ "type": "object",
795
+ "additionalProperties": true
796
+ },
797
+ "complianceClass": {
798
+ "type": "string",
799
+ "enum": [
800
+ "public",
801
+ "pii",
802
+ "phi",
803
+ "pci",
804
+ "regulated"
805
+ ],
806
+ "default": "public",
807
+ "description": "Top-level workflow sensitivity tier. Sets the `openwop.compliance_class` span attribute on every span the run produces. Drives default retention / masking / export-gating policy at observability collectors. See observability.md §Privacy classification (closes O5)."
808
+ },
809
+ "complianceConfig": {
810
+ "type": "object",
811
+ "description": "Optional per-workflow overrides for compliance behavior. The masking mode (`mask` | `omit` | `hash` | `passthrough`) defaults to the server's `Capabilities.compliance.defaultMode`; setting it here forces a specific mode for this workflow. Domain-specific extensions (HIPAA's 18 PHI identifiers, GDPR special categories) can live here as opt-in fields.",
812
+ "properties": {
813
+ "maskingMode": {
814
+ "type": "string",
815
+ "enum": [
816
+ "mask",
817
+ "omit",
818
+ "hash",
819
+ "passthrough"
820
+ ],
821
+ "description": "Per-workflow override of the server's default masking mode."
822
+ }
823
+ },
824
+ "additionalProperties": false
825
+ }
826
+ },
827
+ "additionalProperties": false
828
+ },
829
+ "WorkflowSettings": {
830
+ "type": "object",
831
+ "properties": {
832
+ "timeout": {
833
+ "type": "integer",
834
+ "minimum": 0,
835
+ "description": "Maximum run duration in milliseconds."
836
+ },
837
+ "maxRetries": {
838
+ "type": "integer",
839
+ "minimum": 0
840
+ },
841
+ "logLevel": {
842
+ "type": "string",
843
+ "enum": [
844
+ "debug",
845
+ "info",
846
+ "warn",
847
+ "error"
848
+ ]
849
+ },
850
+ "maxLoopbackIterations": {
851
+ "type": "integer",
852
+ "minimum": 1,
853
+ "default": 5
854
+ },
855
+ "compensation": {
856
+ "$ref": "compensation-policy.schema.json",
857
+ "description": "RFC 0151 §B — the workflow-level compensation policy (WHEN an unwind starts and HOW it runs). OPTIONAL and capability-gated: a host that advertises `capabilities.compensation` MUST validate it at registration; a host that does not MUST refuse the workflow with `capability_required` rather than accept a policy it will never honour. Node-level `nodes[].compensation` declarations remain valid without it — they describe the inverse action; this key requests the unwind."
858
+ }
859
+ },
860
+ "additionalProperties": false
861
+ }
862
+ },
863
+ "x-openwop-seeded-from": "v1"
864
+ }