The direction
All widget kinds should be authored against A2UI/AG-UI rather than living only in the bespoke MCP Apps shell. Stated as a decision about what the product is: the registry's wire form becomes an A2UI catalog, and the React components become a renderer of that catalog — one implementation among possible many — instead of being the format themselves.
What this cannot mean (honesty constraints)
- It cannot mean flattening rich mechanics into the basic catalog. Drag-sort rendered as checkboxes measures something different from drag-sort; a degraded projection must stay labeled as one (the current mapper's stated-fidelity-limits pattern), and
assesses must track the mechanics actually rendered, never the kind's name.
- It cannot mean the model authoring component trees freeform. Invariant 1 gets stronger here: surfaces are pure data, model output still fills Zod specs, and the mapping spec→surface stays human-written code.
The shape: invert the relationship
A2UI's extension mechanism is the custom catalog. The a2learn catalog is the registry, projected:
- each widget kind = one catalog component; its props schema generated from the kind's existing Zod spec (zod → JSON schema is mechanical), so the catalog cannot drift from the registry;
- surfaces referencing the a2learn catalog are full-fidelity; the same spec also projects to the basic catalog where honest, as the universal degraded path (two-tier delivery, both truthfully labeled);
- evidence returns via A2UI actions (the existing
completedAction pattern: no verdict without real checking, gated on assesses) and crosses AG-UI transports as the namespaced a2learn.* custom events /api/pathway/agui already established.
Staged path
- Widen basic-catalog coverage where honest — selected-response/short-answer shapes via the catalog's input components (
CheckBox, TextField); use the A2UI data model for local state (fixes the flashcard flip degradation). Fixture pair per kind, per the conformance gate.
- Registry-owned mapping — the optional
a2ui field on the registry entry (already anticipated in src/lib/a2learn/a2ui.ts's header, tied to the registry-owned-semantics refactor), so adding a kind stays one file.
- The a2learn catalog — versioned, served, schema-vendored like the upstream ones; conformance validates both directions (our surfaces against A2UI envelope schemas, catalog component instances against the generated props schemas), with negative controls.
- The React registry becomes a catalog renderer — the MCP Apps shell re-based as a renderer of a2learn-catalog surfaces rather than a parallel bespoke path.
Relations
Filed as the direction record per the governance rule that contract changes start as issues; phase 1 is actionable as soon as the current stack (#93) clears.
🤖 Generated with Claude Code
The direction
All widget kinds should be authored against A2UI/AG-UI rather than living only in the bespoke MCP Apps shell. Stated as a decision about what the product is: the registry's wire form becomes an A2UI catalog, and the React components become a renderer of that catalog — one implementation among possible many — instead of being the format themselves.
What this cannot mean (honesty constraints)
assessesmust track the mechanics actually rendered, never the kind's name.The shape: invert the relationship
A2UI's extension mechanism is the custom catalog. The a2learn catalog is the registry, projected:
completedActionpattern: no verdict without real checking, gated onassesses) and crosses AG-UI transports as the namespaceda2learn.*custom events/api/pathway/aguialready established.Staged path
CheckBox,TextField); use the A2UI data model for local state (fixes the flashcard flip degradation). Fixture pair per kind, per the conformance gate.a2uifield on the registry entry (already anticipated insrc/lib/a2learn/a2ui.ts's header, tied to the registry-owned-semantics refactor), so adding a kind stays one file.Relations
Filed as the direction record per the governance rule that contract changes start as issues; phase 1 is actionable as soon as the current stack (#93) clears.
🤖 Generated with Claude Code