Alpha: Ships on npm at 7.0.0-alpha.07.0.0-alpha.0
schema.json
The page schema and one schema per Section type, as JSON Schema, and the rules JSON Schema does not carry, so agents check with PageSchema.
| Address | Holds |
|---|---|
/schema.json | PageSchema.toJSONSchema(): the whole record, every bound as maxLength, minItems and maxItems |
/schema/sections/<type>.json | One Section type's schema, such as /schema/sections/stats.json, for all 27 types |
Hand /schema.json to a model as its structured output or tool schema. Then check what it returns with PageSchema.safeParse, never with a JSON Schema validator alone.
What JSON Schema leaves out
Some rules span fields, or allow only some counts inside a range. /schema.json does not carry them; PageSchema does. Each section below keeps every bound in /schema.json, and schema-gap.ts shows PageSchema refusing it:
// Three sections that keep every maxLength, minItems and maxItems in /schema.json,
// and that PageSchema still refuses: rules JSON Schema has no keyword for.
const brand = { href: '/' };
const probes: Record<string, unknown> = {
'a brand with neither wordmark nor mark': { type: 'nav', menu: 'none', brand, links: [] },
'a feature grid of five': { type: 'feature-grid', cellHead: 'none', items: Array.from({ length: 5 }, () => ({ title: 'A feature' })) },
'a footer in columns with no "For agents" column': {
type: 'footer', layout: 'columns', brand: { href: '/', text: 'Vanroster' }, note: ['Vanroster', 'Rendered by @mdxui/site.'],
columns: [{ title: 'Product', links: [['/pricing', 'Pricing']] }, { title: 'Company', links: [['/contact', 'Contact']] }],
},
};
export function gaps(): string[] {
return Object.entries(probes).map(([what, block]) => {
const page = { theme: 'callboard', title: 'Probe', description: 'A probe.', frame: 'none', sections: Array.from({ length: 3 }, () => ({ kind: 'section', shell: { inset: 'contained', density: 'section' }, block })) };
const result = PageSchema.safeParse(page);
const issue = result.success ? undefined : result.error.issues[0];
return `${what}: ${issue ? `${issue.path.join('.')}: ${issue.message}` : 'accepted'}`;
});
}a brand with neither wordmark nor mark: sections.0.block.brand: a brand needs a wordmark or a mark
a feature grid of five: sections.0.block.items: a feature grid holds 2, 3, 4, 6, 8 cells: a count that fills its rows at every width
a footer in columns with no "For agents" column: sections.0.block: a footer in columns has a "For agents" columnRefusals lists every rule with its message.
Fetching /schema/sections/stats.json…