design-system-builder — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited design-system-builder (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Build and evolve enterprise-quality CSS Design Systems on top of Chameleon web components
ch-edit, ch-dialog, ch-accordion-render, etc.) with structure, behavior, and interactivity::part() selectors, and slotted-content stylingComponent-specific styling information — shadow parts, CSS custom properties, and shadow DOM layout — is maintained by the chameleon-controls-library skill. This skill provides the DS-level patterns for applying those styling APIs within a design system context
┌──────────────────────────────────────────────────────┐
│ Application │
├──────────────────────────────────────────────────────┤
│ Design System (CSS + Tokens + Docs) │
├──────────────────────────────────────────────────────┤
│ Chameleon (Web Components) │
├──────────────────────────────────────────────────────┤
│ Browser Platform │
└──────────────────────────────────────────────────────┘CRITICAL — Chameleon skill required: Before writing any component CSS example or documentation, you MUST invoke the chameleon-controls-library skill (via the Skill tool). The DS handles styling only (CSS bundles, classes, tokens) — component APIs (properties, events, slots, model shapes) are documented exclusively in the Chameleon skill. Skipping it leads to wrong prop names, missing events, and broken component wiringFollow these steps in order. Never skip steps. Ask the user when in doubt
Before building anything, ask the user:
If the user says "basta" (or equivalent like "that's enough", "just build it", "go ahead"), stop asking questions and proceed with reasonable defaults for anything not yet discussed
Defaults when not specified:
Before writing any files, present the user with a summary:
Wait for user approval before proceeding
Use the scaffold script to create the initial DS structure:
node <path-to-skill>/scripts/scaffold.mjs --name <ds-name> --dir <target-dir> --brands <brand1,brand2>If the script is not available or fails, create the structure manually following the Directory Structure Reference
Build the DS layer by layer, always in this order (ITCSS):
base.css using the generate-base.mjs script. See below for the two workflows (with/without Figma input)After each layer, update the architecture diagram (generate a architecture.md Mermaid diagram in the DS root)
#### Base Layer — generate-base.mjs
The base.css file is generated by a script, not written by hand. This ensures token fidelity and prevents prefix/naming errors
node <path-to-skill>/scripts/generate-base.mjs --input <tokens.json> --output <ds-root>/base/base.cssPath A — User provides Figma input:
get_variable_defs and/or get_design_context)generate-base.mjs for the input schema)<ds-root>/tokens/<ds-name>-base-input.jsongenerate-base.mjs to produce base.cssPath B — No Figma input:
generate-base.mjsThe script enforces: no DS-name prefix, no em/rem, semantic spacing names, standard body resets
After building CSS and/or documentation, audit all output against these rules before proceeding:
::part() selector must reference a part that exists in the component's styling.md file (consult the chameleon-controls-library skill). No invented parts::part(), no sibling (~), child (>), or descendant ( ) combinators are allowed. ::part() is terminal for combinators per the CSS spec. Each ::part() must stand alone::before, ::after, and ::placeholder can follow ::part(). Pseudo-elements like ::selection and ::first-line CANNOT be chained after ::part(). Standard pseudo-classes (:hover, :focus-visible, :disabled) are always allowed:disabled pseudo-class instead of the [disabled] attribute selector. Keep [aria-disabled="true"] as-is.md docs and showcase .lit.ts files must use verified Chameleon properties, events, and slots. Invoke the chameleon-controls-library skill to verify before writing examples. Common mistakes: label vs caption vs accessibleName, slot names, model shapesch-* tag namesIf any violation is found, fix it immediately before moving to the next phase
For each component built, create co-located .md documentation. See Documentation Reference
Every DS built with this skill MUST include an inner skill at docs/ that enables AI agents (and developers) to use the DS for vibe coding. This skill follows the reference pattern defined in Inner Skill Pattern and must be generated/updated every time the DS evolves
The inner skill lives at {ds-root}/docs/ and includes:
docs/
├── SKILL.md # Entry point — how to use this DS
├── references/
│ ├── component-bundles-table.md # Component → bundle mapping table
│ ├── bundles-index.md # Index of all bundles with links
│ ├── themes-and-variants.md # Theme documentation
│ ├── design-foundations/ # Design language documentation
│ │ ├── color-system.md # Color categories, states, elevation
│ │ ├── typography-system.md # Roles, classes, line-heights
│ │ ├── spacing-system.md # Grid, tokens, border-radius
│ │ ├── icons-system.md # Sizes, classes, icon colors, resolver setup
│ │ ├── design-patterns.md # Buttons, forms, typography hierarchy
│ │ └── figma-token-mapping.md # Figma → token translation
│ ├── installation/
│ │ └── README.md # Framework-specific setup guides
│ └── bundles/
│ ├── components/
│ │ ├── button.md + button.css # Co-located docs + implementation
│ │ ├── dialog.md + dialog.css
│ │ └── …
│ ├── utils/
│ ├── base/
│ ├── scope/
│ └── chameleon/Inner SKILL.md must include:
getImagePathCallback registration), available icon keys, and how consumers reference icons in ch-image and component item modelsSee Usage & Consumption Reference for the detailed ch-theme/getBundles patterns to document in the inner skill
Rules for the inner skill:
components/ MUST have a corresponding .md in docs/references/bundles/components/ documenting its classes, "Applies to", tokens consumed, and statescomponent-bundles-table.md must list every component and its required bundlesbundles-index.md must link to every bundle's .md and .cssGenerate a navigable showcase app so the DS can be browsed visually:
node <path-to-skill>/scripts/scaffold-showcase.mjs --ds-dir <ds-root> --ds-name <ds-name> --components <comp1,comp2>ch-theme/getBundles. It is the first consumer of the DSshowcase/src/styles/showcase-overrides.scss. Each block is marked with TEMP: {component} comments. When the DS adds the component's CSS file, the corresponding temporary block MUST be removed from the showcaseSee Showcase App Reference for full details on structure, Kasstor patterns, and the temporary styles workflow
Check each component against the 10 acceptance criteria. See Quality Gates Reference
When the user requests a component, determine if it exists in Chameleon:
| Category | Chameleon Components |
|---|---|
| Forms | ch-edit, ch-checkbox, ch-switch, ch-slider, ch-radio-group-render, ch-combo-box-render, ch-color-picker, ch-color-field |
| Layout | ch-layout-splitter, ch-flexible-layout-render, ch-sidebar, ch-virtual-scroller |
| Data Display | ch-tabular-grid-render, ch-tree-view-render, ch-smart-grid, ch-paginator-render |
| Navigation | ch-tab-render, ch-navigation-list-render, ch-action-list-render, ch-segmented-control-render |
| Actions | ch-action-group-render, ch-action-menu-render |
| Overlays | ch-dialog, ch-popover, ch-tooltip |
| Feedback | ch-notifications, ch-next-progress-bar, ch-progress, ch-status |
| Content | ch-accordion-render, ch-markdown-viewer, ch-image, ch-code, ch-textblock |
| Media | ch-barcode-scanner, ch-qr, ch-live-kit-room |
| Other | ch-shortcuts, ch-intersection-observer, ch-rating, ch-chat |
If the component exists in Chameleon: Create only the CSS styling (classes, tokens, ::part() selectors) — never reimplement functionality
If the component does NOT exist in Chameleon: Inform the user and offer to implement it using Kasstor — a Lit-based library that builds cross-framework web components compatible with any stack (React, Angular, Vue, vanilla). Kasstor components integrate seamlessly with Chameleon and follow the same web component standards. Use the Kasstor skill (when available) for implementation guidance
When the user points to an existing DS directory:
.dark & inside component CSS)padding-block, inline-size, etc. for RTL support{component}-{variant}em or rem units. All sizing uses design tokens or px from the 4pt grid. Only exception: user explicitly requests em/rem. See Spacing System::part() selector without first checking the component's styling.md (consult the chameleon-controls-library skill). Invalid parts silently fail and produce dead CSSfonts/ directory, partitioned by unicode-range subsets for optimal loadingbutton-primary, accordion-filled. Tokens use semantic names like --color-accent-primary-default, --spacing-padding-xl. NEVER prefix with the DS name (e.g., ~~nova-btn-primary~~, ~~--nova-green-300~~). Primitive tokens in base.css may use a neutral color-scale naming (e.g., --green-300, --neutral-950) but never the DS brand name<ch-edit class="input">, NOT <div class="input"><ch-edit></ch-edit></div>. CSS selectors target the class on the host, and ::part() selectors descend from that class. No wrapper-then-descendant selectors.class ch-component::part(…). Always .class::part(…). The class IS on the component host. CSS bundle files must NEVER contain Chameleon tag names in selectorsbutton-icon-only, not btn-icon. Full words for readability and discoverability attributes** — Don't assume elements use data-* attributes or [data-icon]` selectors unless the user establishes this convention--spacing-padding-xs, --spacing-padding-s, --spacing-gap-m. NEVER use numbered tokens like --spacing-1, --spacing-2 unless they come directly from Figma or the user defines them. Numbers add no semantic meaning::part(), you CANNOT use sibling (~), child (>), or descendant ( ) combinators to reach another part or element. Each ::part() selector is terminal per the CSS spec. Example of INVALID CSS: .checkbox::part(input):focus-visible ~ .checkbox::part(option) — this silently fails. Instead, target the part directly: .checkbox::part(option):focus-visible:disabled instead of [disabled] attribute selector for disabled state styling. The pseudo-class is more robust and follows CSS best practices. Keep [aria-disabled="true"] as a companion selector for elements that don't support the :disabled pseudo-class:hover, :active, :focus-visible, :disabled, :focus, :focus-within) and pseudo-elements (::before, ::after, ::placeholder) can follow ::part(). Pseudo-elements like ::selection and ::first-line CANNOT be chained after ::part(). For state styling, use compound part selectors instead: .class::part(input disabled)<button> and <a> elements in their shadow DOM. NEVER write cursor: pointer, border: none, appearance: none, or text-decoration: none on ::part() selectors that target these internal elements — it's redundant dead CSSdisabled does NOT mean the component has a [disabled] HTML attribute selector. Always prefer compound part selectors for state styling: .class::part(header disabled), NOT .class[disabled]::part(header). Consult the chameleon-controls-library skill's per-component styling.md files to understand which parts exist and how state parts combine with structural partsConsult these reference files for detailed guidance on each topic:
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.