---
name: figma-smart-search
description: Use when searching for components, variables, or styles in a Figma design system using search_design_system — especially when the user asks about a design element by natural language name, when initial search results seem noisy or from wrong libraries, or when search_design_system returns results but none seem to match. Runs fuzzy matching to surface relevant results that exact-term scanning misses.
allowed-tools: Bash, Read
context: fork
---

# Figma Design System Smart Search

`search_design_system` returns results from ALL subscribed libraries. The results often contain what you need, but you will miss it if you scan for exact term matches. This skill uses a fuzzy matching script to rank results against the query so relevant matches are obvious.

**This skill does NOT require figma-use.** It covers `search_design_system` only. Load figma-use separately if you need to write to the canvas.

## Workflow

### Step 1: Call search_design_system broadly

Use short, general single-word queries. Search individual words separately rather than compound phrases:

| User says | Query to use |
|-----------|-------------|
| "primary button" | `button` |
| "heading text style" | `heading` |
| "spacing token" | `space` |
| "primary color" | `primary` |

Use type filters to reduce noise:
- Looking for a component → `includeVariables: false, includeStyles: false`
- Looking for a token/variable → `includeComponents: false, includeStyles: false`
- Looking for a style → `includeComponents: false, includeVariables: false`

### Step 2: Run fuzzy_match.py on the results

`search_design_system` often returns large results (50K+ characters) that exceed context limits. When this happens, Claude Code saves the output to a file and reports an "exceeds maximum allowed tokens" error with a file path. **This is normal and expected — the search succeeded.** Pass that file path directly to the script with `--file`. Do not try to read the file yourself, do not pipe through cat or other commands — the command must start with `python3` to match the skill's allowed-tools grant.

```bash
python3 ${CLAUDE_SKILL_DIR}/fuzzy_match.py "<user's search terms>" --library "<library name>" --file <path to saved results>
```

The script automatically unwraps the MCP response format `[{type, text}]` — no preprocessing needed.

**Arguments:**
- First positional arg: the user's natural language search terms (e.g., `"primary button"`)
- `--library` / `-l`: filter to a specific library name (partial match, case-insensitive)
- `--file` / `-f`: path to JSON file (reads stdin if omitted)
- `--top` / `-t`: max results per category (default: 10)
- `--threshold`: minimum score to include (default: 0.3)

The script tokenizes both the query and result names (splitting camelCase, slashes, hyphens), then scores each result using substring matching, token matching, and fuzzy similarity. Results are ranked by score.

### Step 3: Evaluate the ranked results

Read the output. Each result has a `_score` (0.0–1.0) and `_matchedTokens` showing how its name was parsed.

- **Score > 0.7**: Strong match — very likely what the user wants
- **Score 0.4–0.7**: Partial match — some query terms matched. Look at `_matchedTokens` to see what matched and what didn't. The unmatched term may be a variant name (e.g., "primary" might be a variant of "Button" rather than part of the component name)
- **Score < 0.4**: Weak match — probably not what the user wants

### Step 4: If no good matches, adjust and retry

If `totalMatches` is 0 or scores are all below 0.4:

1. Try a **different query word** with `search_design_system` (synonyms: "btn", "card", "container", "nav", "pill")
2. Run `fuzzy_match.py` again on the new results
3. After 2-3 attempts, **report what you found** and ask the user to clarify — do not switch to `use_figma` or `get_metadata` as search tools

```dot
digraph search_loop {
  "search_design_system (broad query)" -> "fuzzy_match.py (filter + rank)";
  "fuzzy_match.py (filter + rank)" -> "Good matches?" [shape=diamond];
  "Good matches?" -> "Use the results" [label="yes"];
  "Good matches?" -> "Tried 3 queries?" [label="no"];
  "Tried 3 queries?" -> "Try different query word" [label="no"];
  "Try different query word" -> "search_design_system (broad query)";
  "Tried 3 queries?" -> "Report findings, ask user" [label="yes"];
}
```

## Interpreting Partial Matches

A partial score often means the component exists but uses different terminology for the concept you're looking for. Common patterns:

| You searched | Script found | What it means |
|-------------|-------------|---------------|
| "primary button" | `Buttons/Button success` (score 0.47) | "button" matched, "primary" didn't — "success" may be their name for the primary variant, or "primary" is a variant property value. Inspect the component's variants. |
| "heading" | `Text/Display large` (score 0.35) | Different naming convention — "Display" instead of "Heading". Check if this is the right semantic level. |
| "primary color" | `brand/500` (score 0.4) | "primary" partially matched "brand" — this design system uses "brand" instead of "primary". |

**The key insight:** partial matches with one strong token and one weak token usually mean you found the right component but the design system uses different vocabulary for the qualifier. Ask the user or inspect the component rather than searching more.

## What NOT to Do

- **Do not use `use_figma` to search.** It is for creating/modifying design elements.
- **Do not use `get_metadata` to search.** It is for inspecting a specific file's node structure.
- **Do not scan raw search results by eye for exact term matches.** Always run the fuzzy match script — it catches camelCase, slash-separated, and synonym matches you will miss.

## Red Flags — You Are Wandering

- Called `use_figma` to "look for" or "find" something
- Called `get_metadata` hoping to discover component names
- Scanning raw JSON results without running the fuzzy match script
- Reading results from libraries the user didn't ask about
- Made 3+ search calls without using `--library` filter

**All of these mean: STOP. Run the script. Filter. Report.**
