ls-generative-ui

star 1

LiteSuite Generative UI — render interactive widgets inline in Frontier Chat / Sentinel Chat. Use prompt_widget when you need the user's input to continue (confirmations, forms, picks). Use render_widget for fire-and-forget displays (charts, stat cards, dashboards). Triggers on 'render widget', 'prompt widget', 'ls-generative-ui', 'show me a chart', 'ask the user', 'confirm before', 'show a form', or whenever a visual or interactive answer is clearer than prose.

ahostbr By ahostbr schedule Updated 6/3/2026

name: ls-generative-ui description: "LiteSuite Generative UI — render interactive widgets inline in Frontier Chat / Sentinel Chat. Use prompt_widget when you need the user's input to continue (confirmations, forms, picks). Use render_widget for fire-and-forget displays (charts, stat cards, dashboards). Triggers on 'render widget', 'prompt widget', 'ls-generative-ui', 'show me a chart', 'ask the user', 'confirm before', 'show a form', or whenever a visual or interactive answer is clearer than prose."

Generative UI

Render interactive widgets directly inside the chat conversation. Two tools, three bands.

Choose the right tool

Tool Behavior Use when
prompt_widget Blocks until user interacts. Returns {action, data} as tool result. Confirmations, forms, picks. You need the user's input to continue.
render_widget Fire-and-forget. Returns immediately. Pure inline display. Charts, stat cards, status grids, dashboards. No response needed.

Choose the right band

Band When to use
catalog Data fits a named genui.* component exactly. Try this first.
specs Multi-component layout (grids, tabs, dashboards).
html Custom interactivity, charts (Chart.js/D3), unique visuals.

prompt_widget — required fields

When calling prompt_widget, you MUST provide:

  • type"catalog" | "html" | "specs"
  • requestId — unique identifier per call. Generate "widget-{8 random hex chars}" (e.g. "widget-7f3a9e2c"). Must be unique per call.
  • agentId — your agent identifier (session UUID or "sentinel-chat" if unknown)

Plus the band-specific fields below.

Response shape

When the user interacts, prompt_widget returns:

{
  "requestId": "widget-7f3a9e2c",
  "action": "click" | "submit" | "dismiss",
  "data": { /* depends on the widget */ },
  "timestamp": 1779449619556
}

Catalog component reference

Interactive (use with prompt_widget)

genui.Button — single click resolves with {action:"click", data:{label, buttonId?}}

{ "label": "Confirm", "variant": "primary" }

genui.FormField — auto-wraps with Submit/Cancel; Submit resolves with {action:"submit", data:{fields:{[name]:value}}}

{ "name": "email", "type": "text", "label": "Your email", "placeholder": "you@example.com" }

Types: "text", "textarea", "number", "select", "checkbox", "radio". For select/radio pass options: [{label, value}, ...].

genui.Select — dropdown; same form-wrapped resolution as FormField

{ "options": [{ "label": "A", "value": "a" }], "value": "a" }

Display (use with render_widget)

Component Props
genui.StatCard {title, value, trend?, icon?}
genui.MetricRow {metrics: [{label, value}, ...]}
genui.DataTable {columns: ["A","B"], rows: [["x","y"]]}
genui.ProgressRing {value, max, label?}
genui.TLDR {text}
genui.KeyTakeaways {items: [...]}
genui.ExecutiveSummary {title, sections: [{heading, body}]}
genui.StepCard {step, title, description}
genui.CodeBlock {code, language}
genui.CalloutCard {type:"info"|"warning"|"error"|"success", title, message}
genui.LinkCard {url, title, description?}
genui.ToolCard {name, description, status?}
genui.BookCard {title, author, description?}
genui.StatusIndicator {status:"online"|"offline"|"warning", label}
genui.CategoryBadge {category, color}

Layout (use with specs band)

genui.Section ({title, children}), genui.Grid ({columns, children}), genui.Tabs ({tabs:[{label, content}]}), genui.Accordion ({items:[{title, content}]}).

HTML band

Write content as a self-contained snippet — no <!DOCTYPE>, no <html>, no <head>, no <body>. The iframe provides them.

Pre-loaded globals available in every HTML widget:

  • Chart — Chart.js v4 (new Chart(canvas, {...}))
  • d3 — D3 v7

The iframe runs sandbox="allow-scripts" with no parent-DOM access, no same-origin.

Interactive HTML — postMessage protocol

For prompt_widget html-band, your script MUST post a response to resolve the tool:

window.parent.postMessage(
  {
    type: "widget-response", // exact string required
    action: "click", // or "submit", "dismiss", anything you choose
    data: {
      /* your data */
    },
  },
  "*",
);

The type: "widget-response" discriminator is required. Anything else is ignored. Your action + data flow back as the tool result.

CDN allowlist

For libraries beyond Chart.js/D3, any https: script is allowed (sandbox is the boundary). Recommended sources: cdn.jsdelivr.net, cdnjs.cloudflare.com, unpkg.com. External API calls (fetch/XHR) are blocked by CSP — keep widgets self-contained.

Worked examples

1. Confirm action (prompt_widget catalog)

{
  "type": "catalog",
  "component": "genui.Button",
  "props": { "label": "Ship it", "variant": "primary" },
  "title": "Deploy confirmation",
  "requestId": "widget-btn-7f3a9e2c",
  "agentId": "{your-id}"
}

2. Pick from a list (prompt_widget catalog form)

{
  "type": "catalog",
  "component": "genui.FormField",
  "props": {
    "name": "model",
    "label": "Pick a model",
    "type": "select",
    "options": [
      { "label": "Opus", "value": "opus" },
      { "label": "Sonnet", "value": "sonnet" },
      { "label": "Haiku", "value": "haiku" }
    ]
  },
  "title": "Model selection",
  "requestId": "widget-pick-a1b2c3d4",
  "agentId": "{your-id}"
}

3. Display a chart (render_widget html)

{
  "type": "html",
  "title": "Weekly Signups",
  "content": "<canvas id='c' style='max-height:380px'></canvas><script>new Chart(document.getElementById('c'),{type:'bar',data:{labels:['Mon','Tue','Wed','Thu','Fri'],datasets:[{label:'Signups',data:[42,58,35,71,90],backgroundColor:'#d4a853'}]},options:{responsive:true,plugins:{legend:{labels:{color:'#e8e0d4'}}},scales:{x:{ticks:{color:'#94a3b8'}},y:{ticks:{color:'#94a3b8'}}}}})</script>"
}

4. Custom interactive HTML (prompt_widget html)

{
  "type": "html",
  "content": "<button id='b' style='padding:10px 20px;background:#7c3aed;color:white;border:0;border-radius:6px;cursor:pointer'>Click me</button><script>document.getElementById('b').addEventListener('click',function(){window.parent.postMessage({type:'widget-response',action:'click',data:{x:42}},'*');});</script>",
  "title": "Custom HTML widget",
  "requestId": "widget-html-9e2c7f3a",
  "agentId": "{your-id}"
}

5. Dashboard layout (render_widget specs)

{
  "type": "specs",
  "title": "System Health",
  "specs": [
    {
      "component": "genui.Grid",
      "props": { "columns": 2 },
      "children": [
        {
          "component": "genui.StatCard",
          "props": { "title": "CPU", "value": "34%", "trend": "-2%" }
        },
        {
          "component": "genui.StatCard",
          "props": { "title": "Memory", "value": "6.1 GB", "trend": "+0.4 GB" }
        }
      ]
    },
    {
      "component": "genui.ToolCard",
      "props": { "name": "Redis", "description": "Cache layer", "status": "healthy" }
    }
  ]
}

Best practices

  • Catalog first. Catalog components are theme-matched. Reach for html only when the design isn't expressible as catalog/specs.
  • Don't over-widget. A single clear widget beats five cluttered ones. Use genui.Grid or specs to group.
  • Pair tool to intent. Use render_widget for displays you don't need a response to. Use prompt_widget when you'll actually use the user's answer.
  • Always set a title — it gives the widget a header and makes the conversation easier to reference.
  • HTML must be self-contained. No external API calls. All styles + scripts inline.
  • One round-trip per prompt_widget. The tool resolves on the first user response. For multi-step interaction, chain multiple prompt_widget calls.
Install via CLI
npx skills add https://github.com/ahostbr/liteharness-plugin --skill ls-generative-ui
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator