Sdk Features logo

Sdk Features

OrganizationPopular
lightdash
sdk-features

Map Lightdash SDK capabilities to their host-UI names and the app-code wiring each needs. Use when the user asks about a feature by name (Inspect data, drill-down, exports, shareable URLs), when offering newly available features after a template upgrade, or when wiring a host-facing capability into the app.

Overview

Publisherlightdash
Repositorylightdash
Skill namesdk-features
Stars
6.2K
Forks
790
Bundled files
Instructions only
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by lightdash on GitHub. Read the source before you install it.

Installation

Install the Sdk Features AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/lightdash/lightdash/tree/main/sandboxes/data-apps/template/.claude/skills/sdk-features
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/lightdash/lightdash.git /tmp/lightdash
mkdir -p .claude/skills
cp -r /tmp/lightdash/sandboxes/data-apps/template/.claude/skills/sdk-features .claude/skills/sdk-features
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Sdk Features in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Sdk Features on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Sdk Features is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

The @lightdash/query-sdk in this workspace declares its capabilities in a registry: node_modules/@lightdash/query-sdk/dist/features.js (SDK_FEATURES, each { key, label, description, wiring? }). That registry is the source of truth — never invent capabilities from export lists or type definitions. This skill adds what the registry can't: how each feature maps to the Lightdash host UI and the exact wiring recipe.

Vocabulary: users speak host-UI, the SDK speaks keys

Users describe features by what they see in the Lightdash editor. Translate:

User says / host UIRegistry keyWiring
"Inspect data" (Queries panel button)lineagerequired — see below
"select an element", editor element pickerinspectnone (automatic)
thumbnails / screenshots / scheduled deliveriesscreenshotrequired — see below
drill down, click into a chartdrill-downapp code opt-in
drill into a viz data point (reusable visualization)viz-drill-downapp code opt-in
"ask the AI", one-line takeaway, explain this rowai-promptapp code opt-in
"share this view", URL that restores stateurl-stateapp code opt-in
Google Sheets exportgsheet-exportapp code opt-in
"delivery has all tabs", full data in scheduled deliveriesdelivery-renderapp code opt-in
external API dataexternal-fetchapp code opt-in
runs inside a dashboard tileviz-contextrequired — see below
reusable chart/table with pivoted resultsviz-pivoted-resultsrequired — see below
"Data point actions" — native context menu on a data-point click (copy, view underlying data, drill, cross-filter; viz only)point-action-menuapp code opt-in
"view underlying data", raw rows behind a point (viz only)viz-underlying-dataapp code opt-in
Lightdash-owned "View underlying data" dialog (viz only)viz-host-underlying-dataapp code opt-in
light/dark mode, "matches my Lightdash theme"follow-host-themeCSS tokens — see below
"executive summary", "what changed", anomaly callouts, "AI insight", "Analyse this view"ai-insightsapp code opt-in
"Adapts to small tiles", responsive, works on a phone, readable in a narrow or short tile (viz only)viz-responsive-layoutlayout — see below

Automatic (zero wiring — active on any current-SDK bundle)

createClient() mounts these itself: the capability manifest, the editor element inspector (inspect), and the lineage runtime. Core querying (query, saved-chart via useLightdash/savedChart) is just normal SDK usage. If the app calls createClient(), these need nothing from you.

Wiring recipes

lineage — the host's "Inspect data" button

The lineage runtime only announces itself once the DOM contains data-ld-query stamps; until then the host's Inspect data button stays disabled. Spread the lineage props returned by useLightdash onto the root element of every query-bound block:

jsx
const { data, lineage } = useLightdash(myQuery);
return <div {...lineage}>{/* chart rendered from data */}</div>;

Stamp every visualization, not just one — each stamp maps that block to its query in the host's Queries panel.

screenshot — thumbnails and scheduled deliveries

Provided by the template file src/screenshotHandler.js; main.jsx must import and call it (initScreenshotHandler()). Apps migrated from older templates may be missing the file or the call — copy the file from the template and add the call rather than reimplementing.

viz-context — apps embedded as dashboard tiles

Wrap the app in VizContextProvider (see the template main.jsx) and read the host-supplied query context with useVizContext. Only relevant for visualization-style apps meant to run inside dashboards.

follow-host-theme — light/dark mode

The SDK puts the dark class on <html> as the app boots and again whenever the viewer toggles their Lightdash theme, so an app that styles everything through the theme tokens follows along with no code at all. What an older app usually needs is the opposite of wiring — removing what pins it to one mode:

  • drop any className="dark …" on the app shell and any document.documentElement.classList.add('dark');
  • move dark values out of :root and into .dark, leaving a complete set of light values on :root;
  • keep both sets complete for every token the app defines.

For colours CSS can't reach (a chart library's theme object, a logo swap), read the mode: const colorScheme = useColorScheme(); — 'light' | 'dark', re-rendering on every host toggle.

viz-responsive-layout — a chart type that adapts to small tiles

There is no API to call: this is a layout rework. The chart renders in an iframe exactly the size of its tile, and the tile never resizes to its content, so the chart adapts to the tile.

The template makes the frame the container, but a chart type built on an older template carries its own copies of src/main.jsx and src/index.css without that. Add both pieces first if they are missing:

jsx
// src/main.jsx — import useVizContext from '@lightdash/query-sdk', define this,
// and render <VizFrame /> just before <App /> inside <VizContextProvider>.
function VizFrame() {
    const { ready } = useVizContext();
    React.useEffect(() => {
        document.documentElement.toggleAttribute('data-viz-frame', ready);
    }, [ready]);
    return null;
}
css
/* src/index.css — inside the `@layer base` block that holds the `#root` rules. */
html[data-viz-frame] {
  font-size: clamp(12px, calc(4px + 2.5vw), 16px);
}
html[data-viz-frame] #root {
  height: 100vh;
  overflow-y: auto;
}

Then follow the "Fitting the frame" section of the reusable-visualization skill. An older chart type usually needs its fixed column counts and pixel sizes replaced with wrapping, rem-sized ones and its own scroll regions removed; a chart drawn by a library that measures its container often needs nothing more. Keep the declaration (fields, config options, palette) unchanged.

viz-pivoted-results — reusable visualization pivots

Read pivotDetails from useVizContext(). When it is non-null, match pivotDetails.valuesColumns to the mapped metric by referenceField, derive series labels from pivotValues, and read each generated pivotColumnName with getRaw(row, pivotColumnName) or getFormatted(row, pivotColumnName). Generated and ordinary row keys both contain VizContextCell objects; never coerce row[fieldId] directly. Use the remaining metadata for the visualization's actual shape: indexColumn and originalColumns provide row-grain/type semantics, groupByColumns provides header order, sortBy describes result ordering, totalColumnCount exposes truncation, and passthroughDimensions identifies hidden fields retained on rows. Preserve the ordinary fieldMapping path when pivotDetails is null. The full contract is in the reusable-visualization skill.

App-code opt-ins (call the API where it fits the app)

  • drill-down: drillDown(...) derives a more detailed query from a clicked result row — wire it to click handlers on charts/rows.
  • point-action-menu (vizs only): the primary data-point-action contract. On a data-point click, when useVizContext().pointMenu.enabled, call pointMenu.open({ x: event.clientX, y: event.clientY, row: datum.sourceRow, metric: '<field name>' }) and render no menu of your own — Lightdash renders the entire native menu (copy value, view underlying data, drill, dashboard cross-filtering) and owns all subsequent UI. viz-drill-down and viz-underlying-data/viz-host-underlying-data below are the pointMenu.enabled === false fallback for older hosts, not a separate feature to wire in addition.
  • viz-drill-down: in a reusable visualization, when useVizContext().pointMenu.enabled, call pointMenu.open({ x, y, row, metric }) and render no menu of your own — Lightdash's menu offers "Drill into …". Only when pointMenu.enabled is false, fall back to a local data-point action menu gated on drillDown.enabled and call drillDown.open({ row, metric }) on selection. Either way Lightdash opens its drill dialog. Distinct from drill-down, which is the full-app query helper.
  • url-state: useUrlState(...) syncs a piece of app state into the page URL so views can be shared and restored.
  • gsheet-export: exportToSheets(...) sends tabular results to a new Google Sheet — offer it wherever the app renders a table.
  • external-fetch: client.externalFetch(alias, opts) calls an external connection linked to this app. The connection must already be linked by the host; you cannot add one from app code.
  • ai-insights: wire the shipped components in src/components/insights/ (InsightsSummary, InsightMarker / insightCellProps, InvestigateMenuItem, InvestigationCard) rather than writing your own: summary block at the top, markers on every query-bound chart (as both dot and activeDot), Investigate in every point menu, the card under the chart. A short ask ("add AI analysis") gets the whole set. They sit on useInsights() / useInsights(result) and render nothing when the host has no analysis. Full contract in /app/references/ai-analysis.md.
  • ai-prompt: useAiPrompt() returns { available, ask, loading, text, error }; ask({ prompt, sources: [{ result, label }], focus?: { row } }) sends an author-written question over loaded useLightdash results and resolves to plain text. result is the object useLightdash returns (keep a reference to it even when destructuring), never a rebuilt { data, columns }. Hide the control when available is false; trigger from a user action. Full contract in /app/references/ai-analysis.md.
  • delivery-render: useDeliveryRender() is true during scheduled-delivery and delivery-preview capture renders. Gate tab/slide DATA mounting on it so every tab's queries execute during capture while only the active tab stays visible — never mount all tabs unconditionally (interactive loads must stay lazy).
  • viz-underlying-data and viz-host-underlying-data (vizs only): keep the untransformed sourceRow on each interactive datum. When useVizContext().pointMenu.enabled, call pointMenu.open({ x, y, row, metric }) and render no menu of your own. Only when pointMenu.enabled is false, fall back to a local data-point action menu gated on underlyingData.enabled and call underlyingData.open({ row, metric }) on selection. Either way, Lightdash renders the dialog and owns its table, loading, error, and download controls. Full contract in the reusable-visualization skill.

After a template upgrade

An upgrade rebuilds the app on the current SDK, which turns on the automatic capabilities but does NOT add wiring — that is a deliberate rail. When you offer newly available features, offer wiring-required ones too (their registry entries carry a wiring note); implement only when the user asks.

Existing published visualization bundles are not rewritten by this registry. Bundles built before viz-host-underlying-data keep their iframe-owned get/download dialog until the user explicitly upgrades that feature.

Frequently asked questions

What does the Sdk Features AI skill do?

Map Lightdash SDK capabilities to their host-UI names and the app-code wiring each needs. Use when the user asks about a feature by name (Inspect data, drill-down, exports, shareable URLs), when offering newly available features after a template upgrade, or when wiring a host-facing capability into the app.

Why use Sdk Features on TypingMind?

Because you install it once and use it with any model. Sdk Features is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Sdk Features in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/lightdash/lightdash/tree/main/sandboxes/data-apps/template/.claude/skills/sdk-features. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Sdk Features?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Sdk Features?

As many as you like. As long as a model supports skills, you can use Sdk Features with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Sdk Features AI skill free?

It is published on GitHub by lightdash. Check the repository for licensing terms. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇