> Apply codemods for safe DRIFT-T001/T002/T003 token-bypass findings (replace hex / font-family / px-spacing literals with token references) and emit precise suggestions for DRIFT-T004 (deprecated tokens) and all DRIFT-P\* (primitive adoption). The FIX half of design-pipeline drift-remediation sub-project, paired with detect-design-drift.
Scanned 9/11/2026
Install to Claude Code
npx -y skills add Intense-Visions/harness-engineering --skill align-design-system --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Align Design System?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/intense-visions-align-design-system-9687bd56)More formats (shields.io, HTML) on the badges page.
# Align Design System
> Apply codemods for safe DRIFT-T001/T002/T003 token-bypass findings (replace hex / font-family / px-spacing literals with token references) and emit precise suggestions for DRIFT-T004 (deprecated tokens) and all DRIFT-P\* (primitive adoption). The FIX half of design-pipeline drift-remediation sub-project, paired with detect-design-drift.
## When to Use
- After detect-design-drift reports DRIFT-T001/T002/T003 findings — align replaces literals with token references where the fix is unambiguous
- Before a PR that touches UI code lands — pair with detect-design-drift to surface AND fix drift in one shot
- Inside a (future) design-pipeline orchestrator's convergence loop — align is the FIX step the loop runs between DETECT and VERIFY
- When you want to dry-run the fixes first (`--dry-run`) and review the diff before writing
- NOT for primitive-adoption codemods — v1 emits suggestions only for DRIFT-P\*; the prop-translation work lives in v1.x
- NOT for adding new tokens to tokens.json (no auto-add of palette entries; that's a separate intentional act)
- NOT for non-design-system fixes (use cleanup-dead-code, align-documentation, etc. for their respective domains)
## Process
### Phase 1: GATHER — Load drift findings
1. **Read project configuration.** Check `harness.config.json` for:
- `design.strictness` — passes through to detect-design-drift
- `design.audit.driftDetection.*` — passes through to detect
2. **In standalone mode (default):** invoke `detect-design-drift` internally with the same project root + strictness; receive the full `DriftFinding[]`.
3. **In pipeline mode:** read `.harness/handoff.json` and pull `pipeline.driftFindings` (pre-classified by the orchestrator). Honor `pipeline.fixBatch` if present to limit application to a specific subset of findings (the orchestrator may apply fixes in batches across iterations).
### Phase 2: CLASSIFY — Pre-flight safe-codemod vs suggestion
For each finding, the pre-flight classifier inspects file context and chooses:
- **DRIFT-T001 (hex)** — safe-codemod iff token import already present in the file AND hex is in single string-literal context (not a template literal or concatenation) AND exactly one palette token matches by value. Otherwise → suggestion.
- **DRIFT-T002 (font-family)** — same shape as T001 against the typography palette.
- **DRIFT-T003 (px spacing)** — safe-codemod iff token import present AND px matches a spacing token's `$value` EXACTLY (no rounding) AND not in an arithmetic expression. Otherwise → suggestion.
- **DRIFT-T004 (deprecated)** — always suggestion in v1. Migration target may not be in the token's `$description`.
- **DRIFT-P\* (primitive adoption)** — always suggestion in v1. Prop translation across `<button>` ⇄ `<Button>` is genuinely ambiguous (event handlers, ref forwarding, class merging) — codemods deferred to v1.x.
Token import discovery recognizes three forms:
- ES named: `import { tokens } from '...'`
- ES default: `import tokens from '...'`
- CJS: `const tokens = require('...')`
### Phase 3: APPLY — Codemod or emit suggestion
For each finding classified as `safe-codemod`:
1. Read the source file (cached per-run to avoid re-reads when multiple findings hit the same file).
2. Locate the exact match position from the finding's `line` + `evidence.snippet`.
3. Compute the replacement using file-extension-aware syntax:
- `.ts` / `.tsx` / `.js` / `.jsx` → `tokens.<dotted.path>`
- `.css` / `.scss` → `var(--<dotted-path-as-kebab>)`
4. Replace in-place. Emit `FixOutcome.applied` with a structured diff (file / line / before / after).
5. If `--dry-run`: compute the diff but DO NOT write to disk.
6. If the file changed between detect-time and apply-time: skip with `kind: 'skipped-unsafe', reason: 'file changed since finding'`.
For each finding classified as `suggestion`: emit a human-readable description plus a preview of the suggested change. No file mutation.
### Phase 4: REPORT — Aggregate + (pipeline-mode) handoff writeback
1. Aggregate `FixOutcome[]` into a summary: counts by kind (applied / suggestion / skipped / failed) plus files modified and duration.
2. Build a `catalog` of finding codes that produced codemods and codes that produced suggestions.
3. In pipeline mode: write `pipeline.fixesApplied: FixOutcome[]` back to `.harness/handoff.json` so the orchestrator can re-verify only the affected findings on the next loop iteration.
## Harness Integration
- **`harness align-design-system`** — the CLI entry point. `--dry-run` for preview; `--write` is the default. Standard `--json` / `--verbose` / `--quiet` flags.
- **`harness align-design-system --mode pipeline`** — orchestrator-driven mode. Reads pre-classified findings from handoff.json; writes outcomes back.
- **`harness align-design-system --revert`** — inverse-applies the most-recent batch recorded at `.harness/align/last-batch.json`. Skips files edited externally since the apply (content-hash check). Idempotent: a second revert on the same batch is a no-op because the file no longer matches the recorded post-apply text.
- **`mcp__harness__align_design_system`** — MCP tool for agent consumption. Same input/output shape as the function call.
- **`detect-design-drift`** — soft dependency. Standalone mode invokes detect internally; pipeline mode trusts the orchestrator to have done it.
- **`harness check-design`** — composes detect (as 3rd verifier) into a single-pass design check. align is the matching FIX step; together they form the DETECT → FIX cycle that the (future) orchestrator will loop.
- **`DesignConstraintAdapter`** — align does NOT write to the graph. The graph already tracks `VIOLATES_design` edges (the findings). Re-running detect after align shows the delta — no separate fix-edge needed.
## Success Criteria
See `docs/changes/design-pipeline/align-design-system/proposal.md` for the full 34 success criteria. Highlights:
- T001/T002/T003 codemods write to disk only when pre-flight classifier returns `safe-codemod`
- Codemods are idempotent — running twice produces zero additional changes on the second run
- Classifier downgrades to suggestion when token import is missing, when value appears in template/concatenation, or when multiple tokens share the value
- Classifier ALWAYS returns suggestion for T004 + all P\* findings (no source inspection)
- Pipeline mode reads `pipeline.driftFindings` from handoff.json; standalone mode runs detect internally
- Pipeline mode writes `pipeline.fixesApplied` back to handoff.json
- `--dry-run` produces identical `FixOutcome` shapes but never writes files
- Re-running detect after align produces strictly fewer T001/T002/T003 findings
- `--revert` re-applies the inverse of the most-recent `fixesApplied` batch; no-op when the file has been edited externally since the apply
## Rationalizations to Reject
These are common rationalizations that sound reasonable but lead to incorrect results. When you catch yourself thinking any of these, stop and follow the documented process instead.
| Rationalization | Why It Is Wrong |
| ---------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "The token import is missing, but I can just add the import line and then apply the codemod." | Adding an import is its own ambiguity surface — named vs default vs barrel vs relative alias. The classifier deliberately downgrades to a suggestion when no import is present; synthesizing one turns a safe replacement into an unverified edit. |
| "This literal is `13px` and the nearest spacing token is `12px` — close enough to snap it." | Non-exact px matches are a design decision, not a mechanical fix. T003 is safe-codemod only when the px matches a spacing token's `$value` EXACTLY. Rounding invents intent the tool has no authority to invent. |
| "This raw `<button>` obviously maps to the registered `<Button>` — I'll translate the props and apply it." | Prop translation across `<button>` ⇄ `<Button>` is genuinely ambiguous (event handlers, ref forwarding, class merging). v1 ALWAYS emits a suggestion for DRIFT-P\*; there is no codemod path, and auto-applying one produces broken markup. |
| "Two tokens share this hex value, but the brand one is clearly intended — I'll pick it and apply." | When multiple tokens match a value the classifier downgrades to a suggestion by design. Choosing "the obvious one" is exactly the judgment call the pre-flight gate refuses to make; the resolution belongs in DESIGN.md or the source, not a guess. |
| "The file changed since detect ran, but the finding's line still looks right — I'll apply anyway." | Applying against content that moved risks mutating the wrong span. The contract is to skip with `skipped-unsafe / reason: file changed since finding`; re-run detect to get fresh line positions instead of trusting a stale offset. |
## Examples
### Example: Apply a T001 codemod (hex → token reference)
**Input:**
`design-system/tokens.json` has:
```json
{ "color": { "brand": { "primary": { "$type": "color", "$value": "#0066cc" } } } }
```
`src/Card.tsx` has:
```ts
import { tokens } from '@/design-system/tokens';
const styles = { color: '#0066cc' }; // raw literal where token exists
```
**Output:**
```
src/Card.tsx
✓ DRIFT-T001:2 — Hex color "#0066cc" should use a token reference instead of a raw literal
before: const styles = { color: "#0066cc" };
after: const styles = { color: tokens.color.brand.primary };
Summary: 1 applied, 0 suggestions, 0 skipped, 0 failed (1 files modified, 5ms)
```
### Example: Downgrade to suggestion (no token import)
Same finding as above, but `src/Card.tsx` does NOT import tokens. align emits a suggestion instead:
```
src/Card.tsx
? DRIFT-T001:2 — Hex color "#0066cc" should use a token reference instead of a raw literal
Summary: 0 applied, 1 suggestions, 0 skipped, 0 failed (0 files modified, 3ms)
```
(Run with `--verbose` to see the suggestion text and the classifier's reason for downgrading.)
### Example: Suggestion-only for DRIFT-P001
**Input:**
`design-system/DESIGN.md` registers `Button` in `## Component Registry`. `src/SaveButton.tsx` has:
```tsx
export const S = () => <button onClick={() => save()}>Save</button>;
```
**Output:**
```
src/SaveButton.tsx
? DRIFT-P001:1 — Raw <button> element where the registered component "Button" should be used
(use --verbose to see prop-translation suggestion)
```
v1 never auto-applies primitive adoption — prop translation across `<button>` ⇄ `<Button>` is the kind of judgment-call that benefits from a human or LLM review.
### Example: Revert the last batch
After a write run, the applied diffs (plus a SHA-256 of each post-apply file) are persisted to `.harness/align/last-batch.json`. Running `harness align-design-system --revert` reads that batch and inverse-applies each diff:
```
src/Card.tsx
✓ DRIFT-T001:2 — Hex color "#0066cc" should use a token reference instead of a raw literal
before: const styles = { color: tokens.color.brand.primary };
after: const styles = { color: "#0066cc" };
Summary: 1 reverted, 0 suggestions, 0 skipped, 0 failed (1 files modified, 4ms)
```
If the file has been edited externally between apply and revert (the SHA-256 doesn't match), every entry for that file is skipped with `skipped-unsafe / reason: file changed externally since apply`. A second revert on the same batch is a no-op for the same reason — the file's post-revert content no longer matches the recorded post-apply text.
## Gates
- **No autofix without classifier approval.** Every codemod application goes through `classifyFinding`. If the classifier returns `suggestion`, NO file write occurs — even for the same finding code in the same file.
- **No autofix when token import is missing.** Adding the import line is its own ambiguity surface (alias? barrel? relative?). v1 skips with a suggestion.
- **No autofix for non-exact px matches.** "Round 13px to the nearest 16px" is a design decision the tool shouldn't make.
- **No autofix for primitive adoption.** v1 has no codemod for DRIFT-P\* — always suggestions.
- **No autofix in pipeline mode unless a `pipeline.driftFindings` field is present.** Empty handoff = empty run.
- **No graph writes.** align modifies source files; the graph is read-only from align's perspective.
## Escalation
- **When a T001 finding has multiple matching tokens (ambiguous):** the classifier downgrades to suggestion. To resolve, declare a primary token in DESIGN.md `## Token Primary Resolution Overrides` (v1.x), OR pick one in the source manually and re-run.
- **When the codemod corrupts a file (rare):** every application includes a structured diff. Recover via `git checkout <file>`. If the same input repeatedly corrupts, report the case — pre-flight classifier rules are conservative by design.
- **When pipeline-mode run finds no `pipeline.driftFindings` field:** align exits cleanly with empty outcomes. The orchestrator's contract is to write the field BEFORE invoking align.
- **When `--dry-run` shows fixes you don't want applied:** scope with `--files <glob>` to apply only specific files, or invoke align in pipeline mode with a curated `pipeline.fixBatch` list.
- **When you want to undo an apply:** run `harness align-design-system --revert`. It reads `.harness/align/last-batch.json`, content-hash-checks each file, and inverse-applies. Files edited since the apply are skipped (no silent corruption); recover via `git checkout <file>` if the content-hash check blocks revert and the prior commit is still in history.
- **When you want primitive-adoption fixes today:** apply the suggestion manually. The v1.x sub-project will add prop-translation tables + import resolution + revert-on-test-fail.
- **When align is invoked without detect having run first (standalone mode):** standalone mode runs detect internally — no manual ordering needed. Pipeline mode trusts the orchestrator to populate findings.
## Status
**v1 — in implementation.** See:
- Spec: `docs/changes/design-pipeline/align-design-system/proposal.md`
- Roadmap entry: part of the `design-pipeline` initiative (align half) in `docs/roadmap.md`
- Sibling: `detect-design-drift` (detect half)
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!