Files
Trung Nguyen 02b412b178 Docs: answer with cards (steps, tables, notes, follow-up questions) in Gordon chat (#26452)
## Description

Gordon answers everything in plain markdown, even when the answer is a
procedure or a comparison. Those answers are harder to scan than they
need to be. This PR lets Gordon put a small card inside its answer when
that helps:

- **Steps** for procedures, with commands in code boxes
- **Tables** for comparisons (limits, plans, options)
- **Notes** for warnings, active incidents or tips
- **Code snippets** for config files
- **Follow-up questions** as chips. Selecting one asks it as your next
question.

```
You can containerize it with docker init, then run it with Compose.

┌───────────────────────────────────────────────┐
│ Containerize a Node.js app                    │
│ ① Generate the Docker assets                  │
│   [ docker init ]                             │
│ ② Build and run the app                       │
│   [ docker compose up --build ]               │
│ ▌ Use Docker Hardened Images for security     │
│ ( How do I add a database service? )          │
└───────────────────────────────────────────────┘

Sources:
- https://docs.docker.com/guides/nodejs/
```

Short answers, explanations and greetings stay plain markdown.

### How it works

```
chat ── "I can draw cards" (ui: "openui-v1") ──▶ Gordon
chat ◀── markdown answer, with at most one ```openui-lang block ── Gordon
chat: draws the block as a card, everything else as markdown
```

- The chat sends one extra field with each question. Only then does
Gordon's backend tell the model it may add a card. Without the field,
answers are the same as today.
- A card is a fenced block of [OpenUI
Lang](https://www.openui.com/docs/openui-lang) inside the normal answer
text, so the conversation history and stored messages stay plain text.
- The chat draws the block with its own styles. Anything it doesn't
recognize is left out, and if the card code can't load, the block shows
as a plain code block.

### Visual change to all answers

Gordon's answers are no longer inside a grey bubble. A framed card
inside the grey bubble looked like a box in a box. Answers now sit on
the panel background at full width, and the card stands out as its own
block. Your own messages keep the blue bubble.

<!-- screenshots: before / after, light and dark -->

### Rollout

- Cards are **on in local builds and deploy previews**, and **off in
production**.
- To turn them on in production, set `params.gordon.cards: true` in
`hugo.yaml`.
- Gordon's backend already supports this, so no other change is needed.

### Other notes

- **Safety:** card text from the model is only ever inserted as text,
never as HTML.
- **Page weight:** the card code (about 120 KB gzipped) is a separate
bundle. It's only downloaded when an answer first contains a card, never
on page load.
- **Copy button:** copies the answer with cards written out as markdown
(numbered steps, a table, `> [!NOTE]`), not the raw card code. Follow-up
chips are left out.
- **Instructions Gordon gets:** the prompt lives entirely in Gordon's
backend, which injects it when the chat sends `ui: "openui-v1"`. This
repo only has the component list the chat draws
(`assets/js/gordon-cards/components.mjs`). The backend's card prompt
describes the same components, so when adding or changing one, the
backend's prompt changes with it.
- **New dependencies:** `@openuidev/lang-core` (the OpenUI Lang parser)
and `zod`, pinned. Its usage telemetry never runs in a browser, and
`.npmrc` already blocks install scripts.

### How to test

1. Run `docker compose watch` and open http://localhost:1313. Local
builds use Gordon's staging backend.
2. Open Gordon from the header and ask:
- **Should show a card:** "How do I containerize my Node.js app?", "What
are the Docker Hub pull limits?", "How do I set up a registry mirror?"
   - **Should stay plain text:** "What is Docker Scout?", "hi"
3. Select a follow-up chip. It should ask that question.
4. Select **Copy** on an answer with a card. The pasted text should be
markdown.
5. Reload the page. Cards should come back from the conversation
history.
6. Check dark mode.
7. In the browser's Network tab, check:
   - each question to `/public/ask` includes `"ui": "openui-v1"`;
   - `gordon-cards.js` only loads after the first answer with a card.

## Related issues or tickets

<!-- none public -->

## Reviews

- [x] Technical review
- [ ] Editorial review
- [ ] Product review
2026-10-27 17:16:06 +01:00
..