深信号· DEEPSIGNAL
深信号· DEEPSIGNALRSS
SIGNAL DEEP-DIVE

AI 写 UI 总违规?这个 lint 把设计规范变成 agent 能跑的规则

2026-09-16·GitHub·开发工具开源项目lintTailwind设计系统shadcnagent 编程实测
▮ SIGNAL SUMMARY · 摘要快读

@shadcn/lint 是 shadcn/ui 团队刚开源的一个"agent 优先"的 Tailwind 设计系统 linter:把"按钮只能加 margin 不能改 padding"这类规范写成可配置规则,agent 写坏代码时,报错信息直接告诉它该用什么。我装进一个小项目实测:6 个违规全被抓住,报错自带修复引导。官方 150 多次任务跑测,四款模型基本一轮清零违规。

AI 写 UI 总违规?这个 lint 把设计规范变成 agent 能跑的规则

用过 AI 写前端的人,多半见过这种场面

让 Claude 或 Codex 改一个页面:它给你加了 p-4,把按钮的圆角改成 rounded-full,还顺手塞了个 bg-pink-500。代码能跑,看着也还行——但你的设计系统就这么被一点点磨平了:按钮该有的间距、圆角、颜色,全被"顺手"改没了。你逐行 review 能拦得住,可 agent 一分钟产出你十分钟的量,review 根本跟不上。

这个问题的本质是:设计规范是"半显性"的知识。它写在团队脑子和设计文档里,agent 读得到代码,读不到约定。shadcn/ui 团队(就是那个 90 万星的开源组件库)最近开源了 @shadcn/lint(shadcn-ui/lint,MIT,1567★、13 天龄,开源地址),专门治这个病:把设计规范写成 lint 规则,agent 写坏代码时,报错直接告诉它"哪里错了、该用什么、去哪改"。

我把这个包装进一个最小项目实测了一遍。

项目速览

项目@shadcn/lint
开源地址https://github.com/shadcn-ui/lint
Stars1567(数据采集 2026-09-16)
协议MIT
创建2026-09-02(14 天龄)
技术栈TypeScript / ESLint 9.30+ 或 Oxlint 1.80+

它和传统 lint、和 TypeScript 类型,差在哪

传统 lint 查的是"语法对不对":变量没声明、重复 import。TypeScript 类型能管一部分——比如你可以在组件 props 里用 Pick 禁止外部传 padding。但类型报错只说"padding 不允许",不告诉你该用什么

<Button style={{ padding: 16 }}>Submit</Button>
// TS2353: 'padding' does not exist in type ...

agent 看到这条报错,只能自己猜。而 @shadcn/lint 的报错长这样(官方 README 示例,我实测也复现了):

"p-4" is not allowed on <Button>: <Button> owns its spacing.
Use a size (sm, lg), or margin here or gap on the parent for space around it.
Add a size in components/ui/button.tsx only if the design explicitly calls for one.

三个信息全给了:违反了哪条规范、设计系统允许什么、去哪改。agent 不需要猜,照着改就行。这就是它自称"agent-first"的含义——报错信息不是给人看的提示,是给 agent 的修复指引。

规则有六条:no-restyle(不许用 className 改组件样式)、no-raw-colors(不许用 bg-pink-500 这类裸色)、no-arbitrary-values(不许用 p-[13px] 任意值)、no-inline-stylesno-unknown-classesrequire-static-classes。每条都可以按组件配"契约"——比如 Button 只允许 mt-mb-w-full,CardTitle 可以改字号但不可以改字重。

规则本身是普通 ESLint 配置,写在 eslint.config.mjs 里,一个例子就懂(官方 README 原例):

"shadcn/no-restyle": ["error", {
  allow: ["layout"],
  contracts: [
    { pattern: "^Button$", allow: ["w-full", "mt-*", "mb-*"] },
  ],
}]

含义:布局类(margin、width)默认允许;Button 组件额外只允许这三个 class 家族,padding、圆角、颜色一律禁止。它怎么认出 Button 是"你的组件"?读 components.json 指认的组件目录,跟着 import 解析到定义文件,还支持 re-export 改名跟踪(export { Button as Action } 也能认)。不依赖 shadcn/ui,自带组件的项目也能用。

放大镜悬在代码纸上,镜下露出红笔圈出的色块与间距刻度,桌面散落色板卡

实测:装进小项目,六条违规全被抓

我按 README 的 Get started 步骤,在一个最小 TSX 项目里装好(eslint 9.39 + @typescript-eslint/parser),配了一个真实的 Button 组件、components.json 和 Tailwind theme,然后写三行"坏代码"跑 lint:

违规代码期望实测结果
3 条 no-restyle + 1 条 no-raw-colors✅ 全命中
合法(契约允许)✅ 零误报
契约外(只允许 w-full/mt-/mb-✅ 2 条命中

p-4 的报错直接点出"Button owns its spacing,请用 size 变体或在父级加 gap";bg-pink-500 被提示"请用 theme 里已声明的 brand、primary,或在 theme.css 里声明新颜色"。6 个违规全部精准识别,契约允许的写法零误报。

实测三数:成本 0 元(纯本地静态分析,不调模型);耗时 构建 2.8s、单次 lint 约 1.2s;失败率——按 README 早期示例用 @shadcn/lint/tailwind 子路径导入会报"package subpath not defined"(文档坑,Get started 一节用的是 import { plugin as shadcn },写法对不上),改对后一次通过。不确定:我用的 Node 22、ESLint 9.39,Oxlint 通道(官方称 alpha)未测。

官方自测:150 多次任务,四款模型基本一轮清零

作者在 README 贴了一组评估(evals 文档):用多款模型跑了 150 多次 UI 任务,记录 lint 反馈前/后的违规数——

模型完成任务反馈前违规反馈后违规
Sonnet 58/8690
Haiku 4.58/8660
Opus 58/8420
GPT 5.6 Terra8/81170

几乎每个模型在拿到一轮 lint 反馈后都把违规清零。另一组数据更实际:在 Claude 对照实验里,带 lint 反馈的修复成本比只给规则低了 10% 到 48%——因为 agent 不用反复试错猜"什么能改什么不能改"。

这些是作者自测,我没法独立复现,只能转述。但"报错带修复引导"我实测确认了,它确实把 agent 从"猜规范"里解放出来。

它怎么认出你的设计系统

这层能力值得单独说一下。@shadcn/lint 不运行你的应用,纯静态分析:读 components.json 拿到组件目录,解析 import 找到 Button 的定义文件,读出它暴露的 size/variant 变体和默认样式;读 theme.css 里的 @theme 声明,知道你的色板有哪些 token。所以它才能报出"用 size (sm, lg)"和"用 theme 色 brand、primary"这种具体到你自己项目的建议。

它的边界也在这:规则质量取决于它对你组件和 theme 的理解,组件写得绕、theme 没声明完整,报错建议就可能失真——我实测用的是最简单的组件,复杂生产组件下表现如何,不确定/待验证

设计规范的价值,不在文档里,而在"agent 违反它时,系统能不能立刻拦住并教会它"。

落到工程上:谁来写规则,是个真问题

说完了优点,泼一盆冷水。这个工具的定位很诚实:它不提供规范,只提供把规范变成规则的能力。规则得你自己写——你团队的按钮允不允许改 padding、Card 标题能不能动字重,这些判断它替不了你。对设计系统成熟、规范清晰的团队,这是把约定固化成契约的好工具;对"先跑起来再说"、样式本来就在野蛮生长的项目,你可能写不出几条规则,也就享受不到它的价值。

这里要提一下同生态的"前任":Tailwind 官方的 eslint-plugin-tailwindcss 主要做 class 排序、重复类名这些语法级检查,管不到"Button 不许改 padding"这种设计系统级约束。@shadcn/lint 补的正是这一层——它的报错带着你的组件变体名和 theme 色板,是把"你的设计系统"编译进了错误信息里。这也是为什么它能说服 agent:错误本身就是从你的 Button、你的 theme.css 里读出来的,不是通用话术。

机械手握着画笔给稿纸上一个按钮重新涂色与圆角,旁边放着写有组件名的木牌

还有一个生态现实:它绑定 Tailwind v4 + ESLint 9.30+(或 Oxlint 1.80+)。Tailwind v3 项目、老 ESLint 项目要迁移才能用。shadcn/ui 组件库的用户上手最快(自动发现 components.json 和组件),非 shadcn 用户要手动配 settings.shadcn 指认组件目录。

信号强度

前端开发者:如果你在用 agent 写 UI 且深受"改坏设计系统"之苦,它值得一试——尤其你本来就基于 Tailwind v4 + shadcn/ui。装好后把它写进 AGENTS.md,让 agent 改完代码自己跑 lint,等于给 AI 配了个"设计系统守门员"。

Agent 工具链玩家:@shadcn/lint 是"把人的隐性知识变成 agent 可执行契约"的好样本。同样的思路可以复制到代码规范、文案风格等领域——先定义规则,再让 agent 自己验证自己,而不是靠人 review。

设计系统负责人:这套"契约 + 报错引导"的模式,比出一本没人读的设计规范文档管用。规范从"文档"变成"门禁",且门禁是可编程、可共享、可版本化的。

技术管理者:落地成本要算清楚——规则编写、Tailwind v4 迁移、组件目录配置都是人力投入。它省的是"人审 agent 代码"的时间,前提是你的设计规范已经成文。

AI 写代码的速度已经是人的十倍,但"写得对"的标准还在人脑里。@shadcn/lint 的聪明之处,是把标准从人脑里搬出来、变成 agent 看得懂的报错。这个方向我认为是 AI 编程的必经之路——不是让 AI 少写,而是让 AI 写得能被人(和系统)验证。

SIGNAL FILE · 情报档案

@shadcn/lint 解决的是 AI 写 UI 时代的新矛盾——agent 产代码的速度远超人类审代码的速度,而"设计规范"这种半显性的知识,正是 agent 最容易违反、人最懒得逐条查的。它把规范从"人脑里的约定"变成"机器可执行的契约",方向对了;但规则要自己写、组件要自己认,落地成本不低。

本文基于 AI 情报库收录的条目展开深析;事实性信息以原始报道为准,分析与展望为编辑观点。

原始报道:https://github.com/shadcn-ui/lint(GitHub)

RELATED SIGNALS · 关联信号