<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tavero</title>
    <description>The latest articles on DEV Community by Tavero (@taveroui).</description>
    <link>https://dev.to/taveroui</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4204954%2F27920afa-57fc-4761-a926-64c631695cfb.png</url>
      <title>DEV Community: Tavero</title>
      <link>https://dev.to/taveroui</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/taveroui"/>
    <language>en</language>
    <item>
      <title>Vibe-coded UIs drift. I built Tavero to catch it.</title>
      <dc:creator>Tavero</dc:creator>
      <pubDate>Sun, 25 Oct 2026 02:54:44 +0000</pubDate>
      <link>https://dev.to/taveroui/vibe-coded-uis-drift-i-built-tavero-to-catch-it-fk8</link>
      <guid>https://dev.to/taveroui/vibe-coded-uis-drift-i-built-tavero-to-catch-it-fk8</guid>
      <description>&lt;p&gt;If you build React UI with a coding agent, you've probably seen this: every page looks fine on its own, but put them side by side and something's off. The Team page has a flat grey button with a 2px black border. Reports has a pill. Settings has a red one with radius 4. Billing uses &lt;code&gt;#4263eb&lt;/code&gt;, which is &lt;em&gt;almost&lt;/em&gt; your primary color, but not quite.&lt;/p&gt;

&lt;p&gt;Nobody decided this. The agent just wrote a new button inline each time, because it didn't know (or forgot) that &lt;code&gt;src/components/Button.tsx&lt;/code&gt; exists.&lt;/p&gt;

&lt;p&gt;I built &lt;strong&gt;Tavero&lt;/strong&gt; to catch exactly that drift and hand it back to the agent as concrete fixes. It's free and open source.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Tavero scans your &lt;em&gt;running&lt;/em&gt; React app — what the browser actually renders — at mobile, tablet and desktop widths. It runs four rules, and every finding names the component and the source line:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Buttons&lt;/strong&gt; — distinct button styles, near duplicates, and buttons written in page markup instead of the shared component.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cards&lt;/strong&gt; — card-like containers that differ in background, border, radius, padding or shadow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colors&lt;/strong&gt; — colors outside your tokens, the nearest token, and where the literal is written.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scales&lt;/strong&gt; — radius, spacing, font size and shadow values that aren't on the scale your tokens declare.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what a button finding looks like on the Acme demo (6 pages, 3 widths), which turned up 7 text button styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Button "primary" · canonical · 9 renders
  src/components/Button.tsx:4  bg #3b5bdb, radius 6, padding 10/16, 14px/600
written in Team · 3 renders
  src/pages/Team.tsx:6         bg #f0f0f0, radius 0, padding 1/6, 13px/400, border 2px #000
written in Settings · 3 renders
  src/pages/Settings.tsx:12    bg #e03131, radius 4, padding 10/16, 14px/600
written in Billing · 3 renders
  src/pages/Billing.tsx:8      bg #4263eb, radius 8, padding 11/18, 14px/600
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a scale finding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;radius off the scale: 4px, 8px, 14px, 999px · declared: 10px, 6px
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The agent closes the findings
&lt;/h2&gt;

&lt;p&gt;Tavero runs as an MCP server, so the agent can use it directly. The loop is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the context&lt;/strong&gt; — canonical components, tokens and conventions, in about 1,500 tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open a finding&lt;/strong&gt; — file and line, the current value, and the token or component to use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix and rescan&lt;/strong&gt; — only the routes and the rule it touched. Seconds, not minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the diff&lt;/strong&gt; — done when the finding is listed as resolved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In practice:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;› tavero_context
Action button is Button from src/components/Button.tsx (props: variant)
--acme-primary #3b5bdb · --acme-radius 10px · --acme-space 16px

› tavero_findings rule=colors
f_ff30adc07c Color #4263eb is not a project token

› tavero_finding f_ff30adc07c
src/app.css:33 literal #4263eb in source
expected --acme-primary #3b5bdb (ΔE 3.5)
edit src/app.css:33 background: #4263eb → var(--acme-primary)

› tavero_scan routes=/billing rules=colors

› tavero_diff
resolved f_ff30adc07c Color #4263eb is not a project token
resolved f_18862a0332 Hardcoded color #4263eb in 1 place(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That run was Claude Code with Opus 5.5, no shell, 29 seconds, 10 turns, on a copy of the Acme demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  You decide what's intended
&lt;/h2&gt;

&lt;p&gt;Not every difference is a bug. A red destructive button is probably on purpose. So there's a local panel for the person behind the agent: go through findings with the keyboard and mark each one:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fix&lt;/strong&gt; — confirmed work; the agent sees it first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intended&lt;/strong&gt; — hidden from the agent until the finding grows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canonical&lt;/strong&gt; — the reference variant, with a name, used as the expected value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can attach a message to a finding, and each decision reaches the agent on its next call — no rescan needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;Add the MCP config to your client. For Claude Code (&lt;code&gt;.mcp.json&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tavero"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stdio"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"-y"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tavero"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mcp"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cursor uses the same block in &lt;code&gt;.cursor/mcp.json&lt;/code&gt;. There are configs for Codex, Gemini CLI, Antigravity, VS Code and Windsurf too — &lt;code&gt;tavero mcp --print-config&lt;/code&gt; prints all of them.&lt;/p&gt;

&lt;p&gt;Then ask your agent to read &lt;code&gt;tavero_context&lt;/code&gt; before it writes UI.&lt;/p&gt;

&lt;p&gt;More, including the demo findings: &lt;a href="https://taveroui.com" rel="noopener noreferrer"&gt;https://taveroui.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you try it on your app, I'd love to hear what it finds.&lt;/p&gt;

</description>
      <category>react</category>
      <category>ai</category>
      <category>mcp</category>
      <category>designsystems</category>
    </item>
  </channel>
</rss>
