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-web" ~/.claude/skills/intense-visions-harness-engineering-harness-design-web-617435 && rm -rf "$T"
agents/skills/claude-code/harness-design-web/SKILL.mdHarness Design Web
Token-bound web component generation. Scaffold from design tokens and aesthetic intent, implement with Tailwind/CSS and React/Vue/Svelte patterns, and verify every value references the token set — no hardcoded colors, fonts, or spacing.
When to Use
- Generating new web components that must conform to the project's design system tokens
- When
triggers fire with web UI scope requiring token-bound component generationon_new_feature - When
triggers fire and new components contain hardcoded design values that should reference tokenson_commit - Implementing design intent from
into concrete Tailwind classes, CSS custom properties, or CSS-in-JS theme valuesdesign-system/DESIGN.md - Converting mockups or wireframes into token-bound component code for React, Vue, or Svelte
- NOT for generating design tokens themselves (use harness-design-system)
- NOT for establishing aesthetic direction or anti-patterns (use harness-design)
- NOT for accessibility auditing (use harness-accessibility)
- NOT for mobile platform components (use harness-design-mobile)
Process
Phase 1: SCAFFOLD — Read Tokens, Detect Framework, Plan Structure
-
Read design tokens. Load
(W3C DTCG format). Extract:design-system/tokens.json- Color tokens: primary, secondary, accent, neutral ramps, semantic colors (success, warning, error, info)
- Typography tokens: heading and body font families, font weights, font sizes, line heights
- Spacing tokens: spacing scale values (xs through 2xl or equivalent)
- If
does not exist, stop and instruct the user to rundesign-system/tokens.json
first.harness-design-system
-
Read design intent. Load
for:design-system/DESIGN.md- Aesthetic direction (style, tone, differentiator) from harness-design output
- Anti-patterns to avoid (e.g., "no gradients on data elements," "no decorative borders")
- Platform-specific web notes (CSS strategy preferences, animation guidelines, responsive behavior)
- If
does not exist, warn the user and proceed with tokens only. Recommend runningdesign-system/DESIGN.md
for richer output.harness-design
-
Check harness configuration. Read
for:harness.config.json
— enforcement level (design.strictness
,strict
,standard
). Default topermissive
.standard
— confirmdesign.platforms
is in the platforms list.web
— custom token path (default:design.tokenPath
).design-system/tokens.json
-
Detect web framework. Scan the project for:
- React:
containspackage.json
orreact
dependency,next
/.tsx
files exist.jsx - Vue:
containspackage.json
orvue
dependency,nuxt
files exist.vue - Svelte:
containspackage.json
orsvelte
,@sveltejs/kit
files exist.svelte - Vanilla: No framework detected, output plain HTML/CSS
- If the user specified
, use that override.--framework
- React:
-
Detect CSS strategy. Scan for:
- Tailwind:
exists,tailwind.config.*
directives in CSS,@tailwind
with Tailwind utility patternsclass= - CSS Modules:
or.module.css
files exist.module.scss - CSS-in-JS:
,styled-components
,@emotion/styled
imports detectedstitches - Vanilla CSS: Global
/.css
files with no module or utility pattern.scss - If the user specified
, use that override.--cssStrategy
- Tailwind:
-
Load platform-specific web rules. Read
for web-specific design rules including responsive breakpoints, browser compatibility considerations, and CSS best practices.agents/skills/shared/design-knowledge/platform-rules/web.yaml -
Load anti-pattern definitions. Read anti-pattern files from
:agents/skills/shared/design-knowledge/anti-patterns/
— typographic anti-patterns (too many fonts, inconsistent scales)typography.yaml
— color anti-patterns (hardcoded hex, insufficient contrast)color.yaml
— layout anti-patterns (magic numbers, inconsistent spacing)layout.yaml
— motion anti-patterns (excessive animation, missing reduced-motion)motion.yaml
-
Build token-to-CSS mapping. Create a lookup table that maps each token to its CSS representation based on the detected strategy:
- Tailwind:
maps tocolor.primary.500
/text-primary-500
(requiresbg-primary-500
theme extension)tailwind.config - CSS custom properties:
maps tocolor.primary.500var(--color-primary-500) - CSS-in-JS:
maps tocolor.primary.500theme.color.primary[500]
- Tailwind:
-
Plan component structure. For the requested component(s), define:
- Component file path(s) following project conventions
- Props interface / type definition
- Which tokens will be consumed (colors, typography, spacing)
- Responsive behavior (breakpoints, layout changes)
- Present the scaffold plan to the user before proceeding.
Phase 2: IMPLEMENT — Generate Token-Bound Components
-
Generate framework-specific component code. Based on detected framework:
React (TSX):
- Functional component with TypeScript props interface
- All color values reference tokens (via Tailwind classes, CSS variables, or theme object)
- All typography values reference tokens (font family, weight, size from token set)
- All spacing values reference tokens (padding, margin, gap from spacing scale)
- Export component with display name
Vue (SFC):
- Single File Component with
<script setup lang="ts"> - Props defined with
and TypeScript interfacedefineProps - Scoped styles reference CSS custom properties mapped from tokens
- Template uses token-derived classes or inline styles via CSS variables
Svelte:
- Component with TypeScript
<script lang="ts"> - Props exported with
declarationsexport let - Styles reference CSS custom properties mapped from tokens
- Reactive declarations for computed style values
Vanilla HTML/CSS:
- Semantic HTML structure
- CSS custom properties for all design values
- No inline styles with hardcoded values
-
Generate CSS strategy artifacts. Based on detected CSS strategy:
Tailwind:
- Extend
theme with token values (if not already present)tailwind.config - Map tokens to Tailwind utility classes in components
- Use
sparingly — prefer utility classes in markup@apply - Generate token-to-Tailwind mapping comment block at top of component
CSS Custom Properties:
- Generate
declarations for all consumed tokens:root - Components reference
exclusivelyvar(--token-name) - No hardcoded hex, rgb, hsl, or font values in component styles
CSS-in-JS:
- Generate theme object from tokens
- Components consume theme via provider/hook pattern
- All style values reference theme properties
- Extend
-
Apply design intent constraints. For each generated component:
- Check against anti-patterns from
anddesign-system/DESIGN.mdagents/skills/shared/design-knowledge/anti-patterns/ - Enforce style guidelines (e.g., minimal style means no decorative effects)
- Apply tone-appropriate color usage (e.g., cool tone means no warm accents in neutral UI)
- Respect platform-specific web notes (animation preferences, responsive behavior)
- Check against anti-patterns from
-
Add USES_TOKEN annotations. Insert comments in generated code documenting which tokens are consumed:
/* @design-token color.primary.500 — primary action background */ /* @design-token typography.heading.fontFamily — section heading */ /* @design-token spacing.md — card internal padding */These annotations enable the knowledge graph to create
edges from this component to the consumedUSES_TOKEN
nodes.DesignToken
Phase 3: VERIFY — Check Token Binding and Design Constraints
-
Scan for hardcoded values. Use Grep to search generated files for:
- Hardcoded color values: hex (
),#[0-9a-fA-F]{3,8}
,rgb()
, named colorshsl() - Hardcoded font families:
declarations not referencing tokensfont-family: - Hardcoded spacing: pixel/rem values in margin/padding/gap not from the token scale
- Each finding is a violation: the component uses a value not bound to a token.
- Hardcoded color values: hex (
-
Verify token coverage. For every design value in the generated component:
- Confirm it resolves to a token in
design-system/tokens.json - Confirm the token path is valid (e.g.,
exists in the token tree)color.primary.500 - Report orphan references (token annotations pointing to non-existent tokens)
- Confirm it resolves to a token in
-
Check anti-pattern compliance. Cross-reference generated code against anti-patterns declared in
and the anti-pattern definitions indesign-system/DESIGN.md
:agents/skills/shared/design-knowledge/anti-patterns/- Grep for patterns matching each declared anti-pattern
- Flag violations with file path, line number, and the specific anti-pattern violated
-
Query the knowledge graph. If a graph exists at
:.harness/graph/- Use
to verifyDesignIngestor
nodes exist for all referenced tokensDesignToken - Verify
edges exist for web platform tokensPLATFORM_BINDING - Use
to check forDesignConstraintAdapter
edgesVIOLATES_DESIGN - Report any constraint violations with severity based on
design.strictness
- Use
-
Assign severity based on
:designStrictness
— all findings arepermissiveinfo
— hardcoded values and anti-pattern violations arestandard
, accessibility violations arewarnerror
— hardcoded values arestrict
(blocks), anti-pattern violations areerror
, accessibility violations arewarnerror
-
Report verification results. Present:
WEB-001 [warn] Hardcoded color #3b82f6 — should reference token "color.primary.500" File: src/components/Button.tsx:12 Fix: Replace with Tailwind class "bg-primary-500" or var(--color-primary-500) WEB-002 [info] Anti-pattern: gradient on card background File: src/components/MetricCard.tsx:28 Fix: Use solid background from token "color.neutral.50" -
Run
. After verification, run project-level validation to confirm the new components integrate cleanly.harness validate
Harness Integration
— Run after generating components to verify project health. New files must not break existing constraints.harness validate
— Run after component generation to update the knowledge graph with newharness scan
edges from generated components to consumed tokens.USES_TOKEN
(DesignIngestor
) — Verifies thatpackages/graph/src/ingest/DesignIngestor.ts
nodes exist for all tokens referenced by generated components. If tokens are missing from the graph, runDesignToken
to re-ingest.harness scan
(DesignConstraintAdapter
) — Checks forpackages/graph/src/constraints/DesignConstraintAdapter.ts
edges during the VERIFY phase. Reports constraint violations at the configured strictness level.VIOLATES_DESIGN
— Dependency. This skill reads tokens generated by harness-design-system. If tokens do not exist, instruct the user to run harness-design-system first.harness-design-system
— Dependency. This skill reads aesthetic intent from harness-design output (harness-design
). Anti-pattern enforcement and style constraints come from the design intent document.design-system/DESIGN.md
— When tokens change, impact analysis traces which components consume affected tokens viaharness-impact-analysis
edges. Use this to identify components that need regeneration after token updates.USES_TOKEN
Graph naming convention: This skill uses PascalCase for node types (
DesignToken, DesignConstraint) and UPPER_SNAKE for edge types (USES_TOKEN, PLATFORM_BINDING, VIOLATES_DESIGN) as conceptual labels. The graph schema registers these as snake_case identifiers (design_token, design_constraint, uses_token, platform_binding, violates_design). The adapter classes (DesignIngestor, DesignConstraintAdapter) handle the mapping — always use the adapters rather than constructing graph queries with raw type names.
Success Criteria
- Generated components reference design tokens exclusively — no hardcoded color, font, or spacing values
- Framework detection correctly identifies React, Vue, Svelte, or vanilla projects
- CSS strategy detection correctly identifies Tailwind, CSS Modules, CSS-in-JS, or vanilla CSS
- Token-to-CSS mapping produces correct output for each CSS strategy (Tailwind classes, CSS custom properties, theme object references)
annotations are present for every consumed token@design-token- Anti-pattern compliance check catches violations declared in
design-system/DESIGN.md - Verification report uses severity levels matching
configurationdesign.strictness
passes after component generationharness validate
Examples
Example: React + Tailwind Button Component
Context: SaaS dashboard project. React with Tailwind CSS. Tokens generated by harness-design-system. Design intent established by harness-design (minimal style, cool professional tone).
SCAFFOLD output:
Framework detected: React (Next.js) CSS strategy: Tailwind CSS (tailwind.config.ts) Tokens loaded: 42 tokens from design-system/tokens.json Design intent: Minimal, cool professional (from DESIGN.md) Component plan: Button with primary/secondary/ghost variants Token consumption: color.primary.*, color.neutral.*, typography.body, spacing.sm/md
IMPLEMENT output (Button.tsx):
/* @design-token color.primary.500 — primary variant background */ /* @design-token color.primary.700 — primary variant hover */ /* @design-token color.neutral.50 — ghost variant background */ /* @design-token color.neutral.900 — ghost variant text */ /* @design-token typography.body.fontFamily — button label */ /* @design-token typography.body.fontWeight — button label weight */ /* @design-token spacing.sm — button horizontal padding */ /* @design-token spacing.xs — button vertical padding */ import type { ButtonHTMLAttributes } from 'react'; interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> { variant?: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; } export function Button({ variant = 'primary', size = 'md', className = '', children, ...props }: ButtonProps) { const baseClasses = 'inline-flex items-center justify-center font-body font-medium rounded-md transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500'; const variantClasses = { primary: 'bg-primary-500 text-white hover:bg-primary-700', secondary: 'border border-primary-500 text-primary-700 hover:bg-primary-50', ghost: 'text-neutral-900 hover:bg-neutral-100', }; const sizeClasses = { sm: 'px-spacing-sm py-spacing-xs text-sm', md: 'px-spacing-md py-spacing-sm text-base', lg: 'px-spacing-lg py-spacing-md text-lg', }; return ( <button className={`${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]} ${className}`} {...props} > {children} </button> ); }
VERIFY output:
Verification Results -------------------- Hardcoded values: PASS (0 hardcoded colors, fonts, or spacing) Token coverage: PASS (8/8 referenced tokens exist in tokens.json) Anti-pattern check: PASS (no gradients, no decorative borders) Design constraints: PASS (no VIOLATES_DESIGN edges) Harness validate: PASS
Example: Vue + CSS Custom Properties Card Component
Context: E-commerce project. Vue 3 with CSS custom properties. Tokens from harness-design-system.
IMPLEMENT output (ProductCard.vue):
<!-- @design-token color.neutral.50 — card background --> <!-- @design-token color.neutral.200 — card border --> <!-- @design-token color.neutral.900 — card text --> <!-- @design-token typography.heading.fontFamily — product title --> <!-- @design-token typography.body.fontFamily — product description --> <!-- @design-token spacing.md — card padding --> <!-- @design-token spacing.sm — content gap --> <script setup lang="ts"> interface Props { title: string; description: string; price: string; imageUrl: string; imageAlt: string; } defineProps<Props>(); </script> <template> <article class="product-card"> <img :src="imageUrl" :alt="imageAlt" class="product-card__image" /> <div class="product-card__content"> <h3 class="product-card__title">{{ title }}</h3> <p class="product-card__description">{{ description }}</p> <span class="product-card__price">{{ price }}</span> </div> </article> </template> <style scoped> .product-card { background: var(--color-neutral-50); border: 1px solid var(--color-neutral-200); border-radius: var(--radius-md); overflow: hidden; } .product-card__content { padding: var(--spacing-md); display: flex; flex-direction: column; gap: var(--spacing-sm); } .product-card__title { font-family: var(--typography-heading-fontFamily); font-weight: var(--typography-heading-fontWeight); color: var(--color-neutral-900); } .product-card__description { font-family: var(--typography-body-fontFamily); color: var(--color-neutral-700); } </style>
Rationalizations to Reject
| Rationalization | Reality |
|---|---|
| "The tokens file doesn't exist yet, but I know the brand colors — I'll hardcode them as a placeholder and note they should be replaced later." | Hardcoded values in generated output are the exact problem this skill exists to prevent. There is no placeholder exception. If does not exist, instruct the user to run harness-design-system first and stop. |
| "The framework is obviously React — everything in this project is React. I don't need to run detection." | Detection also identifies the CSS strategy (Tailwind vs CSS Modules vs CSS-in-JS), which determines how tokens map to code. Skipping detection produces components that may reference non-existent Tailwind classes or wrong theme paths. |
| "The user hasn't confirmed the scaffold plan, but the component structure is straightforward — I'll just generate it." | The scaffold plan confirmation is a gate. The user must see which tokens will be consumed and what the component structure will be before code is written. Generating first and explaining later inverts the review opportunity. |
| "This component only uses one hardcoded hex value for a shadow — that's not really a design value, so I'll leave it." | Every color, font, and spacing value must reference a token. Shadows use color tokens. "Not really a design value" is not a category the verification phase recognizes. The VERIFY phase will flag it; the IMPLEMENT phase should not introduce it. |
"The annotations are just comments — skipping them on a few components won't affect anything." | These annotations are how creates edges in the knowledge graph. Missing annotations mean harness-impact-analysis cannot trace token changes to affected components. They are structural metadata, not decorative comments. |
Gates
These are hard stops. Violating any gate means the process has broken down.
- No component generation without reading tokens from harness-design-system. The SCAFFOLD phase requires
to exist. If tokens have not been generated, instruct the user to run harness-design-system first. Do not generate components with hardcoded values as a fallback.design-system/tokens.json - No hardcoded design values in generated output. Every color, font, and spacing value must reference a token. If a needed token does not exist, instruct the user to add it via harness-design-system rather than hardcoding the value.
- No framework-specific code without framework detection. The SCAFFOLD phase must detect or receive the target framework before generating components. Do not guess or default to React.
- No generation without scaffold plan confirmation. The SCAFFOLD phase must present a component plan to the user. Do not generate code without the user confirming the structure and token consumption plan.
- No graph mutations without validating node types. When creating
orUSES_TOKEN
edges, verify the node and edge types are registered in the graph schema before writing.PLATFORM_BINDING
Escalation
- When
does not exist: Instruct the user: "Design tokens have not been generated. Rundesign-system/tokens.json
first to createharness-design-system
, then re-rundesign-system/tokens.json
for token-bound component generation."harness-design-web - When the project uses an undetected framework: Ask the user to specify via the
CLI argument. Log: "Could not auto-detect web framework. Please specify:--framework
."harness skill run harness-design-web --framework react|vue|svelte|vanilla - When tokens are insufficient for the requested component: Report which tokens are missing: "Component requires a
token but it does not exist incolor.accent.500
. Runtokens.json
to add the missing token, or choose an existing alternative." Do not hardcode a fallback.harness-design-system - When anti-patterns conflict with the requested design: Present the conflict: "The requested gradient background violates the 'no gradients on data elements' anti-pattern from DESIGN.md. Options: (1) Remove the gradient and use a solid token color, (2) Update the anti-pattern list via
if the intent has changed."harness-design - When the knowledge graph is unavailable: Skip graph operations in SCAFFOLD and VERIFY phases. Log: "Graph not available at
— skipping token node verification and USES_TOKEN edge creation. Run.harness/graph/
later to populate." Continue with file-based operations.harness scan