ux
Blog · Copilot · 2026-05-28

GitHub Copilot design rules: catching AI design fingerprints in Copilot output.

GitHub Copilot is the most-installed AI coding assistant in the world. It is also the assistant most consistently flagged for generating the same default-looking Tailwind UI. Copilot accepts custom instructions, but custom instructions alone do not catch the 68 specific patterns the model reaches for. ux-skill is a deterministic linter that runs on top of Copilot output and flags every pattern by line number.

Why Copilot has a design problem

Copilot is excellent at code completion. It was trained on the bulk of public code on GitHub, which means it has seen every variation of every common pattern. When you ask Copilot to design a landing page, it reaches for the median of what its training data showed: Inter as display, the canonical purple-to-blue gradient, three identical pricing cards, and the "Get started"/"Learn more" CTA pair.

This is not a bug. Copilot is doing exactly what it was designed to do — predict the most probable continuation of the prompt. The problem is that "most probable" on design tasks converges to a recognizable look that ships everywhere. We catalog that look in detail in the AI design fingerprints post.

Copilot has two extension points worth knowing: a custom-instructions surface (per repo) and a code-completion stream that is consumable by external tools. ux-skill plugs into both.

The custom instructions file

Copilot reads project-level instructions from .github/copilot-instructions.md. Anything in that file becomes part of the system context for every Copilot suggestion in that repo. ux-skill ships a generator that writes a Copilot-flavored rules file based on the recommender output.

# Initialize ux-skill for Copilot in your repo
$ uxskill init --target copilot

[OK] Wrote .github/copilot-instructions.md
[OK] Wrote .ux/design-system/MASTER.md
[OK] Wrote tokens.css

The generated file is intentionally short. Copilot's system context has a token budget; verbose rules get truncated. ux-skill condenses the 120 anti-patterns into a single 30-line block plus a reference to .ux/design-system/MASTER.md for deeper context.

A real .github/copilot-instructions.md

Here is the file ux-skill generates for a Next.js project after running discovery for a B2B logistics platform:

# Copilot instructions — logistics-platform
# Generated by ux-skill v2.0.0-alpha.1 — 2026-05-28

This project uses the editorial-precise design system at .ux/design-system/MASTER.md.
Read that file before generating any visual code.

Hard constraints for every generation:

1. Display type is Fraunces (variable opsz). Body is Inter. Mono is JetBrains Mono.
   Do NOT use Inter as a display font (font-size ≥ 40px or text-5xl and above).

2. Color: cool-neutral surface with a single warm accent. No gradient hero.
   No purple-to-blue gradient family (the #7c3aed / #3b82f6 default). No multi-stop
   gradient with more than three color stops.

3. Layout: asymmetric. No three-equal-card row in a hero or pricing block.
   Use a 7-and-5 split, a bento grid, or a 4-with-one-spanning pattern.

4. Motion: hierarchy-aware. Hero opens; supporting content cascades. Differentiate
   by role — do NOT fade-in-up every direct child. Respect prefers-reduced-motion.

5. Copy: no marketing verbs (Elevate, Seamless, Unleash, Revolutionize, Empower,
   Supercharge, Transform) in headlines. No generic CTAs (Click here, Learn more).
   Use plausible regional names: Maya Iqbal, Adam Levin, Wen Zhang, Layla Haddad.

6. Accessibility: every img has alt + width + height. Every interactive svg has
   aria-label or aria-hidden. No outline:none without focus-visible. No
   placeholder-as-label.

7. Tokens: import from tokens.css. Do not hardcode hex values where a variable exists.

Seven rules, mapped to the categories the linter enforces. Copilot reads this on every completion and biases away from the defaults. The linter then catches what slips through anyway.

The deterministic linter runs over what Copilot writes

Custom instructions raise the floor. They do not set the ceiling. The model still drifts, especially on long generations or when the surrounding code already contains a fingerprint and Copilot pattern-matches against it.

The deterministic floor is the linter. Run it on the diff Copilot just generated, and any fingerprint that survived the instructions surfaces with a line number, severity, and fix.

# Lint the file Copilot just wrote
$ uxskill lint src/components/Hero.tsx --threshold high

[FAIL] 3 findings at threshold high · exit 1

  high  inter-as-display          src/components/Hero.tsx:18
                                  Inter used as display font
                                  fix: pair Inter (body) with Fraunces / Geist / Satoshi

  high  purple-to-blue-gradient   src/components/Hero.tsx:42
                                  Default purple-to-blue AI gradient
                                  fix: single restrained accent against neutrals

  high  three-equal-card-grid     src/components/Hero.tsx:96
                                  Three equal cards in a row
                                  fix: asymmetric layouts (bento, 7-and-5, 4 with one spanning)

No LLM call, no token budget, no flakiness. The linter is regex over JSON. Average pass on a 200-file repo: 380 milliseconds cold, 90 milliseconds warm. Documented in the regex linter post.

Copilot plus ux-skill, side by side

Same prompt to Copilot Chat: "build a hero section for a payments dashboard."

Surface Copilot alone Copilot plus ux-skill
Display type Inter at text-7xl Fraunces variable at text-6xl
Background Tailwind purple-to-blue gradient Cool-neutral surface, single warm accent
Layout Three equal pricing cards 7-and-5 split with one feature spanning
Hero copy "Beautiful payments, seamlessly" "The reconciliation layer your finance team never shipped"
CTA "Get started" / "Learn more" "Book a 20-minute demo" / "See the data flow"
Motion fade-in-up on every child Hero opens; supporting content cascades
Lint result 3 high findings, 4 medium 0 high, 0 medium

Same Copilot. Same prompt. Different generation, because the custom instructions and the linter make defaults expensive and explicit choices easier.

Copilot is a great accelerator. ux-skill is the constraint layer that makes its output specific.

The two install paths

Two ways to wire ux-skill into a Copilot workflow. Pick one or both.

Path A — instructions file plus local linter

$ pip install uxskill
$ uxskill init --target copilot   # writes .github/copilot-instructions.md
$ uxskill discover                # 10-field brief, saves to .ux/last-discovery.json
$ uxskill recommend               # runs 5-parallel-search, picks the system
$ uxskill persist save --project-root .

# Then, after Copilot generates code:
$ uxskill lint src/ --threshold high

The instructions file biases Copilot during generation. The linter catches drift after. Both run locally; neither requires a Copilot API key or any GitHub-side configuration.

Path B — GitHub Actions gate

For repos where you want a non-negotiable design floor, wire the linter into GitHub Actions. Every PR push runs the linter; high-severity findings block the merge.

# .github/workflows/ux-lint.yml
name: ux-lint

on:
  pull_request:
    paths:
      - '**/*.tsx'
      - '**/*.jsx'
      - '**/*.vue'
      - '**/*.css'
      - '**/*.html'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: '3.11'
      - run: pip install uxskill
      - run: uxskill lint --threshold high

What ux-skill ships for Copilot users

What ux-skill does not do for Copilot

Be specific about the limits:

Honesty card

The honest framing of the integration.

This is a partial integration. Copilot is closed source; we cannot intercept its completion stream. What we can do is shape the instructions Copilot reads and lint the code it writes. Both are mechanical, deterministic, and offline.

If you want the deepest possible integration, install ux-skill as a Claude Code plugin too and use Claude Code as your primary design surface, with Copilot as the autocomplete-everywhere layer. The two coexist comfortably.

The 5-minute Copilot setup

End to end from a fresh checkout, Copilot already configured:

  1. pip install uxskill — about 6 seconds.
  2. uxskill init --target copilot — writes .github/copilot-instructions.md and the .ux/ directory.
  3. uxskill discover — 10-field interactive brief, about 90 seconds typing.
  4. uxskill recommend — about 200 milliseconds.
  5. uxskill persist save --project-root . — writes MASTER.md, tokens.css, manifest.json.
  6. Commit those files. Copilot reads them on the next completion.
  7. Run uxskill lint src/ after any significant generation. Block on high or critical.

Total wall-clock from pip install to working linter: under five minutes. Total cost: zero. License: MIT. No telemetry, no API key, no account.

How it compares to Copilot custom instructions alone

Copilot has had custom instructions for some time. Why does the linter add anything?

The instructions reduce the rate of slop. The linter sets the non-negotiable floor. Use both.

Install for Copilot

One command. Instructions file plus linter.

The full ux-skill engine works with Copilot through two surfaces: a generated .github/copilot-instructions.md and a deterministic linter that runs on disk after Copilot writes.

$ pip install uxskill
$ uxskill init --target copilot
$ uxskill lint src/ --threshold high
— or via npx —
$ npx uxskill@alpha init --target copilot
— or as a Claude Code plugin alongside Copilot —
$ /plugin install ux@ux-skill