Skip to content

Agentic UI: Lint feature code that reaches into the UI primitives - #5396

Open
youknowriad wants to merge 20 commits into
trunkfrom
add-ui-design-system-guards
Open

youknowriad wants to merge 20 commits into
trunkfrom
add-ui-design-system-guards

Conversation

@youknowriad

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Claude Code picked the rules from the drift the fidelity passes kept fixing, and from the rebuild's design-system lint rules. It wrote the rule and its tests, and added an exception with a reason for each existing case. It also broke a feature file on purpose to confirm that each guard fires.

Proposed Changes

The fidelity passes kept fixing the same drift: feature CSS bending a primitive to match one screen instead of fixing the primitive for every caller. The rebuild blocks this with shadcn/no-restyle. With CSS Modules a className can't be told apart from layout, so these guards catch what we can see in the CSS and the imports:

  • Feature CSS can't reach into a primitive's parts. A selector with [data-slot=…] outside lib/ fails lint.
  • Feature CSS can't set a primitive's private custom properties, such as --button-size, --button-padding-inline, --button-active-*, --alert-tone or --command-radius. The list comes from the primitives' own CSS, minus the theme tokens and the documented hooks (--button-background, --button-hover-background, --button-hover-color), so new primitives are covered without editing the config.
  • No !important in apps/ui CSS, with ESLint's own css/no-important. The reduced-transparency reset and Shiki's inline colors are the two exceptions.
  • Features don't import Base UI directly, as AGENTS.md already asks. Toasts are the one exception: they render in one place, so Toast has no primitive.

The ten existing cases each carry an inline exception with its reason. Each one is a candidate for a primitive prop later, for example a Progress intent for the credits meter. The Publish trigger's exception goes away with #5394.

Not ported from the rebuild: the field-spacing and Settings Save-button rules. Field spacing has no override to catch here, and our Save buttons differ by context (form row, API key, dialog footer), so they don't share one component. Raw values are covered by #5390's token rule.

Testing Instructions

  • npx eslint apps/ui/src passes.
  • Add .x { --button-size: 1px; } or .x [data-slot='field-label'] {} to a feature CSS module, or import { Menu } from '@base-ui/react/menu' in a feature: lint fails with a message pointing to the primitive.
  • npm test -- tools/eslint-plugin-studio

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

🤖 Generated with Claude Code

youknowriad and others added 20 commits October 25, 2026 11:42
…er tokens, and use them instead of literals

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… global svg rule

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…lors to their scene

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re-css-recipes

# Conflicts:
#	apps/ui/README.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-css-design-tokens

# Conflicts:
#	apps/ui/src/features/chats/session-view/conversation/style.module.css
#	apps/ui/src/features/composer/style.module.css
#	apps/ui/src/features/sidebar/site-list/style.module.css
#	apps/ui/src/features/sites/site-preview/style.module.css
…re-css-recipes

# Conflicts:
#	apps/ui/src/features/chats/session-view/conversation/style.module.css
#	apps/ui/src/features/composer/style.module.css
#	apps/ui/src/features/sites/site-preview/style.module.css
…pe-css-surfaces-and-schemes

# Conflicts:
#	apps/ui/src/features/chats/session-view/conversation/style.module.css
… for colors, type, radii, shadows and layers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	apps/ui/src/features/composer/attachment-chips/style.module.css
#	apps/ui/src/features/composer/style.module.css
#	apps/ui/src/features/notifications/notice-history/style.module.css
#	apps/ui/src/features/sidebar/sidebar-header/style.module.css
#	apps/ui/src/features/sidebar/site-list/style.module.css
# Conflicts:
#	apps/ui/src/features/chats/session-view/conversation/agent-question/style.module.css
#	apps/ui/src/lib/theme/tokens.css
#	apps/ui/src/lib/ui/dialog/style.module.css
#	apps/ui/src/lib/ui/input-group/style.module.css
#	apps/ui/src/lib/ui/popover/style.module.css
#	apps/ui/src/lib/ui/switch/style.module.css
…ions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from add-css-design-tokens to trunk October 25, 2026 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant