| name | fondue |
| description | Queries the locally installed `@frontify/fondue/sdk` to surface accurate Fondue component metadata. ALWAYS use when picking a Fondue component (button, dialog, dropdown, tabs, …), finding a design token or utility class, or setting up the `@frontify/fondue` package. |
| allowed-tools | Bash(node *) |
Fondue
Use @frontify/fondue/sdk as the source of truth for every Fondue question. Never invent component names, props, token ids, or imports from memory — query the SDK.
Runs against the project's locally installed Fondue. Invoke node from the project root (or a subdirectory) so @frontify/fondue resolves from node_modules — results reflect the exact version this project depends on, not the version the skill was authored against.
Authored against @frontify/fondue@13.7.2. If the project's installed version differs, this document may be out of sync — trust what the SDK actually returns over anything written here.
Verify the SDK is available
node -e "import('@frontify/fondue/sdk').then((m) => console.log(JSON.stringify({ components: m.components.size, tokens: m.tokens.size, guides: m.guides.size })))"
If that errors with Cannot find package, the project hasn't installed Fondue yet:
pnpm add @frontify/fondue
How to query
The SDK is a synchronous, zero-I/O ES module that resolves from the user's project. Three singletons share the same query surface:
import { components, tokens, guides } from '@frontify/fondue/sdk';
components.list();
components.get('Button');
components.has('Button');
components.where({ text: 'dropdown' });
components.size;
where(filter) clauses AND-combine; array-valued clauses OR within the clause. get and where never throw; missing ids return undefined / [].
Nodes have scalar fields (read as properties) and graph edges (call as methods):
const button = components.get('Button');
button?.importStatement;
button?.props;
button?.category();
button?.related();
Running queries from the agent
For one-liners, use node -e:
node -e "import('@frontify/fondue/sdk').then(({components}) => console.log(JSON.stringify(components.where({text:'dropdown'}).map((c)=>({name:c.name,import:c.importStatement,canonical:c.examples.find((e)=>e.isCanonical)?.code})))))"
For anything multi-line, pipe a module via stdin to avoid quoting hell:
node --input-type=module <<'EOF'
import { components } from '@frontify/fondue/sdk';
const candidates = components.where({ text: 'dropdown', status: 'released' }).slice(0, 5);
console.log(JSON.stringify(candidates.map((c) => ({
name: c.name,
category: c.category().name,
tags: c.tags().map((t) => t.name),
import: c.importStatement,
canonical: c.examples.find((e) => e.isCanonical)?.code ?? c.examples[0]?.code ?? null,
})), null, 2));
EOF
Always emit JSON.stringify(...) so the response is parseable. Never console.log(node) directly — facet methods serialize as [Function].
For the formal contract (every filter clause, node shape, facet method), see reference.md.
Workflow 1 — Setting up Fondue
Read the canonical setup prose from the SDK rather than paraphrasing — the steps change between releases (font URLs, package layout, theme provider API).
node -e "import('@frontify/fondue/sdk').then(({guides}) => console.log(guides.get('getting-started')?.content))"
For upgrades:
node -e "import('@frontify/fondue/sdk').then(({guides}) => console.log(guides.get('upgrading')?.content))"
To discover other bundled guides:
node -e "import('@frontify/fondue/sdk').then(({guides}) => console.log(JSON.stringify(guides.list().map((g)=>({id:g.id,title:g.title})))))"
The output is the same markdown the Storybook docs render. Use it as the source for token imports, component-style imports, font face definitions, the Tailwind preset, ThemeProvider.
Workflow 2 — Finding a component
Start with intent-based search:
node --input-type=module <<'EOF'
import { components } from '@frontify/fondue/sdk';
console.log(JSON.stringify(components.where({ text: 'dropdown' }).map((c) => ({
name: c.name,
category: c.category().name,
status: c.status,
description: c.description,
})), null, 2));
EOF
Narrow by category or tag when the use case maps cleanly:
components.where({ category: 'overlay', status: 'released' });
components.where({ tag: 'cta' });
components.where({ category: 'input', tag: 'cta' });
Once you have a candidate, pull the recommendation shape:
node --input-type=module <<'EOF'
import { components } from '@frontify/fondue/sdk';
const c = components.get('Button');
console.log(JSON.stringify({
name: c.name,
description: c.description,
importStatement: c.importStatement,
canonical: c.examples.find((e) => e.isCanonical)?.code ?? c.examples[0]?.code,
requiredProps: c.props.filter((p) => p.required).map((p) => p.name),
subComponents: c.subComponents.map((sc) => sc.name),
related: c.related().map((r) => r.name),
instructions: c.instructions,
}, null, 2));
EOF
Recommendation shape — when you suggest a component, output: the name, what it's for, the import statement, and the canonical example. If the use case isn't a clean match, list 2–3 candidates with their categories and let the user pick.
Icons live in the components graph under category: 'icon'. They carry status: 'released' but have empty props, empty related(), and instructions: null — don't probe those fields. Find them with:
components.where({ category: 'icon', tag: 'arrow' });
components.get('IconAdobeCreativeCloud')?.importStatement;
When nothing matches:
- Try a related tag —
components.tags().map((t) => t.name) lists every tag.
- Look at the closest hit's
related().
- If there truly is no component for the use case, say so. Don't recommend hand-rolling something Fondue already provides, but don't invent a component name either.
Workflow 3 — Picking tokens for a custom component
Two layers exist:
tokens — atomic design tokens (colors, sizes, shadows, strings). Each has a CSS variable and a Tailwind class.
tokens.utilities — composed Tailwind utilities (typography classes like body-large-strong) bundling multiple token references.
tokens.where({ text: 'primary' });
tokens.where({ category: 'colors', themeable: true });
tokens.where({ keyPathStartsWith: 'colors.text' });
tokens.type('color')?.where({ themeable: true });
const t = tokens.get('color-charts-primary-default');
t?.value;
t?.cssVariable;
t?.tailwindClass;
t?.themeable;
tokens.utilities.where({ keyPathStartsWith: 'utilities.text' });
Rules:
- Prefer
themeable: true tokens for any user-facing surface so dark mode and theming work out of the box.
- Prefer the Tailwind class when the project uses
@frontify/fondue/tokens/tailwind; prefer the CSS variable otherwise.
- For typography, recommend the utility class — not raw font-size / line-height / weight tokens.
- Never invent token ids. If
tokens.get(id) returns undefined, search again.
- If the design calls for a value with no matching token, surface that explicitly — don't silently hardcode. The right answer is usually a token the user didn't know existed.
Common pitfalls
| Mistake | Fix |
|---|
Calling .where() / .get() on the array returned by list() / where() | Arrays are arrays. Use native .filter / .find, or navigate back to a facet to query. |
Assuming a component exists ("there must be a Combobox") | components.has('Combobox') first, or components.where({ text: 'combobox' }) |
| Hardcoding a hex / px value in custom code | tokens.where({ text: '<intent>' }) — most "obvious" values have a token |
Treating icons like normal components, reading props / instructions | Detect with node.category().name === 'icon'. Icons have empty props, related, and null instructions. |
Importing Button from the wrong path | components.get('Button')?.importStatement is authoritative |
| Suggesting setup steps from memory | guides.get('getting-started')?.content — always the live text |
console.log(node) instead of JSON.stringify | Facet methods serialize as [Function]; always stringify before logging |
Going deeper
reference.md is the formal contract: every export, every filter clause per domain, every node and facet type, error semantics. Load it when you need to verify a filter clause is valid (ComponentFilter, TokenFilter, GuideFilter) or that a method exists. Prefer it over web lookups or upstream GitHub.