Design System Discovery
ASecurityDesign system auto-detection — scans repository for installed component libraries, token systems, and variant frameworks to build a structured design-system-profile.yaml. Provides the discoverDesignSystem() algorithm used by devise, strive, and arc workflows. Provides the discoverFrontendStack() algorithm for Layer 1 frontend stack detection with version extraction, used by design-prototype Phase 0. Trigger keywords: shadcn, shadcn/ui, untitled ui, radix ui, design system, design tokens, tail...
- 4 stars
- 0 votes
- 0 copies
- 1 view
- Added September 12, 2026
Works with
Security analysis
100/100Pro scans all 2 files and shows the line behind each finding
npx -y skills add aibot88/sec_skill_store --skill design-system-discovery --agent claude-codeAre you the author of Design System Discovery?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/aibot88-design-system-discovery)---
name: design-system-discovery
description: |
Design system auto-detection — scans repository for installed component libraries,
token systems, and variant frameworks to build a structured design-system-profile.yaml.
Provides the discoverDesignSystem() algorithm used by devise, strive, and arc workflows.
Provides the discoverFrontendStack() algorithm for Layer 1 frontend stack detection with
version extraction, used by design-prototype Phase 0.
Trigger keywords: shadcn, shadcn/ui, untitled ui, radix ui, design system, design tokens,
tailwind, css variables, cva, class-variance-authority, styled-components, tailwind v4,
style-dictionary, token system, component library, design compliance, frontend stack,
figma tokens, dark mode, ui library, component library detection, design system discovery.
user-invocable: false
disable-model-invocation: false
---
# Design System Discovery
Auto-detects the project's component library, token system, and variant framework.
Called by devise Phase 0.5 (pre-brainstorm), strive worker injection (Phase 1.5), and arc Phase 2.8 (semantic verification).
## Output
Writes `tmp/plans/{timestamp}/design-system-profile.yaml` (session-scoped, ephemeral).
Never writes to `.claude/` — that path is reserved for Claude Code platform files only.
## discoverDesignSystem(repoRoot, sessionCacheDir)
**Input**: `repoRoot` — repository root path; `sessionCacheDir` — caller-provided session-scoped temp directory (e.g. `tmp/plans/{timestamp}`)
**Output**: `design-system-profile.yaml` (written to `{sessionCacheDir}/`), profile object returned to caller
### Phase 0: Pre-flight
```
// sessionCacheDir is passed by caller (e.g. tmp/plans/{timestamp})
IF {sessionCacheDir}/design-system-profile.yaml EXISTS:
RETURN cached profile // Re-use within same session
ELSE:
BEGIN tiered scan
```
### Phase 1: Tiered Scanning
Scanning proceeds in 3 tiers (Tier 0: root manifests, Tier 1: shallow scan, Tier 2: deep content scan). Each tier is only entered if the previous tier did not yield a conclusive match (confidence >= 0.90). Early exit saves time in well-configured projects.
See [tiered-scanning.md](references/tiered-scanning.md) for the full signal definitions, file lists, and weight assignments per tier.
### Phase 2–3: Signal Aggregation & Confidence
After all tiers, signals are grouped by category (library, token, variant) and confidence is computed using a weighted formula: `confidence = maxWeight * (matchedCount / totalSignals) ^ 0.3`, with a conclusive single-signal shortcut (weight == 1.0 → confidence = 1.0).
See [signal-aggregation.md](references/signal-aggregation.md) for the aggregation categories, confidence formula, worked examples, and threshold table.
**Winner selection**: The library with the highest confidence is `primary_library`.
If two libraries both exceed 0.50, include both (migration edge case — see §Edge Cases).
### Phase 4–5: Token & Variant System Resolution
Resolves the project's design token format (Tailwind v4 theme, v3 config, Style Dictionary, CSS variables) and variant system (CVA, styled-components, CSS modules). Extracts semantic colors, spacing, border radius, and shadow scales from detected source files.
See [signal-aggregation.md](references/signal-aggregation.md) for the full Phase 4 (Token System Resolution) and Phase 5 (Variant System Resolution) pseudocode.
### Phase 5.5: Domain Inference
Infers the project's business domain (e-commerce, saas, fintech, healthcare, creative, education, content, or general) from 4 signal sources: file/directory keywords (0.4), route patterns (0.3), package dependencies (0.2), and README content (0.1).
Uses a proportional confidence formula: `confidence = sum(matched_weights) / sum(all_weights)`. At least 3 signal sources must agree for confidence >= 0.70. Below that threshold, domain falls back to "general".
Gated by `talisman.yml` → `devise.design_system_discovery.domain_inference.enabled` (default: true). Manual override via `domain_inference.override` bypasses inference entirely.
See [domain-inference.md](references/domain-inference.md) for the full algorithm pseudocode, domain registry (8 domains), signal maps (DOMAIN_KEYWORD_MAP, DOMAIN_ROUTE_MAP, DOMAIN_DEP_MAP), worked examples, and edge cases.
### Phase 6: Component Inventory
```
Glob: {src/,}components/ui/*.tsx (limit 50)
Glob: {src/,}components/**/*.tsx (limit 100, exclude ui/ subdirectory)
components.path = primary component directory
components.naming = detect: PascalCase | kebab-case | snake_case
components.existing = deduplicated list of component names (strip .tsx)
components.count = len(components.existing)
```
### Phase 7: Ancillary Fields
```
accessibility.layer = "radix" IF @radix-ui/* deps >= 3 ELSE "unknown"
class_merge.utility = "cn" IF cn() from utils detected ELSE "clsx" IF clsx used ELSE "none"
class_merge.import = resolved import path of utility
dark_mode.strategy = "class" IF .dark { ... } in CSS ELSE "media" IF @media (prefers-color-scheme) ELSE "unknown"
dark_mode.class_name = "dark" (default shadcn/ui) — read from components.json "darkMode" if present
tailwind.version = "4" | "3" | null
tailwind.config_type = "js" | "ts" | "css" (v4 inline) | null
tailwind.plugins = list of tailwind plugins from config
path_alias = "@" IF tsconfig.json contains "paths": {"@/*": ["./src/*"]} ELSE null
evidence_files = list of all files that contributed a signal (deduplicated)
```
## Output Schema: design-system-profile.yaml
```yaml
# Written to: tmp/plans/{timestamp}/design-system-profile.yaml
# Generated by: discoverDesignSystem() — do not edit manually
library: shadcn_ui # Primary library: shadcn_ui | untitled_ui | custom_design_system | unknown
library_version: "0.8.0" # From components.json "style" or package.json version, null if unknown
confidence: 0.95 # 0.0–1.0 — see confidence formula above
tokens:
format: tailwind-v4-theme # tailwind-v4-theme | tailwind-v3-config | style-dictionary | css-variables | unknown
source_file: app/globals.css # Relative path to token source
semantic_colors:
background: "oklch(1 0 0)"
foreground: "oklch(0.145 0 0)"
primary: "oklch(0.205 0 0)"
# ... additional token values
spacing_scale: [] # List of spacing values, empty if not detected
border_radius_scale:
default: "0.625rem" # --radius from components.json or CSS
shadow_scale: [] # List of shadow values, empty if not detected
variants:
system: cva # cva | css-in-js | css-modules | unknown
pattern: class-variance-authority
components:
path: src/components/ui # Primary component directory (relative)
naming: PascalCase # PascalCase | kebab-case | snake_case
existing: # Discovered component names
- Button
- Card
- Dialog
- Input
count: 4
accessibility:
layer: radix # radix | unknown
class_merge:
utility: cn # cn | clsx | none
import: "@/lib/utils"
dark_mode:
strategy: class # class | media | unknown
class_name: dark
tailwind:
version: "4" # "4" | "3" | null
config_type: css # js | ts | css | null
plugins: [] # e.g., ["@tailwindcss/typography", "tailwindcss-animate"]
domain:
inferred: "e-commerce" # Business domain: e-commerce | saas | fintech | healthcare | creative | education | content | general
confidence: 0.90 # 0.0–1.0 — proportional weighted formula (NOT library detection formula)
source: "inferred" # "inferred" | "talisman_override" | "disabled" | "low_confidence"
path_alias: "@" # "@" | null
evidence_files:
- package.json
- components.json
- app/globals.css
```
## Edge Cases
8 edge cases are handled: Monorepo (EC-1), Migration (EC-2), Custom-on-Radix (EC-3), Bare Tailwind (EC-4), Figma Code Connect (EC-5), Storybook-Only (EC-6), CSS Modules (EC-7), RSC (EC-8).
See [edge-cases.md](references/edge-cases.md) for detection criteria and handling rules for each case.
## discoverUIBuilder(sessionCacheDir, repoRoot, detectedLibrary, figmaFramework)
**Input**: `sessionCacheDir` — session-scoped temp directory; `repoRoot` — repository root path; `detectedLibrary` — (optional) library from `discoverDesignSystem()`, null for independent operation; `figmaFramework` — (optional) framework from `discoverFigmaFramework()`, null when Figma data unavailable
**Output**: `builder-profile.yaml` (written to `{sessionCacheDir}/`), builder config object returned to caller or null
Discovers which UI builder MCP is available. Operates independently of `discoverDesignSystem()` — when called without `detectedLibrary`, skips library-dependent steps (2-4) and runs heuristic-only MCP detection. When called with `detectedLibrary`, runs the full 5-step priority cascade.
Called after `discoverDesignSystem()` during devise Phase 0.5 and strive Phase 1.5. Called independently during design-prototype Phase 0 (Layer 3).
5-step priority cascade: session cache → talisman binding (0.95) → project skill frontmatter (0.90) → plugin skill frontmatter (0.90) → known MCP registry + heuristic (0.50). First match wins. Steps 2-4 require `detectedLibrary`; Step 5 runs unconditionally.
See [ui-builder-discovery.md](references/ui-builder-discovery.md) for the full algorithm, `parseBuilderFrontmatter()`, known MCP registry, heuristic detection, and `builder-profile.yaml` output schema.
## discoverFrontendStack(repoRoot)
**Input**: `repoRoot` — repository root path
**Output**: frontend stack profile object with framework, version, build tool, CSS framework, and confidence
Extends the existing `detectTypeScriptStack()` with version extraction for the design-prototype pipeline (Layer 1 of 3-layer detection). Extracts major version from `package.json` semver strings, detects build tool (vite/next/webpack), and identifies CSS framework with version (Tailwind v3 vs v4).
Fallback: `{ framework: null, css_framework: "tailwind", css_version: 4, confidence: 0.0 }` — ensures the pipeline always has a valid CSS target.
See [tiered-scanning.md](references/tiered-scanning.md) for the full algorithm, `extractMajor()` helper, output schema, and relationship to `detectTypeScriptStack()`.
## discoverFigmaFramework(figmaApiResponse, nodeId)
**Input**: `figmaApiResponse` — full Figma API response object; `nodeId` — target node ID from Figma URL
**Output**: detection result with framework identifier, numeric score (0.0-1.0), match details, and alternatives — or null-safe fallback
Analyzes Figma API component metadata (component names, variant props, icon names, typography styles, effect styles, remote flags) to identify which UI library a design references. Layer 2 of the 3-layer detection pipeline. Called during `design-prototype` Phase 0 after Figma data is fetched. Not called in text-only (`--describe`) mode.
Uses weighted signal matching (component 0.35, variant 0.25, icon 0.15, typography 0.10, effect 0.05, remote 0.10) against the framework signature registry. Returns `framework: null` when score < 0.40 or margin between top two candidates < 0.15.
See [figma-framework-detection.md](references/figma-framework-detection.md) for the full algorithm, signal weights, error handling, and output schema.
See [figma-framework-signatures.md](references/figma-framework-signatures.md) for the framework signature registry (untitled_ui, shadcn_ui, material_ui, ant_design).
## composeDesignContext(frontendStack, figmaFramework, builderMCP, mode)
**Input**: `frontendStack` — Layer 1 output; `figmaFramework` — Layer 2 output (null in text-only mode); `builderMCP` — Layer 3 output (null when no builder); `mode` — `"url"` or `"describe"`
**Output**: unified `DesignContext` object with `synthesis_strategy` (`"library"` | `"hybrid"` | `"tailwind"`)
Merges all 3 detection layers into a single context consumed by `design-prototype` Phase 1+. Includes conflict resolution (e.g., Vue project + shadcn Figma → tailwind), mode guard for text-only paths, and timeout budget (5000ms default).
See [design-context.md](references/design-context.md) for the full composition algorithm, decision matrix, conflict resolution rules, parallelization strategy, and output schema.
## Integration Points
### devise Phase 0.5 (Pre-Brainstorm)
```
profile = discoverDesignSystem(repoRoot, sessionCacheDir)
IF profile.confidence >= talisman.devise.design_system_discovery.confidence_threshold:
INJECT profile summary into brainstorm context
SET brainstorm_context.design_system = profile
// discoverUIBuilder() runs immediately after discoverDesignSystem()
uiBuilder = discoverUIBuilder(sessionCacheDir, repoRoot)
IF uiBuilder is not null:
INJECT builder summary into brainstorm context
SET brainstorm_context.ui_builder = uiBuilder
```
### strive Worker Injection (Phase 1.5)
See [strive worker-prompts.md](../strive/references/worker-prompts.md) for the
component constraint injection protocol.
Workers receive a trimmed profile (max `talisman.strive.frontend_component_context.max_profile_lines` lines).
### arc Phase 2.8 Semantic Verification
During semantic verification, the profile validates that implementation code:
- Uses the correct component import paths (`@/components/ui/*` for shadcn/ui)
- Applies the correct variant system (cva() calls, not ad-hoc className strings)
- Respects dark mode strategy (no hardcoded colors, only semantic tokens)
## Configuration
```yaml
# talisman.yml
devise:
design_system_discovery:
enabled: true # Master switch (default: true)
confidence_threshold: 0.5 # Min confidence to inject profile into context
strive:
frontend_component_context:
enabled: true # Inject profile into strive worker prompts (default: true)
max_profile_lines: 200 # Cap profile size before injection (default: 200)
token_cap_lines: 50 # Cap token constraint section (default: 50)
stack_awareness:
design_compliance: true # Enable design-system-compliance-reviewer (default: true)
```
## Cross-References
- [stacks](../stacks/SKILL.md) — Stack detection; design system discovery is a sub-layer
- [frontend-design-patterns](../frontend-design-patterns/SKILL.md) — Implementation patterns using the discovered system
- [design-sync](../design-sync/SKILL.md) — Figma design synchronization workflow
- [strive](../strive/SKILL.md) — Worker prompt injection for component constraints
- [untitledui-mcp](../untitledui-mcp/SKILL.md) — Built-in UntitledUI builder skill with `builder-protocol` frontmatter (detected by `discoverUIBuilder()`)
- [domain-inference.md](references/domain-inference.md) — Domain inference algorithm, signal maps, and worked examples
Files in this skill
- SKILL.md
- source.json
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.