The Badge that wasn't there
AI prototyping tools don't imagine a screen from nothing. They search your design system for components that fit the prompt, then reuse what they find. So when I searched my production library for "badge," I was watching what the AI sees.
It returned 19 results across several libraries. Only 3 had a description. And in Design System 1.1, the library I actually ship from, nothing was named Badge. The two closest matches were unlabeled frames. The component exists on the canvas, but by name it can't be found.
If retrieval fails, the prompt barely matters. The AI builds something plausible from scratch, and it won't match your system.
Prompting still helps. But it can't fix a library the AI can't reliably find, understand, or implement. That gives you two levers: make components findable, and connect them to real code. I measured both.
Why the search fails
Six gaps show up in a typical library. Each is a way for one of six things an AI needs (identity, intent, naming, variants, relationships, implementation) to go missing.
- Unfindable. The pattern exists but returns nothing usable, as with Badge.
- Inconsistent names. One component, five names.
- No descriptions. Without a stated purpose, neither AI nor people know when to use it.
- Duplicates. Several "Card" components, and the match grabs the wrong one.
- Noise. Icons and leftover test components share the same search space as real UI.
- Competing token scales. Even a correct match looks slightly off.
A seventh cause is operational, and I only found it by trying to fix the rest. I added real descriptions to three undescribed production components and published them. Three re-runs of the same search showed no change: same results, same gaps, same timestamps. The same publish-then-search loop worked every time on a fresh test library, so this was a fixable pipeline failure, not a limit of the tools. A fix that doesn't propagate to where retrieval happens isn't a fix, and nothing warns you when that happens.
The token cost of a messy library
The clearest measured effect is cost. I ran the same 10 prompts (button, card, data table, tabs, badge, tooltip, checkbox, dropdown, text input, accordion) against my production setup and a sandbox library built clean with the same tooling. Retrieval context per prompt fell from about 1,450 tokens to about 135, a ~91% cut, computed from the actual search payloads both libraries returned.
Try it: one query, before and after
Pick a component, then flip the switch.
| Metric | Before | After |
|---|---|---|
| One correct, unambiguous match | 0 / 10 | 10 / 10 |
| Forced to guess between duplicates | 9 / 10 | 0 / 10 |
| No usable match (accordion) | 1 / 10 | 0 / 10 |
| Matches with a description | 6–21% | 100% |
| Retrieval context per prompt | ~1,450 tokens | ~135 tokens |
The token figure counts only what search returns before generation starts. It excludes the prompt, system instructions and the code written afterward, so total savings are larger. Most of it comes from returning 1 result instead of 19, which is the point: every extra candidate is something the assistant has to read and weigh.
[
{"name":"Badge","libraryName":
"Legacy Design System V2"},
{"name":"Badge","libraryName":"Design System 1.0"},
{"name":"Badge","libraryName":
"Legacy Design System V1"},
{"name":"Frame 174374","libraryName":
"Design System 1.1"},
{"name":"badge","libraryName":
"Community Icon Set"},
...14 more
]
19 results. 3 have a description.[
{"name":"Badge",
"assetType":"component_set",
"description":"Small status label for
surfacing a state or category inline
with other content. Variants: Success,
Warning, Danger, Neutral, each with a
tinted background and matching text
from the semantic color tokens."}
]
1 result. It has a description.I also rendered one screen both ways, an info card with a title, supporting text and a button. The sandbox version is a single deliberate component. The production version is one of six incompatible layouts all named "Card," and I picked the closest by hand because nothing in the response says which to use. That flatters production, since an AI has no way to tell the six apart.
Code Connect: retrieve the real component, don't guess it
Cleaning up search gets the AI to the right component. It still has to write the code. A visual reference (a shape on a canvas) leaves it inventing props and styles. An implementation reference tells it what exists. Code Connect is one way to supply that: it maps a Figma component to its real code, so the assistant retrieves your actual Button instead of reconstructing a lookalike.
I tested it on the sandbox Button, a real mapping to an actual source file. Below is the unedited get_design_context response, before and after the mapping existed.
export default function Button({
className, size = "Small",
state = "Default",
variant = "Primary" }: ButtonProps) {
const isPrimaryAndMediumAndDefault =
variant === "Primary" &&
size === "Medium" && state === "Default";
// ...6 more boolean flags
return (
<div className={`flex items-start
rounded-[var(--radius-md,8px)] ${
isSecondaryAndMediumAndDisabled ?
"bg-[var(--color-bg-subtle,#f9fafb)]
border border-[var(--color-border-
default,#d1d5db)] opacity-50 ..."
/* ...6 more guessed style branches */}`}>
...
</div>
);
}
3,784 characters
37 guessed CSS variable references
0 references to real codeimport Button from "src/components/Button.tsx" export default function Button({ className, size = "Small", state = "Default", variant = "Primary" }: ButtonProps) { if (variant === "Primary" && size === "Small" && state === "Disabled") { return ( <CodeConnectSnippet data-node-id="5:4"> <Button /> </CodeConnectSnippet> ); } // ...6 more branches, each rendering // the real <Button /> } 2,229 characters 0 guessed CSS variable references 1 real import of the mapped component
The response is about 41% smaller, and the invented CSS is gone: every style the left panel guessed at now lives in the component that engineers actually ship. That is the same lever as the retrieval numbers above, applied one step later. Fewer tokens for the assistant to read, and nothing left to hallucinate.
variant, size and disabled unset instead of wiring in the actual values. Getting full prop fidelity took more than linking a node to a file, and this is one component, so read it as a demonstration of what changes, not a benchmark. Code Connect only helps as much as what it maps to, so it pairs with library cleanup and doesn't replace it.What to fix first
You don't need a rebuild, just a sequence that follows the evidence. Descriptions moved coverage from as low as 6% to 100%, so that goes first.
- Now: remove junk components, separate icons from UI components, and write descriptions for your top components. Say when to use each one and when not to.
- Next: pick one canonical version of every duplicate, collapse competing token scales, standardize names, and connect your most-used components to real code with Code Connect, wiring the props too.
- Later: schedule a recurring retrieval check that runs your top prompts and confirms each publish reached search.
Until then, name the exact component in your prompts, treat output as a draft to check against the real library, and log every search that returns nothing useful. Those are your cleanup priorities.
What a clean library still can't fix
The AI can still misread intent, choose the wrong pattern from a clean set, invent behavior no spec supports, make accessibility mistakes the library doesn't encode, or miss business rules that live outside the design system. A clean library removes one major failure. It doesn't guarantee good output.
It does have a business payoff. Fewer candidates means fewer tokens spent and fewer correction rounds, and consolidating duplicates cuts the ongoing cost of maintaining near-identical variants. It also means what designers hand off looks like what engineers build.