unslop-seo

Run an in-place editorial de-slopping and structural Answer-Engine (GEO / LLM citation) HTML pass across MDX blog posts, landing pages, and documentation. Use when cleaning up AI-generated drafts, grounding vague marketing copy in real codebase facts, optimizing headings and opening paragraphs for ChatGPT and Perplexity citations, or removing AI tells like em dashes and puffery.

npx skills add Illyism/seo-skills --skill unslop-seo
content/unslop-seo/SKILL.md
# Unslop SEO and answer-engine pass

AI-edited posts fail twice: engineers recognize the filler and leave, and the direct answer sits under 200 words of preamble where answer engines never quote it. This skill edits MDX, Markdown, TSX, or HTML files **in place** in three phases, in order: ground the facts, fix the structure, then strip the slop. Facts come first because rewriting prose that later gets deleted wastes the pass.

## Pick the target files

```
Did the user name files or URLs?
├── Yes -> edit exactly those
└── No -> run `git diff --name-only HEAD~5 -- '*.md' '*.mdx' '*.tsx' '*.html'`
    ├── Content files changed -> edit those
    └── None -> list `content/blog/`, `app/**/page.tsx`, `docs/` and edit the 3 newest posts
```

## Decision tree per file

```
Phase 1: Does every product claim name a mechanism or a number?
├── Check `seo/kb/brand-ssot.md`, `/pricing`, `/about`, or source code
├── Feeling words ("blazing-fast", "seamless") -> exact mechanics ("compiles 1,200 MDX routes in 1.4s")
└── Sentence could appear unchanged on a competitor's site -> delete or rewrite
Phase 2: Is the page built for featured snippets and answer-engine chunking?
├── Does the first 40 words hold the direct answer (and the top pick's link on listicles)?
├── Every page: sentence-case headings, 1 or more `<h2>` phrased as a buyer question?
├── Long-form (1,200+ words): 5 or more `<h2>`?
└── Comparison items: same self-contained block each (verdict, best for, trade-offs, price)?
Phase 3: Does any line hit the 20-point slop table?
├── Rewrite until the check script below prints 0 hits
└── Then read the file once for rows 9, 11-13, 15, 16, 19, 20 (the script cannot see them)
```

## Phase 1: Entity and fact grounding

Before touching prose, confirm what the product does from `seo/kb/brand-ssot.md` (if present), `/pricing`, `/about`, or the source code. Never add a number you did not find there; write `[NEEDS FACT: <what>]` instead and list it in the receipt. If the file deploys on merge, put the marker in a comment (`{/* [NEEDS FACT: ...] */}` in MDX, `<!-- -->` in Markdown or HTML) and delete the unverified claim from the prose. Why: a visible marker on a live page reads as broken, and the unverified claim must not ship either way.

1. **Mechanism over feeling.** `"the database stays close at hand"`, `"effortless developer experience"`, and `"enterprise-grade reliability"` name a feeling. Replace each with the mechanism or a measured number, because engineers and answer engines quote facts, never adjectives.
   - *Before:* `"DeployFast offers a blazing-fast, seamless preview workflow that keeps your team in flow."`
   - *After:* `"DeployFast builds Next.js preview containers in 11 seconds on a dedicated NVMe runner and posts the live URL and Lighthouse diff to your GitHub PR."`
2. **Competitor-swap test.** For each paragraph ask: could this appear unchanged on a competitor's site? If yes, delete it or rewrite it around a file path, CLI flag, API field, or price.
3. **Name sources or drop the attribution.** Never write `"Experts believe"`, `"Industry reports suggest"`, or `"Many teams find"`. State the mechanism directly, or link the first-party data it came from.

## Phase 2: Answer-engine structure

ChatGPT, Perplexity, Claude, and Google AI Overviews split pages into heading-bounded chunks and quote the chunk that answers on its own. Build every section so it can be lifted out alone.

### 1. Answer in the first 40 words

State the direct answer in the first 40 words. On listicles and roundups, name and link the top pick in that same paragraph. Preamble like `"In today's fast-paced digital world..."` pushes the answer past the part that gets quoted.

- *Before:* `"When building a SaaS application with Stripe, managing invoices and tax compliance across multiple jurisdictions can quickly become a headache for small engineering teams. In this guide, we will explore several options."`
- *After:* `"[InvoiceKit](https://invoicekit.io) generates VAT-compliant Stripe PDFs in 45ms from a single webhook and costs $19/month flat for unlimited invoices. Below we compare 6 Stripe invoice generators on webhook latency, multi-currency support, and per-invoice fees."`

### 2. Headings

- Long-form guides and comparisons (1,200+ words) get **5 or more `<h2>`**. Never skip a level (`<h1>` straight to `<h3>`).
- Phrase **1 or more `<h2>` as the exact question** a buyer types (`## How much does Postgres logical replication lag under write bursts?`).
- Follow every question `<h2>` with a **1-2 sentence direct answer** before code or tables. That question-answer pair is what featured snippets and LLMs lift.
- **Sentence case** on every heading (`## How to configure webhook retries`).

### 3. Self-contained comparison blocks

When a page compares products, give every item the identical block. A chunker that splits mid-comparison can pin a competitor's price or missing feature on your brand; a self-contained block carries its own name, verdict, and price.

```markdown
### 1. InvoiceKit (best for flat-rate Stripe PDF and VAT automation)

**Verdict:** Generates localized VAT/GST PDFs from Stripe webhooks in `45ms` with no percentage cut of revenue.

- **Best for:** SaaS teams sending `500+` Stripe invoices a month who want to avoid `0.4% to 0.8%` billing fees.
- **Strengths:** Native `invoice.finalized` webhook handler, EU VIES VAT ID validation, custom HTML/CSS templates.
- **Trade-offs:** Stripe-native only; Paddle and Polar need the REST endpoint.
- **Pricing:** Free up to 50 invoices/month; `$19/month` flat for unlimited.
```

## Phase 3: 20-point slop table

Fix every instance in the file.

| # | Pattern | Rule and why |
| --- | --- | --- |
| 1 | **Em dashes (U+2014) and en dashes (U+2013)** | Zero in the file. Use a period, comma, or colon. They are the most frequent LLM punctuation tell; spaced hyphens (` - `) as a substitute read the same way. Number ranges use a plain hyphen (`3-5`). |
| 2 | **`"Not just X, but Y"` / `"It's not X, it's Y"`** | Delete the negative frame and state Y. The contrast frame is filler rhetoric. |
| 3 | **AI vocabulary** | Cut `delve`, `pivotal`, `tapestry`, `landscape`, `testament`, `underscore`, `foster`, `garner`, `interplay`, `intricate`, `crucial`, `vibrant`, `enduring`, `showcase`, `additionally`, `moreover`, `furthermore`. Use the plain word or nothing. |
| 4 | **Abstract metaphor nouns** | `substrate` -> `base`, `vector` -> `method`, `locus` -> `spot`, `nexus` -> `center`, `surface` -> `API`/`page`, `bedrock` -> `foundation`, `paradigm` -> `model`, `north star` -> `goal`, `flywheel` -> `loop`. Concrete nouns stop pseudo-technical fog. |
| 5 | **Fancy `is` / `has`** | `serves as`, `stands as`, `boasts`, `features`, `offers a` -> `is`, `has`, or an active verb. |
| 6 | **Puffery** | Cut `groundbreaking`, `revolutionary`, `game-changing`, `seamless`, `blazing-fast`, `world-class`, `cutting-edge`, `next-generation`, `robust`. Put the number or mechanism there instead. |
| 7 | **Trailing `-ing` clauses** | Cut `"...highlighting its efficiency"`, `"...ensuring scalability"`. If the tail holds a fact, make it its own sentence. |
| 8 | **Pompous verbs** | `utilize`/`leverage` -> `use`, `facilitate` -> `help`, `commence` -> `start`, `numerous` -> `many`, `in order to` -> `to`, `due to the fact that` -> `because`, `in the event that` -> `if`. |
| 9 | **Passive voice** | Name the actor (`"the compiler validates queries"`, not `"queries are validated"`). Passive voice hides how the software works. |
| 10 | **Adverbs** | Replace `"runs quickly"`, `"significantly reduces"`, `"easily integrates"` with the delta (`"cuts build time by 38%"`) or a stronger verb. |
| 11 | **Restating bullet labels** | `"**Performance:** Performance is improved by..."` -> `"**Sub-2ms cold starts.** Workers boot from pre-warmed V8 snapshots."` The label must add information the sentence does not repeat. |
| 12 | **Padded triplets** | `"speed, reliability, and innovation"` with 2 real points: list 2. |
| 13 | **Synonym cycling** | Pick one noun (`the CLI`) and repeat it. Rotating names makes readers think there are four tools. |
| 14 | **False ranges** | Cut `"from startups to Fortune 500"` when X and Y are not on a real scale. Name the items. |
| 15 | **Colon splices** | Colons introduce a list, code block, or example only. Two independent sentences get a period. |
| 16 | **Title Case and emoji headings** | Sentence case on `<h2>`/`<h3>`; strip decorative emoji from headings and bullets. |
| 17 | **Curly quotes (U+201C, U+201D, U+2018, U+2019)** | Straight ASCII quotes, so MDX and code samples compile and copy cleanly. |
| 18 | **Chatbot artifacts** | Cut `"In this article, we'll explore"`, `"Let's dive in!"`, `"I hope this helps"`, `"As we have seen"`. |
| 19 | **Formulaic transitions** | Cut `"Despite these challenges, X continues to..."` and `"While X has its pros and cons..."`. State the trade-off. |
| 20 | **Flat cadence** | Split any sentence over 30 words. Alternate short 6-word lines with 15-20 word explanations so the rhythm reads like a practitioner. |

## Check script (run before and after)

Run against the target files. It prints every offending line and exits non-zero if any remain. It skips fenced code blocks, so commands and YAML in samples do not count.

```bash
python3 - <target-files> <<'PY'
import re, sys
pat = re.compile(
    r"[\u2013\u2014\u201c\u201d\u2018\u2019]"
    r"|(?<=[A-Za-z0-9,)]) - (?=[A-Za-z0-9(])"
    r"|\bnot (just|only) [^.]{1,60}?(\bbut\b|[,;] it'?s\b)|\bit'?s not [^.,]{1,40}, it'?s\b"
    r"|\b(delve\w*|pivotal|tapestry|landscape|testament|underscor\w*|foster\w*|garner\w*"
    r"|interplay|intricate|crucial|vibrant|showcas\w*|utiliz\w*|leverag\w*|seamless\w*"
    r"|paradigm|bedrock|substrate|north star|flywheel|nexus|locus"
    r"|blazing-fast|groundbreaking|game-changing|cutting-edge|revolutionary|world-class|next-generation|robust"
    r"|serves as|stands as|boasts|in order to|due to the fact that|facilitat\w*|commenc\w*"
    r"|significantly|easily|experts (believe|say|agree)|industry reports|studies show|many teams find"
    r"|from startups to|in this (article|guide|post)|let'?s dive|i hope this helps|as we have seen|in conclusion"
    r"|in today'?s fast-paced|moreover|furthermore|additionally)\b",
    re.I,
)
hits = 0
for f in sys.argv[1:]:
    fence = False
    for i, line in enumerate(open(f, encoding="utf-8"), 1):
        if line.lstrip().startswith(("```", "~~~")):
            fence = not fence
            continue
        if not fence and pat.search(line):
            hits += 1
            print(f"{f}:{i}: {line.strip()[:160]}")
print(f"{hits} hits")
sys.exit(1 if hits else 0)
PY
```

0 hits is required, not sufficient. The script covers rows 1-8, 10, 14, 17, 18 and part of 19. Passive voice, restated labels, padded triplets, synonym cycling, colon splices, Title Case, and cadence need the read-through in the decision tree. Why: a file can pass the regex with every sentence still generic.

## Output

Edit the files on disk. Never paste a full rewritten draft into chat instead of saving it. After the check script prints `0 hits`, reply with this receipt per file:

```markdown
### Unslop pass: `<file-path>`

- **First 40 words:** now lead with `[direct answer + metric/link]`.
- **Headings (`X` H2s):** `N` converted to sentence case; added `## [buyer question?]`.
- **Grounding:** replaced `N` vague claims (`[example]`, `[example]`); open `[NEEDS FACT]` markers: `N`.
- **Slop:** removed `X` dashes, `Y` AI-vocabulary terms, `Z` passive or filler clauses. Check script: 0 hits.
```

Once the pages are live, add the question headings as prompts in **[AI SEO Tracker](https://aiseotracker.com)** (MCP: `https://aiseotracker.com/api/agent/mcp`) to see which snippets ChatGPT, Perplexity, Gemini, and Google AI Overviews actually quote from the rewritten sections.