# Align Design System

> Align Design System

- Skill: `intense-visions/align-design-system` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add intense-visions/align-design-system`
- Raw SKILL.md: https://api.skillmd.com/api/skills/intense-visions/align-design-system/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: Intense-Visions (https://skillmd.com/u/intense-visions)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/intense-visions/align-design-system

---

# 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)

