@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,2693 @@
1
+ openapi: 3.1.0
2
+
3
+ info:
4
+ title: Workflow Orchestration Protocol (openwop) API
5
+ version: "1.1.0"
6
+ summary: REST surface for declaring, executing, suspending, resuming, and observing multi-step workflows.
7
+ description: |
8
+ Canonical OpenAPI 3.1 specification for openwop-compliant servers. Generated from `rest-endpoints.md` and references the JSON Schemas in `schemas/`.
9
+
10
+ See spec docs for semantics:
11
+ - `auth.md` — API key + scope vocabulary
12
+ - `idempotency.md` — `Idempotency-Key` header contract
13
+ - `version-negotiation.md` — `engineVersion` + `eventLogSchemaVersion`
14
+ - `capabilities.md` — `/.well-known/openwop` handshake
15
+ - `stream-modes.md` — SSE consumption modes
16
+ - `run-options.md` — `configurable`/`tags`/`metadata`
17
+ - `interrupt.md` — HITL primitive
18
+ - `replay.md` — `:fork` endpoint
19
+
20
+ **Registry scope (RFC 0094 §I).** This document specifies the HOST
21
+ surface. The production node-pack registry surface (`/v1/packs/*` —
22
+ publish/get/delete/sig, deprecation, yank, key rotation) is specified in
23
+ `spec/v1/node-packs.md` §"Registry HTTP API" + `spec/v1/registry-operations.md`
24
+ and is served by a registry service (e.g. the planned hosted reference
25
+ registry `packs.openwop.dev`, or a third-party/private registry
26
+ implementation) — a distinct deployable, out of scope for this host
27
+ OpenAPI document. Only the test-mode mirror (`/v1/packs-test/*`, RFC 0025)
28
+ is host-mounted and documented here.
29
+ contact:
30
+ name: openwop spec working group
31
+ url: https://openwop.dev/spec/v1/
32
+ license:
33
+ name: Apache-2.0
34
+ identifier: Apache-2.0
35
+
36
+ externalDocs:
37
+ description: openwop spec v1 corpus
38
+ url: https://openwop.dev/spec/v1/
39
+
40
+ servers:
41
+ # No `/v1` here: the version segment lives in the path keys below, so a
42
+ # server base carrying it too resolves every operation to `/v1/v1/*` and
43
+ # the unversioned discovery route to `/v1/.well-known/openwop` (RFC 0149 §A).
44
+ - url: https://{host}
45
+ description: openwop-compliant server
46
+ variables:
47
+ host:
48
+ default: api.example.com
49
+ description: Replace with your server's hostname.
50
+
51
+ # ─────────────────────────────────────────────────────────────────────────────
52
+ # SECURITY
53
+ # ─────────────────────────────────────────────────────────────────────────────
54
+ security:
55
+ - ApiKeyAuth: []
56
+
57
+ # ─────────────────────────────────────────────────────────────────────────────
58
+ # TAGS
59
+ # ─────────────────────────────────────────────────────────────────────────────
60
+ tags:
61
+ - name: discovery
62
+ description: Public capability + spec discovery (no auth required).
63
+ - name: workflows
64
+ description: Workflow definition manifest.
65
+ - name: runs
66
+ description: Run lifecycle — create, read, stream, cancel, fork.
67
+ - name: agents
68
+ description: Manifest-agent inventory (RFC 0072 §A). Read-only; gated on capabilities.agents.manifestRuntime. Dispatch rides the run surface (WorkflowNode.agent + POST /v1/runs).
69
+ - name: tools
70
+ description: Portable tool catalog (RFC 0078 §B). Read-only ToolDescriptor projection across tool sources (node-pack / workflow / mcp / connector / host-extension); gated on capabilities.toolCatalog; authorization-scoped per §F-2.
71
+ - name: hitl
72
+ description: Human-in-the-loop interrupts and approvals.
73
+ - name: artifacts
74
+ description: Run-produced artifacts.
75
+ - name: webhooks
76
+ description: Subscribe to run events via outbound HTTP.
77
+ - name: triggers
78
+ description: Durable trigger-bridge subscriptions (RFC 0083). RFC 0099 adds the external-event create surface (`POST /v1/trigger-subscriptions`); gated on `capabilities.triggerBridge.ingestion.registrationEndpoint`.
79
+ - name: audit
80
+ description: Audit-log integrity verification (gated on the `openwop-audit-log-integrity` profile).
81
+ - name: prompts
82
+ description: Prompt-template library — list, fetch, render, mutate (RFC 0028; gated on `capabilities.prompts.*`).
83
+ - name: content
84
+ description: Localized authored content — public delivery + tenant-scoped admin CRUD (RFC 0103; gated on `capabilities.content.supported`).
85
+ - name: host
86
+ description: Host-capability resources — e.g. the RFC 0059 agent workspace file store (gated on `capabilities.workspace.*`).
87
+ - name: packs-test
88
+ description: |
89
+ RFC 0025 (`Draft`). Test-mode mirror of the production `/v1/packs/*` publish/get/delete/sig surface against
90
+ an isolated catalog. Gated on `capabilities.packs.testMode.supported: true` plus the reference impl's
91
+ `OPENWOP_PACKS_TEST_NAMESPACE_ENABLED=true` env-gate. Lets the conformance suite exercise the documented
92
+ 19-code publish error catalog without `packs:publish` scope on the real registry. Hosts that haven't
93
+ mounted this surface MUST return `404 Not Found` for every path under `/v1/packs-test/`.
94
+
95
+ Scope note (RFC 0094 §I): the PRODUCTION `/v1/packs/*` surface these paths mirror is specified in
96
+ `spec/v1/registry-operations.md` + `node-packs.md` §"Registry HTTP API" and is served by a registry
97
+ service (a distinct deployable from the host), so it is intentionally NOT defined in this host
98
+ OpenAPI document.
99
+
100
+ # ─────────────────────────────────────────────────────────────────────────────
101
+ # PATHS
102
+ # ─────────────────────────────────────────────────────────────────────────────
103
+ paths:
104
+
105
+ # ── Discovery (unauthenticated) ─────────────────────────────────────────
106
+ /.well-known/openwop:
107
+ get:
108
+ tags: [discovery]
109
+ summary: Capability declaration handshake.
110
+ operationId: getCapabilities
111
+ security: []
112
+ parameters:
113
+ - name: If-None-Match
114
+ in: header
115
+ required: false
116
+ schema: { type: string }
117
+ description: >-
118
+ RFC 0165 §C.2. Standard conditional request against the discovery document's `ETag`;
119
+ a matching value SHOULD yield `304 Not Modified`.
120
+ responses:
121
+ '200':
122
+ description: Capabilities object — see `capabilities.md`.
123
+ headers:
124
+ Cache-Control:
125
+ schema: { type: string }
126
+ example: 'public, max-age=300'
127
+ ETag:
128
+ schema: { type: string }
129
+ description: >-
130
+ RFC 0165 §C.2. Standard strong validator for the response bytes (SHOULD be sent).
131
+ Distinct from `Capabilities-Etag`, which validates negotiation safety
132
+ (`capabilities-change-detection.md` §"Cache validators").
133
+ Capabilities-Etag:
134
+ schema: { type: string }
135
+ description: Optional probe handle for mid-session capability change detection. Deprecated toward v2 (RFC 0165 §C.2).
136
+ content:
137
+ application/json:
138
+ schema:
139
+ $ref: '#/components/schemas/Capabilities'
140
+ '304':
141
+ description: RFC 0165 §C.2 — `If-None-Match` matched the current `ETag`; the body is unchanged.
142
+ '503':
143
+ description: Server unable to compute capabilities (transient).
144
+ content:
145
+ application/json:
146
+ schema: { $ref: '#/components/schemas/Error' }
147
+
148
+ /v1/openapi.json:
149
+ get:
150
+ tags: [discovery]
151
+ summary: Self-describing OpenAPI 3.1 spec.
152
+ operationId: getOpenApiSpec
153
+ security: []
154
+ responses:
155
+ '200':
156
+ description: This document.
157
+ content:
158
+ application/json:
159
+ schema:
160
+ type: object
161
+ '503':
162
+ description: Server unable to serve spec (transient).
163
+ content:
164
+ application/json:
165
+ schema: { $ref: '#/components/schemas/Error' }
166
+
167
+ # ── Workflows ───────────────────────────────────────────────────────────
168
+ /v1/workflows/{workflowId}:
169
+ get:
170
+ tags: [workflows]
171
+ summary: Read a workflow definition.
172
+ operationId: getWorkflow
173
+ parameters:
174
+ - $ref: '#/components/parameters/WorkflowId'
175
+ responses:
176
+ '200':
177
+ description: Workflow definition.
178
+ content:
179
+ application/json:
180
+ schema:
181
+ $ref: '../schemas/workflow-definition.schema.json'
182
+ '401': { $ref: '#/components/responses/Unauthenticated' }
183
+ '403': { $ref: '#/components/responses/Forbidden' }
184
+ '404': { $ref: '#/components/responses/NotFound' }
185
+
186
+ # ── Runs ────────────────────────────────────────────────────────────────
187
+ /v1/runs:
188
+ post:
189
+ tags: [runs]
190
+ summary: Create a new run.
191
+ operationId: createRun
192
+ parameters:
193
+ - $ref: '#/components/parameters/IdempotencyKey'
194
+ - in: header
195
+ name: X-Dedup
196
+ schema:
197
+ type: string
198
+ enum: [enforce]
199
+ description: When set, server cross-host claim system rejects duplicate `(tenantId, scopeId)` pairs with `409 Conflict`.
200
+ - in: header
201
+ name: X-Force-Engine-Version
202
+ schema: { type: integer, minimum: 0 }
203
+ description: |
204
+ **Test-keys-only.** When set, the server emits events for this run AS IF it
205
+ were running the specified engine version (must be within the server's
206
+ advertised `Capabilities.testing.forceEngineVersionRange`). Used by the
207
+ conformance suite to verify version-negotiation fold-best-effort tolerance
208
+ across the spec's forward-compat matrix. Servers MUST reject on production
209
+ API keys with `403 force_engine_version_forbidden`. Closes F5.
210
+ requestBody:
211
+ required: true
212
+ content:
213
+ application/json:
214
+ schema:
215
+ # The body is the WorkflowId + inputs + transport-specific
216
+ # routing fields, plus the openwop RunOptions overlay (configurable,
217
+ # tags, metadata) hoisted into a first-class JSON Schema at
218
+ # ../schemas/run-options.schema.json. allOf composes the two
219
+ # so callers see one unified body shape. RFC 0094 §A: neither
220
+ # allOf branch is closed via additionalProperties (two closed
221
+ # branches inside one allOf made every documented body
222
+ # unsatisfiable); the composed request is closed here with
223
+ # `unevaluatedProperties: false` (JSON Schema 2020-12), so
224
+ # undeclared properties still fail at the composition level.
225
+ unevaluatedProperties: false
226
+ allOf:
227
+ - type: object
228
+ properties:
229
+ workflowId: { type: string, minLength: 1 }
230
+ inputs:
231
+ type: object
232
+ description: Workflow inputs (consumed by triggers/nodes).
233
+ residency:
234
+ # RFC 0129 — OPTIONAL data-residency constraint. Closed shape
235
+ # lives in the referenced schema (RFC 0094 §A forbids a closed
236
+ # `additionalProperties:false` branch inside this allOf; the
237
+ # $ref keeps the constraint out of the composition). A host
238
+ # advertising `capabilities.dataResidency` MUST honor-or-reject
239
+ # (accept iff region in advertised regions[], else
240
+ # `residency_unavailable`, create no run). Absent ⇒ no constraint.
241
+ $ref: '../schemas/residency.schema.json'
242
+ tenantId:
243
+ type: string
244
+ description: Tenant scoping. Server typically defaults from API key.
245
+ scopeId:
246
+ type: string
247
+ description: Opaque correlation ID for `X-Dedup` semantics.
248
+ callbackUrl:
249
+ type: string
250
+ format: uri
251
+ description: Signed-token HITL callback URL (see `interrupt.md`).
252
+ mode:
253
+ type: string
254
+ enum: [eval]
255
+ description: |
256
+ RFC 0081 §B. When `eval`, this run is an eval-suite projection
257
+ (not a workflow run): the host runs the `evalSuiteRef` against
258
+ `agentId`, emits the content-free `eval.*` family, and terminates
259
+ with an `EvalSummary` readable via `GET /v1/runs/{runId}/eval-summary`.
260
+ Capability-gated on `capabilities.agents.evalSuite.supported`; a
261
+ host that omits it rejects `mode: "eval"` with 501. Omit for a
262
+ normal workflow run.
263
+ evalSuiteRef:
264
+ type: string
265
+ minLength: 1
266
+ description: RFC 0081 — URI of the `AgentEvalSuite` to run. Required when mode is `eval`.
267
+ agentId:
268
+ type: string
269
+ minLength: 1
270
+ description: RFC 0081 — the manifest agent the eval suite targets. Required when mode is `eval`.
271
+ if:
272
+ properties: { mode: { const: eval } }
273
+ required: [mode]
274
+ then:
275
+ required: [evalSuiteRef, agentId]
276
+ else:
277
+ required: [workflowId]
278
+ - $ref: '../schemas/run-options.schema.json'
279
+ responses:
280
+ '201':
281
+ description: Run accepted.
282
+ headers:
283
+ openwop-Idempotent-Replay:
284
+ schema: { type: boolean }
285
+ description: Set when the response was served from the idempotency cache.
286
+ content:
287
+ application/json:
288
+ schema:
289
+ type: object
290
+ required: [runId, status, eventsUrl]
291
+ properties:
292
+ runId: { type: string }
293
+ status:
294
+ type: string
295
+ enum: [pending, running, waiting-approval, waiting-input, waiting-external]
296
+ eventsUrl: { type: string, format: uri }
297
+ statusUrl: { type: string, format: uri }
298
+ '400': { $ref: '#/components/responses/ValidationError' }
299
+ '401': { $ref: '#/components/responses/Unauthenticated' }
300
+ '403': { $ref: '#/components/responses/Forbidden' }
301
+ '409':
302
+ description: '`X-Dedup` collision OR concurrent `Idempotency-Key` collision.'
303
+ headers:
304
+ Retry-After:
305
+ schema: { type: integer }
306
+ description: Seconds until the active claim is stale-eligible.
307
+ content:
308
+ application/json:
309
+ schema:
310
+ $ref: '#/components/schemas/RunClaimConflict'
311
+ '429': { $ref: '#/components/responses/RateLimited' }
312
+
313
+ /v1/runs/{runId}:
314
+ get:
315
+ tags: [runs]
316
+ summary: Read run state (cached projection).
317
+ operationId: getRun
318
+ parameters:
319
+ - $ref: '#/components/parameters/RunId'
320
+ - in: header
321
+ name: If-None-Match
322
+ required: false
323
+ schema: { type: string }
324
+ description: |
325
+ RFC 0115. Conditional revalidation. When this carries the
326
+ current `ETag`, the host responds `304 Not Modified` with no
327
+ body (capability-gated on `restTransport.conditionalRunGet`).
328
+ responses:
329
+ '200':
330
+ description: Projected run state.
331
+ headers:
332
+ ETag:
333
+ schema: { type: string }
334
+ description: |
335
+ RFC 0115. Strong validator derived from the run's latest
336
+ persisted event-log sequence number; changes on every
337
+ observable state transition, stable while none occurs.
338
+ Content-Encoding:
339
+ required: false
340
+ schema: { type: string, enum: [gzip, br, zstd] }
341
+ description: |
342
+ RFC 0115. Present only when the host negotiated compression
343
+ from `Accept-Encoding`; pairs with `Vary: Accept-Encoding`.
344
+ The decoded body is byte-identical to the identity body.
345
+ content:
346
+ application/json:
347
+ schema:
348
+ $ref: '#/components/schemas/RunSnapshot'
349
+ '304':
350
+ description: 'RFC 0115. Not Modified — `If-None-Match` matched the current `ETag`. Empty body.'
351
+ '401': { $ref: '#/components/responses/Unauthenticated' }
352
+ '403': { $ref: '#/components/responses/Forbidden' }
353
+ '404': { $ref: '#/components/responses/NotFound' }
354
+
355
+ /v1/runs/{runId}/events:
356
+ get:
357
+ tags: [runs]
358
+ summary: SSE stream of run events.
359
+ operationId: streamRunEvents
360
+ parameters:
361
+ - $ref: '#/components/parameters/RunId'
362
+ - in: query
363
+ name: streamMode
364
+ schema:
365
+ type: string
366
+ default: updates
367
+ pattern: '^(values|updates|messages|debug)(,(values|updates|messages|debug))*$'
368
+ description: |
369
+ Single mode: `values` / `updates` / `messages` / `debug`.
370
+ Mixed mode: comma-separated combination (e.g., `updates,messages`)
371
+ per S4 closure — server emits union-of-filters with per-event
372
+ `event:` field labeling which mode admitted each event.
373
+ `values` MUST NOT combine with other modes (state.snapshot semantics
374
+ need exclusive ownership). See `stream-modes.md`. Default `updates`.
375
+ - in: query
376
+ name: bufferMs
377
+ schema:
378
+ type: integer
379
+ minimum: 0
380
+ maximum: 5000
381
+ description: |
382
+ Optional batching hint per S3 closure. When set, the server
383
+ accumulates events for up to N ms (or until a forced-flush
384
+ trigger fires — terminal events, suspensions, connection close)
385
+ and emits a single SSE event with `event: batch` and `data:` as
386
+ a JSON array of `RunEventDoc`. Range 0..5000; `0` = no buffering.
387
+ See `stream-modes.md` §Aggregation hint.
388
+ - in: header
389
+ name: Last-Event-ID
390
+ schema: { type: string }
391
+ description: Resume from sequence after this ID.
392
+ responses:
393
+ '200':
394
+ description: SSE stream. Auto-closes on terminal event. Keep-alive comments every 30s.
395
+ content:
396
+ text/event-stream:
397
+ schema:
398
+ type: string
399
+ description: SSE events. Each event has `id:`, `event:`, `data:` per RFC 8895.
400
+ '400':
401
+ description: Unsupported `streamMode`.
402
+ content:
403
+ application/json:
404
+ schema:
405
+ $ref: '#/components/schemas/UnsupportedStreamMode'
406
+ '401': { $ref: '#/components/responses/Unauthenticated' }
407
+ '403': { $ref: '#/components/responses/Forbidden' }
408
+ '404': { $ref: '#/components/responses/NotFound' }
409
+
410
+ /v1/runs/{runId}/events/poll:
411
+ get:
412
+ tags: [runs]
413
+ summary: Long-poll fallback for non-SSE clients.
414
+ operationId: pollRunEvents
415
+ parameters:
416
+ - $ref: '#/components/parameters/RunId'
417
+ - in: query
418
+ name: lastSequence
419
+ schema: { type: integer, minimum: 0 }
420
+ - in: query
421
+ name: timeout
422
+ schema: { type: integer, minimum: 1, maximum: 60, default: 30 }
423
+ description: Seconds to wait for new events. Max 60.
424
+ responses:
425
+ '200':
426
+ description: Events since `lastSequence`.
427
+ content:
428
+ application/json:
429
+ schema:
430
+ type: object
431
+ required: [events, isComplete]
432
+ properties:
433
+ events:
434
+ type: array
435
+ items:
436
+ $ref: '../schemas/run-event.schema.json'
437
+ isComplete: { type: boolean }
438
+ '401': { $ref: '#/components/responses/Unauthenticated' }
439
+ '403': { $ref: '#/components/responses/Forbidden' }
440
+ '404': { $ref: '#/components/responses/NotFound' }
441
+
442
+ /v1/runs/{runId}/cancel:
443
+ post:
444
+ tags: [runs]
445
+ summary: Cancel an in-flight run.
446
+ operationId: cancelRun
447
+ parameters:
448
+ - $ref: '#/components/parameters/RunId'
449
+ - $ref: '#/components/parameters/IdempotencyKey'
450
+ requestBody:
451
+ content:
452
+ application/json:
453
+ schema:
454
+ type: object
455
+ properties:
456
+ reason: { type: string }
457
+ responses:
458
+ '200':
459
+ description: Run cancellation accepted (cascade may be async).
460
+ content:
461
+ application/json:
462
+ schema:
463
+ type: object
464
+ properties:
465
+ runId: { type: string }
466
+ status: { type: string, enum: [cancelled, cancelling] }
467
+ '401': { $ref: '#/components/responses/Unauthenticated' }
468
+ '403': { $ref: '#/components/responses/Forbidden' }
469
+ '404': { $ref: '#/components/responses/NotFound' }
470
+
471
+ # ── Run feedback / annotations (RFC 0056) ────────────────────────────
472
+ # Gated on `capabilities.feedback.supported: true`. Annotations are a
473
+ # per-run side-resource (NOT replayable run-event-log entries); recording
474
+ # one also emits a live `run.annotated` SSE notification. Hosts without
475
+ # the advertised capability return `501 capability_not_provided`.
476
+ /v1/runs/{runId}/annotations:
477
+ post:
478
+ tags: [runs]
479
+ summary: Record a non-blocking quality annotation on a run (RFC 0056).
480
+ operationId: createAnnotation
481
+ parameters:
482
+ - $ref: '#/components/parameters/RunId'
483
+ - $ref: '#/components/parameters/IdempotencyKey'
484
+ requestBody:
485
+ required: true
486
+ content:
487
+ application/json:
488
+ schema:
489
+ $ref: '../schemas/annotation-create.schema.json'
490
+ responses:
491
+ '201':
492
+ description: Annotation recorded. Returns the persisted annotation.
493
+ content:
494
+ application/json:
495
+ schema:
496
+ $ref: '../schemas/annotation.schema.json'
497
+ '400': { $ref: '#/components/responses/ValidationError' }
498
+ '401': { $ref: '#/components/responses/Unauthenticated' }
499
+ '403': { $ref: '#/components/responses/Forbidden' }
500
+ '404': { $ref: '#/components/responses/NotFound' }
501
+ '501':
502
+ description: 'Host does not advertise capabilities.feedback.supported (RFC 0056).'
503
+ content:
504
+ application/json:
505
+ schema:
506
+ $ref: '../schemas/error-envelope.schema.json'
507
+ get:
508
+ tags: [runs]
509
+ summary: List the annotations recorded on a run (RFC 0056).
510
+ operationId: listAnnotations
511
+ parameters:
512
+ - $ref: '#/components/parameters/RunId'
513
+ responses:
514
+ '200':
515
+ description: Annotations for the run (tenant-scoped).
516
+ content:
517
+ application/json:
518
+ schema:
519
+ type: object
520
+ required: [annotations]
521
+ properties:
522
+ annotations:
523
+ type: array
524
+ items:
525
+ $ref: '../schemas/annotation.schema.json'
526
+ additionalProperties: false
527
+ '401': { $ref: '#/components/responses/Unauthenticated' }
528
+ '403': { $ref: '#/components/responses/Forbidden' }
529
+ '404': { $ref: '#/components/responses/NotFound' }
530
+ '501':
531
+ description: 'Host does not advertise capabilities.feedback.supported (RFC 0056).'
532
+ content:
533
+ application/json:
534
+ schema:
535
+ $ref: '../schemas/error-envelope.schema.json'
536
+
537
+ # ── External-event trigger subscriptions (RFC 0099) ──────────────────
538
+ # Gated on `capabilities.triggerBridge.ingestion.registrationEndpoint: true`.
539
+ # The portable create surface for an external-event (webhook/email/form)
540
+ # subscription that binds a source to a workflow to start. Returns the
541
+ # created TriggerSubscription (RFC 0083 §B) plus a source-specific binding
542
+ # (ingest URL/address + secret fingerprint), returned once at creation.
543
+ # Hosts without the advertised capability return `501 capability_not_provided`.
544
+ /v1/trigger-subscriptions:
545
+ post:
546
+ tags: [triggers]
547
+ summary: Register an external-event trigger subscription (RFC 0099).
548
+ description: |
549
+ Creates an external-event (`webhook`/`email`/`form`) TriggerSubscription
550
+ bound to a workflow, with a dedup config and a source-authenticity
551
+ verification policy (RFC 0099 §F.2). The `workflowId` MUST resolve under
552
+ the caller's RFC 0048 owner triple. The response carries the created
553
+ TriggerSubscription plus a source-specific `binding`; the binding
554
+ secret/URL is returned ONCE and is not re-fetchable in cleartext.
555
+ operationId: createTriggerSubscription
556
+ parameters:
557
+ - $ref: '#/components/parameters/IdempotencyKey'
558
+ requestBody:
559
+ required: true
560
+ content:
561
+ application/json:
562
+ schema:
563
+ $ref: '../schemas/trigger-subscription-registration.schema.json'
564
+ responses:
565
+ '201':
566
+ description: Subscription created. Returns the TriggerSubscription + a source-specific binding.
567
+ content:
568
+ application/json:
569
+ schema:
570
+ type: object
571
+ required: [subscription, binding]
572
+ additionalProperties: false
573
+ properties:
574
+ subscription:
575
+ $ref: '../schemas/trigger-subscription.schema.json'
576
+ binding:
577
+ type: object
578
+ description: |
579
+ Source-specific binding the caller needs to wire the external
580
+ source. For `webhook`: `{ ingestUrl, secretFingerprint }`; for
581
+ `email`: `{ ingestAddress }`; for `form`: `{ ingestUrl }`. The
582
+ secret is returned once at creation (SR-1).
583
+ additionalProperties: true
584
+ properties:
585
+ ingestUrl: { type: string, format: uri }
586
+ ingestAddress: { type: string }
587
+ secretFingerprint: { type: string, maxLength: 32 }
588
+ '400': { $ref: '#/components/responses/ValidationError' }
589
+ '401': { $ref: '#/components/responses/Unauthenticated' }
590
+ '403': { $ref: '#/components/responses/Forbidden' }
591
+ '501':
592
+ description: 'Host does not advertise capabilities.triggerBridge.ingestion.registrationEndpoint (RFC 0099).'
593
+ content:
594
+ application/json:
595
+ schema:
596
+ $ref: '../schemas/error-envelope.schema.json'
597
+
598
+ # ── Localized content surface (RFC 0103) ─────────────────────────────
599
+ # Public, cacheable delivery + tenant-scoped admin CRUD for authored
600
+ # localized content (pages → sections). Locale on the public path is
601
+ # negotiated via `Accept-Language` per the Stable i18n.md annex (no
602
+ # `?locale=`); admin writes target a locale in the body. Gated on
603
+ # `capabilities.content.supported: true` (requires `i18n.supported`).
604
+ # Hosts without the capability return `501 capability_not_provided`.
605
+ /v1/content/pages/{slug}:
606
+ get:
607
+ tags: [content]
608
+ # Public delivery: anonymous-capable, cacheable. Tenant is host-resolved
609
+ # (credential-derived when authenticated; host-defined when anonymous,
610
+ # localized-content.md §F). Clears global ApiKeyAuth like getCapabilities.
611
+ security: []
612
+ summary: Deliver a published content page resolved for the negotiated locale (RFC 0103 §D).
613
+ description: |
614
+ Resolves the published page `slug` for the locale negotiated from
615
+ `Accept-Language` (i18n.md fallback: q-value order → language family →
616
+ `content.baseLocale`), applies the per-section field merge
617
+ (`localized-content.md` §C), and returns the already-merged sections in
618
+ render order. Sets `Content-Language` to the locale used,
619
+ `Vary: Accept-Language, Accept-Encoding`, and
620
+ `Cache-Control: public, max-age=300, stale-while-revalidate=3600`.
621
+ Serves `status: "published"` content only. Tenant is host-resolved
622
+ (`localized-content.md` §F): credential-derived when authenticated,
623
+ host-defined (e.g. domain) when anonymous. A `slug` absent for the
624
+ resolved tenant returns the same `404` as a nonexistent slug (no
625
+ cross-tenant enumeration).
626
+ operationId: getContentPage
627
+ parameters:
628
+ - name: slug
629
+ in: path
630
+ required: true
631
+ schema: { type: string, pattern: '^[a-z][a-z0-9-]*$' }
632
+ description: The page slug.
633
+ - name: Accept-Language
634
+ in: header
635
+ required: false
636
+ schema: { type: string }
637
+ description: BCP-47 preference list; authoritative for locale selection (i18n.md). A malformed value MUST NOT 400.
638
+ responses:
639
+ '200':
640
+ description: The resolved, published page for the negotiated locale.
641
+ headers:
642
+ Content-Language:
643
+ schema: { type: string }
644
+ description: The BCP-47 locale actually used (equals the response `locale`).
645
+ content:
646
+ application/json:
647
+ schema:
648
+ $ref: '../schemas/localized-content-page-response.schema.json'
649
+ '404': { $ref: '#/components/responses/NotFound' }
650
+ '501':
651
+ description: 'Host does not advertise capabilities.content.supported (RFC 0103).'
652
+ content:
653
+ application/json:
654
+ schema:
655
+ $ref: '../schemas/error-envelope.schema.json'
656
+
657
+ /v1/content/pages:
658
+ get:
659
+ tags: [content]
660
+ summary: List content pages for the caller's tenant (RFC 0103 §D, admin).
661
+ description: |
662
+ Tenant-scoped admin listing of pages (draft + published). Requires a
663
+ principal with `content.read` scope.
664
+ operationId: listContentPages
665
+ responses:
666
+ '200':
667
+ description: The caller-tenant's pages.
668
+ content:
669
+ application/json:
670
+ schema:
671
+ type: array
672
+ items:
673
+ $ref: '../schemas/localized-content-page.schema.json'
674
+ '401': { $ref: '#/components/responses/Unauthenticated' }
675
+ '403': { $ref: '#/components/responses/Forbidden' }
676
+ '501':
677
+ description: 'Host does not advertise capabilities.content.supported (RFC 0103).'
678
+ content:
679
+ application/json:
680
+ schema:
681
+ $ref: '../schemas/error-envelope.schema.json'
682
+ post:
683
+ tags: [content]
684
+ summary: Create a content page (RFC 0103 §D, admin).
685
+ description: Tenant-scoped page creation. Requires `content.write` scope.
686
+ operationId: createContentPage
687
+ requestBody:
688
+ required: true
689
+ content:
690
+ application/json:
691
+ schema:
692
+ $ref: '../schemas/localized-content-page.schema.json'
693
+ responses:
694
+ '201':
695
+ description: The created page.
696
+ content:
697
+ application/json:
698
+ schema:
699
+ $ref: '../schemas/localized-content-page.schema.json'
700
+ '400':
701
+ description: 'Invalid request (e.g. baseLocale in supportedLocales, or a malformed locale/slug).'
702
+ content:
703
+ application/json:
704
+ schema:
705
+ $ref: '../schemas/error-envelope.schema.json'
706
+ '401': { $ref: '#/components/responses/Unauthenticated' }
707
+ '403': { $ref: '#/components/responses/Forbidden' }
708
+
709
+ /v1/content/pages/{pageId}/sections/{sectionId}:
710
+ put:
711
+ tags: [content]
712
+ summary: Upsert a section's base or per-locale fields (RFC 0103 §D, admin).
713
+ description: |
714
+ Locale-targeted write: `locale == content.baseLocale` upserts the
715
+ section's base `data`; any other (BCP-47-subset) locale upserts
716
+ `localizations[locale]`. Tenant-scoped; requires `content.write`.
717
+ operationId: putContentSection
718
+ parameters:
719
+ - name: pageId
720
+ in: path
721
+ required: true
722
+ schema: { type: string, minLength: 1 }
723
+ - name: sectionId
724
+ in: path
725
+ required: true
726
+ schema: { type: string, minLength: 1 }
727
+ requestBody:
728
+ required: true
729
+ content:
730
+ application/json:
731
+ schema:
732
+ type: object
733
+ additionalProperties: false
734
+ required: [locale, data]
735
+ properties:
736
+ locale:
737
+ type: string
738
+ pattern: '^[a-z]{2}(-[A-Z]{2})?$'
739
+ description: Target locale; baseLocale upserts `data`, else `localizations[locale]`.
740
+ data:
741
+ type: object
742
+ additionalProperties: true
743
+ description: The field overlay for the target locale.
744
+ responses:
745
+ '200':
746
+ description: The updated section record.
747
+ content:
748
+ application/json:
749
+ schema:
750
+ $ref: '../schemas/localized-content-section.schema.json'
751
+ '400':
752
+ description: 'Invalid request (e.g. baseLocale in supportedLocales, or a malformed locale/slug).'
753
+ content:
754
+ application/json:
755
+ schema:
756
+ $ref: '../schemas/error-envelope.schema.json'
757
+ '401': { $ref: '#/components/responses/Unauthenticated' }
758
+ '403': { $ref: '#/components/responses/Forbidden' }
759
+ '404': { $ref: '#/components/responses/NotFound' }
760
+
761
+ /v1/content/settings:
762
+ get:
763
+ tags: [content]
764
+ summary: Read the tenant's content language settings (RFC 0103 §B, admin).
765
+ description: Tenant-scoped read of `{ baseLocale, supportedLocales, autoTranslateOnPublish }`. Requires `content.read`.
766
+ operationId: getContentSettings
767
+ responses:
768
+ '200':
769
+ description: The tenant's language settings.
770
+ content:
771
+ application/json:
772
+ schema:
773
+ $ref: '../schemas/localized-content-language-settings.schema.json'
774
+ '401': { $ref: '#/components/responses/Unauthenticated' }
775
+ '403': { $ref: '#/components/responses/Forbidden' }
776
+ '501':
777
+ description: 'Host does not advertise capabilities.content.supported (RFC 0103).'
778
+ content:
779
+ application/json:
780
+ schema:
781
+ $ref: '../schemas/error-envelope.schema.json'
782
+ put:
783
+ tags: [content]
784
+ summary: Update the tenant's content language settings (RFC 0103 §B, admin).
785
+ description: |
786
+ Tenant-scoped settings update. The invariant `baseLocale ∉
787
+ supportedLocales` MUST hold (else `400`). Requires `content.write`.
788
+ operationId: putContentSettings
789
+ requestBody:
790
+ required: true
791
+ content:
792
+ application/json:
793
+ schema:
794
+ $ref: '../schemas/localized-content-language-settings.schema.json'
795
+ responses:
796
+ '200':
797
+ description: The updated language settings.
798
+ content:
799
+ application/json:
800
+ schema:
801
+ $ref: '../schemas/localized-content-language-settings.schema.json'
802
+ '400':
803
+ description: 'Invalid request (e.g. baseLocale in supportedLocales, or a malformed locale/slug).'
804
+ content:
805
+ application/json:
806
+ schema:
807
+ $ref: '../schemas/error-envelope.schema.json'
808
+ '401': { $ref: '#/components/responses/Unauthenticated' }
809
+ '403': { $ref: '#/components/responses/Forbidden' }
810
+
811
+ # ── Durable A2A task read seam (RFC 0100) ────────────────────────────
812
+ # Host-extension convenience read of the persisted A2ATaskState projection
813
+ # (RFC 0100 §2). The NORMATIVE A2A surface stays the A2A `tasks/get`
814
+ # JSON-RPC method per A2A v0.3 — this is a non-normative host-extension
815
+ # name under `/v1/host/sample/*`. Gated on `capabilities.a2a.durableTasks`.
816
+ /v1/host/sample/a2a/tasks/{taskId}:
817
+ get:
818
+ tags: [host]
819
+ summary: Read the persisted durable A2A task projection (RFC 0100, host-extension).
820
+ description: |
821
+ Returns the persisted `A2ATaskState` for `taskId` (== the backing
822
+ `runId`) per RFC 0100 §2 — a host-extension convenience read of the
823
+ durable projection that survives caller disconnect. The normative A2A
824
+ read surface remains the A2A `tasks/get` JSON-RPC method. Hosts that do
825
+ not advertise `capabilities.a2a.durableTasks` return `501`.
826
+ operationId: getA2ATaskState
827
+ parameters:
828
+ - name: taskId
829
+ in: path
830
+ required: true
831
+ schema: { type: string, minLength: 1 }
832
+ description: The A2A Task.id (equals the backing OpenWOP runId).
833
+ responses:
834
+ '200':
835
+ description: The persisted durable A2A task projection.
836
+ content:
837
+ application/json:
838
+ schema:
839
+ $ref: '../schemas/a2a-task-state.schema.json'
840
+ '401': { $ref: '#/components/responses/Unauthenticated' }
841
+ '403': { $ref: '#/components/responses/Forbidden' }
842
+ '404': { $ref: '#/components/responses/NotFound' }
843
+ '501':
844
+ description: 'Host does not advertise capabilities.a2a.durableTasks (RFC 0100).'
845
+ content:
846
+ application/json:
847
+ schema:
848
+ $ref: '../schemas/error-envelope.schema.json'
849
+
850
+ # ── Agent workspace files (RFC 0059) ─────────────────────────────────
851
+ # Gated on `capabilities.workspace.supported: true`. A versioned,
852
+ # tenant·workspace-scoped (RFC 0048) ground-truth file store with atomic,
853
+ # optimistically-concurrent (`If-Match`) writes. A successful PUT/DELETE
854
+ # emits a content-free `workspace.updated` event. Hosts without the
855
+ # advertised capability return `501 capability_not_provided`.
856
+ /v1/host/workspace/files:
857
+ get:
858
+ tags: [host]
859
+ summary: List workspace file metadata for the caller's tenant·workspace (RFC 0059).
860
+ description: |
861
+ Returns file metadata (no bodies) for the caller's `{tenant,
862
+ workspace}` per RFC 0059 §C. Optional `?prefix=` filters the flat
863
+ `path` namespace to entries starting with the given prefix.
864
+ operationId: listWorkspaceFiles
865
+ parameters:
866
+ - $ref: '#/components/parameters/WorkspacePrefix'
867
+ responses:
868
+ '200':
869
+ description: Workspace file metadata (tenant·workspace-scoped; bodies omitted).
870
+ content:
871
+ application/json:
872
+ schema:
873
+ type: object
874
+ required: [files]
875
+ properties:
876
+ files:
877
+ type: array
878
+ items:
879
+ $ref: '../schemas/workspace-file.schema.json'
880
+ additionalProperties: false
881
+ '401': { $ref: '#/components/responses/Unauthenticated' }
882
+ '403': { $ref: '#/components/responses/Forbidden' }
883
+ '501':
884
+ description: 'Host does not advertise capabilities.workspace.supported (RFC 0059).'
885
+ content:
886
+ application/json:
887
+ schema:
888
+ $ref: '../schemas/error-envelope.schema.json'
889
+
890
+ /v1/host/workspace/files/{path}:
891
+ get:
892
+ tags: [host]
893
+ summary: Read one workspace file (RFC 0059).
894
+ description: |
895
+ Returns the `WorkspaceFile` at `path` for the caller's `{tenant,
896
+ workspace}`. When `capabilities.workspace.versioned: true`, an
897
+ optional `?version=N` returns the historical snapshot at version N.
898
+ operationId: getWorkspaceFile
899
+ parameters:
900
+ - $ref: '#/components/parameters/WorkspacePath'
901
+ - $ref: '#/components/parameters/WorkspaceVersion'
902
+ responses:
903
+ '200':
904
+ description: The workspace file (current version, or `?version=N` when versioned).
905
+ content:
906
+ application/json:
907
+ schema:
908
+ $ref: '../schemas/workspace-file.schema.json'
909
+ '401': { $ref: '#/components/responses/Unauthenticated' }
910
+ '403': { $ref: '#/components/responses/Forbidden' }
911
+ '404': { $ref: '#/components/responses/NotFound' }
912
+ '501':
913
+ description: 'Host does not advertise capabilities.workspace.supported (RFC 0059).'
914
+ content:
915
+ application/json:
916
+ schema:
917
+ $ref: '../schemas/error-envelope.schema.json'
918
+ put:
919
+ tags: [host]
920
+ summary: Atomic create/replace of a workspace file (RFC 0059).
921
+ description: |
922
+ Atomically creates or replaces the file at `path` per RFC 0059 §C.
923
+ MUST honor `If-Match: <etag>` — a stale token returns `409
924
+ workspace_conflict` (`details.currentVersion` carries the live
925
+ version). On success the host bumps `version`, recomputes `etag`,
926
+ and emits a `workspace.updated` event. A `content` exceeding
927
+ `capabilities.workspace.maxFileBytes` returns `workspace_too_large`.
928
+ operationId: putWorkspaceFile
929
+ parameters:
930
+ - $ref: '#/components/parameters/WorkspacePath'
931
+ - $ref: '#/components/parameters/IfMatch'
932
+ - $ref: '#/components/parameters/IdempotencyKey'
933
+ requestBody:
934
+ required: true
935
+ content:
936
+ application/json:
937
+ schema:
938
+ $ref: '../schemas/workspace-file-create.schema.json'
939
+ responses:
940
+ '200':
941
+ description: File created or replaced. Returns the persisted WorkspaceFile.
942
+ content:
943
+ application/json:
944
+ schema:
945
+ $ref: '../schemas/workspace-file.schema.json'
946
+ '400': { $ref: '#/components/responses/ValidationError' }
947
+ '401': { $ref: '#/components/responses/Unauthenticated' }
948
+ '403': { $ref: '#/components/responses/Forbidden' }
949
+ '409':
950
+ description: 'Stale `If-Match` — the file changed since the supplied etag (`workspace_conflict`).'
951
+ content:
952
+ application/json:
953
+ schema:
954
+ $ref: '../schemas/error-envelope.schema.json'
955
+ '413':
956
+ description: 'Content exceeds `capabilities.workspace.maxFileBytes` (`workspace_too_large`).'
957
+ content:
958
+ application/json:
959
+ schema:
960
+ $ref: '../schemas/error-envelope.schema.json'
961
+ '501':
962
+ description: 'Host does not advertise capabilities.workspace.supported (RFC 0059).'
963
+ content:
964
+ application/json:
965
+ schema:
966
+ $ref: '../schemas/error-envelope.schema.json'
967
+ delete:
968
+ tags: [host]
969
+ summary: Delete a workspace file (RFC 0059).
970
+ description: |
971
+ Removes the file at `path` (and, when `versioned: true`, writes a
972
+ tombstone). Emits a `workspace.updated` event on success.
973
+ operationId: deleteWorkspaceFile
974
+ parameters:
975
+ - $ref: '#/components/parameters/WorkspacePath'
976
+ - $ref: '#/components/parameters/IdempotencyKey'
977
+ responses:
978
+ '204':
979
+ description: File deleted.
980
+ '401': { $ref: '#/components/responses/Unauthenticated' }
981
+ '403': { $ref: '#/components/responses/Forbidden' }
982
+ '404': { $ref: '#/components/responses/NotFound' }
983
+ '501':
984
+ description: 'Host does not advertise capabilities.workspace.supported (RFC 0059).'
985
+ content:
986
+ application/json:
987
+ schema:
988
+ $ref: '../schemas/error-envelope.schema.json'
989
+
990
+ /v1/runs:bulk-cancel:
991
+ post:
992
+ tags: [runs]
993
+ summary: Cancel a set of in-flight runs in a single request.
994
+ description: |
995
+ Per `spec/v1/rest-endpoints.md` §"POST /v1/runs:bulk-cancel". Accepts
996
+ a non-empty array of runIds and processes each cancellation
997
+ independently. Returns `200` with a per-id results array even when
998
+ some individual cancellations fail; the top-level operation succeeds
999
+ when the request reached the host, regardless of per-id outcomes.
1000
+ Hosts enforce a host-defined cap on the array length (RECOMMENDED
1001
+ 100); over-cap requests return `400 validation_error`.
1002
+ operationId: bulkCancelRuns
1003
+ parameters:
1004
+ - $ref: '#/components/parameters/IdempotencyKey'
1005
+ requestBody:
1006
+ required: true
1007
+ content:
1008
+ application/json:
1009
+ schema:
1010
+ type: object
1011
+ required: [runIds]
1012
+ properties:
1013
+ runIds:
1014
+ type: array
1015
+ minItems: 1
1016
+ maxItems: 100
1017
+ items: { type: string, minLength: 1, maxLength: 128 }
1018
+ reason: { type: string, maxLength: 512 }
1019
+ additionalProperties: false
1020
+ responses:
1021
+ '200':
1022
+ description: Per-id cancel results.
1023
+ content:
1024
+ application/json:
1025
+ schema:
1026
+ type: object
1027
+ required: [results]
1028
+ properties:
1029
+ results:
1030
+ type: array
1031
+ items:
1032
+ type: object
1033
+ required: [runId, ok]
1034
+ properties:
1035
+ runId: { type: string, minLength: 1 }
1036
+ ok: { type: boolean }
1037
+ status: { type: string, enum: [cancelled, cancelling] }
1038
+ error:
1039
+ $ref: '../schemas/error-envelope.schema.json'
1040
+ additionalProperties: false
1041
+ additionalProperties: false
1042
+ '400': { $ref: '#/components/responses/ValidationError' }
1043
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1044
+ '403': { $ref: '#/components/responses/Forbidden' }
1045
+
1046
+ /v1/runs/{runId}:fork:
1047
+ post:
1048
+ tags: [runs]
1049
+ summary: Fork the run for replay or branch (see `replay.md`).
1050
+ operationId: forkRun
1051
+ parameters:
1052
+ - $ref: '#/components/parameters/RunId'
1053
+ - $ref: '#/components/parameters/IdempotencyKey'
1054
+ requestBody:
1055
+ required: true
1056
+ content:
1057
+ application/json:
1058
+ schema:
1059
+ type: object
1060
+ required: [mode]
1061
+ properties:
1062
+ fromSeq:
1063
+ type: integer
1064
+ minimum: 0
1065
+ description: |
1066
+ Inclusive — events `< fromSeq` are fixed history; `>= fromSeq` are re-executed.
1067
+ Required for `branch` (the branch point). Optional for `replay`; when omitted,
1068
+ defaults to `0` (full re-execution from source-run start) per `replay.md`
1069
+ §"Replay-mode defaults".
1070
+ mode:
1071
+ type: string
1072
+ enum: [replay, branch]
1073
+ runOptionsOverlay:
1074
+ type: object
1075
+ description: For `branch` mode only — caller-supplied `RunOptions` to overlay.
1076
+ additionalProperties: false
1077
+ responses:
1078
+ '201':
1079
+ description: Fork accepted, new run started.
1080
+ content:
1081
+ application/json:
1082
+ schema:
1083
+ type: object
1084
+ required: [runId, sourceRunId, mode, status, eventsUrl]
1085
+ properties:
1086
+ runId: { type: string }
1087
+ sourceRunId: { type: string }
1088
+ fromSeq: { type: integer }
1089
+ mode: { type: string, enum: [replay, branch] }
1090
+ status: { type: string }
1091
+ eventsUrl: { type: string, format: uri }
1092
+ '400':
1093
+ description: Invalid `fromSeq`, `replay` with non-empty `runOptionsOverlay`, etc.
1094
+ content:
1095
+ application/json:
1096
+ schema: { $ref: '#/components/schemas/Error' }
1097
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1098
+ '403': { $ref: '#/components/responses/Forbidden' }
1099
+ '404': { $ref: '#/components/responses/NotFound' }
1100
+ '422':
1101
+ description: "`fromSeq` references a sequence number that doesn't exist in the source run's event log."
1102
+ content:
1103
+ application/json:
1104
+ schema: { $ref: '#/components/schemas/Error' }
1105
+ /v1/runs/{runId}/ancestry:
1106
+ get:
1107
+ tags: [runs]
1108
+ summary: |
1109
+ RFC 0040 §C — return the run's immediate parent in the cross-host
1110
+ composition chain. Capability-gated on
1111
+ `capabilities.multiAgent.executionModel.crossHostCausation.ancestryEndpointSupported: true`;
1112
+ hosts that don't advertise return 404 not_found. Clients walk the full
1113
+ chain by following `parent.wellKnownUrl` per response, one hop at a
1114
+ time.
1115
+ operationId: getRunAncestry
1116
+ parameters:
1117
+ - $ref: '#/components/parameters/RunId'
1118
+ responses:
1119
+ '200':
1120
+ description: |
1121
+ Run's immediate parent (or `parent: null` for top-level runs).
1122
+ content:
1123
+ application/json:
1124
+ schema:
1125
+ $ref: '../schemas/run-ancestry-response.schema.json'
1126
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1127
+ '403': { $ref: '#/components/responses/Forbidden' }
1128
+ '404':
1129
+ description: |
1130
+ Either the run doesn't exist, OR the host doesn't advertise
1131
+ `crossHostCausation.ancestryEndpointSupported: true` and treats
1132
+ the endpoint as absent. Clients can disambiguate by inspecting
1133
+ the host's discovery doc.
1134
+ content:
1135
+ application/json:
1136
+ schema: { $ref: '#/components/schemas/Error' }
1137
+
1138
+ /v1/agents:
1139
+ get:
1140
+ tags: [agents]
1141
+ summary: |
1142
+ RFC 0072 §A — list the manifest agents this host has installed into its
1143
+ AgentRegistry (RFC 0070). Capability-gated on
1144
+ `capabilities.agents.manifestRuntime.supported: true`; hosts that don't
1145
+ advertise it return 404. Read-only projection — never carries the
1146
+ system-prompt body, resolved handoff schemas, or credential material (SR-1).
1147
+ Dispatch is not a bespoke endpoint: a manifest agent is invoked as a run
1148
+ whose node pins it via `WorkflowNode.agent` + `POST /v1/runs` (RFC 0072 §B).
1149
+ RFC 0074 — the result is scoped to the authenticated principal's owner
1150
+ triple (RFC 0048). When `capabilities.agents.manifestRuntime.installScope`
1151
+ is `'tenant'`, only the agents available to the caller's tenant·workspace
1152
+ are returned (an agent another workspace installed is absent, never
1153
+ disclosed); when `'host'` (default) the inventory is host-global as in
1154
+ RFC 0072. A `'tenant'`-scoped host MUST reject unauthenticated/unscoped
1155
+ requests per its standard auth contract rather than fall back to a global list.
1156
+ operationId: listAgents
1157
+ responses:
1158
+ '200':
1159
+ description: Installed manifest agents (agentId-sorted).
1160
+ content:
1161
+ application/json:
1162
+ schema:
1163
+ $ref: '../schemas/agent-inventory-response.schema.json'
1164
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1165
+ '403': { $ref: '#/components/responses/Forbidden' }
1166
+ '404':
1167
+ description: |
1168
+ Host does not advertise `capabilities.agents.manifestRuntime` and
1169
+ treats the endpoint as absent.
1170
+ content:
1171
+ application/json:
1172
+ schema: { $ref: '#/components/schemas/Error' }
1173
+
1174
+ /v1/agents/{agentId}:
1175
+ get:
1176
+ tags: [agents]
1177
+ summary: |
1178
+ RFC 0072 §A — return one installed manifest agent's inventory entry, or
1179
+ 404 when no such agent is installed (or the host doesn't advertise
1180
+ `capabilities.agents.manifestRuntime`). RFC 0074 — resolved within the
1181
+ authenticated principal's owner triple (RFC 0048): on an
1182
+ `installScope: 'tenant'` host an agent the caller's workspace has not
1183
+ approved 404s identically to "not installed", so the surface never
1184
+ discloses another tenant's inventory.
1185
+ operationId: getAgent
1186
+ parameters:
1187
+ - in: path
1188
+ name: agentId
1189
+ required: true
1190
+ schema: { type: string, pattern: '^(?!roster$|org-chart$).+$' }
1191
+ description: |
1192
+ The manifest agentId. MUST NOT be the reserved literals `roster` or
1193
+ `org-chart` — those name the sibling collection routes
1194
+ (`/v1/agents/roster`, `/v1/agents/org-chart`), so excluding them here
1195
+ keeps `/v1/agents/{agentId}` unambiguous against them.
1196
+ responses:
1197
+ '200':
1198
+ description: The agent's inventory entry.
1199
+ content:
1200
+ application/json:
1201
+ schema:
1202
+ $ref: '../schemas/agent-inventory-response.schema.json#/$defs/AgentInventoryEntry'
1203
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1204
+ '403': { $ref: '#/components/responses/Forbidden' }
1205
+ '404':
1206
+ description: No such agent, or the host doesn't advertise the capability.
1207
+ content:
1208
+ application/json:
1209
+ schema: { $ref: '#/components/schemas/Error' }
1210
+
1211
+ /v1/agents/{agentId}/deployments:
1212
+ get:
1213
+ tags: [agents]
1214
+ summary: |
1215
+ RFC 0082 §C/§E — list the deployment records (per-(agentId, version)) for
1216
+ a manifest agent: the lifecycle `state`, the named `channels`, the canary
1217
+ share, the rollback pointer, and the last-transition provenance. Read-only,
1218
+ content-free of any manifest body or credential (SR-1). Capability-gated on
1219
+ `capabilities.agents.deployment.supported: true`; hosts that don't advertise
1220
+ it return 404. Tenant-scoped to the caller's owner triple (RFC 0048/0074)
1221
+ when `installScope: 'tenant'`.
1222
+ operationId: listAgentDeployments
1223
+ parameters:
1224
+ - in: path
1225
+ name: agentId
1226
+ required: true
1227
+ schema: { type: string, pattern: '^(?!roster$|org-chart$).+$' }
1228
+ description: |
1229
+ The manifest agentId. MUST NOT be the reserved literals `roster` or
1230
+ `org-chart` — those name the sibling collection routes
1231
+ (`/v1/agents/roster/{rosterId}`, `/v1/agents/org-chart/{departmentId}`),
1232
+ so excluding them here keeps `/v1/agents/{agentId}/deployments`
1233
+ unambiguous against them.
1234
+ responses:
1235
+ '200':
1236
+ description: The agent's deployment records (version-sorted).
1237
+ content:
1238
+ application/json:
1239
+ schema:
1240
+ type: array
1241
+ items: { $ref: '../schemas/agent-deployment.schema.json' }
1242
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1243
+ '403': { $ref: '#/components/responses/Forbidden' }
1244
+ '404':
1245
+ description: No such agent, or the host doesn't advertise `capabilities.agents.deployment`.
1246
+ content:
1247
+ application/json:
1248
+ schema: { $ref: '#/components/schemas/Error' }
1249
+ post:
1250
+ tags: [agents]
1251
+ summary: |
1252
+ RFC 0082 §E — request a deployment state transition (promote / pause /
1253
+ deprecate / rollback / adjust-canary). The host MUST authorize fail-closed
1254
+ against the RFC 0049 `deploy:*` scope (absent/unseeded role denies), run any
1255
+ configured RFC 0051 approvalGate, and — when the gate carries `requiredEval`
1256
+ — verify the referenced RFC 0081 eval run is terminal and `EvalSummary.passed`
1257
+ BEFORE emitting `deployment.promoted`. On success returns the updated
1258
+ deployment record and emits the matching content-free `deployment.*` event.
1259
+ operationId: transitionAgentDeployment
1260
+ parameters:
1261
+ - in: path
1262
+ name: agentId
1263
+ required: true
1264
+ schema: { type: string }
1265
+ description: The manifest agentId.
1266
+ - $ref: '#/components/parameters/IdempotencyKey'
1267
+ requestBody:
1268
+ required: true
1269
+ content:
1270
+ application/json:
1271
+ schema:
1272
+ $ref: '../schemas/agent-deployment-transition.schema.json'
1273
+ responses:
1274
+ '200':
1275
+ description: The deployment record after the applied transition.
1276
+ content:
1277
+ application/json:
1278
+ schema:
1279
+ $ref: '../schemas/agent-deployment.schema.json'
1280
+ '400':
1281
+ description: |
1282
+ Validation error, or a transition that the host's advertised
1283
+ `states`/`canary` cannot satisfy, or `no_active_deployment` when a
1284
+ referenced channel resolves to no active version.
1285
+ content:
1286
+ application/json:
1287
+ schema: { $ref: '#/components/schemas/Error' }
1288
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1289
+ '403':
1290
+ description: |
1291
+ Fail-closed authorization denial (the principal lacks the required
1292
+ `deploy:*` scope — RFC 0049), or `eval_gate_unmet` when a `requiredEval`
1293
+ gate's referenced eval run is not terminal-and-passed (RFC 0081).
1294
+ content:
1295
+ application/json:
1296
+ schema: { $ref: '#/components/schemas/Error' }
1297
+ '404':
1298
+ description: No such agent, or the host doesn't advertise `capabilities.agents.deployment`.
1299
+ content:
1300
+ application/json:
1301
+ schema: { $ref: '#/components/schemas/Error' }
1302
+
1303
+ /v1/agents/roster:
1304
+ get:
1305
+ tags: [agents]
1306
+ summary: |
1307
+ RFC 0086 §B — list the standing agent roster (named "digital-twin
1308
+ employee" instances + their workflow portfolios) visible to the
1309
+ caller. Capability-gated on `capabilities.agents.roster.supported:
1310
+ true`; hosts that don't advertise it return 404. Tenant-scoped per
1311
+ RFC 0074 — on an `installScope: 'tenant'` host only the caller's
1312
+ owner-triple entries are returned. Read-only; content-free (SR-1).
1313
+ operationId: listAgentRoster
1314
+ responses:
1315
+ '200':
1316
+ description: The caller's standing roster (rosterId-sorted).
1317
+ content:
1318
+ application/json:
1319
+ schema:
1320
+ $ref: '../schemas/agent-roster-response.schema.json'
1321
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1322
+ '403': { $ref: '#/components/responses/Forbidden' }
1323
+ '404':
1324
+ description: Host does not advertise `capabilities.agents.roster`.
1325
+ content:
1326
+ application/json:
1327
+ schema: { $ref: '#/components/schemas/Error' }
1328
+
1329
+ /v1/agents/roster/{rosterId}:
1330
+ get:
1331
+ tags: [agents]
1332
+ summary: |
1333
+ RFC 0086 §B — return one standing roster entry, or 404 when no such
1334
+ entry exists, the host doesn't advertise `capabilities.agents.roster`,
1335
+ or (on an `installScope: 'tenant'` host) the entry is outside the
1336
+ caller's owner triple — a cross-tenant entry 404s identically to
1337
+ "not found", never disclosing another tenant's roster.
1338
+ operationId: getAgentRosterEntry
1339
+ parameters:
1340
+ - in: path
1341
+ name: rosterId
1342
+ required: true
1343
+ schema: { type: string }
1344
+ description: The standing instance id (a `host:<id>` AgentRef agentId).
1345
+ responses:
1346
+ '200':
1347
+ description: The roster entry.
1348
+ content:
1349
+ application/json:
1350
+ schema:
1351
+ $ref: '../schemas/agent-roster-entry.schema.json'
1352
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1353
+ '403': { $ref: '#/components/responses/Forbidden' }
1354
+ '404':
1355
+ description: No such entry, cross-tenant, or capability unadvertised.
1356
+ content:
1357
+ application/json:
1358
+ schema: { $ref: '#/components/schemas/Error' }
1359
+
1360
+ /v1/agents/org-chart:
1361
+ get:
1362
+ tags: [agents]
1363
+ summary: |
1364
+ RFC 0087 §C — return the caller's agent org-chart (departments + roles
1365
+ + `reportsTo` edges over roster members). Capability-gated on
1366
+ `capabilities.agents.orgChart.supported: true`; hosts that don't
1367
+ advertise it return 404. Tenant-scoped per RFC 0074. DESCRIPTIVE only:
1368
+ an org edge confers no authority (§B `org-position-no-authority-escalation`).
1369
+ operationId: getAgentOrgChart
1370
+ responses:
1371
+ '200':
1372
+ description: The caller's org-chart.
1373
+ content:
1374
+ application/json:
1375
+ schema:
1376
+ $ref: '../schemas/agent-org-chart.schema.json'
1377
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1378
+ '403': { $ref: '#/components/responses/Forbidden' }
1379
+ '404':
1380
+ description: Host does not advertise `capabilities.agents.orgChart`.
1381
+ content:
1382
+ application/json:
1383
+ schema: { $ref: '#/components/schemas/Error' }
1384
+
1385
+ /v1/agents/org-chart/{departmentId}:
1386
+ get:
1387
+ tags: [agents]
1388
+ summary: |
1389
+ RFC 0087 §D — one department's subtree + responsibility roll-up (the
1390
+ union of its members' RFC 0086 portfolios). `?recursive=false` narrows
1391
+ the roll-up to direct members without changing the response shape.
1392
+ 404 when the department is unknown, cross-tenant, or the host doesn't
1393
+ advertise `capabilities.agents.orgChart`. The roll-up grants nothing (§B).
1394
+ operationId: getAgentOrgChartDepartment
1395
+ parameters:
1396
+ - in: path
1397
+ name: departmentId
1398
+ required: true
1399
+ schema: { type: string }
1400
+ description: The department id to root the subtree + roll-up at.
1401
+ - in: query
1402
+ name: recursive
1403
+ required: false
1404
+ schema: { type: boolean, default: true }
1405
+ description: When `false`, the roll-up scopes to direct members only.
1406
+ responses:
1407
+ '200':
1408
+ description: The department subtree + responsibility roll-up.
1409
+ content:
1410
+ application/json:
1411
+ schema:
1412
+ $ref: '../schemas/org-chart-responsibility-view.schema.json'
1413
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1414
+ '403': { $ref: '#/components/responses/Forbidden' }
1415
+ '404':
1416
+ description: Unknown/cross-tenant department, or capability unadvertised.
1417
+ content:
1418
+ application/json:
1419
+ schema: { $ref: '#/components/schemas/Error' }
1420
+
1421
+ /v1/tools:
1422
+ get:
1423
+ tags: [tools]
1424
+ summary: |
1425
+ RFC 0078 §B — list the portable `ToolDescriptor`s visible to the caller
1426
+ across every tool source (node-pack / workflow / mcp / connector /
1427
+ host-extension). Capability-gated on
1428
+ `capabilities.toolCatalog.supported: true`; hosts that don't advertise
1429
+ it return 404. §F-2 — the projection is authorization-scoped: a
1430
+ principal sees only the tools it may invoke, and a second principal MUST
1431
+ NOT see another principal's tools (non-disclosure). Read-only; each
1432
+ descriptor is content-free of any credential material (SR-1).
1433
+ operationId: listTools
1434
+ parameters:
1435
+ - name: view
1436
+ in: query
1437
+ required: false
1438
+ schema: { type: string, enum: [standard, compact], default: standard }
1439
+ description: >
1440
+ RFC 0112. `compact` returns the `{ tools: CompactToolDescriptor[] }`
1441
+ projection — heavy descriptor fields omitted and `inputSchema`
1442
+ bounded to the compact structural subset — when the host advertises
1443
+ `capabilities.toolCatalog.compactView: true`. Defaults to `standard`;
1444
+ a host that does not advertise `compactView` treats `view=compact`
1445
+ as any unknown query param and returns the standard view.
1446
+ responses:
1447
+ '200':
1448
+ description: 'The caller''s authorized tool catalog (standard array, or the compact `{ tools: [] }` projection when `view=compact`).'
1449
+ content:
1450
+ application/json:
1451
+ schema:
1452
+ oneOf:
1453
+ - type: array
1454
+ items: { $ref: '../schemas/tool-descriptor.schema.json' }
1455
+ - type: object
1456
+ required: [tools]
1457
+ properties:
1458
+ tools:
1459
+ type: array
1460
+ items: { $ref: '../schemas/compact-tool-descriptor.schema.json' }
1461
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1462
+ '403': { $ref: '#/components/responses/Forbidden' }
1463
+ '404':
1464
+ description: Host does not advertise `capabilities.toolCatalog`.
1465
+ content:
1466
+ application/json:
1467
+ schema: { $ref: '#/components/schemas/Error' }
1468
+
1469
+ /v1/tools/{toolId}:
1470
+ get:
1471
+ tags: [tools]
1472
+ summary: |
1473
+ RFC 0078 §B — return one `ToolDescriptor` by its stable `toolId`, or 404
1474
+ when no such tool exists, the caller isn't authorized for it (§F-2
1475
+ non-disclosure — a cross-principal tool 404s identically to "not
1476
+ found"), or the host doesn't advertise `capabilities.toolCatalog`.
1477
+ operationId: getTool
1478
+ parameters:
1479
+ - in: path
1480
+ name: toolId
1481
+ required: true
1482
+ schema: { type: string }
1483
+ description: The stable tool id (`ToolDescriptor.toolId`).
1484
+ - name: view
1485
+ in: query
1486
+ required: false
1487
+ schema: { type: string, enum: [standard, compact], default: standard }
1488
+ description: >
1489
+ RFC 0112. `compact` returns one `CompactToolDescriptor` (heavy
1490
+ fields omitted; `inputSchema` bounded to the compact structural
1491
+ subset) when the host advertises
1492
+ `capabilities.toolCatalog.compactView: true`. Defaults to
1493
+ `standard`; a host that does not advertise `compactView` treats
1494
+ `view=compact` as any unknown query param.
1495
+ responses:
1496
+ '200':
1497
+ description: The tool descriptor (standard, or one `CompactToolDescriptor` when `view=compact`).
1498
+ content:
1499
+ application/json:
1500
+ schema:
1501
+ oneOf:
1502
+ - $ref: '../schemas/tool-descriptor.schema.json'
1503
+ - $ref: '../schemas/compact-tool-descriptor.schema.json'
1504
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1505
+ '403': { $ref: '#/components/responses/Forbidden' }
1506
+ '404':
1507
+ description: No such tool, unauthorized, or capability unadvertised.
1508
+ content:
1509
+ application/json:
1510
+ schema: { $ref: '#/components/schemas/Error' }
1511
+
1512
+ /v1/runs/{runId}/eval-summary:
1513
+ get:
1514
+ tags: [runs]
1515
+ summary: |
1516
+ RFC 0081 §C — return the `EvalSummary` scorecard for a terminal eval run
1517
+ (a run started with `mode: "eval"`): aggregate + per-task scores, cost,
1518
+ latency, schema-validity, and redaction-safe safety findings, plus the
1519
+ suite provenance and (regression mode) the score delta vs a baseline.
1520
+ Content-free of task output / rubric prose / credentials (SR-1; the
1521
+ `eval-summary-no-content-leak` invariant). Capability-gated on
1522
+ `capabilities.agents.evalSuite.supported: true`; hosts that don't advertise
1523
+ it return 404. 409 when the run is not yet terminal.
1524
+ operationId: getEvalSummary
1525
+ parameters:
1526
+ - $ref: '#/components/parameters/RunId'
1527
+ responses:
1528
+ '200':
1529
+ description: The eval run's scorecard.
1530
+ content:
1531
+ application/json:
1532
+ schema:
1533
+ $ref: '../schemas/eval-summary.schema.json'
1534
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1535
+ '403': { $ref: '#/components/responses/Forbidden' }
1536
+ '404':
1537
+ description: |
1538
+ No such run, the run is not an eval run, or the host doesn't advertise
1539
+ `capabilities.agents.evalSuite`.
1540
+ content:
1541
+ application/json:
1542
+ schema: { $ref: '#/components/schemas/Error' }
1543
+ '409':
1544
+ description: The eval run is still running; the summary is not yet final.
1545
+ content:
1546
+ application/json:
1547
+ schema: { $ref: '#/components/schemas/Error' }
1548
+
1549
+ /v1/runs/{runId}:diff:
1550
+ get:
1551
+ tags: [runs]
1552
+ summary: |
1553
+ RFC 0054 — return a deterministic, replay-aware structured diff of
1554
+ two runs (typically a run and its RFC 0011 fork): `divergedAtSeq` +
1555
+ ordered `eventDiffs[]` + `stateDiff`. The diff is a pure function of
1556
+ the two event logs (see `replay.md` determinism contract). Requires
1557
+ `runs:read` on BOTH runs. Hosts that don't implement it return 404.
1558
+ operationId: diffRun
1559
+ parameters:
1560
+ - $ref: '#/components/parameters/RunId'
1561
+ - name: against
1562
+ in: query
1563
+ required: true
1564
+ description: The other run id to diff `{runId}` against (the `b` run).
1565
+ schema: { type: string }
1566
+ responses:
1567
+ '200':
1568
+ description: |
1569
+ Structured diff of the two runs. `divergedAtSeq: null` + empty
1570
+ `eventDiffs` when the logs are identical.
1571
+ content:
1572
+ application/json:
1573
+ schema:
1574
+ $ref: '../schemas/run-diff-response.schema.json'
1575
+ '400':
1576
+ description: Missing or malformed `against` query parameter.
1577
+ content:
1578
+ application/json:
1579
+ schema: { $ref: '#/components/schemas/Error' }
1580
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1581
+ '403':
1582
+ description: |
1583
+ Caller lacks `runs:read` on `{runId}` and/or on `against`
1584
+ (`forbidden`); composes with RFC 0048 cross-workspace
1585
+ isolation.
1586
+ content:
1587
+ application/json:
1588
+ schema: { $ref: '#/components/schemas/Error' }
1589
+ '404':
1590
+ description: |
1591
+ Either run doesn't exist, OR the host doesn't implement the diff
1592
+ endpoint and treats the path as absent.
1593
+ content:
1594
+ application/json:
1595
+ schema: { $ref: '#/components/schemas/Error' }
1596
+
1597
+ /v1/runs/{runId}:pause:
1598
+ post:
1599
+ tags: [runs]
1600
+ summary: Administratively pause an in-flight run (RFC Track 13).
1601
+ description: |
1602
+ Operator-driven pause distinct from cancel (terminal) and HITL suspend (workflow-driven).
1603
+ Emits a `run.paused` event when the pause takes effect; exit only via `:resume` or `:cancel`.
1604
+ operationId: pauseRun
1605
+ parameters:
1606
+ - $ref: '#/components/parameters/RunId'
1607
+ - $ref: '#/components/parameters/IdempotencyKey'
1608
+ requestBody:
1609
+ content:
1610
+ application/json:
1611
+ schema:
1612
+ type: object
1613
+ properties:
1614
+ reason:
1615
+ type: string
1616
+ description: Free-form rationale, persisted on the `run.paused` event payload.
1617
+ drainPolicy:
1618
+ type: string
1619
+ enum: [immediate, drain-current-node]
1620
+ default: drain-current-node
1621
+ description: |
1622
+ `immediate` snapshots between events; `drain-current-node` lets the running node
1623
+ reach a terminal before transitioning to `paused`.
1624
+ additionalProperties: false
1625
+ responses:
1626
+ '202':
1627
+ description: Pause requested; transition emits `run.paused` when complete.
1628
+ content:
1629
+ application/json:
1630
+ schema:
1631
+ type: object
1632
+ required: [runId, status]
1633
+ properties:
1634
+ runId: { type: string }
1635
+ status: { type: string, enum: [paused] }
1636
+ pausedAt: { type: string, format: date-time }
1637
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1638
+ '403': { $ref: '#/components/responses/Forbidden' }
1639
+ '404': { $ref: '#/components/responses/NotFound' }
1640
+ '409':
1641
+ description: Run is already paused, terminal, or in a state that cannot be paused.
1642
+ content:
1643
+ application/json:
1644
+ schema: { $ref: '#/components/schemas/Error' }
1645
+
1646
+ /v1/runs/{runId}:resume:
1647
+ post:
1648
+ tags: [runs]
1649
+ summary: Resume a paused run (RFC Track 13).
1650
+ description: |
1651
+ Reverses a prior `:pause`. Run transitions from `paused` to `running` and emits `run.resumed`.
1652
+ operationId: resumeRun
1653
+ parameters:
1654
+ - $ref: '#/components/parameters/RunId'
1655
+ - $ref: '#/components/parameters/IdempotencyKey'
1656
+ requestBody:
1657
+ content:
1658
+ application/json:
1659
+ schema:
1660
+ type: object
1661
+ properties:
1662
+ reason: { type: string }
1663
+ additionalProperties: false
1664
+ responses:
1665
+ '202':
1666
+ description: Resume requested.
1667
+ content:
1668
+ application/json:
1669
+ schema:
1670
+ type: object
1671
+ required: [runId, status]
1672
+ properties:
1673
+ runId: { type: string }
1674
+ status: { type: string, enum: [running] }
1675
+ resumedAt: { type: string, format: date-time }
1676
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1677
+ '403': { $ref: '#/components/responses/Forbidden' }
1678
+ '404': { $ref: '#/components/responses/NotFound' }
1679
+ '409':
1680
+ description: Run is not currently paused.
1681
+ content:
1682
+ application/json:
1683
+ schema: { $ref: '#/components/schemas/Error' }
1684
+
1685
+ # ── HITL ────────────────────────────────────────────────────────────────
1686
+ /v1/runs/{runId}/interrupts/{nodeId}:
1687
+ post:
1688
+ tags: [hitl]
1689
+ summary: Resolve an interrupt via the run-scoped surface.
1690
+ operationId: resolveInterruptByRun
1691
+ parameters:
1692
+ - $ref: '#/components/parameters/RunId'
1693
+ - in: path
1694
+ name: nodeId
1695
+ required: true
1696
+ schema: { type: string, minLength: 1 }
1697
+ - $ref: '#/components/parameters/IdempotencyKey'
1698
+ requestBody:
1699
+ required: true
1700
+ content:
1701
+ application/json:
1702
+ schema:
1703
+ type: object
1704
+ required: [resumeValue]
1705
+ properties:
1706
+ resumeValue:
1707
+ description: Validated against the interrupt's `resumeSchema` if declared.
1708
+ additionalProperties: false
1709
+ responses:
1710
+ '200':
1711
+ description: Interrupt resolved; executor unblocks.
1712
+ content:
1713
+ application/json:
1714
+ schema:
1715
+ type: object
1716
+ properties:
1717
+ runId: { type: string }
1718
+ nodeId: { type: string }
1719
+ status: { type: string }
1720
+ '400': { $ref: '#/components/responses/ValidationError' }
1721
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1722
+ '403': { $ref: '#/components/responses/Forbidden' }
1723
+ '404':
1724
+ description: Interrupt not found or already resolved.
1725
+ content:
1726
+ application/json:
1727
+ schema: { $ref: '#/components/schemas/Error' }
1728
+ '409':
1729
+ description: Concurrent resolve — only one wins.
1730
+ content:
1731
+ application/json:
1732
+ schema: { $ref: '#/components/schemas/Error' }
1733
+ '422':
1734
+ description: Run was cancelled while interrupt was pending.
1735
+ content:
1736
+ application/json:
1737
+ schema: { $ref: '#/components/schemas/Error' }
1738
+
1739
+ /v1/interrupts/{token}:
1740
+ parameters:
1741
+ - in: path
1742
+ name: token
1743
+ required: true
1744
+ schema: { type: string }
1745
+ description: HMAC-signed token issued by the server at suspension time. Format `base64url(payload).hmac_sha256(secret, payload)`.
1746
+ get:
1747
+ tags: [hitl]
1748
+ summary: Inspect an interrupt without resolving (signed-token surface).
1749
+ operationId: inspectInterruptByToken
1750
+ security: [] # token is the auth
1751
+ responses:
1752
+ '200':
1753
+ description: Interrupt details.
1754
+ content:
1755
+ application/json:
1756
+ schema: { $ref: '../schemas/suspend-request.schema.json' }
1757
+ '410':
1758
+ description: Token expired.
1759
+ content:
1760
+ application/json:
1761
+ schema: { $ref: '#/components/schemas/Error' }
1762
+ post:
1763
+ tags: [hitl]
1764
+ summary: Resolve an interrupt via signed token (asynchronous callback).
1765
+ operationId: resolveInterruptByToken
1766
+ security: [] # token is the auth
1767
+ parameters:
1768
+ - $ref: '#/components/parameters/IdempotencyKey'
1769
+ requestBody:
1770
+ required: true
1771
+ content:
1772
+ application/json:
1773
+ schema:
1774
+ type: object
1775
+ required: [resumeValue]
1776
+ properties:
1777
+ resumeValue: {}
1778
+ additionalProperties: false
1779
+ responses:
1780
+ '200':
1781
+ description: Resolution accepted.
1782
+ content:
1783
+ application/json:
1784
+ schema: { type: object }
1785
+ '410':
1786
+ description: Token expired.
1787
+ content:
1788
+ application/json:
1789
+ schema: { $ref: '#/components/schemas/Error' }
1790
+
1791
+ # ── Artifacts ───────────────────────────────────────────────────────────
1792
+ /v1/runs/{runId}/artifacts/{artifactId}:
1793
+ get:
1794
+ tags: [artifacts]
1795
+ summary: Read a run-produced artifact.
1796
+ operationId: getArtifact
1797
+ parameters:
1798
+ - $ref: '#/components/parameters/RunId'
1799
+ - in: path
1800
+ name: artifactId
1801
+ required: true
1802
+ schema: { type: string, minLength: 1 }
1803
+ responses:
1804
+ '200':
1805
+ description: Artifact payload.
1806
+ content:
1807
+ application/json:
1808
+ schema:
1809
+ type: object
1810
+ description: Implementation-defined artifact shape.
1811
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1812
+ '403': { $ref: '#/components/responses/Forbidden' }
1813
+ '404': { $ref: '#/components/responses/NotFound' }
1814
+
1815
+ # ── Webhooks ────────────────────────────────────────────────────────────
1816
+ /v1/webhooks:
1817
+ post:
1818
+ tags: [webhooks]
1819
+ summary: Register a webhook subscription.
1820
+ operationId: registerWebhook
1821
+ parameters:
1822
+ - $ref: '#/components/parameters/IdempotencyKey'
1823
+ requestBody:
1824
+ required: true
1825
+ content:
1826
+ application/json:
1827
+ schema:
1828
+ type: object
1829
+ required: [url, events]
1830
+ properties:
1831
+ url: { type: string, format: uri }
1832
+ events:
1833
+ type: array
1834
+ items: { type: string }
1835
+ description: Event types to subscribe to (see `run-event.schema.json` enum).
1836
+ secret:
1837
+ type: string
1838
+ description: Server signs payloads with this secret using HMAC-SHA256.
1839
+ tags:
1840
+ type: array
1841
+ items: { type: string }
1842
+ description: Filter to runs carrying these tags (see `run-options.md`).
1843
+ additionalProperties: false
1844
+ responses:
1845
+ '201':
1846
+ description: Webhook registered.
1847
+ content:
1848
+ application/json:
1849
+ schema:
1850
+ type: object
1851
+ required: [webhookId]
1852
+ properties:
1853
+ webhookId: { type: string }
1854
+ '400': { $ref: '#/components/responses/ValidationError' }
1855
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1856
+ '403': { $ref: '#/components/responses/Forbidden' }
1857
+
1858
+ /v1/webhooks/{webhookId}:
1859
+ delete:
1860
+ tags: [webhooks]
1861
+ summary: Unregister a webhook.
1862
+ operationId: unregisterWebhook
1863
+ parameters:
1864
+ - in: path
1865
+ name: webhookId
1866
+ required: true
1867
+ schema: { type: string, minLength: 1 }
1868
+ responses:
1869
+ '204':
1870
+ description: Unregistered.
1871
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1872
+ '403': { $ref: '#/components/responses/Forbidden' }
1873
+ '404': { $ref: '#/components/responses/NotFound' }
1874
+
1875
+ # ── Audit-log integrity verification (gated on profile) ────────────────
1876
+ /v1/audit/verify:
1877
+ get:
1878
+ tags: [audit]
1879
+ summary: Verify the audit-log hash chain over [fromSeq, toSeq].
1880
+ description: |
1881
+ Per `spec/v1/auth-profiles.md` §`openwop-audit-log-integrity` §4. The
1882
+ verifier re-walks audit-log entries in the requested range,
1883
+ re-computes each entry's `prevHash` from the canonical RFC 8785 JCS
1884
+ serialization of the prior entry, verifies signed checkpoints
1885
+ against the host's advertised `auditLogIntegrity.checkpointPublicKey`,
1886
+ and returns `chainValid` + an enumeration of any anomalies.
1887
+ Hosts MUST require the `audit:read` scope. Hosts that do NOT
1888
+ advertise the `openwop-audit-log-integrity` profile MAY omit this
1889
+ endpoint entirely (clients SHOULD pre-flight via `/.well-known/openwop`).
1890
+ operationId: verifyAuditLog
1891
+ parameters:
1892
+ - in: query
1893
+ name: fromSeq
1894
+ required: true
1895
+ schema: { type: integer, minimum: 0 }
1896
+ description: First audit-log sequence to include (inclusive).
1897
+ - in: query
1898
+ name: toSeq
1899
+ required: true
1900
+ schema: { type: integer, minimum: 0 }
1901
+ description: Last audit-log sequence to include (inclusive). MUST be >= fromSeq.
1902
+ responses:
1903
+ '200':
1904
+ description: Verification result.
1905
+ content:
1906
+ application/json:
1907
+ schema:
1908
+ $ref: '../schemas/audit-verify-result.schema.json'
1909
+ '400': { $ref: '#/components/responses/ValidationError' }
1910
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1911
+ '403': { $ref: '#/components/responses/Forbidden' }
1912
+ '404':
1913
+ description: Host does not advertise the audit-log-integrity profile.
1914
+ content:
1915
+ application/json:
1916
+ schema:
1917
+ $ref: '../schemas/error-envelope.schema.json'
1918
+
1919
+ # ── Prompt library (RFC 0028) ────────────────────────────────────────
1920
+ # Surface gated on `capabilities.prompts.supported: true`. Mutating
1921
+ # endpoints (POST / PUT / DELETE) are additionally gated on
1922
+ # `capabilities.prompts.mutableLibrary: true`. Hosts without the
1923
+ # advertised capability return `501 capability_not_provided`.
1924
+ /v1/prompts:
1925
+ get:
1926
+ tags: [prompts]
1927
+ summary: List prompt templates available to the caller.
1928
+ operationId: listPromptTemplates
1929
+ parameters:
1930
+ - in: query
1931
+ name: kind
1932
+ schema: { type: string, enum: [system, user, few-shot, schema-hint] }
1933
+ description: Filter by `PromptTemplate.kind`.
1934
+ - in: query
1935
+ name: tag
1936
+ schema: { type: string }
1937
+ description: |
1938
+ Filter to templates whose `tags[]` contains this exact tag.
1939
+ Hosts MAY accept the parameter multiple times; the semantic
1940
+ when repeated is AND (every named tag must be present).
1941
+ - in: query
1942
+ name: modelClass
1943
+ schema: { type: string }
1944
+ description: Filter to templates whose `modelHints.modelClass` matches.
1945
+ - in: query
1946
+ name: source
1947
+ schema: { type: string, enum: [host, pack, user] }
1948
+ description: Filter by `meta.source` provenance.
1949
+ - in: query
1950
+ name: cursor
1951
+ schema: { type: string }
1952
+ description: Opaque pagination cursor.
1953
+ - in: query
1954
+ name: limit
1955
+ schema: { type: integer, minimum: 1, maximum: 200, default: 50 }
1956
+ description: Maximum entries per page.
1957
+ responses:
1958
+ '200':
1959
+ description: Paginated list of templates.
1960
+ content:
1961
+ application/json:
1962
+ schema:
1963
+ type: object
1964
+ required: [items]
1965
+ properties:
1966
+ items:
1967
+ type: array
1968
+ items:
1969
+ $ref: '../schemas/prompt-template.schema.json'
1970
+ nextCursor:
1971
+ type: string
1972
+ description: Opaque cursor; absent on the final page.
1973
+ '401': { $ref: '#/components/responses/Unauthenticated' }
1974
+ '403': { $ref: '#/components/responses/Forbidden' }
1975
+ '501':
1976
+ description: 'Host does not advertise capabilities.prompts.endpointsSupported. (RFC 0028 §A — supported gates Phase A node-execution composition; endpointsSupported gates this REST surface independently.)'
1977
+ content:
1978
+ application/json:
1979
+ schema:
1980
+ $ref: '../schemas/error-envelope.schema.json'
1981
+ post:
1982
+ tags: [prompts]
1983
+ summary: Create a new prompt template (mutable libraries only).
1984
+ operationId: createPromptTemplate
1985
+ parameters:
1986
+ - $ref: '#/components/parameters/IdempotencyKey'
1987
+ requestBody:
1988
+ required: true
1989
+ content:
1990
+ application/json:
1991
+ schema:
1992
+ $ref: '../schemas/prompt-template.schema.json'
1993
+ responses:
1994
+ '201':
1995
+ description: Template created. `Location` header carries the canonical URI.
1996
+ headers:
1997
+ Location:
1998
+ schema: { type: string }
1999
+ description: 'Canonical URI of the new template.'
2000
+ '400': { $ref: '#/components/responses/ValidationError' }
2001
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2002
+ '403': { $ref: '#/components/responses/Forbidden' }
2003
+ '409':
2004
+ description: A template with this `(templateId, version)` pair already exists.
2005
+ content:
2006
+ application/json:
2007
+ schema:
2008
+ $ref: '../schemas/error-envelope.schema.json'
2009
+ '501':
2010
+ description: 'Host does not advertise capabilities.prompts.mutableLibrary.'
2011
+ content:
2012
+ application/json:
2013
+ schema:
2014
+ $ref: '../schemas/error-envelope.schema.json'
2015
+
2016
+ /v1/prompts/{templateId}:
2017
+ parameters:
2018
+ - in: path
2019
+ name: templateId
2020
+ required: true
2021
+ schema:
2022
+ type: string
2023
+ pattern: '^[a-z0-9][a-z0-9._-]{0,127}$'
2024
+ description: PromptTemplate.templateId per RFC 0027.
2025
+ - in: query
2026
+ name: version
2027
+ schema:
2028
+ type: string
2029
+ pattern: '^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$'
2030
+ description: Pin to a specific SemVer version; latest when omitted.
2031
+ - in: query
2032
+ name: libraryId
2033
+ schema:
2034
+ type: string
2035
+ pattern: '^[a-z0-9][a-z0-9._-]{0,127}$'
2036
+ description: |
2037
+ Disambiguate when multiple installed packs ship the same
2038
+ templateId. Hosts MUST return `prompt_ref_ambiguous` if
2039
+ ambiguous and libraryId is omitted.
2040
+ get:
2041
+ tags: [prompts]
2042
+ summary: Fetch a single prompt template.
2043
+ operationId: getPromptTemplate
2044
+ responses:
2045
+ '200':
2046
+ description: The PromptTemplate.
2047
+ headers:
2048
+ ETag:
2049
+ schema: { type: string }
2050
+ description: SHA-256 of the canonical body.
2051
+ Cache-Control:
2052
+ schema: { type: string }
2053
+ description: Honors immutable semantics when version was pinned.
2054
+ content:
2055
+ application/json:
2056
+ schema:
2057
+ $ref: '../schemas/prompt-template.schema.json'
2058
+ '304':
2059
+ description: Conditional revalidation succeeded.
2060
+ '400':
2061
+ description: '`prompt_ref_ambiguous` when libraryId disambiguation is required.'
2062
+ content:
2063
+ application/json:
2064
+ schema:
2065
+ $ref: '../schemas/error-envelope.schema.json'
2066
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2067
+ '403': { $ref: '#/components/responses/Forbidden' }
2068
+ '404':
2069
+ description: No such template (or version).
2070
+ content:
2071
+ application/json:
2072
+ schema:
2073
+ $ref: '../schemas/error-envelope.schema.json'
2074
+ '501':
2075
+ description: 'Host does not advertise capabilities.prompts.endpointsSupported. (RFC 0028 §A — supported gates Phase A node-execution composition; endpointsSupported gates this REST surface independently.)'
2076
+ content:
2077
+ application/json:
2078
+ schema:
2079
+ $ref: '../schemas/error-envelope.schema.json'
2080
+ put:
2081
+ tags: [prompts]
2082
+ summary: Replace a prompt template (mutable libraries; user-source only).
2083
+ operationId: updatePromptTemplate
2084
+ parameters:
2085
+ - $ref: '#/components/parameters/IdempotencyKey'
2086
+ requestBody:
2087
+ required: true
2088
+ content:
2089
+ application/json:
2090
+ schema:
2091
+ $ref: '../schemas/prompt-template.schema.json'
2092
+ responses:
2093
+ '200':
2094
+ description: Template updated.
2095
+ content:
2096
+ application/json:
2097
+ schema:
2098
+ $ref: '../schemas/prompt-template.schema.json'
2099
+ '400': { $ref: '#/components/responses/ValidationError' }
2100
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2101
+ '403':
2102
+ description: Template is pack-sourced or host-built-in (read-only).
2103
+ content:
2104
+ application/json:
2105
+ schema:
2106
+ $ref: '../schemas/error-envelope.schema.json'
2107
+ '404':
2108
+ description: No such template.
2109
+ content:
2110
+ application/json:
2111
+ schema:
2112
+ $ref: '../schemas/error-envelope.schema.json'
2113
+ '409':
2114
+ description: Submitted version does not exceed stored version (SemVer).
2115
+ content:
2116
+ application/json:
2117
+ schema:
2118
+ $ref: '../schemas/error-envelope.schema.json'
2119
+ '501':
2120
+ description: 'Host does not advertise capabilities.prompts.mutableLibrary.'
2121
+ content:
2122
+ application/json:
2123
+ schema:
2124
+ $ref: '../schemas/error-envelope.schema.json'
2125
+ delete:
2126
+ tags: [prompts]
2127
+ summary: Delete a prompt template (mutable libraries; user-source only).
2128
+ operationId: deletePromptTemplate
2129
+ responses:
2130
+ '204':
2131
+ description: Template deleted.
2132
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2133
+ '403':
2134
+ description: Template is pack-sourced or host-built-in (read-only).
2135
+ content:
2136
+ application/json:
2137
+ schema:
2138
+ $ref: '../schemas/error-envelope.schema.json'
2139
+ '404':
2140
+ description: No such template.
2141
+ content:
2142
+ application/json:
2143
+ schema:
2144
+ $ref: '../schemas/error-envelope.schema.json'
2145
+ '501':
2146
+ description: 'Host does not advertise capabilities.prompts.mutableLibrary.'
2147
+ content:
2148
+ application/json:
2149
+ schema:
2150
+ $ref: '../schemas/error-envelope.schema.json'
2151
+
2152
+ /v1/prompts:render:
2153
+ post:
2154
+ tags: [prompts]
2155
+ summary: Render a prompt template with supplied variable bindings.
2156
+ description: |
2157
+ Returns the composed body + sha256 hash + per-variable hashes.
2158
+ The response's `hash` MUST equal the `hash` that a matching
2159
+ `prompt.composed` event would carry at dispatch time for the
2160
+ same `(ref, variables, contentTrust)` inputs (RFC 0028 §A
2161
+ deterministic-render invariant; RFC 0027 §F replay invariant).
2162
+ Does NOT dispatch an LLM call. Secret-source variable values
2163
+ MUST be supplied as `[REDACTED:<credentialRef>]` markers; the
2164
+ host resolves the plaintext internally and never echoes it in
2165
+ the `composed` response field per SR-1.
2166
+ operationId: renderPromptTemplate
2167
+ requestBody:
2168
+ required: true
2169
+ content:
2170
+ application/json:
2171
+ schema:
2172
+ type: object
2173
+ required: [ref, variables]
2174
+ properties:
2175
+ ref:
2176
+ $ref: '../schemas/prompt-ref.schema.json'
2177
+ variables:
2178
+ type: object
2179
+ description: |
2180
+ Variable bindings keyed by `PromptVariable.name`.
2181
+ Secret-source bindings carry `[REDACTED:<credentialRef>]`
2182
+ markers; the host resolves the real value internally.
2183
+ additionalProperties: true
2184
+ contentTrust:
2185
+ type: string
2186
+ enum: [trusted, untrusted]
2187
+ description: |
2188
+ Aggregate trust marker for the supplied bindings,
2189
+ propagated through composition per RFC 0027 §E.
2190
+ responses:
2191
+ '200':
2192
+ description: Composed result.
2193
+ content:
2194
+ application/json:
2195
+ schema:
2196
+ type: object
2197
+ required: [hash, refs, variableHashes]
2198
+ properties:
2199
+ composed:
2200
+ type: string
2201
+ description: Full composed body. Present only when observability is `full`.
2202
+ hash:
2203
+ type: string
2204
+ pattern: '^sha256:[0-9a-f]{64}$'
2205
+ refs:
2206
+ type: array
2207
+ items:
2208
+ type: string
2209
+ variableHashes:
2210
+ type: object
2211
+ additionalProperties:
2212
+ type: string
2213
+ pattern: '^sha256:[0-9a-f]{64}$'
2214
+ contentTrust:
2215
+ type: string
2216
+ enum: [trusted, untrusted]
2217
+ '400':
2218
+ description: |
2219
+ `prompt_variable_unresolved` (required variable missing),
2220
+ `prompt_variable_type_mismatch` (bound type vs. declared type),
2221
+ or `prompt_ref_invalid` (malformed PromptRef).
2222
+ content:
2223
+ application/json:
2224
+ schema:
2225
+ $ref: '../schemas/error-envelope.schema.json'
2226
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2227
+ '403': { $ref: '#/components/responses/Forbidden' }
2228
+ '404':
2229
+ description: Referenced template does not exist.
2230
+ content:
2231
+ application/json:
2232
+ schema:
2233
+ $ref: '../schemas/error-envelope.schema.json'
2234
+ '501':
2235
+ description: 'Host does not advertise capabilities.prompts.endpointsSupported. (RFC 0028 §A — supported gates Phase A node-execution composition; endpointsSupported gates this REST surface independently.)'
2236
+ content:
2237
+ application/json:
2238
+ schema:
2239
+ $ref: '../schemas/error-envelope.schema.json'
2240
+
2241
+ # ── Test-mode pack registry namespace (RFC 0025) ─────────────────────────
2242
+ # Mirrors the production /v1/packs/* PUT/GET/DELETE/.sig surface against an
2243
+ # isolated catalog. Conformance scenarios under
2244
+ # `conformance/src/scenarios/pack-registry-publish.test.ts` exercise the
2245
+ # 19-code publish error catalog through this namespace. Hosts that don't
2246
+ # advertise `capabilities.packs.testMode.supported: true` MUST return
2247
+ # 404 for every path below.
2248
+
2249
+ /v1/packs-test/{name}/-/{version}.tgz:
2250
+ parameters:
2251
+ - $ref: '#/components/parameters/PackName'
2252
+ - $ref: '#/components/parameters/PackVersion'
2253
+ put:
2254
+ tags: [packs-test]
2255
+ summary: Publish a pack tarball to the isolated test catalog.
2256
+ description: |
2257
+ Mirror of `PUT /v1/packs/{name}/-/{version}.tgz` per
2258
+ `spec/v1/node-packs.md` §"PUT /v1/packs/{name}/-/{version}.tgz".
2259
+ Request shape, response shape, status codes, and the 19-code
2260
+ publish error catalog (`invalid_pack_scope`, `invalid_pack_name`,
2261
+ `invalid_version`, `invalid_body`, eight `tarball_*` codes,
2262
+ `invalid_manifest`, `manifest_mismatch` (or the granular
2263
+ `manifest_name_mismatch` / `manifest_version_mismatch` pair),
2264
+ `pack_integrity_failure`, `unsupported_runtime`, `forbidden`,
2265
+ `conflict`/`version_conflict`) MUST be served verbatim. The
2266
+ test catalog MUST be isolated per RFC 0025 §C — a pack PUT'd
2267
+ here MUST NOT appear in `GET /v1/packs/{name}` listings.
2268
+ The mirrored production path is registry-service surface
2269
+ (`registry-operations.md`), not defined in this host document
2270
+ (see the `packs-test` tag scope note).
2271
+ operationId: putTestPackTarball
2272
+ parameters:
2273
+ - in: header
2274
+ name: X-Pack-Signing-Method
2275
+ required: false
2276
+ schema: { type: string, enum: [sigstore, manual, none] }
2277
+ - in: header
2278
+ name: X-Pack-Sha256
2279
+ required: false
2280
+ schema:
2281
+ type: string
2282
+ pattern: '^sha256-[A-Za-z0-9+/=]+$'
2283
+ description: Caller-asserted SHA-256 (server verifies; mismatch surfaces `pack_integrity_failure`).
2284
+ requestBody:
2285
+ required: true
2286
+ description: Gzipped tarball bytes (`application/tar+gzip`, `application/gzip`, `application/x-gzip`, or `application/octet-stream`).
2287
+ content:
2288
+ application/gzip:
2289
+ schema: { type: string, format: binary }
2290
+ application/x-gzip:
2291
+ schema: { type: string, format: binary }
2292
+ application/tar+gzip:
2293
+ schema: { type: string, format: binary }
2294
+ application/octet-stream:
2295
+ schema: { type: string, format: binary }
2296
+ responses:
2297
+ '200':
2298
+ description: Idempotent re-publish — identical sha256 content already published; existing record returned.
2299
+ content:
2300
+ application/json:
2301
+ schema: { $ref: '#/components/schemas/TestPackPublishRecord' }
2302
+ '201':
2303
+ description: New version published to the test catalog.
2304
+ content:
2305
+ application/json:
2306
+ schema: { $ref: '#/components/schemas/TestPackPublishRecord' }
2307
+ '400':
2308
+ description: |
2309
+ One of the 17 spec-documented 400-class publish error codes:
2310
+ URL/scope (`invalid_pack_scope`, `invalid_pack_name`, `invalid_version`),
2311
+ body shape (`invalid_body`),
2312
+ tarball extraction (`tarball_gunzip_failed`, `tarball_too_large`,
2313
+ `tarball_manifest_missing`, `tarball_manifest_too_large`,
2314
+ `tarball_manifest_not_json`, `tarball_entry_missing`,
2315
+ `tarball_entry_too_large`, `tarball_path_traversal`,
2316
+ `tarball_tar_parse_failed`),
2317
+ manifest contents (`invalid_manifest`, `manifest_mismatch` or
2318
+ the granular `manifest_name_mismatch` / `manifest_version_mismatch` pair,
2319
+ `pack_integrity_failure`, `unsupported_runtime`).
2320
+ content:
2321
+ application/json:
2322
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2323
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2324
+ '403':
2325
+ description: '`forbidden` — caller lacks `packs:publish` scope or the namespace claim.'
2326
+ content:
2327
+ application/json:
2328
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2329
+ '404':
2330
+ description: 'Host does not advertise `capabilities.packs.testMode.supported: true`, or the test-mode env-gate is unset.'
2331
+ content:
2332
+ application/json:
2333
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2334
+ '409':
2335
+ description: '`conflict` (or `version_conflict`) — `(name, version)` already published with different content.'
2336
+ content:
2337
+ application/json:
2338
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2339
+ get:
2340
+ tags: [packs-test]
2341
+ summary: Fetch a published test-catalog tarball.
2342
+ description: 'Mirror of `GET /v1/packs/{name}/-/{version}.tgz`. Returns the gzipped tarball bytes with `Content-Type: application/tar+gzip` and an `ETag: "sha256-..."` matching the manifest''s `tarballSha256`. The mirrored production path is registry-service surface (`registry-operations.md`), not defined in this host document (see the `packs-test` tag scope note).'
2343
+ operationId: getTestPackTarball
2344
+ responses:
2345
+ '200':
2346
+ description: Tarball bytes.
2347
+ content:
2348
+ application/tar+gzip:
2349
+ schema: { type: string, format: binary }
2350
+ '400':
2351
+ description: '`invalid_pack_name` or `invalid_version` — URL params malformed.'
2352
+ content:
2353
+ application/json:
2354
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2355
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2356
+ '403':
2357
+ description: '`forbidden` — caller lacks `packs:read` scope.'
2358
+ content:
2359
+ application/json:
2360
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2361
+ '404':
2362
+ description: 'Pack version not found in the test catalog (or host does not advertise `capabilities.packs.testMode.supported: true`).'
2363
+ content:
2364
+ application/json:
2365
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2366
+ /v1/packs-test/{name}/-/{version}:
2367
+ parameters:
2368
+ - $ref: '#/components/parameters/PackName'
2369
+ - $ref: '#/components/parameters/PackVersion'
2370
+ delete:
2371
+ tags: [packs-test]
2372
+ summary: Unpublish a test-catalog version (mirrors unpublish-window semantics).
2373
+ description: |
2374
+ Mirror of `DELETE /v1/packs/{name}/-/{version}` per
2375
+ `spec/v1/node-packs.md`. Returns `400 unpublish_window_expired`
2376
+ for versions older than the registry's unpublish window
2377
+ (default 72h). Test-mode implementations MAY shorten the
2378
+ window for tractable conformance fixtures but MUST surface
2379
+ the same error code. The mirrored production path is
2380
+ registry-service surface (`registry-operations.md`), not
2381
+ defined in this host document (see the `packs-test` tag
2382
+ scope note).
2383
+ operationId: deleteTestPackVersion
2384
+ responses:
2385
+ '204':
2386
+ description: Version successfully unpublished from the test catalog.
2387
+ '400':
2388
+ description: '`unpublish_window_expired`, `invalid_pack_name`, or `invalid_version`.'
2389
+ content:
2390
+ application/json:
2391
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2392
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2393
+ '403':
2394
+ description: '`forbidden` — caller lacks `packs:publish` scope.'
2395
+ content:
2396
+ application/json:
2397
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2398
+ '404':
2399
+ description: Version doesn't exist in the test catalog, or host does not advertise the test-mode capability.
2400
+ content:
2401
+ application/json:
2402
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2403
+
2404
+ /v1/packs-test/{name}/-/{version}.sig:
2405
+ parameters:
2406
+ - $ref: '#/components/parameters/PackName'
2407
+ - $ref: '#/components/parameters/PackVersion'
2408
+ get:
2409
+ tags: [packs-test]
2410
+ summary: Fetch the detached Ed25519 signature for a test-catalog pack.
2411
+ description: |
2412
+ Mirror of `GET /v1/packs/{name}/-/{version}.sig`. Returns the
2413
+ signature blob over `pack.json` for this version. MAY 302-redirect
2414
+ to a storage-backend signed URL. The mirrored production path is
2415
+ registry-service surface (`registry-operations.md`), not defined
2416
+ in this host document (see the `packs-test` tag scope note).
2417
+ operationId: getTestPackSignature
2418
+ responses:
2419
+ '200':
2420
+ description: Signature blob.
2421
+ content:
2422
+ application/octet-stream:
2423
+ schema: { type: string, format: binary }
2424
+ '302':
2425
+ description: Redirect to a storage-backend signed URL (clients SHOULD follow).
2426
+ headers:
2427
+ Location:
2428
+ schema: { type: string, format: uri }
2429
+ '400':
2430
+ description: '`invalid_pack_name` or `invalid_version` — URL params malformed.'
2431
+ content:
2432
+ application/json:
2433
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2434
+ '401': { $ref: '#/components/responses/Unauthenticated' }
2435
+ '403':
2436
+ description: '`forbidden` — caller lacks `packs:read` scope.'
2437
+ content:
2438
+ application/json:
2439
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2440
+ '404':
2441
+ description: |
2442
+ `signature_not_available` — version is missing, yanked,
2443
+ unsigned at publish time, OR the registry's storage backend
2444
+ is unwired. The four cases are intentionally
2445
+ indistinguishable per spec/v1/node-packs.md §"GET /v1/packs/{name}/-/{version}.sig".
2446
+ Also returned when the host does not advertise
2447
+ `capabilities.packs.testMode.supported: true`.
2448
+ content:
2449
+ application/json:
2450
+ schema: { $ref: '../schemas/error-envelope.schema.json' }
2451
+
2452
+ # ─────────────────────────────────────────────────────────────────────────────
2453
+ # COMPONENTS
2454
+ # ─────────────────────────────────────────────────────────────────────────────
2455
+ components:
2456
+
2457
+ securitySchemes:
2458
+ ApiKeyAuth:
2459
+ type: http
2460
+ scheme: bearer
2461
+ bearerFormat: API key
2462
+ description: |
2463
+ openwop API key. Format implementation-defined; reference impl uses `hk_`/`hk_test_` prefixes.
2464
+ Each key carries one or more scopes from the canonical vocabulary
2465
+ (`manifest:read`, `runs:create`, `runs:read`, `runs:cancel`,
2466
+ `artifacts:read`, `webhooks:manage`, `approvals:respond`, `audit:read`).
2467
+ See `auth.md`.
2468
+
2469
+ parameters:
2470
+ WorkflowId:
2471
+ in: path
2472
+ name: workflowId
2473
+ required: true
2474
+ schema: { type: string, minLength: 1, maxLength: 128 }
2475
+
2476
+ RunId:
2477
+ in: path
2478
+ name: runId
2479
+ required: true
2480
+ schema: { type: string, minLength: 1, maxLength: 128 }
2481
+
2482
+ IdempotencyKey:
2483
+ in: header
2484
+ name: Idempotency-Key
2485
+ required: false
2486
+ schema:
2487
+ type: string
2488
+ maxLength: 255
2489
+ description: |
2490
+ Per-mutation idempotency token (see `idempotency.md` Layer 1).
2491
+ Server caches `(tenantId, endpoint, key)` → response for ≥24h.
2492
+ Duplicate requests return the cached response with header
2493
+ `openwop-Idempotent-Replay: true`.
2494
+
2495
+ WorkspacePath:
2496
+ in: path
2497
+ name: path
2498
+ required: true
2499
+ schema:
2500
+ type: string
2501
+ pattern: '^[A-Za-z0-9][A-Za-z0-9._/-]{0,255}$'
2502
+ description: |
2503
+ RFC 0059 workspace-relative file path. Flat namespace with
2504
+ `/`-in-names; no `..`, no leading `/`. Matches
2505
+ `workspace-file.schema.json#path`.
2506
+
2507
+ WorkspacePrefix:
2508
+ in: query
2509
+ name: prefix
2510
+ required: false
2511
+ schema: { type: string, maxLength: 256 }
2512
+ description: RFC 0059. Optional prefix filter over the flat `path` namespace for `listWorkspaceFiles`.
2513
+
2514
+ WorkspaceVersion:
2515
+ in: query
2516
+ name: version
2517
+ required: false
2518
+ schema: { type: integer, minimum: 1 }
2519
+ description: |
2520
+ RFC 0059. When `capabilities.workspace.versioned: true`, request the
2521
+ historical snapshot at this version. Absent = latest.
2522
+
2523
+ IfMatch:
2524
+ in: header
2525
+ name: If-Match
2526
+ required: false
2527
+ schema: { type: string, maxLength: 255 }
2528
+ description: |
2529
+ RFC 0059 optimistic-concurrency token — the file's current `etag`.
2530
+ A `PUT` carrying a stale `If-Match` returns `409 workspace_conflict`.
2531
+
2532
+ PackName:
2533
+ in: path
2534
+ name: name
2535
+ required: true
2536
+ schema:
2537
+ type: string
2538
+ minLength: 3
2539
+ maxLength: 214
2540
+ description: Reverse-DNS pack name per `spec/v1/node-packs.md` §Naming (e.g. `vendor.acme.salesforce-tools`).
2541
+
2542
+ PackVersion:
2543
+ in: path
2544
+ name: version
2545
+ required: true
2546
+ schema:
2547
+ type: string
2548
+ pattern: '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?$'
2549
+ description: SemVer 2.0.0 version of the pack.
2550
+
2551
+ responses:
2552
+ Unauthenticated:
2553
+ description: Missing or invalid credential.
2554
+ content:
2555
+ application/json:
2556
+ schema: { $ref: '#/components/schemas/Error' }
2557
+
2558
+ Forbidden:
2559
+ description: Credential valid but lacks required scope or fails resource binding.
2560
+ content:
2561
+ application/json:
2562
+ schema: { $ref: '#/components/schemas/Error' }
2563
+
2564
+ NotFound:
2565
+ description: Resource doesn't exist or caller can't see it (do not leak existence).
2566
+ content:
2567
+ application/json:
2568
+ schema: { $ref: '#/components/schemas/Error' }
2569
+
2570
+ ValidationError:
2571
+ description: Request body or parameters malformed.
2572
+ content:
2573
+ application/json:
2574
+ schema: { $ref: '#/components/schemas/Error' }
2575
+
2576
+ RateLimited:
2577
+ description: Too many requests.
2578
+ headers:
2579
+ Retry-After:
2580
+ schema: { type: integer }
2581
+ content:
2582
+ application/json:
2583
+ schema: { $ref: '#/components/schemas/Error' }
2584
+
2585
+ schemas:
2586
+
2587
+ # Hoisted to first-class JSON Schemas in ../schemas/ so the SDK and
2588
+ # conformance suite can validate against the same source. The
2589
+ # in-line aliases below pull them via $ref so existing
2590
+ # `#/components/schemas/Error` references keep working.
2591
+
2592
+ Error:
2593
+ $ref: '../schemas/error-envelope.schema.json'
2594
+
2595
+ Capabilities:
2596
+ $ref: '../schemas/capabilities.schema.json'
2597
+
2598
+ # Pre-loaded so redocly's $ref resolver registers them at lint time.
2599
+ # capabilities.schema.json `$ref`s prompt-kind.schema.json by its
2600
+ # canonical openwop.dev URL — redocly resolves absolute URIs against
2601
+ # already-loaded `$id`s, so the schema must be pulled in here even
2602
+ # though no operation references it directly. See RFC 0027 §A.
2603
+ PromptKind:
2604
+ $ref: '../schemas/prompt-kind.schema.json'
2605
+
2606
+ PromptTemplate:
2607
+ $ref: '../schemas/prompt-template.schema.json'
2608
+
2609
+ PromptRef:
2610
+ $ref: '../schemas/prompt-ref.schema.json'
2611
+
2612
+ RunSnapshot:
2613
+ $ref: '../schemas/run-snapshot.schema.json'
2614
+
2615
+ RunClaimConflict:
2616
+ description: |
2617
+ Specialization of the canonical `ErrorEnvelope` shape for
2618
+ `run_already_active`. Conflict metadata lives under `details`
2619
+ so the top-level error shape remains `{error, message, details?}`.
2620
+ allOf:
2621
+ - $ref: '#/components/schemas/Error'
2622
+ - type: object
2623
+ required: [error, message, details]
2624
+ properties:
2625
+ error:
2626
+ type: string
2627
+ enum: [run_already_active]
2628
+ message: { type: string }
2629
+ details:
2630
+ type: object
2631
+ required: [activeRunId, activeHost]
2632
+ properties:
2633
+ activeRunId: { type: string }
2634
+ activeHost:
2635
+ type: string
2636
+ enum: [browser, cloud]
2637
+ retryAfter:
2638
+ type: integer
2639
+ description: 'Seconds. Mirrors the `Retry-After` header.'
2640
+
2641
+ UnsupportedStreamMode:
2642
+ description: |
2643
+ Specialization of the canonical `ErrorEnvelope` shape (see
2644
+ `error-envelope.schema.json`) for the `unsupported_stream_mode`
2645
+ case. The `supported` array lives in `details` per the canonical
2646
+ envelope's contextual-data slot, NOT at the top level. SDK
2647
+ consumers using a generic ErrorEnvelope parser will find the
2648
+ list under `details.supported` regardless of which validator
2649
+ fired.
2650
+ allOf:
2651
+ - $ref: '#/components/schemas/Error'
2652
+ - type: object
2653
+ required: [error, message, details]
2654
+ properties:
2655
+ error:
2656
+ type: string
2657
+ enum: [unsupported_stream_mode]
2658
+ message: { type: string }
2659
+ details:
2660
+ type: object
2661
+ required: [supported]
2662
+ properties:
2663
+ supported:
2664
+ type: array
2665
+ items: { type: string, enum: [values, updates, messages, debug] }
2666
+
2667
+ TestPackPublishRecord:
2668
+ description: |
2669
+ Response body for a successful publish against the test-mode
2670
+ registry namespace (RFC 0025). Mirror of the production publish
2671
+ record returned by `PUT /v1/packs/{name}/-/{version}.tgz`.
2672
+ type: object
2673
+ required: [name, version, tarballSha256, publishedAt]
2674
+ properties:
2675
+ name:
2676
+ type: string
2677
+ description: Reverse-DNS pack name as PUT'd.
2678
+ version:
2679
+ type: string
2680
+ description: SemVer 2.0.0 version as PUT'd.
2681
+ tarballSha256:
2682
+ type: string
2683
+ pattern: '^sha256-[A-Za-z0-9+/=]+$'
2684
+ description: Server-computed SHA-256 over the uploaded tarball bytes.
2685
+ publishedAt:
2686
+ type: string
2687
+ format: date-time
2688
+ signed:
2689
+ type: boolean
2690
+ description: Whether a sibling `.sig` signature blob was persisted.
2691
+ signingMethod:
2692
+ type: string
2693
+ enum: [sigstore, manual, none]