CLI tool that scans React source code and detects design system inconsistencies, offering suggestions and automated fixes.
npm install -g remediationOr run directly with npx:
npx remediation scanremediation initInteractive wizard that creates a remediation.config.js in the current directory. Prompts for ignore patterns, rule severity overrides, and token mappings.
remediation scan [path]Returns exit code 1 if any error-severity violations are found (use rules config to promote rules to error).
| Flag | Description |
|---|---|
--verbose |
Show all violations in terminal |
--output <file> |
Write report to file |
--rule <pattern> |
Filter by rule name (e.g., colors, drift) |
--format json |
Output results as JSON (for CI/CD) |
--save-baseline |
Save current violations as baseline (see Baseline) |
--ignore-baseline |
Ignore baseline file even if it exists |
remediation tokens [path]Shorthand for scan --rule colors/,spacing/,typography/,radius/,shadows/. Runs only the hardcoded-value rules, skipping structural rules like drift and token-bypass.
| Flag | Description |
|---|---|
--verbose |
Show all violations in terminal |
--output <file> |
Write report to file |
--format json |
Output results as JSON (for CI/CD) |
--save-baseline |
Save current violations as baseline |
--ignore-baseline |
Ignore baseline file even if it exists |
remediation analyze [path]| Flag | Description |
|---|---|
--codemod |
Preview token replacements (dry-run by default) |
--codemod --no-dry-run |
Apply token replacements to files |
--output <file> |
Generate tokens.ts file |
--min-confidence <level> |
Filter proposals by confidence (high, medium, low) |
Detect hardcoded values that should be replaced with design tokens. Comments and import statements are excluded from analysis to avoid false positives.
| Rule | Description |
|---|---|
colors/hardcoded |
Detects hardcoded color values (hex, rgb, hsl), including inside shorthand values like border: '1px solid #e4e4e7' and CSS-in-JS tagged templates |
spacing/hardcoded |
Detects hardcoded spacing values (px, rem, em) |
typography/hardcoded |
Detects hardcoded font sizes and weights |
radius/hardcoded |
Detects hardcoded border-radius values |
shadows/hardcoded |
Detects hardcoded box-shadow values |
| Rule | Description |
|---|---|
token-bypass |
Detects hardcoded values when a matching token already exists — requires tokens to be configured |
drift |
Detects components with similar names or identical JSX structure that should be merged |
remediation analyze runs a full pipeline:
EXTRACTION → NORMALIZATION → CLUSTERING → DECISION → CODEMOD
- Extraction — Scans codebase for all design values (colors, spacing, typography)
- Normalization — Converts all values to canonical form (hex, px)
- Clustering — Groups similar values using color distance algorithm
- Decision — Proposes tokens with confidence levels (high, medium, low)
- Codemod — Replaces hardcoded values with token references
⚡ ████████████████████████ 2423/2423
⚡ Scanned 2423 files in 3.4s
Violations by rule:
colors/hardcoded 237 ████████████████ 45 files
spacing/hardcoded 102 ██████░░░░░░░░░░ 31 files
token-bypass 58 ███░░░░░░░░░░░░░ 22 files
typography/hardcoded 21 █░░░░░░░░░░░░░░░ 14 files
drift 4 █░░░░░░░░░░░░░░░ 3 files
Top affected files:
31 src/components/Button.tsx
18 src/pages/Dashboard.tsx
14 src/components/Card.tsx
9 src/components/Badge.tsx
8 src/components/Text.tsx
... and 40 more files
Run with --verbose to see all violations, --rule <name> to filter by rule.
┌─ Summary ─────────────────────────────┐
│ ✖ 237 errors ████████████████
│ ⚠ 185 warnings ████████████░░░░
│ ────────────────────────────────────
│ 422 total violations
│ 45 files affected
└────────────────────────────────────────┘
┌─ Health Score ─────────────────────────┐
│ ██████░░░░░░░░░░░░░░░░░░░░░░░░ 18/100
│ Critical
│
│ █████████████░░░░░░░░░░░░░░░░░ 41/100
│ Potential after fixes
└────────────────────────────────────────┘
Health score: 100 = clean codebase, 0 = critical. Labels: Excellent / Good / Needs work / Poor / Critical.
⚡ Analyzing design system...
⚡ Analysis complete in 1.2s
┌─ Extraction ──────────────────────────┐
│ 284 design values found
│ color 189
│ spacing 71
│ typography 24
└────────────────────────────────────────┘
┌─ Color Clusters ──────────────────────┐
│ #2563eb 5x (5 files)
│ #dc2626 3x (3 files)
│ #ffffff 4x (4 files)
│ #27272a 3x (3 files)
│ ... and 8 more
└────────────────────────────────────────┘
┌─ Spacing Clusters ────────────────────┐
│ 8px 9x (6 files)
│ 16px 5x (5 files)
│ 24px 2x (2 files)
└────────────────────────────────────────┘
┌─ Token Proposals ─────────────────────┐
│ 16 tokens proposed
│ ● 4 high confidence
│ ● 12 medium confidence
│
│ Top proposals:
│ ● blue = #2563eb (5x)
│ ● sm = 8px (9x)
│ ● md = 16px (5x)
│ ● red = #dc2626 (3x)
│ ● white = #ffffff (4x)
│ ... and 11 more
└────────────────────────────────────────┘
remediation analyze [path] --codemodCodemod Preview
════════════════════════════════════════════════════════════
📄 src/components/Button.tsx
────────────────────────────────────────────────────────────
L14:26 '#2563eb' → colors.blue
L16:23 16px → spacing.md
L16:19 8px → spacing.sm
L15:16 '#ffffff' → colors.white
📄 src/components/Card.tsx
────────────────────────────────────────────────────────────
L8:18 1px → spacing.xs
L11:24 16px → spacing.md
L9:24 8px → spacing.sm
L7:26 '#ffffff' → colors.white
L15:27 '#27272a' → colors.black
════════════════════════════════════════════════════════════
Total: 57 changes in 7 files
DRY RUN — no changes applied
Run with --codemod --no-dry-run to apply changes
Run remediation init to generate the config interactively, or create remediation.config.js manually in your project root:
module.exports = {
// Ignore files/patterns
ignore: ['*.test.tsx', '*.stories.tsx'],
// Rule severity: 'error' | 'warning' | 'info' | 'off'
// 'error' violations cause exit code 1 (blocks CI)
rules: {
'colors/hardcoded': 'error',
'drift': 'warning',
'token-bypass': 'off',
},
// Token mappings for the token-bypass rule
// Maps hardcoded values to their token name in your design system
tokens: {
'#1976D2': 'colors.primary',
'#D32F2F': 'colors.danger',
},
// Module the codemod imports token references from.
// When set, `analyze --codemod --no-dry-run` injects the needed import
// into every file it edits. When omitted, the codemod still applies the
// replacements but lists the imports you need to add by hand.
tokensImport: '@/design/tokens',
};The tokens map powers the token-bypass rule: when a hardcoded value matches a key, the rule flags it and suggests the token name as a replacement. The codemod reuses these mappings, so #1976D2 is rewritten to colors.primary (your name) rather than an auto-generated one. Bare numeric or keyword font weights are also accepted as keys (e.g. '600': 'typography.semibold').
analyze --codemod rewrites hardcoded values to token references by editing the source in place (it never regenerates or reformats your files):
- Whole-value literals become bare references:
'#1976D2'→colors.primary. - Compound and shorthand values become template literals, preserving the surrounding text:
'8px 16px'→`${spacing.sm} ${spacing.md}`,'0 2px 4px #000000'→`0 2px 4px ${colors.black}`,'1px solid #e4e4e7'→`1px solid ${colors.gray200}`. Shorthand props (border,background,outline) are recognized. - CSS-in-JS tagged templates (
styled.div\...`,css`...`) are rewritten in place — matched values become${...}` interpolations and existing interpolations are left untouched. - Typography is handled too, including numeric weights:
fontSize: '14px'→typography.sm,fontWeight: 600→typography.semibold. - Imports for the token roots used (
colors,spacing,typography, …) are injected fromtokensImportwhen configured.
Auto-generated token names encode their value when two clusters would collide on the same scale name (spacing.md_16 / spacing.md_15, colors.blue_2563eb), so names stay readable and stable across runs; non-colliding clusters keep clean scale names (sm, md, blue).
Preview with --codemod; write changes with --codemod --no-dry-run.
These directories are ignored by default:
node_modules, dist, build, .next, .nuxt, out, coverage, .cache, .parcel-cache, .webpack, .turbo, .vercel, .netlify, tmp, temp
The baseline lets you adopt remediation on a large existing codebase without being blocked by legacy violations — only new violations are reported.
# Save current state (run once, commit the baseline file)
remediation scan --save-baseline
# Future scans only report violations introduced since the baseline
remediation scan
# Ignore baseline for a full audit
remediation scan --ignore-baselineThe baseline is saved to .remediation-baseline.json. Commit it alongside your code so CI and teammates share the same starting point.
Use this skill when you want an AI coding agent (Claude Code, opencode, Cursor, …) to find or fix design-system drift for you — it encodes the safe workflow: scan first, configure token names, preview the codemod, apply, and verify the diff.
Install across 75+ agents via the skills CLI:
npx skills add arnaudmanaranche/remediationOr as a Claude Code plugin:
/plugin marketplace add arnaudmanaranche/remediation
/plugin install remediation@remediation
The skill lives at .claude/skills/remediation/SKILL.md and activates automatically on drift/tokenization requests.
- name: Scan design system
run: npx remediation scan --format json --output report.jsonWith error-severity rules configured, the command exits with code 1 on violations — blocking the pipeline. Use --save-baseline on first adoption to avoid failing on pre-existing violations.
scan, tokens, and analyze send anonymous usage data (command name, duration, violation counts, CLI/Node/OS version) via OpenTelemetry — never file paths, code, or identifiers. By default this is exported to the maintainer's Axiom project. If you've forked this CLI or run a private build, point it at your own backend with OTEL_EXPORTER_OTLP_ENDPOINT (or REMEDIATION_OTEL_ENDPOINT) and OTEL_EXPORTER_OTLP_HEADERS — these always override the built-in default. See docs/knowledge/telemetry.md.
Disable telemetry with:
remediation scan --no-telemetry
# or
REMEDIATION_TELEMETRY=0 remediation scan
# or, respected automatically:
DO_NOT_TRACK=1 remediation scanSee docs/knowledge/telemetry.md for what's collected and the implementation.
MIT