From harness-claude
Detects hardcoded values where design tokens exist and raw HTML primitives where registered components should be used. Reports findings without modifying source.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:detect-design-driftThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Detect design-system drift — hardcoded values where tokens exist, and raw HTML primitives where registered components exist. The rule-based floor of design-pipeline #1 (detect half). Reports findings; never modifies source. Pairs with a separate align-design-system fixer skill (deferred to a sibling sub-project).
Detect design-system drift — hardcoded values where tokens exist, and raw HTML primitives where registered components exist. The rule-based floor of design-pipeline #1 (detect half). Reports findings; never modifies source. Pairs with a separate align-design-system fixer skill (deferred to a sibling sub-project).
## Component Registry, to find existing raw-HTML usages that should adopt itharness validate so drift surfaces continuously, not only on demandharness check-design (alongside audit-component-anatomy and harness-design-craft)Read project configuration. Check harness.config.json for:
design.strictness — strict / standard / permissive (default standard)design.audit.driftDetection.enabled — gate for the verifier (default true)design.audit.driftDetection.rules.{tokenBypass,primitiveAdoption} — per-rule togglesdesign.audit.driftDetection.fastMode.maxFiles — validate-time scope capLoad resolvers (soft-dependency — silent skip when absent):
design-system/tokens.json (W3C DTCG format) — parsed by loadTokenSet. Extracts colors, font families, spacing scale, and deprecated token paths. Returns null when the file doesn't exist; token-bypass rules then skip silently.design-system/DESIGN.md ## Component Registry — parsed by loadComponentRegistry. Maps registered component types (Button/Input/Textarea/Link/Anchor) to their HTML primitive tag. Returns null when DESIGN.md or the section is absent; primitive-adoption rules then skip silently.Collect candidate files. Walk the project root (or honor an explicit files arg from the caller). Skip node_modules, dist, build, coverage, and any dotfile directory. Honor only these extensions: .ts, .tsx, .js, .jsx, .css, .scss.
Token bypass rules (DRIFT-T*) — regex-based detection. For each file when tokens were loaded:
#abc, #aabbcc, etc.) NOT present in the loaded palette. Case-insensitive palette match. Deduplicated per line:value.sans-serif, serif, monospace, system-ui, inherit) are always allowed.$deprecated: true (or $extensions.harness.deprecated: true) in tokens.json. Matched in both 'token.path.form' and CSS-var kebab form (--token-path-form).Primitive adoption rules (DRIFT-P*) — TS Compiler API JSX parsing. For each .jsx/.tsx file when the registry was loaded:
<button> JSX where Button is registered<input> JSX where Input is registered<a> JSX where Link or Anchor is registered<textarea> JSX where Textarea is registered<Foo.Bar>) are skipped.Severity from design.strictness:
strict — every finding error (CI blocks)standard — DRIFT-T001/T002/P001 → error; everything else → warnpermissive — everything → infoAggregate the run summary. bySeverity, byCode, totalFiles, durationMs. Also report catalog.rulesApplied (which rule families fired) and meta.{tokensLoaded, registryLoaded, mode} so callers can see what was active.
Persist findings to the graph (when composed by check-design). The check-design orchestrator passes drift findings to DesignConstraintAdapter.recordFindings() alongside anatomy and craft findings. Each finding becomes an idempotent VIOLATES_design edge keyed by (file, code, line) — re-runs do not double-write.
harness validate — Fast-mode hook runs the detect-drift verifier. Findings respect design.strictness. Failures degrade gracefully: if the verifier throws, validate logs a warning and continues with other checks.harness check-design — One of three composed verifiers. The orchestrator aggregates findings across audit-anatomy, design-craft, and detect-drift; persists all three to the graph; and surfaces a unified report.mcp__harness__detect_drift — Programmatic API. Input: { path, mode, files?, designStrictness?, rules? }. Output: { findings, summary, catalog, meta }. Consumed by the design-pipeline orchestrator (sub-project #5).DesignConstraintAdapter.recordFindings() — Generic graph persistence entry point shipped in PR #390. Drift findings reuse the adapter; no extra graph plumbing.See docs/changes/design-pipeline/detect-design-drift/proposal.md for the full 34 success criteria. Highlights:
harness validate runtime budget < 3s on a 500-file repo with both rule families enabledInput: src/Card.tsx contains const styles = { color: "#ff0000" };, and design-system/tokens.json defines color.brand.primary as #0066cc (but no #ff0000).
Output:
DRIFT-T001 [error] src/Card.tsx:14 — Hardcoded color "#ff0000" is not in the design token palette
Fix: Replace "#ff0000" with a token reference (e.g. var(--color-...) or a token-system lookup).
If the color is intentionally one-off, add it to tokens.json first.
Severity is error under standard because brand-color drift is high-impact.
<button> where Button is registeredInput: src/SaveButton.tsx contains <button onClick={...}>Save</button>, and design-system/DESIGN.md ## Component Registry lists Button mapped to packages/ui/src/Button.tsx.
Output:
DRIFT-P001 [error] src/SaveButton.tsx:8 — Raw <button> element where the registered component "Button" should be used
Fix: Import Button from your component library and replace <button> with <Button>.
If this raw primitive is intentional (e.g. inside the Button component's own implementation),
add a JSDoc `@allow-raw-primitive` annotation on the file.
Input: src/legacy.css contains .x { color: var(--color-brand-500); }, and tokens.json flags color.brand.500 as $deprecated: true with $description: "Use color.brand.primary instead".
Output:
DRIFT-T004 [warn] src/legacy.css:3 — Token "color.brand.500" is deprecated and should be migrated
Fix: Migrate references to "color.brand.500" to the replacement token noted in tokens.json $description,
or remove the deprecation if the token is still load-bearing.
tokens.json is absent, all T* rules silently skip. If DESIGN.md ## Component Registry is absent, all P* rules silently skip. Either resolver failing is not a verifier failure — the project simply hasn't opted in.<select>, <details>, etc.) are not in scope for v1 — even if the project registers a component for them. Subsumption ships in v1.x.design.strictness from harness.config.json; default to standard if absent.tokens.json (preferred — makes the palette authoritative) or scope the file via design.audit.driftDetection.rules.tokenBypass: false for a narrow path-overrides block (v1.x).@allow-raw-primitive JSDoc on the file (v1.x — annotation honored by the rule), or (2) extract the raw <button> into a private internal component until the annotation lands.harness validate runtime exceeds 3 seconds. Set design.audit.driftDetection.fastMode.maxFiles to cap the scope. The MCP tool ignores the cap (fast/full are equivalent in v1 — the cap is validate-side only).v1 — in implementation. See:
docs/changes/design-pipeline/detect-design-drift/proposal.mddesign-pipeline sub-project #1 (detect half) in docs/roadmap.mdalign-design-system (fix half — deferred to a separate sub-project)npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeApplies codemods to replace hex, font-family, and px-spacing literals with design token references based on DRIFT findings. Dry-run support included.
Detects design system tokens and components in code, identifying drift with paired evidence blocks. Use when auditing design system consistency across a codebase.
Identifies system-wide drift in design systems: components diverging from specs, local token overrides, forked patterns across teams. Classifies severity, origins, and generates response recommendations.