From harness-claude
Generates token-bound web components from design tokens and aesthetic intent, implementing with Tailwind/CSS and React/Vue/Svelte patterns while enforcing no hardcoded design values.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:harness-design-webThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> 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.
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.
on_new_feature triggers fire with web UI scope requiring token-bound component generationon_commit triggers fire and new components contain hardcoded design values that should reference tokensdesign-system/DESIGN.md into concrete Tailwind classes, CSS custom properties, or CSS-in-JS theme valuesRead design tokens. Load design-system/tokens.json (W3C DTCG format). Extract:
design-system/tokens.json does not exist, stop and instruct the user to run harness-design-system first.Read design intent. Load design-system/DESIGN.md for:
design-system/DESIGN.md does not exist, warn the user and proceed with tokens only. Recommend running harness-design for richer output.Check harness configuration. Read harness.config.json for:
design.strictness — enforcement level (strict, standard, permissive). Default to standard.design.platforms — confirm web is in the platforms list.design.tokenPath — custom token path (default: design-system/tokens.json).Detect web framework. Scan the project for:
package.json contains react or next dependency, .tsx/.jsx files existpackage.json contains vue or nuxt dependency, .vue files existpackage.json contains svelte or @sveltejs/kit, .svelte files exist--framework, use that override.Detect CSS strategy. Scan for:
tailwind.config.* exists, @tailwind directives in CSS, class= with Tailwind utility patterns.module.css or .module.scss files existstyled-components, @emotion/styled, stitches imports detected.css/.scss files with no module or utility pattern--cssStrategy, use that override.Load platform-specific web rules. Read agents/skills/shared/design-knowledge/platform-rules/web.yaml for web-specific design rules including responsive breakpoints, browser compatibility considerations, and CSS best practices.
Load anti-pattern definitions. Read anti-pattern files from agents/skills/shared/design-knowledge/anti-patterns/:
typography.yaml — typographic anti-patterns (too many fonts, inconsistent scales)color.yaml — color anti-patterns (hardcoded hex, insufficient contrast)layout.yaml — layout anti-patterns (magic numbers, inconsistent spacing)motion.yaml — motion anti-patterns (excessive animation, missing reduced-motion)Build token-to-CSS mapping. Create a lookup table that maps each token to its CSS representation based on the detected strategy:
color.primary.500 maps to text-primary-500 / bg-primary-500 (requires tailwind.config theme extension)color.primary.500 maps to var(--color-primary-500)color.primary.500 maps to theme.color.primary[500]Plan component structure. For the requested component(s), define:
Generate framework-specific component code. Based on detected framework:
React (TSX):
Vue (SFC):
<script setup lang="ts">defineProps and TypeScript interfaceSvelte:
<script lang="ts">export let declarationsVanilla HTML/CSS:
Generate CSS strategy artifacts. Based on detected CSS strategy:
Tailwind:
tailwind.config theme with token values (if not already present)@apply sparingly — prefer utility classes in markupCSS Custom Properties:
:root declarations for all consumed tokensvar(--token-name) exclusivelyCSS-in-JS:
Apply design intent constraints. For each generated component:
design-system/DESIGN.md and agents/skills/shared/design-knowledge/anti-patterns/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 USES_TOKEN edges from this component to the consumed DesignToken nodes.
Scan for hardcoded values. Use Grep to search generated files for:
#[0-9a-fA-F]{3,8}), rgb(), hsl(), named colorsfont-family: declarations not referencing tokensVerify token coverage. For every design value in the generated component:
design-system/tokens.jsoncolor.primary.500 exists in the token tree)Check anti-pattern compliance. Cross-reference generated code against anti-patterns declared in design-system/DESIGN.md and the anti-pattern definitions in agents/skills/shared/design-knowledge/anti-patterns/:
Query the knowledge graph. If a graph exists at .harness/graph/:
DesignIngestor to verify DesignToken nodes exist for all referenced tokensPLATFORM_BINDING edges exist for web platform tokensDesignConstraintAdapter to check for VIOLATES_DESIGN edgesdesign.strictnessAssign severity based on designStrictness:
permissive — all findings are infostandard — hardcoded values and anti-pattern violations are warn, accessibility violations are errorstrict — hardcoded values are error (blocks), anti-pattern violations are warn, accessibility violations are errorReport 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 harness validate. After verification, run project-level validation to confirm the new components integrate cleanly.
harness validate — Run after generating components to verify project health. New files must not break existing constraints.harness scan — Run after component generation to update the knowledge graph with new USES_TOKEN edges from generated components to consumed tokens.DesignIngestor (packages/graph/src/ingest/DesignIngestor.ts) — Verifies that DesignToken nodes exist for all tokens referenced by generated components. If tokens are missing from the graph, run harness scan to re-ingest.DesignConstraintAdapter (packages/graph/src/constraints/DesignConstraintAdapter.ts) — Checks for VIOLATES_DESIGN edges during the VERIFY phase. Reports constraint violations at the configured strictness level.harness-design-system — 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 — Dependency. This skill reads aesthetic intent from harness-design output (design-system/DESIGN.md). Anti-pattern enforcement and style constraints come from the design intent document.harness-impact-analysis — When tokens change, impact analysis traces which components consume affected tokens via USES_TOKEN edges. Use this to identify components that need regeneration after token updates.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.
@design-token annotations are present for every consumed tokendesign-system/DESIGN.mddesign.strictness configurationharness validate passes after component generationContext: 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
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>
| 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 design-system/tokens.json 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 @design-token annotations are just comments — skipping them on a few components won't affect anything." | These annotations are how harness scan creates USES_TOKEN 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. |
These are hard stops. Violating any gate means the process has broken down.
design-system/tokens.json 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.USES_TOKEN or PLATFORM_BINDING edges, verify the node and edge types are registered in the graph schema before writing.design-system/tokens.json does not exist: Instruct the user: "Design tokens have not been generated. Run harness-design-system first to create design-system/tokens.json, then re-run harness-design-web for token-bound component generation."--framework CLI argument. Log: "Could not auto-detect web framework. Please specify: harness skill run harness-design-web --framework react|vue|svelte|vanilla."color.accent.500 token but it does not exist in tokens.json. Run harness-design-system to add the missing token, or choose an existing alternative." Do not hardcode a fallback.harness-design if the intent has changed.".harness/graph/ — skipping token node verification and USES_TOKEN edge creation. Run harness scan later to populate." Continue with file-based operations.npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeBuilds accessible, responsive, performant frontend components using design systems, modern CSS, WCAG patterns, and React/Vue/Svelte examples.
Applies agentic design patterns to frontend design token management, component scaffolding, multi-tenant theming, Keycloak exports, and accessibility UI generation.
Manages design systems by detecting reusable UI patterns, extracting design tokens, organizing components with Atomic Design, and warning on hard-coded values or duplicates. Activates on component libraries, style guides, or patterns.