Repository navigation
feat: A2UI cards become data, not code #84
Description
Is your feature request related to a problem?
An A2UI card used to be code: a Python dict in one 843-line src/assistant/a2ui.py plus a bespoke Svelte component per card. Nothing about a card was addressable from outside a release — you could not add, edit or turn one off, and a plugin (#75) had no way to carry one.
The rendered card is still bound to its chat. A surface is persisted as an A2UISurface event in the chat's own event log (projected from the turn's A2UI messages by durable_surfaces_from_messages()), and its data updates are events on that same stream. Nothing can revisit or update it from another chat or a scheduled task, and deleting the chat deletes the card.
Describe the solution you'd like
Cards stop being code and become data:
- A card definition is a file, layered Bundled / Global / Profile like skills, so the user can drop one in, a plugin can install one, and either can be disabled or suppressed per profile. — implemented in feat(a2ui): Cards become files, drawn from a shared vocabulary #117 (in review)
- A card instance is a file too, living in the profile's file space rather than inside a thread, so a card made on Monday is still there on Friday. — feat: a saved A2UI card outlives its chat #86
- A card fetches its own data: its backend part refreshes the instance deterministically, without the LLM. — feat: an A2UI card fetches its own data, without the LLM #122
- Cards compose into screens the user builds — dashboards, aggregators, boards. — feat: screens — user-composed dashboards of live A2UI cards #123
Status
Implemented in #117, in review (ADRs 0036–0039):
*.card.yamlfiles in three layers —src/assistant/cards/bundled/,<root>/cards/, the profile'sworkspace/cards/— withname,description, optionaltopic,fields,layout(Basic-catalog primitives plus a small app vocabulary,src/assistant/cards/VOCABULARY.md) and oneexample.- The server expands a Card instance into primitives; every bespoke Svelte card renderer is deleted — one generic renderer draws them all.
cards.jsonswitches (install-wide Disable, per-profile Suppression), the same semantics as skills.- The catalog is disclosed through the bundled
rich-viewsSkill; its description names each available Card'stopic.
Sub-issues:
- feat: the A2UI card catalog lives in a directory #85 — the card catalog lives in a directory (implemented in feat(a2ui): Cards become files, drawn from a shared vocabulary #117; closes on merge)
- feat: a saved A2UI card outlives its chat #86 — a saved card outlives its chat
- feat: A2UI cards as editable files in the Files tree #87 — cards in the Files tree, plus a Settings page
- feat: a bundled skill that authors A2UI cards #88 — a bundled skill that authors cards
- feat: an A2UI card fetches its own data, without the LLM #122 — a card fetches its own data, without the LLM
- feat: screens — user-composed dashboards of live A2UI cards #123 — screens: user-composed dashboards of live cards
- related: Agent capabilities apply on the next message, not on the next reload #121 — Card/skill changes reach a running chat only on profile reload
AG2 upstream: ag2ai/ag2#3321 (component-owned, LLM-undeclared actions), ag2ai/ag2#3322 (client-initiated refresh), ag2ai/ag2#3323 (updating a surface outside a turn), ag2ai/ag2#3325 (SkillPlugin catalog per turn), ag2ai/ag2#3324 (a turn's prompt extends the agent's).
Additional context
src/assistant/cards/— format, loader, expansion;src/assistant/a2ui.py—CardCatalog, validation middleware;src/assistant/a2ui_skill.py— therich-viewsSkill- ADR 0016 (skill layers), ADRs 0036–0039 (Cards)
Direction: one place outside chats that shows live cards and screens (#123). Unlike live artifacts that the model re-renders, a card's data here is refreshed by the backend (#122).
See also: #75 (plugins should be able to carry cards), #67 (skills as editable files), #68 (tasks as editable files).
Activity