Skip to content
Back to skills

Generative Ui

ASecurity

Use when presenting information already in hand as a small, static structured panel in the conversation — status, results, comparisons, or a compact summary — rather than prose, a markdown table, a widget, or an app.

  • 41 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 5, 2026
ai-agentsnodeexpress

Security analysis

A100/100

Scanned September 5, 2026

npx -y skills add bearlike/Assistant --skill generative-ui --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Generative Ui?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Generative Ui
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/bearlike-generative-ui/badge)](https://www.skillsdirectory.com/skills/bearlike-generative-ui)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: generative-ui
description: Use when presenting information already in hand as a small, static structured panel in the conversation — status, results, comparisons, or a compact summary — rather than prose, a markdown table, a widget, or an app.
requires-capabilities: [generative_ui]
---

# Generative UI panels

`present_ui` displays a static, allowlisted, no-code panel. Call it directly; it
is not a widget or an app.

## Choose the smallest surface

| Need | Use |
|---|---|
| An explanation, conclusion, or short list | Plain prose |
| A small comparison that reads well as text and needs no visual grouping | A markdown table |
| Information already in hand that benefits from status, cards, grouped fields, or a compact visual summary | `present_ui` |
| A chart, interactive controls, or a custom interactive display | Delegate to `st-widget-builder`; its Streamlit widget runs code in a browser sandbox |
| A durable surface with its own data and pipelines | Delegate to `app-builder` |

A panel lays out known information with fixed components. It does not fetch data,
run code, accept input, or become a durable application.

## The call

Three arguments, all top level. `root` is a **list**; there is no wrapper object
around it.

```json
{
  "summary": "Release checks for main",
  "root": [
    {"component": "Heading", "value": "Release checks", "level": 2},
    {
      "component": "Card",
      "title": "Current status",
      "children": [
        {"component": "Badge", "label": "Ready", "status": "success"},
        {
          "component": "KeyValue",
          "items": [
            {"label": "Tests", "value": "Passed"},
            {"label": "Review", "value": "Complete"}
          ]
        },
        {"component": "Alert", "body": "No remaining blockers.", "variant": "info"}
      ]
    }
  ]
}
```

Every node is **flat**: `component` names the type, and that type's fields sit
beside it on the same object. Only `Card` and `Stack` accept `children`.

## Component vocabulary

**The `present_ui` description carries it, flat, and that copy is the only one.**
It is derived from the same models that validate your call, so it lists every
component with its required and optional fields and cannot be out of date. Read
it there rather than expecting a list here — a second copy in this file could
only ever be older.

Two shapes the flat list cannot express: a `KeyValue` item is
`{"label": ..., "value": ...}`, and a `Table` row is a list of cells exactly as
long as `columns`. Keep panels small enough to take in at a glance.

## Do not reverse-engineer the shape

Everything the call needs is above. Traced sessions have spent four consecutive
rejected calls rediscovering that `root` is a list, and one model announced a
shape it had already disproved and sent it anyway. If a call is rejected, read
the returned error — it states the correct shape and every component's fields —
and fix that one thing. Do not probe with a test panel; a rejected call costs a
step and a successful probe still shows the user a panel they did not ask for.

The names in the schema's `$defs` are the component names themselves (`Alert`,
`Card`); there is nothing else to look up, and they are not tools — searching for
them finds nothing.

## Delegate widgets without prescribing them

For a widget, delegate with `spawn_agent(agent_type="st-widget-builder", ...)`.
Give its task only the user's purpose and the path plus field names of the data it
needs. Do not prescribe layout, sections, controls, component types, chart axes,
colours, themes, or implementation details; the sub-agent owns the runnable
Streamlit application. When its `widget_ready` event arrives, the widget is
already visible — do not recreate it as a panel or invent a link to it.

For an app, delegate to `app-builder` with the user's intent and workspace choice.
It owns the durable data surface and pipelines.

## Build rich panels in small steps

One monolithic tree is the shape most likely to arrive corrupted. Present a
small skeleton first — a heading and a `Card` or `Stack` carrying an `id` — then
grow it call by call: `operation="append"` adds nodes to the panel (or inside
the container named by `target`), and `operation="update"` with `target`
replaces that one container. Each result reports the panel's current size and
the container ids you can address next.

## After presenting

`present_ui` emits the panel but does not end the turn: continue the task or give
the normal closing reply. What to put in that reply — and why restating the panel
is wasted — is in the tool's own description; it is not repeated here.

The tool result returns a panel id. Pass it as `ui_id` in a later call to
address that panel — replace it wholesale, or extend it as above — instead of
adding another one below it.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.