@ouispec/contract 0.1.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 (48) hide show
  1. package/INTEGRATOR-GUIDE.md +729 -0
  2. package/LICENSE +21 -0
  3. package/README.md +10 -0
  4. package/dist/codegen.d.ts +71 -0
  5. package/dist/codegen.d.ts.map +1 -0
  6. package/dist/codegen.js +195 -0
  7. package/dist/codegen.js.map +1 -0
  8. package/dist/generated/contract.d.ts +1286 -0
  9. package/dist/generated/contract.d.ts.map +1 -0
  10. package/dist/generated/contract.js +14 -0
  11. package/dist/generated/contract.js.map +1 -0
  12. package/dist/generated/schemas.d.ts +111 -0
  13. package/dist/generated/schemas.d.ts.map +1 -0
  14. package/dist/generated/schemas.js +3256 -0
  15. package/dist/generated/schemas.js.map +1 -0
  16. package/dist/index.d.ts +29 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +28 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/render-contract.d.ts +47 -0
  21. package/dist/render-contract.d.ts.map +1 -0
  22. package/dist/render-contract.js +123 -0
  23. package/dist/render-contract.js.map +1 -0
  24. package/dist/render-guide.d.ts +4 -0
  25. package/dist/render-guide.d.ts.map +1 -0
  26. package/dist/render-guide.js +132 -0
  27. package/dist/render-guide.js.map +1 -0
  28. package/dist/schema-document.d.ts +7 -0
  29. package/dist/schema-document.d.ts.map +1 -0
  30. package/dist/schema-document.js +2 -0
  31. package/dist/schema-document.js.map +1 -0
  32. package/dist/validate.d.ts +22 -0
  33. package/dist/validate.d.ts.map +1 -0
  34. package/dist/validate.js +89 -0
  35. package/dist/validate.js.map +1 -0
  36. package/package.json +65 -0
  37. package/schemas/action-effect.json +113 -0
  38. package/schemas/agent-binding.json +58 -0
  39. package/schemas/approvals.json +249 -0
  40. package/schemas/control-kind-registration.json +187 -0
  41. package/schemas/control-table.json +276 -0
  42. package/schemas/event-declarations.json +316 -0
  43. package/schemas/generated-knowledge.json +58 -0
  44. package/schemas/json-schema.json +153 -0
  45. package/schemas/oui-config.json +178 -0
  46. package/schemas/oui-manifest.json +346 -0
  47. package/schemas/room-catalog-data.json +455 -0
  48. package/schemas/tier2-mapping.json +195 -0
@@ -0,0 +1,3256 @@
1
+ // GENERATED FILE — DO NOT EDIT.
2
+ //
3
+ // Generated from schemas/*.json, the OUI integrator contract, by @ouispec/contract.
4
+ // Edit the schemas, then: pnpm generate (in packages/contract).
5
+ /** Every schema of the contract, by file name, exactly as `schemas/` holds it. */
6
+ export const CONTRACT_SCHEMAS = {
7
+ 'json-schema.json': {
8
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
9
+ "$id": "https://schemas.closurestudio.ai/oui/v1/json-schema.json",
10
+ "title": "JsonSchema",
11
+ "description": "The subset of JSON Schema (draft 2020-12) every capability declares its input and values in. It is what assistant tool inputs are written in, so a declared or derived schema is used as is. `x-unit` names the unit a number is in: `px`, `%`, `°`.",
12
+ "type": "object",
13
+ "properties": {
14
+ "type": {
15
+ "anyOf": [
16
+ {
17
+ "$ref": "#/$defs/JsonSchemaType"
18
+ },
19
+ {
20
+ "type": "array",
21
+ "items": {
22
+ "$ref": "#/$defs/JsonSchemaType"
23
+ }
24
+ }
25
+ ]
26
+ },
27
+ "description": {
28
+ "type": "string"
29
+ },
30
+ "enum": {
31
+ "type": "array",
32
+ "items": {
33
+ "anyOf": [
34
+ {
35
+ "type": "string"
36
+ },
37
+ {
38
+ "type": "number"
39
+ },
40
+ {
41
+ "type": "boolean"
42
+ },
43
+ {
44
+ "type": "null"
45
+ }
46
+ ]
47
+ }
48
+ },
49
+ "const": {
50
+ "anyOf": [
51
+ {
52
+ "type": "string"
53
+ },
54
+ {
55
+ "type": "number"
56
+ },
57
+ {
58
+ "type": "boolean"
59
+ },
60
+ {
61
+ "type": "null"
62
+ }
63
+ ]
64
+ },
65
+ "properties": {
66
+ "type": "object",
67
+ "additionalProperties": {
68
+ "$ref": "#"
69
+ }
70
+ },
71
+ "required": {
72
+ "type": "array",
73
+ "items": {
74
+ "type": "string"
75
+ }
76
+ },
77
+ "additionalProperties": {
78
+ "anyOf": [
79
+ {
80
+ "type": "boolean"
81
+ },
82
+ {
83
+ "$ref": "#"
84
+ }
85
+ ]
86
+ },
87
+ "items": {
88
+ "$ref": "#"
89
+ },
90
+ "minItems": {
91
+ "type": "number"
92
+ },
93
+ "maxItems": {
94
+ "type": "number"
95
+ },
96
+ "uniqueItems": {
97
+ "description": "No two items are the same.",
98
+ "type": "boolean"
99
+ },
100
+ "minimum": {
101
+ "type": "number"
102
+ },
103
+ "maximum": {
104
+ "type": "number"
105
+ },
106
+ "multipleOf": {
107
+ "type": "number"
108
+ },
109
+ "minLength": {
110
+ "type": "number"
111
+ },
112
+ "maxLength": {
113
+ "type": "number"
114
+ },
115
+ "pattern": {
116
+ "type": "string"
117
+ },
118
+ "format": {
119
+ "type": "string"
120
+ },
121
+ "oneOf": {
122
+ "type": "array",
123
+ "items": {
124
+ "$ref": "#"
125
+ }
126
+ },
127
+ "anyOf": {
128
+ "type": "array",
129
+ "items": {
130
+ "$ref": "#"
131
+ }
132
+ },
133
+ "default": {
134
+ "$comment": "ts: unknown"
135
+ },
136
+ "x-unit": {
137
+ "description": "The unit a number is in: `px`, `%`, `°`.",
138
+ "type": "string"
139
+ },
140
+ "x-enum-omitted": {
141
+ "description": "How many allowed values a shortened `enum` leaves out. Only in the page state, where a row's options are summarised; a tool's input schema always lists every value.",
142
+ "type": "number"
143
+ }
144
+ },
145
+ "$defs": {
146
+ "JsonSchemaType": {
147
+ "description": "A JSON Schema type name.",
148
+ "enum": [
149
+ "object",
150
+ "array",
151
+ "string",
152
+ "number",
153
+ "integer",
154
+ "boolean",
155
+ "null"
156
+ ]
157
+ }
158
+ }
159
+ },
160
+ 'action-effect.json': {
161
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
162
+ "$id": "https://schemas.closurestudio.ai/oui/v1/action-effect.json",
163
+ "title": "ActionEffect",
164
+ "description": "What using an action does (ADR-0226 §2.6): one vocabulary for a design-system control's binding, a room catalog's entry and a generated API tool, so a page control, a room action and an API call are told apart by what they change, never by where they are declared.\n\n| Effect | What it changes | ADR-0210 access |\n|---|---|---|\n| `view`, `selection`, `navigate`, `open` | What is shown | read |\n| `edit` | The document, one undo step | write |\n| `file` | Imports or exports a file | write |\n| `mutate` | Backend data, through an API operation | write |\n| `job` | Starts work that outlives the call, settled on its outcome | write |\n| `transaction` | An irreversible external act: an order, a payment, a send, a publish | write, approved |\n\nA `transaction`, and any `write` declared `destructive`, runs only on an approval the person gave, bound to the call (ADR-0228).",
165
+ "oneOf": [
166
+ {
167
+ "$ref": "#/$defs/SimpleEffect"
168
+ },
169
+ {
170
+ "description": "Goes to another page: a route pattern from the app's routes.",
171
+ "type": "object",
172
+ "properties": {
173
+ "kind": {
174
+ "const": "navigate"
175
+ },
176
+ "to": {
177
+ "type": "string",
178
+ "minLength": 1
179
+ }
180
+ },
181
+ "required": [
182
+ "kind",
183
+ "to"
184
+ ],
185
+ "additionalProperties": false
186
+ },
187
+ {
188
+ "description": "Opens a container on the page: the binding id of a dialog, drawer, popover or tab set.",
189
+ "type": "object",
190
+ "properties": {
191
+ "kind": {
192
+ "const": "open"
193
+ },
194
+ "container": {
195
+ "type": "string",
196
+ "minLength": 1
197
+ }
198
+ },
199
+ "required": [
200
+ "kind",
201
+ "container"
202
+ ],
203
+ "additionalProperties": false
204
+ },
205
+ {
206
+ "description": "Changes backend data through an API operation, by its `operationId` (`updateVoice`).",
207
+ "type": "object",
208
+ "properties": {
209
+ "kind": {
210
+ "const": "mutate"
211
+ },
212
+ "operation": {
213
+ "type": "string",
214
+ "minLength": 1
215
+ }
216
+ },
217
+ "required": [
218
+ "kind",
219
+ "operation"
220
+ ],
221
+ "additionalProperties": false
222
+ },
223
+ {
224
+ "description": "Starts work that outlives the call, such as a GPU job. The handler returns `{ ok: true, pending: { jobId } }`; the action is reported done only when the job's completion arrives, failed when it fails, and never done when it has not finished within `timeoutMs` (default 5 minutes). Its states are `JobStatus`.",
225
+ "type": "object",
226
+ "properties": {
227
+ "kind": {
228
+ "const": "job"
229
+ },
230
+ "estimatedDuration": {
231
+ "type": "string"
232
+ },
233
+ "timeoutMs": {
234
+ "type": "number",
235
+ "exclusiveMinimum": 0
236
+ }
237
+ },
238
+ "required": [
239
+ "kind"
240
+ ],
241
+ "additionalProperties": false
242
+ },
243
+ {
244
+ "description": "An irreversible external act: an order placed, a payment made, a message sent, something published. Modelled on `job`: its handler may return `pending: { jobId }` and it settles on the outcome. It always needs the person's approval of the exact call (ADR-0228), which no policy waives.\n\n- `operation`: the API operation it goes through, when it is one.\n- `approvalMinutes`: how long an approval of it lasts, at most 30 (default 5).",
245
+ "type": "object",
246
+ "properties": {
247
+ "kind": {
248
+ "const": "transaction"
249
+ },
250
+ "operation": {
251
+ "type": "string",
252
+ "minLength": 1
253
+ },
254
+ "estimatedDuration": {
255
+ "type": "string"
256
+ },
257
+ "timeoutMs": {
258
+ "type": "number",
259
+ "exclusiveMinimum": 0
260
+ },
261
+ "approvalMinutes": {
262
+ "type": "integer",
263
+ "minimum": 1,
264
+ "maximum": 30
265
+ }
266
+ },
267
+ "required": [
268
+ "kind"
269
+ ],
270
+ "additionalProperties": false
271
+ }
272
+ ],
273
+ "$defs": {
274
+ "SimpleEffect": {
275
+ "description": "An effect that needs nothing but its name.",
276
+ "enum": [
277
+ "view",
278
+ "selection",
279
+ "edit",
280
+ "file"
281
+ ]
282
+ },
283
+ "ActionEffectKind": {
284
+ "description": "The effect kinds, in the order of the table above. The vocabulary, what each one may change, and what needs the person's approval are OUI's (`oui-spec`).",
285
+ "enum": [
286
+ "view",
287
+ "selection",
288
+ "navigate",
289
+ "open",
290
+ "edit",
291
+ "file",
292
+ "mutate",
293
+ "job",
294
+ "transaction"
295
+ ]
296
+ },
297
+ "EffectAccess": {
298
+ "description": "Whether an effect only changes what is shown (`read`), or changes something (`write`), as ADR-0210 names it. An action that declares no effect is a `write`.",
299
+ "enum": [
300
+ "read",
301
+ "write"
302
+ ]
303
+ },
304
+ "JobStatus": {
305
+ "description": "Where an action whose effect is `job` or `transaction` is (plan §2.3, #205/#209):\n\n- `started`: the handler returned; the job is tracked from this moment, so an outcome that arrives before the first poll is kept.\n- `running`: still going; the runtime polls the app's `JobTracker`.\n- `complete`: the job's declared completion arrived; the result exists.\n- `failed`: its declared failure arrived; the result never will.\n- `timeout`: it did not finish within `timeoutMs`. A failure, never a late success.\n- `unverified`: no `JobTracker`, or no job id to follow: the work was started but cannot be confirmed from the page.",
306
+ "enum": [
307
+ "started",
308
+ "running",
309
+ "complete",
310
+ "failed",
311
+ "timeout",
312
+ "unverified"
313
+ ]
314
+ },
315
+ "JobOutcome": {
316
+ "description": "A job's end, as the assistant is told it. `complete` means the result exists; `failed` that it never will. A `complete` outcome carries the declared result fields beside its job id.",
317
+ "oneOf": [
318
+ {
319
+ "type": "object",
320
+ "properties": {
321
+ "status": {
322
+ "const": "complete"
323
+ },
324
+ "jobId": {
325
+ "type": "string"
326
+ }
327
+ },
328
+ "required": [
329
+ "status",
330
+ "jobId"
331
+ ],
332
+ "additionalProperties": true
333
+ },
334
+ {
335
+ "type": "object",
336
+ "properties": {
337
+ "status": {
338
+ "const": "failed"
339
+ },
340
+ "jobId": {
341
+ "type": "string"
342
+ },
343
+ "error": {
344
+ "type": "string"
345
+ }
346
+ },
347
+ "required": [
348
+ "status",
349
+ "jobId",
350
+ "error"
351
+ ],
352
+ "additionalProperties": false
353
+ }
354
+ ]
355
+ },
356
+ "JobSettlement": {
357
+ "description": "What an action that settles on a job reports, from its first answer to its last: `started` (with the job id when the handler gave one), `running` while it polls, then the `JobOutcome`, or `unverified`. A `timeout` is reported as the error `TIMEOUT`, never as data.",
358
+ "oneOf": [
359
+ {
360
+ "type": "object",
361
+ "properties": {
362
+ "status": {
363
+ "const": "started"
364
+ },
365
+ "jobId": {
366
+ "type": "string"
367
+ }
368
+ },
369
+ "required": [
370
+ "status"
371
+ ],
372
+ "additionalProperties": true
373
+ },
374
+ {
375
+ "type": "object",
376
+ "properties": {
377
+ "status": {
378
+ "const": "running"
379
+ },
380
+ "jobId": {
381
+ "type": "string"
382
+ }
383
+ },
384
+ "required": [
385
+ "status",
386
+ "jobId"
387
+ ],
388
+ "additionalProperties": false
389
+ },
390
+ {
391
+ "$ref": "#/$defs/JobOutcome"
392
+ },
393
+ {
394
+ "type": "object",
395
+ "properties": {
396
+ "status": {
397
+ "const": "unverified"
398
+ },
399
+ "message": {
400
+ "type": "string"
401
+ }
402
+ },
403
+ "required": [
404
+ "status",
405
+ "message"
406
+ ],
407
+ "additionalProperties": false
408
+ }
409
+ ]
410
+ }
411
+ }
412
+ },
413
+ 'agent-binding.json': {
414
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
415
+ "$id": "https://schemas.closurestudio.ai/oui/v1/agent-binding.json",
416
+ "title": "AgentBinding",
417
+ "description": "The semantic binding a design-system control carries (ADR-0220 §2.2): what the control means, in the user's terms, declared where the page uses it, as its `agent` prop.\n\nIt uses a room catalog entry's vocabulary (id, title and description; `ActionEffect`; `destructive`), so to the generator a page control and a room entry look the same. What is never written: the input schema, which is derived from the control's own props, and where the control is, which the generator derives from the page's component tree.\n\n**Every value is a build-time constant** (#203). The generator reads bindings from source without running it, so each value is a literal, a `const` it can follow, a property of a constant object, a template literal or `+` over those, or a single-literal type read through the type checker. A value built by a call (`t('save')`, `format(...)`) is refused, naming the binding. A field's build-time `hint` and `placeholder` are added to its tool description the same way.",
418
+ "type": "object",
419
+ "properties": {
420
+ "id": {
421
+ "description": "Stable, globally unique, dotted and lower-kebab: `voices.library`, `voices.detail.engine`. The first segment is the area. The tool name is the id with `.` and `-` as `_`, at most 64 characters.",
422
+ "type": "string",
423
+ "pattern": "^[a-z][a-z0-9-]*(\\.[a-z0-9][a-z0-9-]*)+$"
424
+ },
425
+ "title": {
426
+ "description": "Defaults to the control's visible label or aria-label.",
427
+ "type": "string"
428
+ },
429
+ "description": {
430
+ "description": "What using it does, for someone who cannot see the screen.",
431
+ "type": "string",
432
+ "minLength": 1
433
+ },
434
+ "effect": {
435
+ "description": "What using it does: what reach paths, data and verification are derived from (ADR-0226 §2.6).",
436
+ "$ref": "action-effect.json"
437
+ },
438
+ "destructive": {
439
+ "description": "It removes or replaces something the person made; running it needs the person's approval (ADR-0228).",
440
+ "type": "boolean"
441
+ },
442
+ "confirm": {
443
+ "description": "It changes what the person is working in (their account, project or role) rather than their work; the assistant asks before using it.",
444
+ "type": "boolean"
445
+ },
446
+ "item": {
447
+ "description": "Set when the control is one of a list's rows: which row.",
448
+ "$ref": "#/$defs/AgentItem"
449
+ }
450
+ },
451
+ "required": [
452
+ "id",
453
+ "description"
454
+ ],
455
+ "additionalProperties": false,
456
+ "$defs": {
457
+ "AgentItem": {
458
+ "description": "One of several of the same control rendered from a list: which one it is.",
459
+ "type": "object",
460
+ "properties": {
461
+ "key": {
462
+ "description": "The id of what the row shows (a voice id, a project id).",
463
+ "type": "string"
464
+ },
465
+ "title": {
466
+ "description": "What the row is called on screen (the voice's name).",
467
+ "type": "string"
468
+ },
469
+ "description": {
470
+ "description": "What this row is, when the rows' meanings are only known at run time (a model's parameters, from its manifest). Shown with the row in the page state.",
471
+ "type": "string"
472
+ }
473
+ },
474
+ "required": [
475
+ "key",
476
+ "title"
477
+ ],
478
+ "additionalProperties": false
479
+ },
480
+ "NonAgentBinding": {
481
+ "description": "On a control the assistant must never operate — purely decorative, or chrome that duplicates a bound control. The reason is required and is reviewed like any other declaration.",
482
+ "type": "object",
483
+ "properties": {
484
+ "nonAgent": {
485
+ "type": "string",
486
+ "minLength": 1
487
+ }
488
+ },
489
+ "required": [
490
+ "nonAgent"
491
+ ],
492
+ "additionalProperties": false
493
+ },
494
+ "AgentProp": {
495
+ "description": "The `agent` prop of a single-purpose control.",
496
+ "anyOf": [
497
+ {
498
+ "$ref": "#"
499
+ },
500
+ {
501
+ "$ref": "#/$defs/NonAgentBinding"
502
+ }
503
+ ]
504
+ }
505
+ }
506
+ },
507
+ 'control-kind-registration.json': {
508
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
509
+ "$id": "https://schemas.closurestudio.ai/oui/v1/control-kind-registration.json",
510
+ "title": "ControlKindRegistration",
511
+ "description": "A control kind a design system adds (ADR-0226 §2.6). `ControlKind` is closed: a design system adds a kind only by registering it, under an `x-` name. The registration ships in the design system's control table (`$kinds`), where the generator reads it, and the design system registers it at run time with `registerControlKind`, so the browser and the generator derive the same schema.",
512
+ "type": "object",
513
+ "properties": {
514
+ "kind": {
515
+ "$ref": "#/$defs/RegisteredControlKind"
516
+ },
517
+ "verb": {
518
+ "description": "What using it does, as a tool description starts: \"Set the price range of\".",
519
+ "type": "string",
520
+ "minLength": 1,
521
+ "pattern": "\\S"
522
+ },
523
+ "deriveSchema": {
524
+ "$ref": "#/$defs/KindSchemaDerivation"
525
+ }
526
+ },
527
+ "required": [
528
+ "kind",
529
+ "verb",
530
+ "deriveSchema"
531
+ ],
532
+ "additionalProperties": false,
533
+ "$defs": {
534
+ "ControlKind": {
535
+ "description": "The built-in control kinds, closed:\n\n- `button`: press it (buttons, toolbar buttons, menu items, a row's action).\n- `toggle`: set it on or off (switches, checkboxes).\n- `text`: type into it (inputs, text areas).\n- `number`: set a number (sliders, scrub fields).\n- `choice`: choose one of its options (selects, radio groups, preset tiles).\n- `multi-choice`: choose any of its options (multi-selects, checkbox groups, filter chips).\n- `color`: set a colour or paint (colour pickers, swatches).\n- `font`: choose a family and style (font pickers).\n- `tabs`: select a tab.\n- `date`: set a date.\n- `date-range`: set a start and an end date.\n- `dialog`: close it. Opening is its trigger's.",
536
+ "enum": [
537
+ "button",
538
+ "toggle",
539
+ "text",
540
+ "number",
541
+ "choice",
542
+ "multi-choice",
543
+ "color",
544
+ "font",
545
+ "tabs",
546
+ "date",
547
+ "date-range",
548
+ "dialog"
549
+ ]
550
+ },
551
+ "RegisteredControlKind": {
552
+ "description": "A kind a design system registers: `x-` and lower-kebab, so it never collides with a built-in one.",
553
+ "type": "string",
554
+ "pattern": "^x-[a-z][a-z0-9]*(-[a-z0-9]+)*$",
555
+ "$comment": "ts: `x-${string}`"
556
+ },
557
+ "AnyControlKind": {
558
+ "description": "A built-in kind, or one a design system registers.",
559
+ "anyOf": [
560
+ {
561
+ "$ref": "#/$defs/ControlKind"
562
+ },
563
+ {
564
+ "$ref": "#/$defs/RegisteredControlKind"
565
+ }
566
+ ]
567
+ },
568
+ "SchemaPropName": {
569
+ "description": "A key of `SchemaProps`: a prop a control's value schema is derived from.",
570
+ "enum": [
571
+ "min",
572
+ "max",
573
+ "step",
574
+ "unit",
575
+ "wrap",
576
+ "options",
577
+ "minLength",
578
+ "maxLength",
579
+ "pattern",
580
+ "inputType",
581
+ "paintKinds",
582
+ "allowNone",
583
+ "clearable"
584
+ ]
585
+ },
586
+ "ControlOption": {
587
+ "description": "One option of a choice, tab set or menu, as the control shows it.",
588
+ "type": "object",
589
+ "properties": {
590
+ "value": {
591
+ "anyOf": [
592
+ {
593
+ "type": "string"
594
+ },
595
+ {
596
+ "type": "number"
597
+ }
598
+ ]
599
+ },
600
+ "title": {
601
+ "type": "string"
602
+ },
603
+ "disabled": {
604
+ "type": "boolean"
605
+ }
606
+ },
607
+ "required": [
608
+ "value",
609
+ "title"
610
+ ],
611
+ "additionalProperties": false
612
+ },
613
+ "SchemaProps": {
614
+ "description": "The props a control's input schema is derived from, by the one derivation (`deriveInputSchema`) the browser runs on live props and the generator on the props it reads statically. A live schema may narrow the generated one but never widen it.",
615
+ "type": "object",
616
+ "properties": {
617
+ "min": {
618
+ "type": "number"
619
+ },
620
+ "max": {
621
+ "type": "number"
622
+ },
623
+ "step": {
624
+ "type": "number"
625
+ },
626
+ "unit": {
627
+ "type": "string"
628
+ },
629
+ "wrap": {
630
+ "description": "Wraps past either end: an angle, where 181° is −179°.",
631
+ "type": "boolean"
632
+ },
633
+ "options": {
634
+ "type": "array",
635
+ "items": {
636
+ "$ref": "#/$defs/ControlOption"
637
+ }
638
+ },
639
+ "minLength": {
640
+ "type": "number"
641
+ },
642
+ "maxLength": {
643
+ "type": "number"
644
+ },
645
+ "pattern": {
646
+ "type": "string"
647
+ },
648
+ "inputType": {
649
+ "description": "An input's `type`: `email`, `url`, `number`, `password`…",
650
+ "type": "string"
651
+ },
652
+ "paintKinds": {
653
+ "description": "The paint kinds a colour control offers: `solid`, `linear`, `radial`.",
654
+ "type": "array",
655
+ "items": {
656
+ "type": "string"
657
+ }
658
+ },
659
+ "allowNone": {
660
+ "description": "A colour control can be set to no paint.",
661
+ "type": "boolean"
662
+ },
663
+ "clearable": {
664
+ "description": "A choice that can be cleared (a toggleable tile grid).",
665
+ "type": "boolean"
666
+ }
667
+ },
668
+ "additionalProperties": false
669
+ },
670
+ "KindSchemaDerivation": {
671
+ "description": "How a registered kind's value schema follows from a control's props, as data, so the browser and the generator derive it with the same function: the schema, and which of its keywords each prop sets, by JSON Pointer. `options` sets a keyword to the values of the options that are not disabled.\n\n```json\n{ \"schema\": { \"type\": \"object\", \"properties\": { \"low\": { \"type\": \"number\" }, \"high\": { \"type\": \"number\" } } },\n \"props\": { \"/properties/low/minimum\": \"min\", \"/properties/high/maximum\": \"max\" } }\n```",
672
+ "type": "object",
673
+ "properties": {
674
+ "schema": {
675
+ "$ref": "json-schema.json"
676
+ },
677
+ "props": {
678
+ "type": "object",
679
+ "propertyNames": {
680
+ "pattern": "^/"
681
+ },
682
+ "additionalProperties": {
683
+ "$ref": "#/$defs/SchemaPropName"
684
+ }
685
+ }
686
+ },
687
+ "required": [
688
+ "schema"
689
+ ],
690
+ "additionalProperties": false
691
+ }
692
+ }
693
+ },
694
+ 'control-table.json': {
695
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
696
+ "$id": "https://schemas.closurestudio.ai/oui/v1/control-table.json",
697
+ "title": "ControlTableFile",
698
+ "description": "A design-system package's control table as it ships (`agent-controls.json`, ADR-0226 §2.2 rule 4): each interactive export's `ControlDescriptor` by export name, and under `$kinds` the control kinds the design system registers, if any. The package declares the table next to its controls, writes it at build time, and names it in its `package.json` under `oui.agentControls` (`closure.agentControls` is read during the transition; declaring both is an error). The conformance kit holds every listed component to registering with the kind declared here.",
699
+ "type": "object",
700
+ "properties": {
701
+ "$kinds": {
702
+ "description": "The control kinds this design system registers.",
703
+ "type": "array",
704
+ "items": {
705
+ "$ref": "control-kind-registration.json"
706
+ }
707
+ }
708
+ },
709
+ "propertyNames": {
710
+ "anyOf": [
711
+ {
712
+ "const": "$kinds"
713
+ },
714
+ {
715
+ "pattern": "^[A-Z][A-Za-z0-9]*$"
716
+ }
717
+ ]
718
+ },
719
+ "additionalProperties": {
720
+ "$ref": "#/$defs/ControlDescriptor"
721
+ },
722
+ "$defs": {
723
+ "ControlTable": {
724
+ "description": "A design-system package's controls, by export name: the table without its `$kinds`.",
725
+ "type": "object",
726
+ "additionalProperties": {
727
+ "$ref": "#/$defs/ControlDescriptor"
728
+ }
729
+ },
730
+ "SlotDescriptor": {
731
+ "description": "One slot of a composite: its kind and the callback it binds. `callback` absent: the slot is always interactive (a toast host's toasts, whatever the page passes). `rows`: the slot registers once per row the control renders (a table's rows, a filter bar's pills), so its action takes an `item`. `defaults`: what the slot always registers, over the component's (a table's sort can be cleared), so the declared schema is as wide as the live one.",
732
+ "type": "object",
733
+ "properties": {
734
+ "kind": {
735
+ "$ref": "control-kind-registration.json#/$defs/AnyControlKind"
736
+ },
737
+ "callback": {
738
+ "type": "string",
739
+ "minLength": 1
740
+ },
741
+ "rows": {
742
+ "type": "boolean"
743
+ },
744
+ "defaults": {
745
+ "$ref": "control-kind-registration.json#/$defs/SchemaProps"
746
+ }
747
+ },
748
+ "required": [
749
+ "kind"
750
+ ],
751
+ "additionalProperties": false
752
+ },
753
+ "EntriesDescriptor": {
754
+ "description": "An array prop whose entries carry their own `agent` (toolbar items, menu items, selection actions).",
755
+ "type": "object",
756
+ "properties": {
757
+ "prop": {
758
+ "type": "string",
759
+ "minLength": 1
760
+ },
761
+ "kind": {
762
+ "$ref": "control-kind-registration.json#/$defs/AnyControlKind"
763
+ },
764
+ "callback": {
765
+ "type": "string",
766
+ "minLength": 1
767
+ },
768
+ "titleKey": {
769
+ "type": "string",
770
+ "minLength": 1
771
+ }
772
+ },
773
+ "required": [
774
+ "prop",
775
+ "kind",
776
+ "callback",
777
+ "titleKey"
778
+ ],
779
+ "additionalProperties": false
780
+ },
781
+ "ControlDescriptor": {
782
+ "description": "How the generator reads one design-system component where a page uses it: what kind of control it is, which of its props make it interactive, and where its schema, options, slots and nested bindings come from. The component itself registers through `useAgentBinding` with the same kind.",
783
+ "type": "object",
784
+ "properties": {
785
+ "kind": {
786
+ "description": "What a binding on the component itself makes. Absent when it binds only per slot or per entry.",
787
+ "$ref": "control-kind-registration.json#/$defs/AnyControlKind"
788
+ },
789
+ "callbacks": {
790
+ "description": "Props whose presence makes a use interactive — a use with one of them must be bound. Empty: always.",
791
+ "type": "array",
792
+ "items": {
793
+ "type": "string",
794
+ "minLength": 1
795
+ }
796
+ },
797
+ "schemaProps": {
798
+ "description": "Props the schema is derived from, by `SchemaProps` key: the prop of the component each comes from.",
799
+ "$ref": "#/$defs/SchemaPropSources"
800
+ },
801
+ "options": {
802
+ "description": "Where the options come from: the prop, and the keys of each option's value and title.",
803
+ "$ref": "#/$defs/OptionsSource"
804
+ },
805
+ "slots": {
806
+ "description": "A composite with several callbacks: slot name → its kind and the callback it binds.",
807
+ "type": "object",
808
+ "additionalProperties": {
809
+ "$ref": "#/$defs/SlotDescriptor"
810
+ }
811
+ },
812
+ "entries": {
813
+ "$ref": "#/$defs/EntriesDescriptor"
814
+ },
815
+ "rows": {
816
+ "description": "The control registers one binding per row it renders (a selectable grid), so its action takes an `item`.",
817
+ "type": "boolean"
818
+ },
819
+ "container": {
820
+ "description": "A container: a dialog whose prop says whether it shows, or a tab set whose prop selects a panel.",
821
+ "type": "object",
822
+ "properties": {
823
+ "kind": {
824
+ "enum": [
825
+ "dialog",
826
+ "tabs"
827
+ ]
828
+ },
829
+ "stateProp": {
830
+ "type": "string",
831
+ "minLength": 1
832
+ }
833
+ },
834
+ "required": [
835
+ "kind",
836
+ "stateProp"
837
+ ],
838
+ "additionalProperties": false
839
+ },
840
+ "defaults": {
841
+ "description": "What the schema props are when the page leaves them out, as the component defaults them. The declared schema is the widest the control can take; the live one may only narrow it.",
842
+ "$ref": "control-kind-registration.json#/$defs/SchemaProps"
843
+ },
844
+ "display": {
845
+ "description": "It shows facts rather than taking input (a clip's parameters): a binding on it names what it shows, and the page reports its facts by label. Its facts are the array prop `itemsProp`, each labelled by `labelKey`. Not a control, so a use without a binding is not unbound.",
846
+ "type": "object",
847
+ "properties": {
848
+ "itemsProp": {
849
+ "type": "string",
850
+ "minLength": 1
851
+ },
852
+ "labelKey": {
853
+ "type": "string",
854
+ "minLength": 1
855
+ }
856
+ },
857
+ "required": [
858
+ "itemsProp",
859
+ "labelKey"
860
+ ],
861
+ "additionalProperties": false
862
+ },
863
+ "titleProps": {
864
+ "description": "Props that give a default title, in order. `children` means the element's text.",
865
+ "type": "array",
866
+ "items": {
867
+ "type": "string",
868
+ "minLength": 1
869
+ }
870
+ }
871
+ },
872
+ "required": [
873
+ "callbacks",
874
+ "titleProps"
875
+ ],
876
+ "additionalProperties": false
877
+ },
878
+ "OptionsSource": {
879
+ "description": "Where a control's options come from: the prop that holds them, and the keys of each option's value and title.",
880
+ "type": "object",
881
+ "properties": {
882
+ "prop": {
883
+ "type": "string",
884
+ "minLength": 1
885
+ },
886
+ "value": {
887
+ "type": "string",
888
+ "minLength": 1
889
+ },
890
+ "title": {
891
+ "type": "string",
892
+ "minLength": 1
893
+ }
894
+ },
895
+ "required": [
896
+ "prop",
897
+ "value",
898
+ "title"
899
+ ],
900
+ "additionalProperties": false
901
+ },
902
+ "OuiPackageDeclaration": {
903
+ "description": "What a package declares to the generator under the `oui` key of its `package.json` (ADR-0226 §2.2): its control table, its room catalog, and the components only the person may use. During the transition the generator and the kit also read `closure.agentControls` and `closure.agentCatalog`; a package declaring a key under both `oui` and `closure` is an error.",
904
+ "type": "object",
905
+ "properties": {
906
+ "agentControls": {
907
+ "description": "The path of the package's control table, relative to the package.",
908
+ "type": "string",
909
+ "minLength": 1
910
+ },
911
+ "agentCatalog": {
912
+ "$ref": "room-catalog-data.json#/$defs/AgentCatalogManifestEntry"
913
+ },
914
+ "personOnly": {
915
+ "description": "Export name → why only the person may use it, such as the approval card (ADR-0228). The generator refuses an `agent` binding on one.",
916
+ "type": "object",
917
+ "additionalProperties": {
918
+ "type": "string",
919
+ "minLength": 1
920
+ }
921
+ }
922
+ },
923
+ "additionalProperties": false
924
+ },
925
+ "SchemaPropSources": {
926
+ "description": "Props a control's schema is derived from, by `SchemaProps` key (every key but `options`, which `OptionsSource` gives): the prop of the component each comes from.",
927
+ "type": "object",
928
+ "properties": {
929
+ "min": {
930
+ "type": "string"
931
+ },
932
+ "max": {
933
+ "type": "string"
934
+ },
935
+ "step": {
936
+ "type": "string"
937
+ },
938
+ "unit": {
939
+ "type": "string"
940
+ },
941
+ "wrap": {
942
+ "type": "string"
943
+ },
944
+ "minLength": {
945
+ "type": "string"
946
+ },
947
+ "maxLength": {
948
+ "type": "string"
949
+ },
950
+ "pattern": {
951
+ "type": "string"
952
+ },
953
+ "inputType": {
954
+ "type": "string"
955
+ },
956
+ "paintKinds": {
957
+ "type": "string"
958
+ },
959
+ "allowNone": {
960
+ "type": "string"
961
+ },
962
+ "clearable": {
963
+ "type": "string"
964
+ }
965
+ },
966
+ "additionalProperties": false
967
+ }
968
+ }
969
+ },
970
+ 'tier2-mapping.json': {
971
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
972
+ "$id": "https://schemas.closurestudio.ai/oui/v1/tier2-mapping.json",
973
+ "title": "Tier2Mapping",
974
+ "description": "A tier 2 mapping (ADR-0226 §2.3): how an app binds the controls of a third-party design system it does not own (MUI, Mantine, shadcn/Radix). It is a declaration, not handler code: `oui generate` emits one module per mapping into `<out>/bound/`. Each wrapper accepts `agent`, calls `useAgentBinding` with the app's own callback, returns that callback's result (§2.2 rule 3), and renders the third-party component unchanged. The emitted module ships its own control table and is treated exactly like a tier 1 package. On an enforced page, importing a mapped component straight from the third-party package fails the build.",
975
+ "type": "object",
976
+ "properties": {
977
+ "$schema": {
978
+ "type": "string"
979
+ },
980
+ "package": {
981
+ "description": "The third-party package the controls are imported from (`@mantine/core`).",
982
+ "type": "string",
983
+ "minLength": 1
984
+ },
985
+ "controls": {
986
+ "description": "Each mapped export, by its export name in that package.",
987
+ "type": "object",
988
+ "minProperties": 1,
989
+ "propertyNames": {
990
+ "pattern": "^[A-Z][A-Za-z0-9]*$"
991
+ },
992
+ "additionalProperties": {
993
+ "$ref": "#/$defs/Tier2Control"
994
+ }
995
+ }
996
+ },
997
+ "required": [
998
+ "package",
999
+ "controls"
1000
+ ],
1001
+ "additionalProperties": false,
1002
+ "$defs": {
1003
+ "ValueFrom": {
1004
+ "description": "Where the new value is in the callback's arguments: `{ \"arg\": 0 }` for Mantine's `onChange(value)`, `{ \"arg\": 1 }` for MUI's `onChange(event, value)`, and `{ \"arg\": 0, \"path\": \"target.value\" }` for a native-style event. The wrapper builds those arguments when the assistant sets the value, and reads them back when the person does.",
1005
+ "type": "object",
1006
+ "properties": {
1007
+ "arg": {
1008
+ "description": "The argument's position.",
1009
+ "type": "integer",
1010
+ "minimum": 0
1011
+ },
1012
+ "path": {
1013
+ "description": "A dotted path into that argument.",
1014
+ "type": "string",
1015
+ "pattern": "^[A-Za-z_$][A-Za-z0-9_$]*(\\.[A-Za-z_$][A-Za-z0-9_$]*)*$"
1016
+ }
1017
+ },
1018
+ "required": [
1019
+ "arg"
1020
+ ],
1021
+ "additionalProperties": false
1022
+ },
1023
+ "Tier2Part": {
1024
+ "description": "One part of a control exported under a namespace: the export path of that part (`Select.Root`, `Select.Item`, `Tabs.Tab`). A path is an export of the package, or one member of one (one dot at most).",
1025
+ "type": "object",
1026
+ "properties": {
1027
+ "export": {
1028
+ "description": "The part's export path: an export of the package, or one member of it, dotted (`Select.Item`).",
1029
+ "type": "string",
1030
+ "pattern": "^[A-Z][A-Za-z0-9]*(\\.[A-Z][A-Za-z0-9]*)?$"
1031
+ },
1032
+ "valueProp": {
1033
+ "description": "On an item part: the prop that is the option's value.",
1034
+ "type": "string",
1035
+ "minLength": 1
1036
+ },
1037
+ "titleProps": {
1038
+ "description": "On an item part: the props, in order, that give the option's title. `children` means its text.",
1039
+ "type": "array",
1040
+ "items": {
1041
+ "type": "string",
1042
+ "minLength": 1
1043
+ }
1044
+ }
1045
+ },
1046
+ "required": [
1047
+ "export"
1048
+ ],
1049
+ "additionalProperties": false
1050
+ },
1051
+ "Tier2Control": {
1052
+ "description": "One mapped control. The bound wrapper reports the component's `disabled` prop, so a control the page disables is not offered (a disabled job control is still followed until its job settles).",
1053
+ "type": "object",
1054
+ "properties": {
1055
+ "kind": {
1056
+ "$ref": "control-kind-registration.json#/$defs/AnyControlKind"
1057
+ },
1058
+ "callbacks": {
1059
+ "description": "Props whose presence makes a use interactive. The first is the one a binding runs: for a value, with the arguments `valueFrom` describes; for a button or a dialog, with an event-shaped argument whose `isTrusted` is false.",
1060
+ "type": "array",
1061
+ "minItems": 1,
1062
+ "items": {
1063
+ "type": "string",
1064
+ "minLength": 1
1065
+ }
1066
+ },
1067
+ "valueFrom": {
1068
+ "description": "Required for every kind that takes a value (all but `button` and `dialog`).",
1069
+ "$ref": "#/$defs/ValueFrom"
1070
+ },
1071
+ "controlled": {
1072
+ "description": "The prop that shows the value. The generator reports every use of the control that does not pass it: there the handler would run, but the control would not show the new value.",
1073
+ "type": "string",
1074
+ "minLength": 1
1075
+ },
1076
+ "options": {
1077
+ "description": "Where the options come from: the prop, and the keys of each option's value and title.",
1078
+ "$ref": "control-table.json#/$defs/OptionsSource"
1079
+ },
1080
+ "titleProps": {
1081
+ "description": "Props that give a default title, in order. `children` means the element's text.",
1082
+ "type": "array",
1083
+ "items": {
1084
+ "type": "string",
1085
+ "minLength": 1
1086
+ }
1087
+ },
1088
+ "schemaProps": {
1089
+ "description": "Props the value schema is derived from, by `SchemaProps` key.",
1090
+ "$ref": "control-table.json#/$defs/SchemaPropSources"
1091
+ },
1092
+ "defaults": {
1093
+ "description": "What the schema props are when the app leaves them out, as the component defaults them.",
1094
+ "$ref": "control-kind-registration.json#/$defs/SchemaProps"
1095
+ },
1096
+ "parts": {
1097
+ "description": "A control exported under a namespace (Radix `Switch.Root`) or made of parts (Radix `Select.Root` / `Select.Item`, Mantine `Tabs` / `Tabs.Tab`): its `root`, which takes the callbacks, and, when the options are the items it renders, its `item`. The bound module keeps every other member of each namespace (`Select.Trigger`, `Tabs.List`).",
1098
+ "type": "object",
1099
+ "properties": {
1100
+ "root": {
1101
+ "$ref": "#/$defs/Tier2Part"
1102
+ },
1103
+ "item": {
1104
+ "$ref": "#/$defs/Tier2Part"
1105
+ }
1106
+ },
1107
+ "required": [
1108
+ "root"
1109
+ ],
1110
+ "additionalProperties": false
1111
+ }
1112
+ },
1113
+ "required": [
1114
+ "kind",
1115
+ "callbacks"
1116
+ ],
1117
+ "additionalProperties": false,
1118
+ "allOf": [
1119
+ {
1120
+ "if": {
1121
+ "properties": {
1122
+ "kind": {
1123
+ "not": {
1124
+ "enum": [
1125
+ "button",
1126
+ "dialog"
1127
+ ]
1128
+ }
1129
+ }
1130
+ }
1131
+ },
1132
+ "then": {
1133
+ "required": [
1134
+ "valueFrom",
1135
+ "controlled"
1136
+ ]
1137
+ }
1138
+ },
1139
+ {
1140
+ "if": {
1141
+ "required": [
1142
+ "parts"
1143
+ ],
1144
+ "properties": {
1145
+ "parts": {
1146
+ "type": "object",
1147
+ "required": [
1148
+ "item"
1149
+ ]
1150
+ }
1151
+ }
1152
+ },
1153
+ "then": {
1154
+ "not": {
1155
+ "required": [
1156
+ "options"
1157
+ ]
1158
+ }
1159
+ }
1160
+ }
1161
+ ]
1162
+ }
1163
+ }
1164
+ },
1165
+ 'room-catalog-data.json': {
1166
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
1167
+ "$id": "https://schemas.closurestudio.ai/oui/v1/room-catalog-data.json",
1168
+ "title": "RoomCatalogData",
1169
+ "description": "A room catalog as plain data (ADR-0220 §2.3, tier 3 of ADR-0226): what a room with its own editing model — a canvas, a chart, a timeline, a player — declares about everything a person can do in it, so the assistant's actions and knowledge are generated from the room's code. Every declaration, none of the functions: a room's package writes it as `agent-catalog.json` (named in `package.json` under `oui.agentCatalog`) so a build-time generator reads the catalog without loading React or the room's code; an app's own catalog is read through the app's Vite config.\n\n- **actions**: its operations, each carried out through the room's own reducer and commands, with a JSON schema for the input;\n- **fields**: its inspector's fields, each with its value's schema, unit, range, its animation where the room has a timeline, and which kinds of thing it applies to;\n- **commands**: its keymap, each command with its keys and what it does;\n- **observations**: what the host reports about the room's state, including the problems it has drawing it.\n\nA room derives each action's input from the schema its reducer already validates with (`z.toJSONSchema`) and re-checks input with the same schema before applying it.",
1170
+ "type": "object",
1171
+ "properties": {
1172
+ "room": {
1173
+ "description": "The room's id: the surface id its assistant surface is published under (`room:<id>`).",
1174
+ "type": "string",
1175
+ "minLength": 1
1176
+ },
1177
+ "title": {
1178
+ "type": "string",
1179
+ "minLength": 1
1180
+ },
1181
+ "description": {
1182
+ "description": "What the room is for, in one or two sentences.",
1183
+ "type": "string",
1184
+ "minLength": 1
1185
+ },
1186
+ "actions": {
1187
+ "type": "array",
1188
+ "items": {
1189
+ "$ref": "#/$defs/RoomActionData"
1190
+ }
1191
+ },
1192
+ "fields": {
1193
+ "type": "array",
1194
+ "items": {
1195
+ "$ref": "#/$defs/RoomFieldData"
1196
+ }
1197
+ },
1198
+ "commands": {
1199
+ "type": "array",
1200
+ "items": {
1201
+ "$ref": "#/$defs/RoomCommand"
1202
+ }
1203
+ },
1204
+ "observations": {
1205
+ "type": "array",
1206
+ "items": {
1207
+ "$ref": "#/$defs/RoomObservation"
1208
+ }
1209
+ },
1210
+ "problems": {
1211
+ "description": "The kinds of problem it reports, in its own vocabulary. Default: the generic `problems` schema.",
1212
+ "type": "array",
1213
+ "items": {
1214
+ "$ref": "#/$defs/RoomProblemKind"
1215
+ }
1216
+ },
1217
+ "recipes": {
1218
+ "description": "Tasks its tools carry out together, which only the room knows.",
1219
+ "type": "array",
1220
+ "items": {
1221
+ "$ref": "#/$defs/RoomRecipe"
1222
+ }
1223
+ }
1224
+ },
1225
+ "required": [
1226
+ "room",
1227
+ "title",
1228
+ "description",
1229
+ "actions",
1230
+ "fields",
1231
+ "commands",
1232
+ "observations"
1233
+ ],
1234
+ "additionalProperties": false,
1235
+ "$defs": {
1236
+ "RoomEntryInfo": {
1237
+ "description": "What every catalog entry says about itself. Knowledge is generated from these words alone.",
1238
+ "type": "object",
1239
+ "properties": {
1240
+ "id": {
1241
+ "description": "Stable, kebab-case, unique among the room's entries of its kind.",
1242
+ "type": "string",
1243
+ "minLength": 1
1244
+ },
1245
+ "title": {
1246
+ "description": "What the UI calls it: a button's label, a field's label, a command's name.",
1247
+ "type": "string"
1248
+ },
1249
+ "description": {
1250
+ "description": "What it does, in a sentence or two, in the room's own terms.",
1251
+ "type": "string"
1252
+ },
1253
+ "control": {
1254
+ "description": "Where a person does it: the tool, panel, button, key or gesture.",
1255
+ "type": "string"
1256
+ }
1257
+ },
1258
+ "required": [
1259
+ "id",
1260
+ "title",
1261
+ "description",
1262
+ "control"
1263
+ ]
1264
+ },
1265
+ "RoomActionData": {
1266
+ "description": "One operation of the room, without its `run`.",
1267
+ "type": "object",
1268
+ "allOf": [
1269
+ {
1270
+ "$ref": "#/$defs/RoomEntryInfo"
1271
+ },
1272
+ {
1273
+ "type": "object",
1274
+ "properties": {
1275
+ "kind": {
1276
+ "const": "action"
1277
+ },
1278
+ "input": {
1279
+ "description": "An object schema: a tool's input is one, never a union at its top level. Its property descriptions are the parameters' documentation.",
1280
+ "$ref": "json-schema.json"
1281
+ },
1282
+ "effect": {
1283
+ "description": "What it changes: the document (`edit`), the selection, the view, files, backend data, a job, a transaction.",
1284
+ "$ref": "action-effect.json"
1285
+ },
1286
+ "destructive": {
1287
+ "description": "It removes or replaces something the person made; running it needs the person's approval (ADR-0228).",
1288
+ "type": "boolean"
1289
+ }
1290
+ },
1291
+ "required": [
1292
+ "kind",
1293
+ "input",
1294
+ "effect"
1295
+ ]
1296
+ }
1297
+ ],
1298
+ "unevaluatedProperties": false
1299
+ },
1300
+ "RoomSection": {
1301
+ "description": "Which inspector section a field is in, as the inspector titles it.",
1302
+ "type": "object",
1303
+ "properties": {
1304
+ "id": {
1305
+ "type": "string"
1306
+ },
1307
+ "title": {
1308
+ "type": "string"
1309
+ }
1310
+ },
1311
+ "required": [
1312
+ "id",
1313
+ "title"
1314
+ ],
1315
+ "additionalProperties": false
1316
+ },
1317
+ "RoomFieldAnimation": {
1318
+ "description": "A field's animation, in a room with a timeline. Animation is a capability, not a requirement (ADR-0226 §2.6).",
1319
+ "type": "object",
1320
+ "properties": {
1321
+ "keyframeable": {
1322
+ "description": "Set at the playhead, it is a keyframe there when the property is animated.",
1323
+ "type": "boolean"
1324
+ }
1325
+ },
1326
+ "required": [
1327
+ "keyframeable"
1328
+ ],
1329
+ "additionalProperties": false
1330
+ },
1331
+ "RoomFieldData": {
1332
+ "description": "One inspector field, without its `read` and `write`: what it shows for the selection, and what setting it does.",
1333
+ "type": "object",
1334
+ "allOf": [
1335
+ {
1336
+ "$ref": "#/$defs/RoomEntryInfo"
1337
+ },
1338
+ {
1339
+ "type": "object",
1340
+ "properties": {
1341
+ "kind": {
1342
+ "const": "field"
1343
+ },
1344
+ "section": {
1345
+ "$ref": "#/$defs/RoomSection"
1346
+ },
1347
+ "appliesTo": {
1348
+ "description": "The kinds of thing it applies to, in the room's vocabulary (`text`, `shape`, `artboard`…).",
1349
+ "type": "array",
1350
+ "items": {
1351
+ "type": "string"
1352
+ }
1353
+ },
1354
+ "value": {
1355
+ "description": "The value's schema: its type, range (`minimum`/`maximum`), options (`enum`) and unit (`x-unit`).",
1356
+ "$ref": "json-schema.json"
1357
+ },
1358
+ "animation": {
1359
+ "description": "How it animates, in a room with a timeline. A room without one leaves it out.",
1360
+ "$ref": "#/$defs/RoomFieldAnimation"
1361
+ },
1362
+ "keyframeable": {
1363
+ "description": "Deprecated since oui-bindings 0.8: `animation: { keyframeable }`. Read for one minor.",
1364
+ "type": "boolean"
1365
+ }
1366
+ },
1367
+ "required": [
1368
+ "kind",
1369
+ "section",
1370
+ "appliesTo",
1371
+ "value"
1372
+ ]
1373
+ }
1374
+ ],
1375
+ "unevaluatedProperties": false
1376
+ },
1377
+ "RoomCommand": {
1378
+ "description": "One keymap command: what its key does.",
1379
+ "type": "object",
1380
+ "allOf": [
1381
+ {
1382
+ "$ref": "#/$defs/RoomEntryInfo"
1383
+ },
1384
+ {
1385
+ "type": "object",
1386
+ "properties": {
1387
+ "kind": {
1388
+ "const": "command"
1389
+ },
1390
+ "group": {
1391
+ "description": "The group the room lists it under: tools, objects, edit, view.",
1392
+ "type": "string"
1393
+ },
1394
+ "keys": {
1395
+ "description": "Its keys as a person reads them (`⇧⌘G`). Empty when it has none.",
1396
+ "type": "array",
1397
+ "items": {
1398
+ "type": "string"
1399
+ }
1400
+ },
1401
+ "status": {
1402
+ "description": "`reserved`: its key is kept for a feature that is not built; it does nothing. Never offered.",
1403
+ "enum": [
1404
+ "available",
1405
+ "reserved"
1406
+ ]
1407
+ },
1408
+ "options": {
1409
+ "description": "Options the command takes beyond the selection (a nudge's direction).",
1410
+ "$ref": "json-schema.json"
1411
+ }
1412
+ },
1413
+ "required": [
1414
+ "kind",
1415
+ "group",
1416
+ "keys",
1417
+ "status"
1418
+ ]
1419
+ }
1420
+ ],
1421
+ "unevaluatedProperties": false
1422
+ },
1423
+ "RoomObservation": {
1424
+ "description": "Something the room reports about its state: the document, what is selected, or the problems it has drawing it. The host pushes the value; the catalog declares what it means.",
1425
+ "type": "object",
1426
+ "properties": {
1427
+ "id": {
1428
+ "type": "string",
1429
+ "minLength": 1
1430
+ },
1431
+ "description": {
1432
+ "type": "string"
1433
+ },
1434
+ "schema": {
1435
+ "$ref": "json-schema.json"
1436
+ }
1437
+ },
1438
+ "required": [
1439
+ "id",
1440
+ "description",
1441
+ "schema"
1442
+ ],
1443
+ "additionalProperties": false
1444
+ },
1445
+ "RoomProblemKind": {
1446
+ "description": "One kind of problem a room or page reports, in its own vocabulary (`missing-font`, `order-rejected`): the kind, and what it means.",
1447
+ "type": "object",
1448
+ "properties": {
1449
+ "kind": {
1450
+ "type": "string",
1451
+ "minLength": 1
1452
+ },
1453
+ "description": {
1454
+ "type": "string",
1455
+ "minLength": 1
1456
+ }
1457
+ },
1458
+ "required": [
1459
+ "kind",
1460
+ "description"
1461
+ ],
1462
+ "additionalProperties": false
1463
+ },
1464
+ "RoomRecipe": {
1465
+ "description": "A task the room's own tools carry out together, declared by the room because only it knows the task (animating a property, placing an order). The generator turns it into a knowledge recipe and ends it with reading what the room reports.\n\nIn `name`, `trigger` and each step, `{room}` is the room's title, and these name the tool that does a step, checked against the catalog when the knowledge is generated:\n- `{action:<id>}`: the action's tool;\n- `{command:<id>}`: the command, run with the `run-command` action;\n- `{field:<id>}`: the field, set with the `set-properties` action;\n- `{keyframeable}`: the ids of the fields that animate.",
1466
+ "type": "object",
1467
+ "properties": {
1468
+ "name": {
1469
+ "type": "string",
1470
+ "minLength": 1
1471
+ },
1472
+ "trigger": {
1473
+ "type": "string",
1474
+ "minLength": 1
1475
+ },
1476
+ "steps": {
1477
+ "type": "array",
1478
+ "items": {
1479
+ "type": "string"
1480
+ }
1481
+ }
1482
+ },
1483
+ "required": [
1484
+ "name",
1485
+ "trigger",
1486
+ "steps"
1487
+ ],
1488
+ "additionalProperties": false
1489
+ },
1490
+ "RoomProblem": {
1491
+ "description": "A problem a room or page has drawing or reading what the person is working on: a face it cannot load, text it therefore does not draw, an asset that failed, something an import could not reproduce. Reported in a `problems` observation, so an assistant sees what the person sees in the banners.",
1492
+ "type": "object",
1493
+ "properties": {
1494
+ "kind": {
1495
+ "description": "`missing-font`, `font-error`, `unsupported-import`, `asset-failed`, `access-required`…",
1496
+ "type": "string"
1497
+ },
1498
+ "message": {
1499
+ "description": "The room's own words for it, as its banner says it.",
1500
+ "type": "string"
1501
+ },
1502
+ "hides": {
1503
+ "description": "Ids of the things not drawn because of it.",
1504
+ "type": "array",
1505
+ "items": {
1506
+ "type": "string"
1507
+ }
1508
+ },
1509
+ "resolve": {
1510
+ "description": "How the person resolves it in the room: an action of this catalog, and the choices it offers.",
1511
+ "type": "object",
1512
+ "properties": {
1513
+ "action": {
1514
+ "type": "string"
1515
+ },
1516
+ "choices": {
1517
+ "type": "array",
1518
+ "items": {
1519
+ "type": "object",
1520
+ "additionalProperties": true
1521
+ }
1522
+ }
1523
+ },
1524
+ "required": [
1525
+ "action"
1526
+ ],
1527
+ "additionalProperties": false
1528
+ },
1529
+ "detail": {
1530
+ "description": "Anything else that names the problem precisely (the face, the element).",
1531
+ "type": "object",
1532
+ "additionalProperties": true
1533
+ }
1534
+ },
1535
+ "required": [
1536
+ "kind",
1537
+ "message"
1538
+ ],
1539
+ "additionalProperties": false
1540
+ },
1541
+ "RoomResult": {
1542
+ "description": "What running a catalog entry or a bound control did: its data, or why it could not be done, in words a person would read. `pending` says the work outlives the call: a job was started and is done only when its completion arrives (an action whose effect is `job` or `transaction`). Every binding's `run` returns what the consumer's callback returned (ADR-0226 §2.2 rule 3, #209), so a handler's `{ ok, pending: { jobId } }` reaches the runtime.",
1543
+ "oneOf": [
1544
+ {
1545
+ "type": "object",
1546
+ "properties": {
1547
+ "ok": {
1548
+ "const": true
1549
+ },
1550
+ "data": {
1551
+ "type": "object",
1552
+ "additionalProperties": true
1553
+ },
1554
+ "pending": {
1555
+ "type": "object",
1556
+ "properties": {
1557
+ "jobId": {
1558
+ "type": "string"
1559
+ }
1560
+ },
1561
+ "required": [
1562
+ "jobId"
1563
+ ],
1564
+ "additionalProperties": false
1565
+ }
1566
+ },
1567
+ "required": [
1568
+ "ok"
1569
+ ],
1570
+ "additionalProperties": false
1571
+ },
1572
+ {
1573
+ "type": "object",
1574
+ "properties": {
1575
+ "ok": {
1576
+ "const": false
1577
+ },
1578
+ "code": {
1579
+ "type": "string"
1580
+ },
1581
+ "message": {
1582
+ "type": "string"
1583
+ }
1584
+ },
1585
+ "required": [
1586
+ "ok",
1587
+ "code",
1588
+ "message"
1589
+ ],
1590
+ "additionalProperties": false
1591
+ }
1592
+ ]
1593
+ },
1594
+ "AgentCatalogManifestEntry": {
1595
+ "description": "Where a room package names its catalog, under `oui.agentCatalog` in its `package.json` (`closure.agentCatalog` is read during the transition). `hosts` are the exported components that mount the room (and register it); a page that renders one has the room's surface.\n\n```json\n\"oui\": { \"agentCatalog\": { \"path\": \"./dist/agent-catalog.json\", \"hosts\": [\"VectorStudioRoom\"] } }\n```",
1596
+ "type": "object",
1597
+ "properties": {
1598
+ "path": {
1599
+ "type": "string",
1600
+ "minLength": 1
1601
+ },
1602
+ "hosts": {
1603
+ "type": "array",
1604
+ "items": {
1605
+ "type": "string",
1606
+ "minLength": 1
1607
+ },
1608
+ "minItems": 1,
1609
+ "$comment": "ts: string[]"
1610
+ }
1611
+ },
1612
+ "required": [
1613
+ "path",
1614
+ "hosts"
1615
+ ],
1616
+ "additionalProperties": false
1617
+ }
1618
+ }
1619
+ },
1620
+ 'oui-manifest.json': {
1621
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
1622
+ "$id": "https://schemas.closurestudio.ai/oui/v1/oui-manifest.json",
1623
+ "title": "OuiManifest",
1624
+ "description": "What the generator emits for each build (`oui-manifest.json`, ADR-0220 §2.4–2.5): every surface, action and observation the build's UI offers. The runtime (`connectBindings`) offers the intersection of the manifest and the handlers mounted right now, so an action the build declares is a tool only while its control, or its room, is on screen. CI regenerates it and diffs it (`oui generate --check`).",
1625
+ "type": "object",
1626
+ "properties": {
1627
+ "version": {
1628
+ "description": "The contract major (`MANIFEST_VERSION`). A breaking change to any of these schemas bumps it.",
1629
+ "const": 1
1630
+ },
1631
+ "buildId": {
1632
+ "description": "A hash of everything else in the manifest and the knowledge: the build's identity to the assistant.",
1633
+ "type": "string",
1634
+ "minLength": 1
1635
+ },
1636
+ "surfaces": {
1637
+ "type": "array",
1638
+ "items": {
1639
+ "$ref": "#/$defs/ManifestSurface"
1640
+ }
1641
+ }
1642
+ },
1643
+ "required": [
1644
+ "version",
1645
+ "buildId",
1646
+ "surfaces"
1647
+ ],
1648
+ "additionalProperties": false,
1649
+ "$defs": {
1650
+ "ReachStep": {
1651
+ "description": "One step of the way a person reaches a capability.",
1652
+ "oneOf": [
1653
+ {
1654
+ "description": "Go to the page. `nav` is where the sidebar lists it.",
1655
+ "type": "object",
1656
+ "properties": {
1657
+ "kind": {
1658
+ "const": "route"
1659
+ },
1660
+ "path": {
1661
+ "type": "string"
1662
+ },
1663
+ "title": {
1664
+ "type": "string"
1665
+ },
1666
+ "nav": {
1667
+ "type": "string"
1668
+ }
1669
+ },
1670
+ "required": [
1671
+ "kind",
1672
+ "path",
1673
+ "title"
1674
+ ],
1675
+ "additionalProperties": false
1676
+ },
1677
+ {
1678
+ "description": "Select a tab: the tab set's binding (its tool) and the tab's value.",
1679
+ "type": "object",
1680
+ "properties": {
1681
+ "kind": {
1682
+ "const": "tab"
1683
+ },
1684
+ "binding": {
1685
+ "type": "string"
1686
+ },
1687
+ "value": {
1688
+ "anyOf": [
1689
+ {
1690
+ "type": "string"
1691
+ },
1692
+ {
1693
+ "type": "number"
1694
+ }
1695
+ ]
1696
+ },
1697
+ "title": {
1698
+ "type": "string"
1699
+ }
1700
+ },
1701
+ "required": [
1702
+ "kind",
1703
+ "binding",
1704
+ "value",
1705
+ "title"
1706
+ ],
1707
+ "additionalProperties": false
1708
+ },
1709
+ {
1710
+ "description": "Open a dialog, drawer or popover, with one of the controls that open it.",
1711
+ "type": "object",
1712
+ "properties": {
1713
+ "kind": {
1714
+ "const": "dialog"
1715
+ },
1716
+ "binding": {
1717
+ "type": "string"
1718
+ },
1719
+ "title": {
1720
+ "type": "string"
1721
+ },
1722
+ "openedBy": {
1723
+ "type": "array",
1724
+ "items": {
1725
+ "type": "string"
1726
+ }
1727
+ }
1728
+ },
1729
+ "required": [
1730
+ "kind",
1731
+ "title",
1732
+ "openedBy"
1733
+ ],
1734
+ "additionalProperties": false
1735
+ },
1736
+ {
1737
+ "description": "Show a part of the page that appears once a control sets its state (a detail panel opened by choosing a row).",
1738
+ "type": "object",
1739
+ "properties": {
1740
+ "kind": {
1741
+ "const": "panel"
1742
+ },
1743
+ "title": {
1744
+ "type": "string"
1745
+ },
1746
+ "openedBy": {
1747
+ "type": "array",
1748
+ "items": {
1749
+ "type": "string"
1750
+ }
1751
+ }
1752
+ },
1753
+ "required": [
1754
+ "kind",
1755
+ "title",
1756
+ "openedBy"
1757
+ ],
1758
+ "additionalProperties": false
1759
+ },
1760
+ {
1761
+ "description": "Open a menu or toolbar the control is an entry of.",
1762
+ "type": "object",
1763
+ "properties": {
1764
+ "kind": {
1765
+ "const": "menu"
1766
+ },
1767
+ "title": {
1768
+ "type": "string"
1769
+ }
1770
+ },
1771
+ "required": [
1772
+ "kind",
1773
+ "title"
1774
+ ],
1775
+ "additionalProperties": false
1776
+ },
1777
+ {
1778
+ "description": "A room's own place for it: its tool, panel, section, key or gesture, as the room says.",
1779
+ "type": "object",
1780
+ "properties": {
1781
+ "kind": {
1782
+ "const": "room"
1783
+ },
1784
+ "room": {
1785
+ "type": "string"
1786
+ },
1787
+ "where": {
1788
+ "type": "string"
1789
+ },
1790
+ "selection": {
1791
+ "type": "array",
1792
+ "items": {
1793
+ "type": "string"
1794
+ }
1795
+ }
1796
+ },
1797
+ "required": [
1798
+ "kind",
1799
+ "room",
1800
+ "where"
1801
+ ],
1802
+ "additionalProperties": false
1803
+ }
1804
+ ]
1805
+ },
1806
+ "ManifestActionSource": {
1807
+ "description": "Where an action comes from: a bound control, a room's catalog entry, or the generated navigation.",
1808
+ "enum": [
1809
+ "control",
1810
+ "room-action",
1811
+ "navigation"
1812
+ ]
1813
+ },
1814
+ "ManifestAction": {
1815
+ "description": "One action a surface offers: one tool.",
1816
+ "type": "object",
1817
+ "properties": {
1818
+ "name": {
1819
+ "description": "The tool name: unique across the build.",
1820
+ "type": "string",
1821
+ "pattern": "^[a-z0-9_]{1,64}$"
1822
+ },
1823
+ "id": {
1824
+ "description": "The binding id, or `<room>/<kind>/<entry>` for a room's.",
1825
+ "type": "string",
1826
+ "minLength": 1
1827
+ },
1828
+ "source": {
1829
+ "$ref": "#/$defs/ManifestActionSource"
1830
+ },
1831
+ "control": {
1832
+ "description": "The control kind, for a control: a built-in one, or one its design system registers.",
1833
+ "$ref": "control-kind-registration.json#/$defs/AnyControlKind"
1834
+ },
1835
+ "title": {
1836
+ "type": "string"
1837
+ },
1838
+ "description": {
1839
+ "type": "string"
1840
+ },
1841
+ "input": {
1842
+ "description": "The tool's input: one object schema, never a union at its top level.",
1843
+ "$ref": "json-schema.json"
1844
+ },
1845
+ "effect": {
1846
+ "description": "What running it does. A `job` or `transaction` settles on its outcome (`JobSettlement`); a `transaction`, or a destructive `write`, runs only on the person's approval of the exact call.",
1847
+ "$ref": "action-effect.json"
1848
+ },
1849
+ "destructive": {
1850
+ "type": "boolean"
1851
+ },
1852
+ "confirm": {
1853
+ "description": "It changes what the person is working in (account, project, role): the assistant asks first.",
1854
+ "type": "boolean"
1855
+ },
1856
+ "itemized": {
1857
+ "description": "One of a list's rows: the action takes the row as `item`.",
1858
+ "type": "boolean"
1859
+ },
1860
+ "reach": {
1861
+ "description": "How a person gets to it, from the page.",
1862
+ "type": "array",
1863
+ "items": {
1864
+ "$ref": "#/$defs/ReachStep"
1865
+ }
1866
+ },
1867
+ "declaredIn": {
1868
+ "description": "The source file that declares it, relative to the app.",
1869
+ "type": "string"
1870
+ }
1871
+ },
1872
+ "required": [
1873
+ "name",
1874
+ "id",
1875
+ "source",
1876
+ "title",
1877
+ "description",
1878
+ "input",
1879
+ "reach"
1880
+ ],
1881
+ "additionalProperties": false
1882
+ },
1883
+ "ManifestObservation": {
1884
+ "description": "One observation a surface reports: its id, what it means, and its value's schema.",
1885
+ "type": "object",
1886
+ "properties": {
1887
+ "id": {
1888
+ "type": "string",
1889
+ "minLength": 1
1890
+ },
1891
+ "description": {
1892
+ "type": "string"
1893
+ },
1894
+ "schema": {
1895
+ "$ref": "json-schema.json"
1896
+ }
1897
+ },
1898
+ "required": [
1899
+ "id",
1900
+ "description",
1901
+ "schema"
1902
+ ],
1903
+ "additionalProperties": false
1904
+ },
1905
+ "ManifestSurfaceKind": {
1906
+ "description": "A page, a room on a page, a component shared by pages, the app's frame around the pages (`shell`, from `oui.config.json`'s `shell` entries), or the app's pages themselves: going to one by address (`navigation`).",
1907
+ "enum": [
1908
+ "page",
1909
+ "room",
1910
+ "shared",
1911
+ "shell",
1912
+ "navigation"
1913
+ ]
1914
+ },
1915
+ "ManifestSurface": {
1916
+ "description": "One surface: what it offers, where it can be mounted, and what it reports.",
1917
+ "type": "object",
1918
+ "properties": {
1919
+ "id": {
1920
+ "description": "`page:VoicesPage`, `room:vector-studio`, `shared:MoveToProjectModal`, `shell:StudioShell`, `app:navigation`.",
1921
+ "type": "string",
1922
+ "pattern": "^(page|room|shared|shell|app):.+$"
1923
+ },
1924
+ "kind": {
1925
+ "$ref": "#/$defs/ManifestSurfaceKind"
1926
+ },
1927
+ "title": {
1928
+ "type": "string"
1929
+ },
1930
+ "description": {
1931
+ "type": "string"
1932
+ },
1933
+ "routes": {
1934
+ "description": "The route patterns where it can be mounted.",
1935
+ "type": "array",
1936
+ "items": {
1937
+ "type": "string"
1938
+ }
1939
+ },
1940
+ "actions": {
1941
+ "type": "array",
1942
+ "items": {
1943
+ "$ref": "#/$defs/ManifestAction"
1944
+ }
1945
+ },
1946
+ "observations": {
1947
+ "type": "array",
1948
+ "items": {
1949
+ "$ref": "#/$defs/ManifestObservation"
1950
+ }
1951
+ }
1952
+ },
1953
+ "required": [
1954
+ "id",
1955
+ "kind",
1956
+ "title",
1957
+ "description",
1958
+ "routes",
1959
+ "actions",
1960
+ "observations"
1961
+ ],
1962
+ "additionalProperties": false
1963
+ }
1964
+ }
1965
+ },
1966
+ 'generated-knowledge.json': {
1967
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
1968
+ "$id": "https://schemas.closurestudio.ai/oui/v1/generated-knowledge.json",
1969
+ "title": "GeneratedKnowledge",
1970
+ "description": "The knowledge the generator emits with the manifest (`oui-knowledge.json`, ADR-0220 §2.5), from the same declarations: the map of the app, every page in full with its relationships and recipes, and the app's frame. No word of it is written by hand. Each turn carries the part for the page the person is on (`resolveKnowledge`): the map, the frame parts around that page, the page in full, and one paragraph for each adjacent page.",
1971
+ "type": "object",
1972
+ "properties": {
1973
+ "version": {
1974
+ "description": "The contract major (`MANIFEST_VERSION`).",
1975
+ "const": 1
1976
+ },
1977
+ "buildId": {
1978
+ "description": "The manifest's build id: the two are one build.",
1979
+ "type": "string",
1980
+ "minLength": 1
1981
+ },
1982
+ "overview": {
1983
+ "description": "Every page, one line each: the map of the app.",
1984
+ "$ref": "#/$defs/KnowledgeEntry"
1985
+ },
1986
+ "pages": {
1987
+ "type": "array",
1988
+ "items": {
1989
+ "$ref": "#/$defs/PageKnowledge"
1990
+ }
1991
+ },
1992
+ "frames": {
1993
+ "description": "The app's frame around the pages (`shell` surfaces), each part with the route patterns it frames.",
1994
+ "type": "array",
1995
+ "items": {
1996
+ "$ref": "#/$defs/PageKnowledge"
1997
+ }
1998
+ }
1999
+ },
2000
+ "required": [
2001
+ "version",
2002
+ "buildId",
2003
+ "overview",
2004
+ "pages"
2005
+ ],
2006
+ "additionalProperties": false,
2007
+ "$defs": {
2008
+ "KnowledgeEntry": {
2009
+ "description": "One block of knowledge, as the assistant's prompt shows it.",
2010
+ "type": "object",
2011
+ "properties": {
2012
+ "title": {
2013
+ "type": "string"
2014
+ },
2015
+ "content": {
2016
+ "type": "string"
2017
+ }
2018
+ },
2019
+ "required": [
2020
+ "title",
2021
+ "content"
2022
+ ],
2023
+ "additionalProperties": false
2024
+ },
2025
+ "KnowledgeRecipe": {
2026
+ "description": "A task recipe the UI implies, as the assistant's prompt shows a workflow.",
2027
+ "type": "object",
2028
+ "properties": {
2029
+ "name": {
2030
+ "type": "string"
2031
+ },
2032
+ "trigger": {
2033
+ "type": "string"
2034
+ },
2035
+ "steps": {
2036
+ "type": "array",
2037
+ "items": {
2038
+ "type": "string"
2039
+ }
2040
+ }
2041
+ },
2042
+ "required": [
2043
+ "name",
2044
+ "trigger",
2045
+ "steps"
2046
+ ],
2047
+ "additionalProperties": false
2048
+ },
2049
+ "PageKnowledge": {
2050
+ "description": "What the assistant knows of one page, or one part of the app's frame.",
2051
+ "type": "object",
2052
+ "properties": {
2053
+ "surface": {
2054
+ "description": "The page surface this describes.",
2055
+ "type": "string"
2056
+ },
2057
+ "routes": {
2058
+ "type": "array",
2059
+ "items": {
2060
+ "type": "string"
2061
+ }
2062
+ },
2063
+ "summary": {
2064
+ "description": "One paragraph: what the page is for, for when the user is elsewhere.",
2065
+ "$ref": "#/$defs/KnowledgeEntry"
2066
+ },
2067
+ "detail": {
2068
+ "description": "Everything the page and its rooms offer, where each thing is, and its parameters.",
2069
+ "$ref": "#/$defs/KnowledgeEntry"
2070
+ },
2071
+ "relationships": {
2072
+ "description": "Relationships derived from types: which fields apply to what, which animate, what leads where.",
2073
+ "anyOf": [
2074
+ {
2075
+ "$ref": "#/$defs/KnowledgeEntry"
2076
+ },
2077
+ {
2078
+ "type": "null"
2079
+ }
2080
+ ]
2081
+ },
2082
+ "recipes": {
2083
+ "type": "array",
2084
+ "items": {
2085
+ "$ref": "#/$defs/KnowledgeRecipe"
2086
+ }
2087
+ },
2088
+ "adjacent": {
2089
+ "description": "Page surfaces this page leads to or is reached from.",
2090
+ "type": "array",
2091
+ "items": {
2092
+ "type": "string"
2093
+ }
2094
+ }
2095
+ },
2096
+ "required": [
2097
+ "surface",
2098
+ "routes",
2099
+ "summary",
2100
+ "detail",
2101
+ "relationships",
2102
+ "recipes",
2103
+ "adjacent"
2104
+ ],
2105
+ "additionalProperties": false
2106
+ }
2107
+ }
2108
+ },
2109
+ 'oui-config.json': {
2110
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2111
+ "$id": "https://schemas.closurestudio.ai/oui/v1/oui-config.json",
2112
+ "title": "OuiConfigFile",
2113
+ "description": "`oui.config.json` at the app's root (ADR-0226 §2.4): where the app keeps its routes, navigation and output, which design systems and mappings its controls come from, where its API is described, and which of its pages are not yet bound. Paths are relative to the file. It is required and explicit: nothing an app depends on has a default, so a misconfigured app fails here, naming the setting, instead of generating an assistant that can do nothing. A setting the generator does not know is an error.",
2114
+ "type": "object",
2115
+ "properties": {
2116
+ "$schema": {
2117
+ "description": "This schema's URL, for editors.",
2118
+ "type": "string"
2119
+ },
2120
+ "$comment": {
2121
+ "type": "string"
2122
+ },
2123
+ "tsconfig": {
2124
+ "description": "The tsconfig the app's source compiles with.",
2125
+ "type": "string",
2126
+ "minLength": 1,
2127
+ "pattern": "\\S"
2128
+ },
2129
+ "routes": {
2130
+ "description": "The file whose routes decide where the app can go: `<Route>` elements (nested paths are joined to their parent, `index` routes kept, `React.lazy` followed) or a data router (`createBrowserRouter([...])`).",
2131
+ "type": "string",
2132
+ "minLength": 1,
2133
+ "pattern": "\\S"
2134
+ },
2135
+ "routeWrappers": {
2136
+ "description": "Components a route's element is wrapped in that are never the page (`Suspense`, `ErrorBoundary`). Default none.",
2137
+ "type": "array",
2138
+ "items": {
2139
+ "type": "string",
2140
+ "minLength": 1,
2141
+ "pattern": "\\S"
2142
+ }
2143
+ },
2144
+ "nav": {
2145
+ "description": "Files holding the navigation entries (`{ label, route, group }` object literals). Default none.",
2146
+ "type": "array",
2147
+ "items": {
2148
+ "type": "string",
2149
+ "minLength": 1,
2150
+ "pattern": "\\S"
2151
+ }
2152
+ },
2153
+ "out": {
2154
+ "description": "Where generated output goes.",
2155
+ "type": "string",
2156
+ "minLength": 1,
2157
+ "pattern": "\\S"
2158
+ },
2159
+ "designSystem": {
2160
+ "description": "Design-system packages whose controls carry bindings (tier 1). Each must resolve from the app and name its control table in its `package.json` (`oui.agentControls`). `[]`: every control is tier 2 or in a room.",
2161
+ "type": "array",
2162
+ "items": {
2163
+ "type": "string",
2164
+ "minLength": 1,
2165
+ "pattern": "\\S"
2166
+ }
2167
+ },
2168
+ "mappings": {
2169
+ "description": "Tier 2 mappings (`tier2-mapping.json`), one per third-party design system the app does not own, by path. `oui generate` emits a bound module per mapping into `<out>/bound/` (named after the package: `@mantine/core` → `mantine-core.ts`, with its control table beside it), and reads every use of a bound control as it reads a tier 1 control. On an enforced page, importing a mapped control straight from its package is an error naming the bound import. A package is in `designSystem` or mapped, never both. Default none.",
2170
+ "type": "array",
2171
+ "items": {
2172
+ "type": "string",
2173
+ "minLength": 1,
2174
+ "pattern": "\\S"
2175
+ }
2176
+ },
2177
+ "apiSpec": {
2178
+ "description": "The API's OpenAPI 3 document, by module path, as the installed API client ships it (`@traidr/api-client/openapi.json`) — never a sibling checkout path, so the generator reads exactly the spec of the client version the app installs; or a path inside the app. Every `mutate` effect names one of its `operationId`s. `null`: the app declares no API, and a `mutate` effect is an error.",
2179
+ "anyOf": [
2180
+ {
2181
+ "type": "string",
2182
+ "minLength": 1,
2183
+ "pattern": "\\S"
2184
+ },
2185
+ {
2186
+ "type": "null"
2187
+ }
2188
+ ]
2189
+ },
2190
+ "unbound": {
2191
+ "description": "Page components whose interactive controls are not all bound yet. It may only get shorter: the generator fails for a listed page that is fully bound, so the list cannot rot. Every other page is enforced. Default none.",
2192
+ "type": "array",
2193
+ "items": {
2194
+ "type": "string",
2195
+ "minLength": 1,
2196
+ "pattern": "\\S"
2197
+ }
2198
+ },
2199
+ "appCatalogs": {
2200
+ "description": "Room catalogs the app itself declares (tier 3, a page's own editor), each loaded through the app's own Vite config so its modules resolve as the app build resolves them: the app needs `vite` among its own dependencies. Only their declarations are read. Default none.",
2201
+ "type": "array",
2202
+ "items": {
2203
+ "$ref": "#/$defs/AppCatalogEntry"
2204
+ }
2205
+ },
2206
+ "shell": {
2207
+ "description": "The app's frame: components mounted around the pages rather than by a route (a sidebar, a top bar, a phone tab bar, a toast host). Each becomes a `shell:` surface offered on the routes it frames, and its controls are enforced as a page's are, unless listed in `unbound`. Default none.",
2208
+ "type": "array",
2209
+ "items": {
2210
+ "$ref": "#/$defs/ShellEntry"
2211
+ }
2212
+ }
2213
+ },
2214
+ "required": [
2215
+ "tsconfig",
2216
+ "routes",
2217
+ "designSystem",
2218
+ "apiSpec",
2219
+ "out"
2220
+ ],
2221
+ "additionalProperties": false,
2222
+ "$defs": {
2223
+ "ShellEntry": {
2224
+ "description": "One part of the app's frame.",
2225
+ "type": "object",
2226
+ "properties": {
2227
+ "module": {
2228
+ "description": "The module, relative to the app root.",
2229
+ "type": "string",
2230
+ "minLength": 1,
2231
+ "pattern": "\\S"
2232
+ },
2233
+ "export": {
2234
+ "description": "The export that is the frame's component.",
2235
+ "type": "string",
2236
+ "minLength": 1,
2237
+ "pattern": "\\S"
2238
+ },
2239
+ "routes": {
2240
+ "description": "The route patterns it frames. Default every route (`*`).",
2241
+ "type": "array",
2242
+ "items": {
2243
+ "type": "string"
2244
+ }
2245
+ }
2246
+ },
2247
+ "required": [
2248
+ "module",
2249
+ "export"
2250
+ ],
2251
+ "additionalProperties": false
2252
+ },
2253
+ "AppCatalogEntry": {
2254
+ "description": "A room catalog the app declares.",
2255
+ "type": "object",
2256
+ "properties": {
2257
+ "module": {
2258
+ "description": "The module, relative to the app root.",
2259
+ "type": "string",
2260
+ "minLength": 1,
2261
+ "pattern": "\\S"
2262
+ },
2263
+ "export": {
2264
+ "description": "The export that is the catalog.",
2265
+ "type": "string",
2266
+ "minLength": 1,
2267
+ "pattern": "\\S"
2268
+ },
2269
+ "hosts": {
2270
+ "description": "App components whose use puts the room on a page.",
2271
+ "type": "array",
2272
+ "items": {
2273
+ "type": "string",
2274
+ "minLength": 1
2275
+ }
2276
+ }
2277
+ },
2278
+ "required": [
2279
+ "module",
2280
+ "export",
2281
+ "hosts"
2282
+ ],
2283
+ "additionalProperties": false
2284
+ }
2285
+ }
2286
+ },
2287
+ 'approvals.json': {
2288
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2289
+ "$id": "https://schemas.closurestudio.ai/oui/v1/approvals.json",
2290
+ "title": "Approvals",
2291
+ "description": "Approvals (ADR-0228): the shapes the agent worker, the approval store in the realtime server, the browser's approval card, OUI's surface runtime and a conversation engine exchange. An irreversible action — a `transaction`, or a `write` declared `destructive` — runs only on an approval the person gave, bound to the exact call by a single-use token.\n\n1. The worker stops the turn at the call and stores it (`PendingApprovalInput`); the person's tab receives `agent:approval_required` (`ApprovalRequiredEvent`) and renders the approval card from its `preview`, whose every word comes from the action's declaration, never from the model.\n2. In a UI only a click on the card counts: the card sends `approval:decide` (`ApprovalDecidePayload`) from the person's own socket. On a conversation channel, the verbatim `readback` and an affirmative next turn (ADR-0210 §2.6).\n3. The store answers the decider only (`ApprovalDecideResult`): a single-use token, a compact JWS (`ApprovalTokenClaims`), and the call's `argsHash`. The tab's OUI runtime holds an `ApprovalGrant`.\n4. The next turn carries the token (`ApprovalContinuation`); the worker redeems it for the stored call, exactly (`ApprovedCall`), and runs it. A UI action request then carries `approval` (`ActionRequestApproval`), which the browser checks against its grant before it runs the handler.\n\nThe args hash is SHA-256 over the RFC 8785 (JCS) canonical JSON of the call's arguments, lowercase hex; `oui-spec/approval-vectors.json` holds every implementation, in any language, to it.",
2292
+ "$defs": {
2293
+ "ArgsHash": {
2294
+ "description": "SHA-256 of the RFC 8785 canonical JSON of a call's arguments, lowercase hex.",
2295
+ "type": "string",
2296
+ "pattern": "^[0-9a-f]{64}$"
2297
+ },
2298
+ "ApprovalChannel": {
2299
+ "description": "Where the person confirmed. In a UI only a click on the card counts (`ui`); in a conversation channel, the verbatim readback and an affirmative next turn (ADR-0210 §2.6).",
2300
+ "enum": [
2301
+ "ui",
2302
+ "voice",
2303
+ "phone",
2304
+ "sms",
2305
+ "chat"
2306
+ ]
2307
+ },
2308
+ "ApprovalDecision": {
2309
+ "enum": [
2310
+ "approve",
2311
+ "decline"
2312
+ ]
2313
+ },
2314
+ "ApprovalPreviewArgument": {
2315
+ "description": "One argument of the call, as the person reads it: its declared label and its value in words.",
2316
+ "type": "object",
2317
+ "properties": {
2318
+ "name": {
2319
+ "description": "The argument's name in the call.",
2320
+ "type": "string"
2321
+ },
2322
+ "label": {
2323
+ "description": "Its label, from the action's input schema.",
2324
+ "type": "string"
2325
+ },
2326
+ "value": {
2327
+ "description": "Its value, as text.",
2328
+ "type": "string"
2329
+ }
2330
+ },
2331
+ "required": [
2332
+ "name",
2333
+ "label",
2334
+ "value"
2335
+ ],
2336
+ "additionalProperties": false
2337
+ },
2338
+ "ApprovalPreview": {
2339
+ "description": "What the person is asked to approve. Every word comes from the action's declaration (its title, description and input schema labels), never from the model (ADR-0228 §2.2).",
2340
+ "type": "object",
2341
+ "properties": {
2342
+ "title": {
2343
+ "type": "string"
2344
+ },
2345
+ "consequence": {
2346
+ "description": "What running it does, from the declaration.",
2347
+ "type": "string"
2348
+ },
2349
+ "arguments": {
2350
+ "type": "array",
2351
+ "items": {
2352
+ "$ref": "#/$defs/ApprovalPreviewArgument"
2353
+ }
2354
+ },
2355
+ "readback": {
2356
+ "description": "One sentence composed from the fields above, read or sent verbatim on a conversation channel.",
2357
+ "type": "string"
2358
+ }
2359
+ },
2360
+ "required": [
2361
+ "title",
2362
+ "arguments",
2363
+ "readback"
2364
+ ],
2365
+ "additionalProperties": false
2366
+ },
2367
+ "ApprovalEffect": {
2368
+ "description": "The effect the approval is for: the action's declared effect kind (ADR-0226 §2.6, `transaction` for an irreversible external act), or `write` when it declares none.",
2369
+ "type": "string",
2370
+ "minLength": 1
2371
+ },
2372
+ "PendingApprovalInput": {
2373
+ "description": "A call waiting for the person's approval, as the worker stores it (`POST /internal/approvals`).",
2374
+ "type": "object",
2375
+ "properties": {
2376
+ "approvalId": {
2377
+ "description": "Equals the tool call id.",
2378
+ "type": "string"
2379
+ },
2380
+ "toolCallId": {
2381
+ "type": "string"
2382
+ },
2383
+ "conversationId": {
2384
+ "type": "string"
2385
+ },
2386
+ "turnId": {
2387
+ "type": "string"
2388
+ },
2389
+ "userId": {
2390
+ "description": "The user whose turn made the call: the only one who may decide it.",
2391
+ "type": "string"
2392
+ },
2393
+ "tool": {
2394
+ "type": "string"
2395
+ },
2396
+ "args": {
2397
+ "type": "object",
2398
+ "additionalProperties": true
2399
+ },
2400
+ "argsHash": {
2401
+ "description": "`argsHash(args)`; the store checks it.",
2402
+ "$ref": "#/$defs/ArgsHash"
2403
+ },
2404
+ "effect": {
2405
+ "$ref": "#/$defs/ApprovalEffect"
2406
+ },
2407
+ "destructive": {
2408
+ "type": "boolean"
2409
+ },
2410
+ "argsSensitive": {
2411
+ "description": "Whether the arguments may be written to logs. They are only when the declaration says they are not sensitive.",
2412
+ "type": "boolean"
2413
+ },
2414
+ "expiresAt": {
2415
+ "description": "Epoch ms, at most 30 minutes away (`MAX_APPROVAL_TTL_MS`).",
2416
+ "type": "number"
2417
+ },
2418
+ "preview": {
2419
+ "$ref": "#/$defs/ApprovalPreview"
2420
+ }
2421
+ },
2422
+ "required": [
2423
+ "approvalId",
2424
+ "toolCallId",
2425
+ "conversationId",
2426
+ "turnId",
2427
+ "userId",
2428
+ "tool",
2429
+ "args",
2430
+ "argsHash",
2431
+ "effect",
2432
+ "destructive",
2433
+ "argsSensitive",
2434
+ "expiresAt",
2435
+ "preview"
2436
+ ],
2437
+ "additionalProperties": false
2438
+ },
2439
+ "ApprovalRequiredEvent": {
2440
+ "description": "`agent:approval_required`: the worker stopped the turn at a call that needs the person's approval. The approval card renders it.",
2441
+ "type": "object",
2442
+ "properties": {
2443
+ "turnId": {
2444
+ "type": "string"
2445
+ },
2446
+ "conversationId": {
2447
+ "type": "string"
2448
+ },
2449
+ "approvalId": {
2450
+ "type": "string"
2451
+ },
2452
+ "tool": {
2453
+ "type": "string"
2454
+ },
2455
+ "effect": {
2456
+ "$ref": "#/$defs/ApprovalEffect"
2457
+ },
2458
+ "destructive": {
2459
+ "type": "boolean"
2460
+ },
2461
+ "preview": {
2462
+ "$ref": "#/$defs/ApprovalPreview"
2463
+ },
2464
+ "expiresAt": {
2465
+ "type": "number"
2466
+ },
2467
+ "timestamp": {
2468
+ "type": "number"
2469
+ }
2470
+ },
2471
+ "required": [
2472
+ "turnId",
2473
+ "conversationId",
2474
+ "approvalId",
2475
+ "tool",
2476
+ "effect",
2477
+ "destructive",
2478
+ "preview",
2479
+ "expiresAt",
2480
+ "timestamp"
2481
+ ],
2482
+ "additionalProperties": false
2483
+ },
2484
+ "ApprovalDecidePayload": {
2485
+ "description": "`approval:decide`, from the person's own socket: the card's click.",
2486
+ "type": "object",
2487
+ "properties": {
2488
+ "approvalId": {
2489
+ "type": "string"
2490
+ },
2491
+ "decision": {
2492
+ "$ref": "#/$defs/ApprovalDecision"
2493
+ }
2494
+ },
2495
+ "required": [
2496
+ "approvalId",
2497
+ "decision"
2498
+ ],
2499
+ "additionalProperties": false
2500
+ },
2501
+ "ApprovalRefusalReason": {
2502
+ "description": "Why an approval was refused:\n\n- `unknown`: no such pending approval: never stored, already declined or redeemed, or expired and gone.\n- `forbidden`: another user's approval, or another conversation's.\n- `expired`.\n- `decided`: already decided.\n- `used`: already redeemed.\n- `invalid`: not a token this environment signed, or malformed.\n- `mismatch`: signed, but not for the stored call.\n- `channel`: a decision from a channel that may not make it.",
2503
+ "enum": [
2504
+ "unknown",
2505
+ "forbidden",
2506
+ "expired",
2507
+ "decided",
2508
+ "used",
2509
+ "invalid",
2510
+ "mismatch",
2511
+ "channel"
2512
+ ]
2513
+ },
2514
+ "ApprovalRefusal": {
2515
+ "type": "object",
2516
+ "properties": {
2517
+ "ok": {
2518
+ "const": false
2519
+ },
2520
+ "reason": {
2521
+ "$ref": "#/$defs/ApprovalRefusalReason"
2522
+ },
2523
+ "error": {
2524
+ "type": "string"
2525
+ }
2526
+ },
2527
+ "required": [
2528
+ "ok",
2529
+ "reason",
2530
+ "error"
2531
+ ],
2532
+ "additionalProperties": false
2533
+ },
2534
+ "ApprovalDecideResult": {
2535
+ "description": "The answer to a decision. An approval's token goes only to the decider: the socket that clicked, or the engine that asked.",
2536
+ "oneOf": [
2537
+ {
2538
+ "type": "object",
2539
+ "properties": {
2540
+ "ok": {
2541
+ "const": true
2542
+ },
2543
+ "decision": {
2544
+ "const": "approve"
2545
+ },
2546
+ "approvalId": {
2547
+ "type": "string"
2548
+ },
2549
+ "token": {
2550
+ "description": "The single-use token the continuation turn redeems.",
2551
+ "type": "string"
2552
+ },
2553
+ "argsHash": {
2554
+ "description": "What the browser checks a UI action's params against before it runs it.",
2555
+ "$ref": "#/$defs/ArgsHash"
2556
+ },
2557
+ "expiresAt": {
2558
+ "type": "number"
2559
+ },
2560
+ "channel": {
2561
+ "$ref": "#/$defs/ApprovalChannel"
2562
+ }
2563
+ },
2564
+ "required": [
2565
+ "ok",
2566
+ "decision",
2567
+ "approvalId",
2568
+ "token",
2569
+ "argsHash",
2570
+ "expiresAt",
2571
+ "channel"
2572
+ ],
2573
+ "additionalProperties": false
2574
+ },
2575
+ {
2576
+ "type": "object",
2577
+ "properties": {
2578
+ "ok": {
2579
+ "const": true
2580
+ },
2581
+ "decision": {
2582
+ "const": "decline"
2583
+ },
2584
+ "approvalId": {
2585
+ "type": "string"
2586
+ }
2587
+ },
2588
+ "required": [
2589
+ "ok",
2590
+ "decision",
2591
+ "approvalId"
2592
+ ],
2593
+ "additionalProperties": false
2594
+ },
2595
+ {
2596
+ "$ref": "#/$defs/ApprovalRefusal"
2597
+ }
2598
+ ]
2599
+ },
2600
+ "ApprovalTokenClaims": {
2601
+ "description": "The token's claims: a compact JWS (HS256), signed with the environment's approval key.",
2602
+ "type": "object",
2603
+ "properties": {
2604
+ "aid": {
2605
+ "description": "The approval id, which is the tool call id.",
2606
+ "type": "string"
2607
+ },
2608
+ "sub": {
2609
+ "description": "The user.",
2610
+ "type": "string"
2611
+ },
2612
+ "cid": {
2613
+ "description": "The conversation.",
2614
+ "type": "string"
2615
+ },
2616
+ "tool": {
2617
+ "type": "string"
2618
+ },
2619
+ "ah": {
2620
+ "description": "The args hash.",
2621
+ "$ref": "#/$defs/ArgsHash"
2622
+ },
2623
+ "eff": {
2624
+ "description": "The effect.",
2625
+ "$ref": "#/$defs/ApprovalEffect"
2626
+ },
2627
+ "ch": {
2628
+ "description": "Where the user confirmed.",
2629
+ "$ref": "#/$defs/ApprovalChannel"
2630
+ },
2631
+ "iat": {
2632
+ "description": "Issued at, epoch seconds.",
2633
+ "type": "integer"
2634
+ },
2635
+ "exp": {
2636
+ "description": "Expires at, epoch seconds.",
2637
+ "type": "integer"
2638
+ },
2639
+ "jti": {
2640
+ "description": "A nonce.",
2641
+ "type": "string"
2642
+ }
2643
+ },
2644
+ "required": [
2645
+ "aid",
2646
+ "sub",
2647
+ "cid",
2648
+ "tool",
2649
+ "ah",
2650
+ "eff",
2651
+ "ch",
2652
+ "iat",
2653
+ "exp",
2654
+ "jti"
2655
+ ],
2656
+ "additionalProperties": false
2657
+ },
2658
+ "ApprovedCall": {
2659
+ "description": "What redeeming a token returns: the stored call, exactly, for the worker to run.",
2660
+ "type": "object",
2661
+ "properties": {
2662
+ "approvalId": {
2663
+ "type": "string"
2664
+ },
2665
+ "toolCallId": {
2666
+ "type": "string"
2667
+ },
2668
+ "conversationId": {
2669
+ "type": "string"
2670
+ },
2671
+ "turnId": {
2672
+ "type": "string"
2673
+ },
2674
+ "userId": {
2675
+ "type": "string"
2676
+ },
2677
+ "tool": {
2678
+ "type": "string"
2679
+ },
2680
+ "args": {
2681
+ "type": "object",
2682
+ "additionalProperties": true
2683
+ },
2684
+ "argsHash": {
2685
+ "$ref": "#/$defs/ArgsHash"
2686
+ },
2687
+ "effect": {
2688
+ "$ref": "#/$defs/ApprovalEffect"
2689
+ },
2690
+ "destructive": {
2691
+ "type": "boolean"
2692
+ },
2693
+ "channel": {
2694
+ "$ref": "#/$defs/ApprovalChannel"
2695
+ }
2696
+ },
2697
+ "required": [
2698
+ "approvalId",
2699
+ "toolCallId",
2700
+ "conversationId",
2701
+ "turnId",
2702
+ "userId",
2703
+ "tool",
2704
+ "args",
2705
+ "argsHash",
2706
+ "effect",
2707
+ "destructive",
2708
+ "channel"
2709
+ ],
2710
+ "additionalProperties": false
2711
+ },
2712
+ "ApprovalRedeemResult": {
2713
+ "oneOf": [
2714
+ {
2715
+ "type": "object",
2716
+ "properties": {
2717
+ "ok": {
2718
+ "const": true
2719
+ },
2720
+ "call": {
2721
+ "$ref": "#/$defs/ApprovedCall"
2722
+ }
2723
+ },
2724
+ "required": [
2725
+ "ok",
2726
+ "call"
2727
+ ],
2728
+ "additionalProperties": false
2729
+ },
2730
+ {
2731
+ "$ref": "#/$defs/ApprovalRefusal"
2732
+ }
2733
+ ]
2734
+ },
2735
+ "ApprovalStatus": {
2736
+ "description": "An approval's state, for the turn that follows a decision.",
2737
+ "type": "object",
2738
+ "properties": {
2739
+ "approvalId": {
2740
+ "type": "string"
2741
+ },
2742
+ "status": {
2743
+ "enum": [
2744
+ "pending",
2745
+ "approved",
2746
+ "declined"
2747
+ ]
2748
+ },
2749
+ "tool": {
2750
+ "type": "string"
2751
+ },
2752
+ "title": {
2753
+ "type": "string"
2754
+ }
2755
+ },
2756
+ "required": [
2757
+ "approvalId",
2758
+ "status",
2759
+ "tool",
2760
+ "title"
2761
+ ],
2762
+ "additionalProperties": false
2763
+ },
2764
+ "ApprovalContinuation": {
2765
+ "description": "What a turn that follows a decision carries, outside the message text: the token to redeem, or that the person declined.",
2766
+ "oneOf": [
2767
+ {
2768
+ "type": "object",
2769
+ "properties": {
2770
+ "approvalId": {
2771
+ "type": "string"
2772
+ },
2773
+ "decision": {
2774
+ "const": "approve"
2775
+ },
2776
+ "token": {
2777
+ "type": "string"
2778
+ }
2779
+ },
2780
+ "required": [
2781
+ "approvalId",
2782
+ "decision",
2783
+ "token"
2784
+ ],
2785
+ "additionalProperties": false
2786
+ },
2787
+ {
2788
+ "type": "object",
2789
+ "properties": {
2790
+ "approvalId": {
2791
+ "type": "string"
2792
+ },
2793
+ "decision": {
2794
+ "const": "decline"
2795
+ }
2796
+ },
2797
+ "required": [
2798
+ "approvalId",
2799
+ "decision"
2800
+ ],
2801
+ "additionalProperties": false
2802
+ }
2803
+ ]
2804
+ },
2805
+ "ActionRequestApproval": {
2806
+ "description": "What a UI action request carries when it runs an approved call (`OUIActionApproval`): the browser runs a `transaction` or destructive action only when this matches a grant this tab received from its own card click (ADR-0228 §2.2.6).",
2807
+ "type": "object",
2808
+ "properties": {
2809
+ "approvalId": {
2810
+ "type": "string"
2811
+ },
2812
+ "argsHash": {
2813
+ "description": "`argsHash(params)` of the request the user approved.",
2814
+ "$ref": "#/$defs/ArgsHash"
2815
+ }
2816
+ },
2817
+ "required": [
2818
+ "approvalId",
2819
+ "argsHash"
2820
+ ],
2821
+ "additionalProperties": false
2822
+ },
2823
+ "ApprovalGrant": {
2824
+ "description": "What the person's approval click gives this tab's OUI runtime (`runtime.grantApproval`, `OUIApprovalGrant`): the request it approved, until it expires.",
2825
+ "type": "object",
2826
+ "properties": {
2827
+ "approvalId": {
2828
+ "type": "string"
2829
+ },
2830
+ "argsHash": {
2831
+ "$ref": "#/$defs/ArgsHash"
2832
+ },
2833
+ "expiresAt": {
2834
+ "description": "Epoch ms after which the grant no longer admits anything.",
2835
+ "type": "number"
2836
+ }
2837
+ },
2838
+ "required": [
2839
+ "approvalId",
2840
+ "argsHash",
2841
+ "expiresAt"
2842
+ ],
2843
+ "additionalProperties": false
2844
+ }
2845
+ }
2846
+ },
2847
+ 'event-declarations.json': {
2848
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2849
+ "$id": "https://schemas.closurestudio.ai/agent-sdk/event-declarations/v1.json",
2850
+ "title": "Event declarations",
2851
+ "description": "Every event a product emits over realtime: its payload schema, the rooms it is published to, its correlation fields and its role in a job (ADR-0227 §2.4).",
2852
+ "type": "object",
2853
+ "required": [
2854
+ "version",
2855
+ "product",
2856
+ "rooms",
2857
+ "events"
2858
+ ],
2859
+ "additionalProperties": false,
2860
+ "properties": {
2861
+ "$schema": {
2862
+ "type": "string"
2863
+ },
2864
+ "version": {
2865
+ "description": "The version of this document's format.",
2866
+ "const": 1
2867
+ },
2868
+ "product": {
2869
+ "description": "Who declares these events.",
2870
+ "type": "string",
2871
+ "minLength": 1
2872
+ },
2873
+ "description": {
2874
+ "type": "string"
2875
+ },
2876
+ "$defs": {
2877
+ "description": "Payload shapes the events share, referenced as `#/$defs/<Name>`.",
2878
+ "type": "object",
2879
+ "propertyNames": {
2880
+ "pattern": "^[A-Z][A-Za-z0-9]*$"
2881
+ },
2882
+ "additionalProperties": {
2883
+ "$ref": "#/$defs/EventPayloadSchema"
2884
+ }
2885
+ },
2886
+ "rooms": {
2887
+ "description": "Every room these events go to, by name.",
2888
+ "type": "object",
2889
+ "propertyNames": {
2890
+ "pattern": "^[a-z][A-Za-z0-9]*$"
2891
+ },
2892
+ "additionalProperties": {
2893
+ "$ref": "#/$defs/RoomDeclaration"
2894
+ }
2895
+ },
2896
+ "events": {
2897
+ "description": "Every event, by its name on the wire.",
2898
+ "type": "object",
2899
+ "propertyNames": {
2900
+ "pattern": "^[a-z][a-z0-9_-]*(:[a-z][a-z0-9_-]*)*$"
2901
+ },
2902
+ "additionalProperties": {
2903
+ "$ref": "#/$defs/EventDeclaration"
2904
+ }
2905
+ }
2906
+ },
2907
+ "$defs": {
2908
+ "JsonType": {
2909
+ "description": "The JSON Schema types a payload may use.",
2910
+ "enum": [
2911
+ "object",
2912
+ "array",
2913
+ "string",
2914
+ "number",
2915
+ "integer",
2916
+ "boolean",
2917
+ "null"
2918
+ ]
2919
+ },
2920
+ "EventPayloadSchema": {
2921
+ "description": "A JSON Schema (draft 2020-12). A payload may use any keyword; the platform reads `$ref` (to the document's `$defs`), `allOf`, `type`, `properties` and `required` to find the fields it correlates and reports on, and validates the rest with a full validator.",
2922
+ "type": "object",
2923
+ "properties": {
2924
+ "$ref": {
2925
+ "type": "string"
2926
+ },
2927
+ "type": {
2928
+ "description": "A JSON Schema type name, or a list of them.",
2929
+ "$comment": "ts: JsonType | readonly JsonType[]"
2930
+ },
2931
+ "description": {
2932
+ "type": "string"
2933
+ },
2934
+ "properties": {
2935
+ "type": "object",
2936
+ "additionalProperties": {
2937
+ "$ref": "#/$defs/EventPayloadSchema"
2938
+ }
2939
+ },
2940
+ "required": {
2941
+ "type": "array",
2942
+ "items": {
2943
+ "type": "string"
2944
+ }
2945
+ },
2946
+ "additionalProperties": {
2947
+ "description": "`false`, or the schema every other property follows.",
2948
+ "$comment": "ts: boolean | EventPayloadSchema"
2949
+ },
2950
+ "items": {
2951
+ "$ref": "#/$defs/EventPayloadSchema"
2952
+ },
2953
+ "enum": {
2954
+ "type": "array"
2955
+ },
2956
+ "const": {},
2957
+ "allOf": {
2958
+ "type": "array",
2959
+ "items": {
2960
+ "$ref": "#/$defs/EventPayloadSchema"
2961
+ }
2962
+ },
2963
+ "anyOf": {
2964
+ "type": "array",
2965
+ "items": {
2966
+ "$ref": "#/$defs/EventPayloadSchema"
2967
+ }
2968
+ },
2969
+ "oneOf": {
2970
+ "type": "array",
2971
+ "items": {
2972
+ "$ref": "#/$defs/EventPayloadSchema"
2973
+ }
2974
+ }
2975
+ },
2976
+ "additionalProperties": true
2977
+ },
2978
+ "RoomDeclaration": {
2979
+ "type": "object",
2980
+ "required": [
2981
+ "pattern"
2982
+ ],
2983
+ "additionalProperties": false,
2984
+ "properties": {
2985
+ "pattern": {
2986
+ "description": "The room's name with `{placeholder}`s for its ids, e.g. `generation:{jobId}`. An id is letters, digits, `_` and `-`.",
2987
+ "type": "string",
2988
+ "pattern": "^([a-z0-9_:-]|\\{[a-zA-Z][a-zA-Z0-9]*\\})+$"
2989
+ },
2990
+ "description": {
2991
+ "type": "string"
2992
+ }
2993
+ }
2994
+ },
2995
+ "EventRole": {
2996
+ "description": "What an event is for, as the platform acts on it:\n- `completion`: a job of kind `completes` produced its result. A wait on the job ends well.\n- `failure`: a job of kind `completes` ended without a result. A wait on the job ends with its reason.\n- `progress`: a job is still running. Nothing waits on it: resolving a wait on progress reports a running job as done.\n- `notice`: anything else a client is told.",
2997
+ "enum": [
2998
+ "completion",
2999
+ "failure",
3000
+ "progress",
3001
+ "notice"
3002
+ ]
3003
+ },
3004
+ "FailureReason": {
3005
+ "description": "Where a settling event says why a job failed.",
3006
+ "type": "object",
3007
+ "required": [
3008
+ "field",
3009
+ "fallback"
3010
+ ],
3011
+ "additionalProperties": false,
3012
+ "properties": {
3013
+ "field": {
3014
+ "description": "The payload field carrying the reason.",
3015
+ "type": "string",
3016
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
3017
+ },
3018
+ "fallback": {
3019
+ "description": "What the reason is when the field is absent.",
3020
+ "type": "string",
3021
+ "minLength": 1
3022
+ }
3023
+ }
3024
+ },
3025
+ "EventDeclaration": {
3026
+ "type": "object",
3027
+ "required": [
3028
+ "description",
3029
+ "payload",
3030
+ "rooms",
3031
+ "correlation",
3032
+ "role"
3033
+ ],
3034
+ "additionalProperties": false,
3035
+ "properties": {
3036
+ "description": {
3037
+ "type": "string",
3038
+ "minLength": 1
3039
+ },
3040
+ "payload": {
3041
+ "description": "The payload's JSON Schema: an object. `$ref`s point into the document's `$defs`. Every correlation, result and reason field is one of its properties.",
3042
+ "$ref": "#/$defs/EventPayloadSchema"
3043
+ },
3044
+ "typeName": {
3045
+ "description": "The name generated code gives the payload type. Default: the event name in PascalCase (`generation:completed` → `GenerationCompleted`).",
3046
+ "type": "string",
3047
+ "pattern": "^[A-Z][A-Za-z0-9]*$"
3048
+ },
3049
+ "rooms": {
3050
+ "description": "The rooms the event is published to: names from the document's `rooms`, or `turn` for the room of the agent turn it belongs to (the host names that room in each turn).",
3051
+ "type": "array",
3052
+ "items": {
3053
+ "type": "string",
3054
+ "minLength": 1
3055
+ },
3056
+ "minItems": 1,
3057
+ "uniqueItems": true
3058
+ },
3059
+ "correlation": {
3060
+ "description": "The payload fields that say which job, or which resource, the event is about (e.g. `jobId`). A completion or failure has exactly one.",
3061
+ "type": "array",
3062
+ "items": {
3063
+ "type": "string",
3064
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
3065
+ },
3066
+ "uniqueItems": true
3067
+ },
3068
+ "role": {
3069
+ "$ref": "#/$defs/EventRole"
3070
+ },
3071
+ "completes": {
3072
+ "description": "For a completion or failure: the kind of job it settles.",
3073
+ "type": "string",
3074
+ "pattern": "^[a-z][A-Za-z0-9]*$"
3075
+ },
3076
+ "result": {
3077
+ "description": "For a completion: the payload fields that are the job's result, as a follower reports them.",
3078
+ "type": "array",
3079
+ "items": {
3080
+ "type": "string",
3081
+ "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
3082
+ },
3083
+ "uniqueItems": true
3084
+ },
3085
+ "reason": {
3086
+ "description": "For a failure: where its reason is.",
3087
+ "$ref": "#/$defs/FailureReason"
3088
+ }
3089
+ },
3090
+ "allOf": [
3091
+ {
3092
+ "if": {
3093
+ "properties": {
3094
+ "role": {
3095
+ "enum": [
3096
+ "completion",
3097
+ "failure"
3098
+ ]
3099
+ }
3100
+ }
3101
+ },
3102
+ "then": {
3103
+ "required": [
3104
+ "completes"
3105
+ ],
3106
+ "properties": {
3107
+ "correlation": {
3108
+ "type": "array",
3109
+ "minItems": 1,
3110
+ "maxItems": 1
3111
+ }
3112
+ }
3113
+ },
3114
+ "else": {
3115
+ "not": {
3116
+ "required": [
3117
+ "completes"
3118
+ ]
3119
+ }
3120
+ }
3121
+ },
3122
+ {
3123
+ "if": {
3124
+ "properties": {
3125
+ "role": {
3126
+ "const": "completion"
3127
+ }
3128
+ }
3129
+ },
3130
+ "else": {
3131
+ "not": {
3132
+ "required": [
3133
+ "result"
3134
+ ]
3135
+ }
3136
+ }
3137
+ },
3138
+ {
3139
+ "if": {
3140
+ "properties": {
3141
+ "role": {
3142
+ "const": "failure"
3143
+ }
3144
+ }
3145
+ },
3146
+ "then": {
3147
+ "required": [
3148
+ "reason"
3149
+ ]
3150
+ },
3151
+ "else": {
3152
+ "not": {
3153
+ "required": [
3154
+ "reason"
3155
+ ]
3156
+ }
3157
+ }
3158
+ }
3159
+ ]
3160
+ }
3161
+ }
3162
+ },
3163
+ };
3164
+ /**
3165
+ * Each generated type, by name, and the schema it is generated from (`file`, or
3166
+ * `file#/$defs/Name`).
3167
+ */
3168
+ export const CONTRACT_TYPES = {
3169
+ JsonSchema: 'json-schema.json',
3170
+ JsonSchemaType: 'json-schema.json#/$defs/JsonSchemaType',
3171
+ ActionEffect: 'action-effect.json',
3172
+ SimpleEffect: 'action-effect.json#/$defs/SimpleEffect',
3173
+ ActionEffectKind: 'action-effect.json#/$defs/ActionEffectKind',
3174
+ EffectAccess: 'action-effect.json#/$defs/EffectAccess',
3175
+ JobStatus: 'action-effect.json#/$defs/JobStatus',
3176
+ JobOutcome: 'action-effect.json#/$defs/JobOutcome',
3177
+ JobSettlement: 'action-effect.json#/$defs/JobSettlement',
3178
+ AgentBinding: 'agent-binding.json',
3179
+ AgentItem: 'agent-binding.json#/$defs/AgentItem',
3180
+ NonAgentBinding: 'agent-binding.json#/$defs/NonAgentBinding',
3181
+ AgentProp: 'agent-binding.json#/$defs/AgentProp',
3182
+ ControlKindRegistration: 'control-kind-registration.json',
3183
+ ControlKind: 'control-kind-registration.json#/$defs/ControlKind',
3184
+ RegisteredControlKind: 'control-kind-registration.json#/$defs/RegisteredControlKind',
3185
+ AnyControlKind: 'control-kind-registration.json#/$defs/AnyControlKind',
3186
+ SchemaPropName: 'control-kind-registration.json#/$defs/SchemaPropName',
3187
+ ControlOption: 'control-kind-registration.json#/$defs/ControlOption',
3188
+ SchemaProps: 'control-kind-registration.json#/$defs/SchemaProps',
3189
+ KindSchemaDerivation: 'control-kind-registration.json#/$defs/KindSchemaDerivation',
3190
+ ControlTableFile: 'control-table.json',
3191
+ ControlTable: 'control-table.json#/$defs/ControlTable',
3192
+ SlotDescriptor: 'control-table.json#/$defs/SlotDescriptor',
3193
+ EntriesDescriptor: 'control-table.json#/$defs/EntriesDescriptor',
3194
+ ControlDescriptor: 'control-table.json#/$defs/ControlDescriptor',
3195
+ OptionsSource: 'control-table.json#/$defs/OptionsSource',
3196
+ OuiPackageDeclaration: 'control-table.json#/$defs/OuiPackageDeclaration',
3197
+ SchemaPropSources: 'control-table.json#/$defs/SchemaPropSources',
3198
+ Tier2Mapping: 'tier2-mapping.json',
3199
+ ValueFrom: 'tier2-mapping.json#/$defs/ValueFrom',
3200
+ Tier2Part: 'tier2-mapping.json#/$defs/Tier2Part',
3201
+ Tier2Control: 'tier2-mapping.json#/$defs/Tier2Control',
3202
+ RoomCatalogData: 'room-catalog-data.json',
3203
+ RoomEntryInfo: 'room-catalog-data.json#/$defs/RoomEntryInfo',
3204
+ RoomActionData: 'room-catalog-data.json#/$defs/RoomActionData',
3205
+ RoomSection: 'room-catalog-data.json#/$defs/RoomSection',
3206
+ RoomFieldAnimation: 'room-catalog-data.json#/$defs/RoomFieldAnimation',
3207
+ RoomFieldData: 'room-catalog-data.json#/$defs/RoomFieldData',
3208
+ RoomCommand: 'room-catalog-data.json#/$defs/RoomCommand',
3209
+ RoomObservation: 'room-catalog-data.json#/$defs/RoomObservation',
3210
+ RoomProblemKind: 'room-catalog-data.json#/$defs/RoomProblemKind',
3211
+ RoomRecipe: 'room-catalog-data.json#/$defs/RoomRecipe',
3212
+ RoomProblem: 'room-catalog-data.json#/$defs/RoomProblem',
3213
+ RoomResult: 'room-catalog-data.json#/$defs/RoomResult',
3214
+ AgentCatalogManifestEntry: 'room-catalog-data.json#/$defs/AgentCatalogManifestEntry',
3215
+ OuiManifest: 'oui-manifest.json',
3216
+ ReachStep: 'oui-manifest.json#/$defs/ReachStep',
3217
+ ManifestActionSource: 'oui-manifest.json#/$defs/ManifestActionSource',
3218
+ ManifestAction: 'oui-manifest.json#/$defs/ManifestAction',
3219
+ ManifestObservation: 'oui-manifest.json#/$defs/ManifestObservation',
3220
+ ManifestSurfaceKind: 'oui-manifest.json#/$defs/ManifestSurfaceKind',
3221
+ ManifestSurface: 'oui-manifest.json#/$defs/ManifestSurface',
3222
+ GeneratedKnowledge: 'generated-knowledge.json',
3223
+ KnowledgeEntry: 'generated-knowledge.json#/$defs/KnowledgeEntry',
3224
+ KnowledgeRecipe: 'generated-knowledge.json#/$defs/KnowledgeRecipe',
3225
+ PageKnowledge: 'generated-knowledge.json#/$defs/PageKnowledge',
3226
+ OuiConfigFile: 'oui-config.json',
3227
+ ShellEntry: 'oui-config.json#/$defs/ShellEntry',
3228
+ AppCatalogEntry: 'oui-config.json#/$defs/AppCatalogEntry',
3229
+ ArgsHash: 'approvals.json#/$defs/ArgsHash',
3230
+ ApprovalChannel: 'approvals.json#/$defs/ApprovalChannel',
3231
+ ApprovalDecision: 'approvals.json#/$defs/ApprovalDecision',
3232
+ ApprovalPreviewArgument: 'approvals.json#/$defs/ApprovalPreviewArgument',
3233
+ ApprovalPreview: 'approvals.json#/$defs/ApprovalPreview',
3234
+ ApprovalEffect: 'approvals.json#/$defs/ApprovalEffect',
3235
+ PendingApprovalInput: 'approvals.json#/$defs/PendingApprovalInput',
3236
+ ApprovalRequiredEvent: 'approvals.json#/$defs/ApprovalRequiredEvent',
3237
+ ApprovalDecidePayload: 'approvals.json#/$defs/ApprovalDecidePayload',
3238
+ ApprovalRefusalReason: 'approvals.json#/$defs/ApprovalRefusalReason',
3239
+ ApprovalRefusal: 'approvals.json#/$defs/ApprovalRefusal',
3240
+ ApprovalDecideResult: 'approvals.json#/$defs/ApprovalDecideResult',
3241
+ ApprovalTokenClaims: 'approvals.json#/$defs/ApprovalTokenClaims',
3242
+ ApprovedCall: 'approvals.json#/$defs/ApprovedCall',
3243
+ ApprovalRedeemResult: 'approvals.json#/$defs/ApprovalRedeemResult',
3244
+ ApprovalStatus: 'approvals.json#/$defs/ApprovalStatus',
3245
+ ApprovalContinuation: 'approvals.json#/$defs/ApprovalContinuation',
3246
+ ActionRequestApproval: 'approvals.json#/$defs/ActionRequestApproval',
3247
+ ApprovalGrant: 'approvals.json#/$defs/ApprovalGrant',
3248
+ EventDeclarationDocument: 'event-declarations.json',
3249
+ JsonType: 'event-declarations.json#/$defs/JsonType',
3250
+ EventPayloadSchema: 'event-declarations.json#/$defs/EventPayloadSchema',
3251
+ RoomDeclaration: 'event-declarations.json#/$defs/RoomDeclaration',
3252
+ EventRole: 'event-declarations.json#/$defs/EventRole',
3253
+ FailureReason: 'event-declarations.json#/$defs/FailureReason',
3254
+ EventDeclaration: 'event-declarations.json#/$defs/EventDeclaration',
3255
+ };
3256
+ //# sourceMappingURL=schemas.js.map