data a widget accepts. When a kind has one, render_widget validates the payload before rendering and returns a structured, correctable error with a dotted path (MISSING_FIELD at data.lines, INVALID_TYPE at data.lines.0.qty) instead of a blank or misleading render. Kinds without a schema render leniently. Descriptors carry their schema verbatim in list_widgets, so agents see the shape before they call.
The supported subset
Schemas use a bounded subset of JSON Schema. Unknown keywords are ignored.pattern is guarded against pathological input: patterns over the length cap, patterns the RegExp constructor rejects, and patterns with nested quantifiers are ignored rather than enforced, and tested strings are capped in length. A violation reports INVALID_TYPE at the value’s path. The caps are listed in Limits.
Inline or shared
An inline schema lives in the widget asdescriptor.dataSchema. It is the right choice when the shape belongs to that one widget.
A shared schema is its own entry, defined once and referenced by many widgets:
descriptor.dataSchemaRef in place of dataSchema:
- Never both. A descriptor carrying
dataSchemaanddataSchemaRefis refused withINVALID_SHAPE. - The reference must exist. A
dataSchemaRefnaming no saved schema of yours is refused on write withUNKNOWN_SCHEMA. - Resolved at composition. When your catalog is composed for a request, the server copies the shared schema into the referencing descriptor. Downstream (the renderer,
list_widgets, agents) the reference does not exist; they see adataSchema. - One edit reaches every widget. Save a change to
personand the next render of every widget referencing it validates against the new shape, without the widgets being touched. - Deletion is guarded. Deleting a schema that widgets still reference is refused with
SCHEMA_IN_USE, naming those widgets.
name follows the identifier charset ^[a-zA-Z0-9._-]+$, the same as widget kinds and theme names.
The schema builder
Both the widget designer’s Data schema section and the standalone designer edit a schema through a structured builder and a JSON pane. They project one value: a property added in the builder appears in the JSON, an edit in the JSON appears in the builder, and invalid JSON keeps the last valid schema with the parse error shown. The builder reads flat, one slim row per property, with the type select fitted to the selected value and the removal control revealed on hover. A nullable toggle handles the[type, "null"] form: the row shows the primary type with the toggle set, constraints such as pattern and enum follow the primary type, and clearing the toggle writes "type": "string" back while preserving the constraint. Type arrays beyond that pattern stay JSON-pane territory and survive untouched until the type controls are edited.
In the widget designer, choose Define inline to edit descriptor.dataSchema in place, or Use shared to pick one of your saved schemas, which is then shown read-only while the draft stores the reference. dataExample is cross-checked against whichever schema is in effect, with dotted paths in the diagnostic, and a reference to a schema you no longer have is reported at the section. Path completions in the template panel resolve a shared schema exactly like an inline one.
The Data schemas designer
The Data schemas section of the app manages shared schemas under the same regime as widgets and themes: entries are listed, open read-only on selection with Edit and Delete, and save through your session. The designer edits the entry’s identity (name, optional label and description) and its schema, validating on every change: the identifier charset for name, a plain object for schema.
Import and Export are two independent sections, Import first. Import accepts the entry JSON above, the exact shape an agent drafts from the authoring guide, re-validates it, and leaves the working entry untouched when it fails. Export stays operable in read-only mode.