git clone https://github.com/Intense-Visions/harness-engineering
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/harness-design-system" ~/.claude/skills/intense-visions-harness-engineering-harness-design-system-c5014a && rm -rf "$T"
agents/skills/claude-code/harness-design-system/SKILL.mdHarness Design System
Token-first design management. Discover existing design patterns, define intent through curated palettes and typography, generate W3C DTCG tokens, and validate every color pair for WCAG compliance.
When to Use
- Starting a new project that needs design tokens (colors, typography, spacing)
- Adding design consistency to an existing project that lacks a token system
- When
triggers fire and the project has noon_project_initdesign-system/tokens.json - When
triggers fire with design scope (new theme, new component library, rebrand)on_new_feature - Regenerating tokens after stakeholder feedback on palette or typography choices
- NOT for accessibility auditing of existing components (use harness-accessibility)
- NOT for aesthetic direction, mood boards, or brand strategy (use harness-design, Phase 4)
- NOT for platform-specific implementation of tokens into CSS/Tailwind/etc. (use harness-design-web/mobile, Phase 5)
- NOT for fixing individual contrast failures in code (use harness-accessibility fix phase)
Process
Phase 1: DISCOVER -- Detect Existing Design System
-
Read existing design files. Search for:
-- existing W3C DTCG tokensdesign-system/tokens.json
-- existing design intent documentationdesign-system/DESIGN.md
-- Tailwind CSS configuration with theme overridestailwind.config.*- CSS files with custom properties (
,--color-*
,--font-*
)--space-*
,theme.ts
,theme.js
-- CSS-in-JS or preprocessor variablesstyles/variables.*
-
Check harness configuration. Read
for:harness.config.json
-- enforcement level (design.strictness
,strict
,standard
)permissive
-- which platforms are enabled (web, mobile)design.platforms
-- path to tokens file (default:design.tokenPath
)design-system/tokens.json
-- path to design intent doc (default:design.aestheticIntent
)design-system/DESIGN.md
-
Detect framework. Identify the CSS strategy in use:
- Tailwind CSS (presence of
)tailwind.config.* - CSS-in-JS (styled-components, Emotion, Stitches imports)
- CSS Modules (
or.module.css
files).module.scss - Vanilla CSS/SCSS (global stylesheets)
- None detected (greenfield)
- Tailwind CSS (presence of
-
Identify existing patterns. Use Grep to find:
- Color values: hex codes (
), rgb/hsl functions#[0-9a-fA-F]{3,8} - Font declarations:
properties,font-family
rules@font-face - Spacing patterns: margin/padding values, gap values
- Count unique values to estimate design debt (many unique colors = high debt)
- Color values: hex codes (
-
Load industry recommendations. If an industry is specified (via CLI arg or config), read the industry profile from
. This provides sector-specific guidance on color psychology, typography conventions, and regulatory considerations.agents/skills/shared/design-knowledge/industries/{industry}.yaml -
Report findings before proceeding. Present a summary:
- Existing token file: yes/no
- Framework detected: [name]
- Unique colors found: [count]
- Unique fonts found: [count]
- Industry profile loaded: yes/no
- Design debt assessment: low/medium/high
Phase 2: DEFINE -- Select Palette, Typography, and Spacing
-
Present palette options. Load curated palettes from
. Filter by industry tags if an industry is specified. Present 3-5 palette options with:agents/skills/shared/design-knowledge/palettes/curated.yaml- Palette name and description
- Primary, secondary, accent, neutral color ramps
- Semantic colors (success, warning, error, info)
- Pre-computed contrast ratios for common pairs (text-on-background)
-
Present typography pairings. Load pairings from
. Present 3-5 options with:agents/skills/shared/design-knowledge/typography/pairings.yaml- Heading font + body font combination
- Fallback stacks for each font
- Recommended size scale (base size, scale ratio)
- Line height and letter spacing recommendations
-
Define spacing scale. Default: 4px base with multipliers [0.25, 0.5, 1, 1.5, 2, 3, 4, 6, 8, 12, 16]. Allow customization of:
- Base unit (4px, 8px)
- Scale multipliers
- Named aliases (xs, sm, md, lg, xl, 2xl, etc.)
-
Capture design intent. Ask the user to define:
- Style: minimal, expressive, corporate, playful, editorial
- Tone: warm, cool, neutral, bold, muted
- Key differentiator: what makes this product's visual identity unique
- Anti-patterns: specific design choices to avoid
-
Confirm all choices. Present a complete summary of palette, typography, spacing, and intent. Wait for user confirmation before generating. This is a hard gate -- no generation without confirmation.
Phase 3: GENERATE -- Create Tokens and Documentation
-
Generate
in W3C Design Token Community Group (DTCG) format. Structure:design-system/tokens.json{ "color": { "primary": { "50": { "$value": "#eff6ff", "$type": "color", "$description": "Lightest primary" }, "500": { "$value": "#3b82f6", "$type": "color", "$description": "Base primary" }, "900": { "$value": "#1e3a5f", "$type": "color", "$description": "Darkest primary" } }, "semantic": { "success": { "$value": "{color.green.500}", "$type": "color", "$description": "Success state" }, "error": { "$value": "{color.red.500}", "$type": "color", "$description": "Error state" } } }, "typography": { "heading": { "fontFamily": { "$value": "Inter, system-ui, sans-serif", "$type": "fontFamily" }, "fontWeight": { "$value": 600, "$type": "fontWeight" } }, "body": { "fontFamily": { "$value": "Source Sans 3, system-ui, sans-serif", "$type": "fontFamily" }, "fontSize": { "$value": "1rem", "$type": "dimension" } } }, "spacing": { "xs": { "$value": "4px", "$type": "dimension", "$description": "Extra small spacing" }, "sm": { "$value": "8px", "$type": "dimension", "$description": "Small spacing" }, "md": { "$value": "16px", "$type": "dimension", "$description": "Medium spacing" }, "lg": { "$value": "24px", "$type": "dimension", "$description": "Large spacing" }, "xl": { "$value": "32px", "$type": "dimension", "$description": "Extra large spacing" } } } -
Generate
with:design-system/DESIGN.md- Aesthetic direction (style, tone, differentiator)
- Color usage guidelines (when to use primary vs. secondary vs. accent)
- Typography hierarchy (h1-h6 sizing, body text, captions)
- Spacing conventions (component padding, layout gaps, section margins)
- Anti-patterns (explicitly forbidden design choices)
- Platform-specific notes (Tailwind class mappings, CSS variable names)
- Strictness override instructions (how to change
)design.strictness
-
Populate the knowledge graph. If a graph exists at
, run.harness/graph/
fromDesignIngestor
to create graph nodes for:packages/graph/src/ingest/DesignIngestor.ts- Each color token (type:
, subtype:design_token
)color - Each typography token (type:
, subtype:design_token
)typography - Each spacing token (type:
, subtype:design_token
)spacing - The aesthetic intent (type:
) with style, tone, differentiator, and strictness propertiesaesthetic_intent
edges from the project to the aesthetic intent nodedeclares_intent
- Each color token (type:
Phase 4: VALIDATE -- Verify Tokens and Compliance
-
Parse
against W3C DTCG structure. Verify:tokens.json- Every token has
and$value
fields$type - Token references (e.g.,
) resolve to existing tokens{color.primary.500} - No orphan tokens (defined but never referenced in DESIGN.md or usage guidelines)
- Every token has
-
Check color contrast compliance. For every declared contrast pair:
- Calculate the contrast ratio using the WCAG 2.1 relative luminance formula
- Normal text (< 18px): require >= 4.5:1 ratio (WCAG AA)
- Large text (>= 18px or >= 14px bold): require >= 3:1 ratio (WCAG AA)
- Report each pair with its ratio and pass/fail status
-
Verify typography completeness. Check that:
- Every font family declaration includes a fallback stack (at least
orsystem-ui
/sans-serif
/serif
)monospace - Heading and body fonts are different (unless intentional single-font system)
- Font weights are specified as numbers, not names
- Every font family declaration includes a fallback stack (at least
-
Verify spacing scale. Check that:
- Spacing values are monotonically increasing
- No gaps in the scale (e.g., jumping from 8px to 48px with nothing between)
- Base unit is consistent across all values
-
Run project health check. Execute
to ensure the new files do not break any existing constraints.harness validate -
Report validation results. Present a summary:
- DTCG structure: pass/fail with details
- Contrast pairs: N passed, M failed (list failures)
- Typography: pass/fail with details
- Spacing: pass/fail with details
- Harness validate: pass/fail
Harness Integration
-- Run after generating tokens to verify project health. Token generation must not break existing constraints.harness validate
-- Run after token changes to refresh the knowledge graph. Updated graph enables impact analysis when tokens are modified later.harness scan
(DesignIngestor
) -- Parsespackages/graph/src/ingest/DesignIngestor.ts
andtokens.json
to create graph nodes representing the design system. Called during the GENERATE phase.DESIGN.md
(DesignConstraintAdapter
) -- Enforces design constraints by checking forpackages/graph/src/constraints/DesignConstraintAdapter.ts
edges in the graph. Used during validation to detect constraint violations.VIOLATES
-- When tokens change, impact analysis traces which components consume affected tokens, enabling targeted re-validation.harness-impact-analysis
Success Criteria
exists and is valid W3C DTCG format (every token hasdesign-system/tokens.json
and$value
)$type
exists with aesthetic direction, usage guidelines, anti-patterns, and platform notesdesign-system/DESIGN.md- All declared color contrast pairs pass WCAG AA thresholds (4.5:1 normal text, 3:1 large text)
- Every font family has a fallback stack
- Spacing scale is monotonically increasing with no gaps
- Graph nodes created for each token (if graph exists at
).harness/graph/
passes after token generationharness validate- User confirmed palette and typography choices before generation
Examples
Example: SaaS Dashboard Project
Context: New SaaS analytics dashboard. Industry:
saas. No existing design system.
DISCOVER output:
Design System Discovery Report ------------------------------- Existing token file: No Framework detected: Tailwind CSS (tailwind.config.ts) Unique colors found: 23 (high debt -- colors scattered across components) Unique fonts found: 4 (medium debt -- inconsistent font usage) Industry profile: Loaded (saas) -- recommends professional blues, clean sans-serif Design debt assessment: High -- no centralized design system, ad-hoc color usage
DEFINE choices:
Selected palette: "Ocean Professional" (blue primary, slate neutral, emerald accent) Selected typography: Inter (headings, 600 weight) + Source Sans 3 (body, 400 weight) Spacing base: 4px with standard multipliers Style: Minimal, data-focused Tone: Cool, professional Differentiator: Dense information display with generous whitespace between sections Anti-patterns: No gradients on data elements, no decorative borders on cards
GENERATE output (tokens.json snippet):
{ "color": { "primary": { "50": { "$value": "#eff6ff", "$type": "color", "$description": "Background tint" }, "100": { "$value": "#dbeafe", "$type": "color", "$description": "Hover state" }, "500": { "$value": "#3b82f6", "$type": "color", "$description": "Primary action" }, "700": { "$value": "#1d4ed8", "$type": "color", "$description": "Primary text on light" }, "900": { "$value": "#1e3a5f", "$type": "color", "$description": "Darkest primary" } }, "neutral": { "50": { "$value": "#f8fafc", "$type": "color", "$description": "Page background" }, "900": { "$value": "#0f172a", "$type": "color", "$description": "Primary text" } } }, "typography": { "heading": { "fontFamily": { "$value": "Inter, system-ui, sans-serif", "$type": "fontFamily" } }, "body": { "fontFamily": { "$value": "Source Sans 3, system-ui, sans-serif", "$type": "fontFamily" } } } }
VALIDATE output:
Validation Results ------------------ DTCG structure: PASS (42 tokens, all have $value and $type) Contrast pairs: PASS (12/12 pairs meet WCAG AA) - primary-700 on neutral-50: 8.1:1 PASS (normal text) - neutral-900 on neutral-50: 15.4:1 PASS (normal text) - neutral-50 on primary-500: 4.7:1 PASS (normal text) Typography: PASS (all fonts have fallback stacks) Spacing: PASS (monotonically increasing, no gaps) Harness validate: PASS
Rationalizations to Reject
| Rationalization | Reality |
|---|---|
| "The project already has a tailwind.config with colors — I can derive the token set from that and skip the DEFINE phase." | Existing Tailwind config represents design debt, not design intent. The DEFINE phase exists to make deliberate choices about palette and typography. Deriving tokens from scattered config perpetuates the inconsistency the skill is meant to resolve. |
| "One of the contrast pairs is 4.3:1 — close enough to 4.5:1 to pass. I'll mark it as passing." | 4.3:1 fails WCAG AA for normal text. There is no "close enough." Flag the failure and ask the user to choose an alternative. Silently accepting sub-threshold contrast is a compliance defect. |
| "The user confirmed the palette in our conversation, so I can skip the formal confirmation gate and generate immediately." | The confirmation gate exists as a structural checkpoint, not a courtesy. Generate only after presenting the full palette + typography + spacing summary and receiving explicit approval. Conversation context can drift. |
| "There are no existing design files, so I can skip the DISCOVER phase and go straight to defining." | The DISCOVER phase also detects the CSS framework and existing color/font usage. Skipping it means the generated tokens may not map to the actual CSS strategy and the design debt assessment is lost. |
| "Fonts without fallback stacks are probably fine — modern browsers handle missing fonts gracefully." | A missing fallback stack is a token validation failure regardless of browser behavior. Every token must include at least one generic fallback. This is a VALIDATE phase gate, not a style preference. |
Gates
These are hard stops. Violating any gate means the process has broken down.
- No tokens generated without user confirming palette and typography choices. The DEFINE phase must end with explicit user confirmation. Do not auto-select and generate.
- No
written without passing DTCG schema validation. Every token must havetokens.json
and$value
. Malformed tokens are rejected before writing to disk.$type - No contrast pair allowed below 4.5:1 for normal text. If a selected palette produces a failing contrast pair, flag it and ask the user to choose an alternative. Do not silently accept.
- No fonts without fallback stacks. Every
token must include at least one generic fallback (fontFamily
,sans-serif
,serif
, ormonospace
).system-ui - No spacing scale with non-monotonic values. If a user customizes spacing, validate that values increase. Reject scales where
is larger thanmd
.lg
Escalation
- After 3 failed contrast validations on the same palette: Suggest an alternative palette from the curated set that has pre-verified contrast ratios. Present the alternative with a comparison showing which pairs now pass.
- When user rejects all curated palettes: Accept custom colors but warn: "Custom colors have not been pre-validated for contrast compliance. Running full contrast check now." Run validation and report results before generating.
- When existing project has conflicting design patterns: Surface the specific conflicts (e.g., "Found 5 different blue values across 12 components"). Ask the user to choose: consolidate to the new palette, or map each existing value to the nearest token. Do not silently override existing colors.
- When
is set todesign.strictness
but contrast fails: Still report the failure as a warning. Permissive mode does not suppress contrast checks -- it only changes the severity from error to warning.permissive - When the graph is unavailable: Skip the graph population step in GENERATE. Log: "Graph not available at .harness/graph/ -- skipping token graph population. Run
later to populate." Continue with file generation.harness scan