lemma-widget
GitHub用于通过display_resource创建轻量级内联Lemma小部件,支持指标、列表、图表等结构化数据展示。基于原生HTML/CSS/JS或SVG,利用浏览器SDK获取实时Pod数据,强调简洁性与无框架依赖,适用于对话中的视觉层级呈现。
触发场景
安装
npx skills add lemma-work/lemma-platform --skill lemma-widget -g -y
SKILL.md
Frontmatter
{
"name": "lemma-widget",
"description": "Create lightweight inline Lemma widgets for conversations via display_resource(type=\"WIDGET\"): self-contained HTML\/CSS\/JS or SVG for metrics, lists, comparisons, timelines, record details, previews, and charts, optionally powered by live pod data through the browser Lemma SDK. Use an app, not a widget, when the UI needs React, routing, or substantial application state."
}
Lemma Widget
A widget is the default way to show an answer that is more than short prose.
Use display_resource(type="WIDGET") whenever the useful result has structure or
visual hierarchy: several values, records, statuses, steps, comparisons, a timeline,
a compact table, a preview, or a chart.
Use plain text only for a single fact, a short explanation, or narration around the widget. If an existing FILE, TABLE, APP, or other pod resource already represents the answer, display that resource directly instead of recreating it as a widget.
Widget or app?
- Widget: one compact inline view; plain HTML/CSS/JS or SVG; quick to render in the conversation; little local state.
- Vite app: React, routing, multiple screens, reusable components, substantial interaction/state, or a UI people will return to as a product.
Do not load React, ReactDOM, Tailwind, or the agent web-component bundle inside a widget. Lemma already has full Vite app support for that class of UI. A widget may be saved as an HTML app later, but it should remain lightweight.
Widgets are display surfaces. They do not submit values into the conversation. Use
ask_user for fixed choices or ask for free-form input in prose.
Build one
-
If the widget uses pod data, inspect the real table and column names first:
lemma pods describe lemma tables list lemma query run "select * from <table> limit 5" -
Load the closest maintained starter with
load_skill, usingname="lemma-widget"and one of theseresource_pathvalues:Answer shape Starter Metrics grouped by one field assets/widget-starter-v1.htmlCompact record list assets/widget-list-v1.htmlBar chart grouped by one field assets/widget-chart-v1.htmlOne record with selected fields assets/widget-detail-v1.html -
Replace every uppercase
__PLACEHOLDER__with inspected names and useful labels. For__FIELD_CONFIG__, insert a JSON array such as[{"label":"Owner","field":"owner"}]. -
Adapt the content and styling, then call
display_resourcewithtype="WIDGET". Do not rebuild the SDK loader or loading/empty/error scaffolding from scratch.
The backend rejects unresolved placeholders and broken SDK loaders before display.
Fixed contract
- Send an HTML/SVG fragment, never
<!doctype>,<html>,<head>, or<body>. - Keep all CSS local. The widget runs in its own iframe and inherits no frontend CSS.
- Use plain browser JavaScript. No build step, JSX, React, or framework runtime.
- Never put secrets, credentials, a pod id, or an environment hostname in the HTML.
- Show deliberate loading, empty, error, and narrow-screen states.
- Escape values before inserting them with
innerHTML; prefertextContent. - Keep the view compact: no fixed positioning or nested scrolling.
The starters are platform-themed and system-aware by default. Preserve their
prefers-color-scheme: dark rules and semantic fallbacks. They consume the small
public token layer --lemma-widget-bg, surface, subtle, text, muted,
border, accent, danger, radius, font, and color-scheme (each with the full
--lemma-widget- prefix). Chart starters also expose chart-1 through chart-5.
Use only the tokens the widget needs; do not copy Lemma's full frontend token file.
Never reference frontend-only variables such as --text-primary directly.
For a data-backed widget, preserve the starter's browser SDK loader:
- Build the SDK URL from
window.__LEMMA_CONFIG__.apiUrl. - Load
/public/sdk/lemma-client.jsdynamically and start insdk.onload. - Construct
new window.LemmaClient.LemmaClient()with no arguments. - Call
client.initialize()and handle a non-authenticated state. - SDK calls run as the signed-in user under normal RLS and grants.
- Shared files use
/…; personal files use/me; never use/pod/....
Common calls:
await client.records.list("tickets", { limit: 50 });
await client.records.get("tickets", "record-id");
await client.datastore.query(
"select status, count(*) as total from tickets group by status"
);
await client.files.search("quarterly planning", { limit: 10 });
await client.files.children.markdown("/knowledge/report.pdf");
await client.files.children.content(
"/knowledge/report.pdf/pages/page_0001.jpg"
);
Prefer datastore.query for aggregates. Never poll with setInterval; if a widget
must stay live, use client.datastore.watchChanges.
Visual standard
- Lead with the answer, not a title-heavy dashboard shell.
- Follow Lemma's neutral surfaces, near-black/near-white text, indigo action color, restrained borders, and compact radii unless the content needs a distinct visual language.
- For a very small widget, the token-light set is just
surface,text,muted,border, andaccent. - Format numbers and dates for humans.
- Use a list for repeated records, cards for a handful of metrics, a detail layout for one record, and a chart only when shape or comparison matters.
- For Chart.js, give the canvas wrapper an explicit height and read chart/text/grid colors from the starter's semantic variables.
- Keep explanation outside the widget in the assistant response.
Before display
- The chosen view is genuinely more useful than short prose.
- The closest versioned starter was used and all placeholders were replaced.
- The fragment contains no full-document tags, secrets, hardcoded hosts, or pod ids.
- SDK code uses injected config and boots from the script load handler.
- Loading, empty, error, and mobile states are present.
For React or a full product UI, load lemma-builder and follow
references/apps.md. For interaction-tool behavior, see
lemma-builder/references/agent-tools.md.
版本历史
- 0b61713 当前 2026-07-19 09:57


