# AI Tells

> Use when checking whether a UI looks machine-generated: `transition: all`, `scale(0)`, pure-black shadows, default violet gradients, uniform radii, and emoji bullets.

- Skill: `agentsorg/ai-tells` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add agentsorg/ai-tells`
- Raw SKILL.md: https://api.skillmd.com/api/skills/agentsorg/ai-tells/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: agentsorg (https://skillmd.com/u/agentsorg)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/agentsorg/ai-tells

---



# Spotting Machine-Generated UI

Run one question over the whole surface: **could this have been produced in one prompt with nothing specified?** If yes, the tells below are why. This is not an anti-AI scan — plenty of generated UI is excellent, because whoever prompted it specified the type, the palette, the elevation ladder, and the curves. The tells appear where *nobody decided anything*, so every fix is an opinion, not an avoidance. Default posture: **fix in place.** A tell has exactly one correct replacement and no interesting argument attached to it, so editing the file is cheaper and more honest than writing a report and waiting.

Two siblings share the neighbourhood and the boundary is the shape of the answer. `ui-review` promises a verdict over every dimension of a diff; this skill answers one question against a fixed, greppable list and returns a patch rather than a judgment. `design-critique` teaches a looking order that finds things no list contains; this one matches literal tokens. If the user asked "is this well built?" they are not asking this skill.

**Before replacing anything, find the project's own answer.** The replacement values here are house defaults for a codebase with no system. Grep the token file, the Tailwind theme, the CSS custom properties, and `package.json` first: if the project already defines an accent, a shadow ladder, a radius scale, or an easing set, the replacement *is* the project's token and the raw value in the catalog is wrong for this repo. Never resolve a tell by introducing a second styling system alongside the one already there.

## Quick reference

| Topic | File | Open it when |
|---|---|---|
| The full catalog — grep pattern, why it reads as generated, replacement value | `references/tells.md` | Open it at the start of every scan; it is the list the scan runs against, and the replacement column is the only place the exact values live. |

## The scan, in four passes

Run them in order. Each pass is cheaper than the next and catches things the next one would let through.

| Pass | What you do | Judgment required |
|---|---|---|
| 1. Grep | Match the literal token set from `references/tells.md` | None — a hit is a hit |
| 2. Strings | Read every user-visible string: headings, CTAs, empty states, errors, numbers, names | Low |
| 3. Composition | Read the page skeleton, the radius set, the accent count, the section pattern | Medium |
| 4. Decisions | Ask what was *chosen* here that a default would not have chosen | High — this is the real test |

Pass 4 is the frame restated. A page can survive passes 1–3 and still fail: identical card treatment for unrelated content, every route on the same template, a hero followed by three feature cards followed by an FAQ. Nothing there is technically wrong. Nothing there was decided either.

## Core principles

1. **Grep before you look.** The literal set is unambiguous and costs one pass: `transition: all`, `scale(0)`, `ease-in` on a UI element, `transform-origin: center` on a popover, an animation on a keyboard-initiated action, `#000` or `black` as a dark background, `#fff` as text on dark, `0 2px 8px rgba(0,0,0,0.1)`, violet/indigo/fuchsia gradient utilities, `lorem`, `John Doe`, `Acme`. *Exception:* a deliberate `#000` on an OLED-targeted app is a committed choice — confirm it is committed before replacing it.

2. **Fix in place, do not report.** Each tell has one replacement, so a report just adds a round trip before the same edit happens. *Exception:* when the replacement needs a decision the project has never made — picking a display typeface, choosing the brand accent — leave the tell, and say in one line which decision is missing.

3. **Replace the value, never the system.** The fix for a violet gradient hero is one solid accent from the project's ramp, not a new palette; the fix for a Bootstrap shadow is a layered shadow at `4–6%` opacity on a `#111` base, not an elevation redesign. *Exception:* if grep finds no scale of any kind, the smallest honest fix is to introduce one scale for that one dimension and say so.

4. **One saturated accent in the chrome.** More than one accent is the loudest visual tell, because a default palette hands you three and a decision keeps one. The house replacement set: a warm off-white `#fdfdfc` in place of `#fff`, a grey ladder with `rgba(0,0,0,.4)` as the workhorse secondary in place of a second hue, and one saturated accent everywhere else — `color` owns the ramp these come from. *Exception:* semantic status colors — success, warning, danger — are not accents and do not count against the budget.

5. **Rounded numbers and placeholder names are content tells, and content tells are the loudest.** `100+ customers` reads as an approximation because it is one; `127 customers` implies somebody looked at the data. Same for `John Doe`, `Acme Inc.`, and `user@example.com`. *Exception:* never invent a specific number to replace a vague one — if the real figure is unknown, delete the claim instead of fabricating precision.

6. **Uniform radius is a tell, and so is random radius.** A single value applied to every element from the page shell down to the badge means the radius was never chosen. The fix is a small scale with concentric nesting: inner radius = outer radius − padding. *Exception:* a fully-round pill or avatar sits outside the scale and stays that way.

7. **Emoji as list markers, in headings, or inside button labels is a tell.** Emoji carry their own metrics — they ignore the inherited font weight and color and sit on their own optical baseline — so a list bulleted with them breaks vertical rhythm in a way no designed marker does. Replace with a real list marker or an icon from the project's set, sized to the type. *Exception:* user-authored content, where the emoji is data and not design.

8. **A tell is a flag, not a verdict.** Some entries are correct in context: a long duration on a rare celebration, a spinner on a genuinely slow call, an asymmetric grid on a marketing page. Check the context before editing. *Exception:* the five lint-level prohibitions in pass 1 have no legitimate context and are replaced unconditionally.

## Smells

| Smell | Fix |
|---|---|
| Violet → indigo → fuchsia gradient on the hero | One solid accent from the project's ramp |
| `background: #000` in dark mode | `#18181b`, or the project's darkest surface token |
| `color: #fff` on a dark surface | `rgba(255,255,255,0.92)` |
| `box-shadow: 0 2px 8px rgba(0,0,0,0.1)` | Layered shadows at `4–6%` opacity on a `#111` base |
| Same `border-radius` on every element | A radius scale; nest concentrically |
| Lorem ipsum, "Coming soon", "Section title" | Real copy, or delete the section |
| "Get started" as the primary CTA | The actual verb: "Create project", "Import repo" |
| "Oops! Something went wrong" | What happened and what to do: "Couldn't save. Try again." |
| Crossfade between two icons | Transform one icon; `iconography` owns the shape constraint |
| Spinner on a sub-`800ms` call | Nothing; `ui-states` owns the threshold ladder |
| Emoji bullets in a feature list | The project's icon set at the type's optical size |

## Output format

Apply the edits, then report in two short lists. **Replaced** — one line per tell: the pattern, the file, and the value it became. **Left alone** — one line per tell that survived, naming the context that justified it or the decision the project still owes. No table, no verdict, no severity ranking; if the user needs those, they wanted `ui-review`.

## Checklist

- [ ] Project tokens grepped before any replacement value was chosen
- [ ] Pass 1 literal set grepped across the whole surface, not just the changed files
- [ ] Every user-visible string read, including empty and error states
- [ ] Accent count checked — one saturated accent in the chrome
- [ ] Radius set checked for uniformity and for concentric nesting
- [ ] Emoji markers, headings, and button labels checked
- [ ] Every replacement is the project's own token where one exists
- [ ] Edits applied in place, not described
- [ ] Survivors listed with the context or the missing decision that spared them
- [ ] No number invented to replace a vague one

