Design systemDraft
Artifact card
An agent made something durable (a document, a report, a page, a dashboard, a diagram, a deck, a small app) and it lives on the box, versioned, private by default. This card is how it shows in chat; the panel it opens is the full viewer. Agreed with the artifacts team (AR1-AR8, CHAT.md, 30 Sep) and cohesion-2; the panel/diff/list-row reuse below was agreed there first and is restated here as part of the one chat-components contract. New 30 Sep.
| Surface | Implementing file | Status |
|---|---|---|
| Deck | none | not built |
| App | none | not built |
| Lumen | none | not built |
Anatomy: chat card
A compact row-card, height 56, padding 10 12, radius --radius-card (12), fill --panel, 1 px
--rule:
- Icon, 32: a kind glyph (doc, report, page, dashboard, diagram, deck) on
--hover, radius 8- never a live-rendered thumbnail in chat (that's the panel's job; the row stays cheap).
- Title and meta, a column: title (base 600,
--text, one line, ellipsis) - "kind · vN · made by <agent> · <relative time>" (meta,--label). - Actions, right: Open (outline, opens the panel) and Share (ghost, opens the share sheet, AR3/AR8) side by side.
Anatomy: panel (artifacts-options.html section 3, Option A, confirmed)
panel:<name> (ADR 0033's slot grammar), 340 wide by default; a page or deck kind may widen to
50% of the window with one control (docs/design/system/layout.md's named exception, committed
9c8479f5) - every other kind stays at 340.
- Version bar, 44 tall, padding 0 16: the title, then right-aligned a version toggle (pill
buttons per version,
v1v2..., the current one filled--text/--bg, others outline), Changes (ghost, toggles the diff view below) and Share (ghost). - Content, by kind:
- doc / report: Vyre's own Markdown renderer, in the design system (type scale, no custom CSS from the artifact itself).
- diagram: Mermaid or inline SVG, same renderer as everywhere else diagrams appear.
- dashboard: a chart spec drawn with the dataviz palette (the project's existing chart conventions, not a new one).
- page / app: HTML inside a sandboxed iframe,
sandbox="allow-scripts"with noallow-same-origin, matching ADR 0033's/m/<module>/rule exactly (confirmed 06:38, CHAT.md) - the raw content URL also carries its own restrictive CSP so even a top-level open runs at an opaque origin.
- Changes view (when toggled):
diff.md's unified diff between the selected version and the one before it - added on the bone wash, removed struck... no, perdiff.md's own rule, removed on the neutral wash with no strikethrough. Exactlydiff.md, not a second diff renderer.
Anatomy: Artifacts tab (per project)
A list-row.md list: title, kind/creator/date meta, a visibility chip (chip.md's Tag: "Public ·
29 days" in a neutral, "Only you" otherwise - never an accent, matching every
other neutral-chip rule in this system) right-aligned. Sits beside Threads/Brief/Files/Memory as
its own tab (artifacts-options.html section 3).
Variants
- Chat card, phone: same anatomy, full width, Open leads to the full-screen sheet instead of a panel.
- Panel, phone: full-screen sheet (ADR 0033's
panel:<name>phone rule), version bar becomes a bottom bar (Versions / Changes / Share, per the confirmed mockup) rather than top-of-panel, since the phone's safe-area top is precious and the title needs the space instead. - Lumen (compact): not drawn at all in the panel/rows/footer shell - "Open in the Deck" only,
same rule as every other rich-content card here (
pr-review.md,email-thread.md,calendar.md's compose forms).
Sizes
Chat card 56 tall. Panel 340 default / 50% widened (page, deck only). Version pills 28 tall, 8 horizontal padding.
States
- Open as above.
- Loading (panel content still rendering): a skeleton block matching the content kind's rough shape (text lines for doc/report, a blank canvas for diagram/dashboard).
- Diff loading: the version bar's Changes button shows a spinner in place, content stays on the current version until the diff is ready.
- Shared: the chat card's meta line gains the visibility chip too, so a shared artifact reads the same in chat as it does in the Artifacts tab.
- Error (page/app failed to render in the sandbox): "This page didn't load" with the failed
mark,
--text, no further detail leaked from the sandboxed origin (nothing to leak by design).
Keyboard and touch
Version pills are a radiogroup; ← → move between them when focused. Share opens with S when
the panel has focus (no conflict - draft-card.md's "D" is Discard, this panel has no Discard).
Motion
Panel open/close at --motion-panel (220), matching every other panel:<name>. Version switch
crossfades the content, no slide (a slide would misread as "this is a different artifact," not
"this is the same artifact, an earlier moment").
Copy
"kind · vN · made by <agent> · <relative time>", "Open", "Share", "Changes", "Public · <n> days", "Only you". Never "AI-generated" as a label - the "made by <agent>" meta already says who/what made it, in the same plain register avatar.md's teammate-tag rule uses elsewhere.
Emission (agreed with artifacts, sessions, native-core - AR1/AR2)
thread.artifact {thread, artifact, version, kind, title} (AR2, agreed in CHAT.md) drives the
chat card. The panel reads the artifact's own versions via artifacts.get/artifacts.diff
(AR1) directly, not through a chat event - opening the panel is a navigation, not a new message.
What the person's actions do
Open navigates to the panel/sheet, a read action, no Gate involvement. Share opens the share
sheet (AR3/AR8's artifacts.share, outward: post - held with Touch ID only when an agent
decided to share alone, matching every other outward classification in this contract; runs at
once when the person tapped or asked, per "asking is approving"). Restoring an old version
(artifacts.restore, if the panel exposes it - flagged to artifacts as a possible addition, not
yet in AR1's tool list) would be a write to the person's own project, not outward, so no Touch ID.
What agents can do for the person
An agent creates and updates artifacts on its own (artifacts_create/artifacts_update, AR4's
harness-brief line) without asking each time - that's the whole point, replacing scattered
one-off publishing with one governed store. It may never share one publicly on its own without
the person's Touch ID (AR1's artifacts.share classification), and it may never delete one
without an explicit ask (AR1 lists delete as a plain tool, not outward, but a destructive
action the person didn't ask for still needs "asking is approving" to actually match a said
intent - flagged to vault/assistant to confirm delete's Gate treatment, since AR1's own table
doesn't mark it held).
Accessibility
- The chat card is a
button-like row (role="link"semantics: Open is the default action). - The panel is a
dialogregion (matching every otherpanel:<name>'s existing pattern) labelled by the artifact's title. - The sandboxed iframe carries
titledescribing the artifact, so assistive tech announces what it's entering even though its content is opaque to the host page.
Gaps
Everything - new component, no surface has built it. Depends on AR1's tools and AR2's event landing first (artifacts' own build order).