# Scan a web project

> Point the dependency-free scanner at a project path, interpret grouped vs JSON reports, and verify findings against detection rules.

- Repository: yetone/kill-ai-slop
- GitHub: https://github.com/yetone/kill-ai-slop
- Human docs: https://grok-wiki.com/public/docs/yetone-kill-ai-slop-c0d8c9670cbb
- Complete Markdown: https://grok-wiki.com/public/docs/yetone-kill-ai-slop-c0d8c9670cbb/llms-full.txt

## Source Files

- `skill/scripts/scan.mjs`
- `skill/references/detection.md`
- `skill/README.md`
- `README.md`
- `skill/references/taxonomy.md`

---

---
title: "Scan a web project"
description: "Point the dependency-free scanner at a project path, interpret grouped vs JSON reports, and verify findings against detection rules."
---

`skill/scripts/scan.mjs` is a Node-only, dependency-free walker that greps frontend source for the 23 AI-slop tells encoded in its `TELLS` table (aligned with `skill/references/detection.md`). Point it at a project root, read the grouped `file:line` report or `--json` output, and treat every hit as a lead to confirm in code—not a verdict. The scanner never edits files.

## Prerequisites

- Node.js available as `node` (ESM: `import` from `node:fs` / `node:path`).
- A local checkout that includes `skill/scripts/scan.mjs` (no `npm install` for the scanner itself).
- A web project path to scan (HTML/CSS, React/Vue/Svelte/Astro, Tailwind, Markdown, and related frontend source).

<Note>
Standalone scan is read-only. Proposing or applying clean fixes is the agent skill path (`skill/SKILL.md`), not this script.
</Note>

## Invoke the scanner

Usage from the script header:

```text
node scan.mjs [root] [--json] [--no-color]
```

From a full repo checkout:

```bash
node skill/scripts/scan.mjs path/to/project          # grouped report
node skill/scripts/scan.mjs path/to/project --json    # machine-readable
```

From inside `skill/` (paths in `skill/README.md`):

```bash
node scripts/scan.mjs path/to/src          # human-readable report
node scripts/scan.mjs path/to/src --json   # machine-readable
```

### CLI inputs

| Input | Behavior |
| --- | --- |
| `root` (positional) | First argv token that does not start with `-`. Default: `.` |
| `--json` | Machine-readable report mode (`asJson`). Disables ANSI color. |
| `--no-color` | Force plain console output even when stdout is a TTY. |

Color is enabled only when all of these hold: `--no-color` is absent, stdout is a TTY (`process.stdout.isTTY`), and `--json` is absent.

## What the walker includes and skips

`walk(dir)` recurses from `root` and collects files for `scanFile`.

### Included extensions and special names

`EXTS` in `scan.mjs`:

| Extension | Notes |
| --- | --- |
| `.html`, `.css`, `.scss`, `.sass`, `.less` | Markup and styles |
| `.tsx`, `.jsx`, `.ts`, `.js`, `.mjs`, `.cjs` | App/source JS/TS |
| `.vue`, `.svelte`, `.astro` | Framework SFCs |
| `.md`, `.mdx` | Prose / docs copy |

Also included by basename: any `tailwind.config.*` file (matched with `/^tailwind\.config\./`).

`detection.md` documents the same frontend scope (with a slightly shorter extension list in prose); the implementation in `scan.mjs` is authoritative for what the script actually opens.

### Skipped directories

`SKIP_DIRS`:

`node_modules`, `.git`, `dist`, `build`, `out`, `.next`, `.astro`, `.output`, `.svelte-kit`, `.nuxt`, `coverage`, `vendor`, `.cache`, `.vercel`, `.turbo`

Dot-directories that appear in `SKIP_DIRS` are skipped; other walk errors on `readdirSync` return the files collected so far.

### Skipped files

- `*.min.js` / `*.min.css`
- Lockfiles matching `package-lock`, `pnpm-lock`, or `yarn.lock` in the basename
- Files larger than **512 KiB** (`st.size > 512 * 1024`) — treated as large/generated; `scanFile` returns no hits
- Unreadable paths (`statSync` / `readFileSync` failures return `[]`)

## Tell catalogue encoded in the scanner

Each entry in `TELLS` has:

| Field | Role |
| --- | --- |
| `id` | Two-digit tell id (`"01"` … `"23"`), shared with taxonomy/detection language |
| `group` | Bucket used for reporting: `color`, `type`, `copy`, `component`, `layout`, `evolved` |
| `name` | Short human label |
| `fix` | One-line remediation hint printed with the tell |
| `patterns` | One or more `RegExp`s applied to file text |
| `copy` | Optional; when `true`, the tell is a copy tell (prose-oriented). Set on **10**, **11**, **12** |

Script comment: code tells target code/style files; copy tells also read prose. `scanFile` begins an `isCode` branch after the read (remainder of match/filter logic is in the full script); pattern lists themselves are fully declared in `TELLS`.

### Tell inventory (ids and groups)

| Id | Group | Name | Fix (scanner one-liner) |
| --- | --- | --- | --- |
| 01 | color | indigo→violet gradient | one solid, chosen accent |
| 02 | color | gradient-clip headline | solid ink, scale up |
| 03 | color | warm ‘cozy’ palette | neutral base + one warm accent |
| 04 | color | default semantic palette | one palette: neutrals + a couple of chosen states |
| 05 | color | one-hue status box | state in words; one muted accent on neutral |
| 06 | color | gradients as atmosphere | one flat bg; depth from a hairline |
| 07 | type | serif-italic emphasis | emphasise by weight, one voice |
| 08 | type | serif where sans belongs | one legible UI sans |
| 09 | type | decorative strikes & highlights | strike for edits, underline for links |
| 10 | copy | highlighted keywords | let structure carry emphasis |
| 11 | copy | AI copywriting voice | say the specific thing |
| 12 | copy | emoji everywhere | cut emoji from product copy |
| 13 | component | glowing status dot | flat dot + a word; no halo |
| 14 | component | left-border callout | one aside, rest is body |
| 15 | component | pastel icon tiles | labelled list with specifics |
| 16 | component | max-radius / glassmorphism | one small radius, solid surfaces |
| 17 | component | oversized drop shadow | tight elevation, never bigger than the element |
| 18 | component | corners that don't nest | inner = outer − padding |
| 19 | component | badge / pill spam | badges only for real status |
| 20 | component | AI-drawn SVG icon | a real, high-quality icon (a designer, or a strong image model) |
| 21 | component | icon in a tint of itself | no tinted tile; inherit text color |
| 22 | layout | all-caps card grid | show the one key thing fully |
| 23 | evolved | tasteful-terminal | mono for code only |

Human-oriented pattern notes, false positives, and confirm checks live in `skill/references/detection.md`. Taxonomy prose lives in `skill/references/taxonomy.md`.

## Interpreting reports

### Grouped (default)

Default mode prints a **grouped report of `file:line` hits** for matching tells. Expect human-oriented grouping by tell (ids/names/fixes from `TELLS`) and path/line locations relative to the walk root—not a pass/fail grade.

Success signals:

- Process exits after printing (no write side effects).
- Hits appear as locations you can open in an editor.
- Empty or sparse output means no pattern matched under the walk rules (not proof that the UI is free of slop).

### JSON (`--json`)

`--json` selects machine-readable output and turns color off. Use it for piping into triage tooling or agent hosts. Treat payload fields as whatever the script emits at runtime; wire consumers against a real run of `scan.mjs` rather than inventing a schema from this page.

### Constraint shared by both modes

From the scanner header and READMEs:

- **Never edits files**
- **Every hit is a lead to confirm by reading the code, not a verdict**

A gradient, serif, emoji, or monospaced UI can be intentional design. The skill (when used) triages slop vs chosen design; the standalone scanner only surfaces signals.

## Verify findings against detection rules

Use `skill/references/detection.md` as the human checklist for each tell id. Workflow:

<Steps>
  <Step title="Map the hit to a tell id">
    Match the report’s tell id/name to the same numbered section in `detection.md` (and the taxonomy entry in `taxonomy.md` for “why it reads as machine-made” and the intended fix direction).
  </Step>
  <Step title="Open the file at the reported line">
    Confirm the match is real in context (class list, CSS, markup, or copy), not a partial string inside an unrelated token.
  </Step>
  <Step title="Apply the confirm / false-positive rules">
    Detection entries call out usual lies of each pattern—for example brand-true purple vs indigo→violet factory gradient; logo wordmark vs default gradient headings; food/craft warm identity vs cozy-as-default; emoji in documented code samples vs emoji on every chrome heading.
  </Step>
  <Step title="Keep defended choices">
    Taxonomy rule: slop is the *absence of a decision*. Keep anything clearly intentional; only treat default, unchosen machine patterns as fix candidates.
  </Step>
</Steps>

### Representative confirm checks (from detection.md)

| Id | Confirm / false-positive stance |
| --- | --- |
| 01 | Slop is the *combination* (purple gradient + glow + pill + “AI-powered” eyebrow), not every purple brand accent |
| 02 | Logo wordmark or one deliberate hero treatment can be fine; default gradient heading style is the tell |
| 04 | Confirm several stock `-50` / `-600` semantic pairs together, unrelated to brand |
| 05 | Same hue on border, text, and `/10` background on one alert |
| 11 | Quotes or docs *discussing* the phrases (including this project’s own docs) can false-positive |
| 12 | Code samples, emoji pickers, UGC are not chrome spam |
| 16 | `rounded-full` on avatars/pills is expected; on cards/inputs as default surface is the concern |
| 17 | 60px+ blur/spread fog under a small element; large surfaces with proportionate shadow can be fine |
| 18 | Same large radius on nested boxes (inner should be outer − padding) |
| 20 | Visual judgment on blob-with-dot-eyes / primitive mascot SVGs, not every `<svg>` |

When a pattern is “hard to grep” in detection notes (e.g. serif-italic *inside* a sans heading, nested corner math), the scanner’s regexes are still leads—open the structure and decide.

## Runbook: first report

<Steps>
  <Step title="Point at a tree">
    Prefer the app’s source root (or monorepo package path), not a parent full of unrelated repos, so skip lists and path noise stay useful.
  </Step>
  <Step title="Run grouped once">
    ```bash
    node skill/scripts/scan.mjs path/to/project
    ```
  </Step>
  <Step title="Optionally capture JSON">
    ```bash
    node skill/scripts/scan.mjs path/to/project --json > slop-report.json
    ```
  </Step>
  <Step title="Triage by id">
    Work tell-by-tell using `detection.md` confirm notes; drop false positives before any fix work.
  </Step>
  <Step title="Hand off to remediation only when ready">
    Map confirmed hits to `skill/references/fixes.md` / agent fix flow. Do not expect `scan.mjs` to rewrite the tree.
  </Step>
</Steps>

## Failure modes and quiet results

| Situation | What the script does | What to check |
| --- | --- | --- |
| Path missing or unreadable | `walk` / `scanFile` soft-fail toward empty collections | Permissions, path spelling, root default `.` |
| Only build artifacts under root | Skipped via `SKIP_DIRS` | Point at `src` / app package |
| Large generated bundles | Files &gt; 512 KiB skipped | Scan sources, not minified dumps |
| Zero hits | No matching patterns in included files | Patterns are heuristic; visual review still applies |
| Hits on this repo’s own docs | Copy patterns can match documented phrases | Apply false-positive guidance for tell 11 (and similar) |

## Relationship to the agent skill

| Surface | Role |
| --- | --- |
| `skill/scripts/scan.mjs` | Read-only signal report |
| Agent skill (`kill-ai-slop`) | Scan → triage → report → propose/apply fixes per `skill/SKILL.md` |
| `skill/references/detection.md` | Human pattern book; scanner encodes the same class of signals |
| `skill/references/taxonomy.md` | What each tell is and the fix direction |
| `skill/references/fixes.md` | Before→after remediation patterns |

After a confirmed report, move to clean fixes through the skill or the remediation playbook—not by expecting the scanner to mutate files.

## Related pages

<CardGroup>
  <Card title="Scanner CLI reference" href="/scanner-cli-reference">
    Invocation, flags, walk/scan behavior, and the hard no-edit constraint.
  </Card>
  <Card title="Detection patterns" href="/detection-patterns">
    Per-tell patterns, match targets, and false-positive notes.
  </Card>
  <Card title="Skill workflow" href="/skill-workflow">
    Full agent lifecycle: scan, triage, report, then propose or apply fixes.
  </Card>
  <Card title="Apply clean fixes" href="/apply-clean-fixes">
    Map confirmed hits to the fixes playbook and agent propose vs apply.
  </Card>
  <Card title="Slop taxonomy" href="/slop-taxonomy">
    Categories and named signals shared by the field guide and skill.
  </Card>
  <Card title="Quickstart" href="/quickstart">
    Shortest path to a first scanner report and field-guide run.
  </Card>
</CardGroup>
