Tech27 min read

30 Open-Source SEO Skills for Claude Code, Cursor and Codex (and How to Chain Them)

Install 30 open-source SEO skills in Claude Code, Cursor or Codex with one command. Four chained workflows that end in merged PRs, proof-backed posts and links.

30 open-source SEO skills for Claude Code and Cursor: a rocket launching from a code terminal up a ladder of ten search results to position 1
TL;DR
  • What it is: 30 open-source SKILL.md workflows (Illyism/seo-skills v1.3.0, MIT) that make Claude Code, Cursor, and Codex ship SEO work as PRs and files in your repo.
  • Install: npx skills add Illyism/seo-skills
  • Browse: every skill with a copyable prompt at /skills. Source on GitHub (Illyism/seo-skills).
  • Site doesn't rank and you don't know why: run seo-roast first.
  • SEO that runs daily without you: seo-autopilot.
  • One money page stuck on page 2: blitz-seo.
  • Missing from ChatGPT and Perplexity answers: aiseotracker.
  • New product at DR 0: directory-submissions.

I open-sourced 30 SEO skills for Claude Code, Cursor, and Codex. Each one is a SKILL.md file that ends in something you can merge or send: a fix PR, a rewritten MDX post, a 301 redirect map, an outreach batch. One command installs all 30.

In June I wrote Outputmaxxing after finding that my best revenue month was mostly someone else's blog post. I ended it with one test: after someone uses your tool, what exists that didn't exist before? This repo is that test applied to SEO. Below are the four chains I'd run, the prompts to copy, and the files each one leaves in your repo.

Disclosure: the paid products linked below (LinkDR, AI SEO Tracker, GenPPT, Scribiz, Awesome Tools, SEO Roast, XOutlier) are mine and sponsor the repo. The skills are MIT-licensed, and 24 of the 30 run without any of them.

Why do generic AI SEO prompts end in a 40-page audit nobody reads?

A prompt has no rule for what matters first and no access to your code. So the model lists every issue it can find, ranks none of them, and stops at the report.

Dusty grey binder labeled 40-Page Audit PDF beside a glowing green pull request card labeled Merged PR + Rankings lifting off over a rising bar chart

You've seen the result. Missing alt text, meta descriptions a few characters too long, an H3 before an H2. All of it sits at the same priority as the one line in robots.txt that hides the site from Bing. The list is correct and nobody acts on it.

In Outputmaxxing I wrote that a good audit used to be worth $5,000 because finding the problems was hard. An agent now does it for about $0.50 of tokens. The audit stopped being the scarce part. The merged fix still is.

A skill swaps the open prompt for a decision tree. This is the core rule in seo-roast, copied from its SKILL.md:

issue found
├── FATAL: blocks crawling, indexing, or rendering of a revenue page
│   └── Fix in this PR. Nothing else ships until this tier is empty.
├── REVENUE: page indexes but cannot rank or cannot convert
│   └── Fix in this PR if it takes under 1 hour of code, else top of roadmap.
├── COMPOUNDING: authority, links, AI visibility
│   └── Roadmap with owner and first action.
└── FLUFF: alt text, meta length, heading order, minor schema warnings
    └── One line at the bottom of the roadmap. Do not fix while FATAL or REVENUE rows remain.

The agent now has an order, so the alt tags wait until the crawl blocker is gone. And the file runs inside Claude Code, Cursor, or Codex, where the agent already has your repo open. It edits robots.txt, rewrites the MDX, builds the redirect map, and opens the PR. I wrote the skills to end there, in a diff or a file you can review.

How do SEO skills work in Claude Code, Cursor, and Codex?

An SEO skill is a folder with a SKILL.md file: Markdown instructions, decision trees, and output templates that follow the open Agent Skills specification. Your agent reads only each skill's name and description at startup and opens the full file when your prompt matches.

Install takes one command:

# all 30 skills
npx skills add Illyism/seo-skills

# one skill
npx skills add Illyism/seo-skills --skill seo-roast

# list what's in the repo
npx skills add Illyism/seo-skills --list
AgentWhere SKILL.md livesInstall
Claude Code
.claude/skills/ or ~/.claude/skills/
npx skills add Illyism/seo-skills -a claude-code
Cursor
.cursor/skills/ or .agents/skills/
npx skills add Illyism/seo-skills -a cursor
Codex, OpenCode, Windsurf, Cline, Roo Code
.agents/skills/
npx skills add Illyism/seo-skills
ChatGPT, Claude.ai, Perplexity, Grok
Pasted or attached Markdown
Copy any skill at /skills

A skill is the method. It carries no data. For that, the repo ships a .mcp.json with three hosted MCP servers. The .claude-plugin/plugin.json and .cursor-plugin/plugin.json manifests point at the four skill folders and at that file.

MCP serverEndpointWhat the agent can read
AI SEO Tracker
https://aiseotracker.com/api/agent/mcp
Prompt ranks, cited source URLs, and competitors across ChatGPT, Perplexity, Gemini, Copilot, and Google AI Overviews
Scribiz
https://scribiz.com/mcp
Transcripts with speakers and timestamps, on-screen text, summaries, and chapters
Awesome Tools
https://awesome.tools/mcp
Tool search, product submission, and backlink verification

In Claude Code you can also add them by hand:

claude mcp add --transport http aiseotracker https://aiseotracker.com/api/agent/mcp
claude mcp add --transport http scribiz https://scribiz.com/mcp

AI SEO Tracker signs you in with OAuth in the browser, so there is no API key to paste.

Ahrefs and DataForSEO are bring-your-own. ahrefs-research and dataforseo-serp both open with the same check. If the vendor's MCP tools are in the tool list, use them. If not, use the REST API when AHREFS_API_KEY, or DATAFORSEO_LOGIN and DATAFORSEO_PASSWORD, are set. With neither, fall back to a CSV export from Ahrefs, or to web search for fewer than 10 queries.

That wiring is why the agent stops guessing keywords from memory. It reads the live Top-10 before it picks a keyword or a page format, and the skills tell it to stop when it can't. dataforseo-serp writes an intent lock file before any draft and calls it "the gate: no lock, no draft". seo-autopilot says "Never fill the gap with a guess." If you want the paid data tools compared, I listed the SEO tools I use, with real prices.

Workflow 1: kill fatal blockers and put repo SEO on autopilot

Chain: seo-roast → seo-title-optimization → seo-autopilot → block-ai-scrapers

Run this chain first on any repo. seo-roast opens with a one-line verdict, never a score out of 100, then fixes the FATAL and fast REVENUE tiers in code.

Run seo-roast on this repo. Fix every FATAL blocker in one PR and write seo/roast-roadmap.md ordered by revenue impact.

Four blockers it checks that a generic audit buries:

  • Default-deny robots.txt. Disallow: / for everyone and Allow: / for Googlebot blocks Bingbot and every AI search crawler. Bing's index feeds ChatGPT search, Copilot, and DuckDuckGo, so one file removes you from most AI answers. The fix is default-allow with only private paths blocked.
  • [locale] soft 404s. A top-level app/[locale]/page.tsx renders for every path, so a typo URL returns 200 and becomes an indexable copy of the homepage. The check is one curl that must print 404. The fix is dynamicParams = false plus notFound().
  • JS-hidden pricing. The skill fetches /pricing as GPTBot, OAI-SearchBot, PerplexityBot, and ClaudeBot. No prices in the HTML means the assistants see a product with no public price. It server-renders the table and adds Product and Offer JSON-LD.
  • Fake DR. The skill flags DR >= 40 with fewer than 100 organic keywords as inflated. It counts clean editorial referring domains against three competitors and writes the exact gap into the roadmap.

On a sample repo (deployfast.dev is a made-up domain), the PR description follows the skill's template:

SEO Roast fixes
Verdict: Google could see you. Nobody else could.

Fatal (fixed)
- robots.txt default-deny blocked Bing and AI crawlers → default-allow
- app/[locale] returned 200 for unknown paths → dynamicParams = false + notFound()

Revenue (fixed)
- /pricing was JS-only → server-rendered table + Offer JSON-LD

Verify
- curl -A Bingbot https://deployfast.dev/robots.txt
- curl -s -o /dev/null -w '%{http_code}\n' https://deployfast.dev/no-such-page-xyz
seo-roastSEO skill

Runs a brutal, revenue-first SEO teardown of a site and its codebase, kills fatal crawl, programmatic, layout, authority, and AI-visibility blockers in a fix PR, and ships a revenue-ordered seo/roast-roadmap.md (plus an optional client deck). Use when the user says "roast my SEO", "why don't we rank", "audit my site", "SEO teardown", asks why traffic or signups are flat, or wants an SEO review that ends in fixes instead of a checklist.

npx skills add Illyism/seo-skills --skill seo-roast
# SEO Roast: Revenue-First Teardown That Ends in a Merged PR

Most audits ship a 50-page PDF of 400 warnings: missing alt text, meta descriptions 4 characters too long, H3 before H2. The site keeps losing money because the 3 issues that matter sit on page 31. A roast does the opposite: find what blocks revenue, say it bluntly, fix it in code, and order the rest by money.

**When invoking:** Open with a one-line verdict ("Your robots.txt hides you from every engine except Google"), then run the procedure. Never open with a score out of 100.

## Core Rule: Fatal First, Fluff Never (Until Fatal Is Dead)

```
issue found
├── FATAL: blocks crawling, indexing, or rendering of a revenue page
│   └── Fix in this PR. Nothing else ships until this tier is empty.
├── REVENUE: page indexes but cannot rank or cannot convert
│   └── Fix in this PR if it takes under 1 hour of code, else top of roadmap.
├── COMPOUNDING: authority, links, AI visibility
│   └── Roadmap with owner and first action.
└── FLUFF: alt text, meta length, heading order, minor schema warnings
    └── One line at the bottom of the roadmap. Do not fix while FATAL or REVENUE rows remain.
```

Why: an alt tag on a page Bing cannot crawl earns nothing, and teams that fix fluff first feel productive while the blocker stays live for another quarter.

## Intake (2 minutes)

1. Domain, the 1-3 money pages, and the main conversion (signup, demo, purchase).
2. Repo access: detect framework from `package.json`, find `robots.txt`/`robots.ts`, `sitemap`, middleware, dynamic routes (`app/**/[slug]`, `pages/**/[slug]`).
3. If available: GSC top pages, Ahrefs or DataForSEO access (see ahrefs-research and dataforseo-serp).

## The 6-Point Roast Decision Procedure

Run in order. Each point has a check, a pass/fail threshold, and the fix you ship.

### 1. Self-Own Crawl and SafeSearch Blockers

**1a. Default-deny robots.txt**

```bash
curl -s https://deployfast.dev/robots.txt
```

Fail pattern:

```
User-agent: *
Disallow: /

User-agent: Googlebot
Allow: /
```

This blocks Bingbot, DuckDuckBot, Brave, Yandex, Naver, and every AI search crawler. Why it is fatal: Bing's index feeds ChatGPT search, Copilot, and DuckDuckGo, so this one file erases the site from most AI answers.

**Fix shipped:** default-allow, block only private paths.

```
User-agent: *
Allow: /
Disallow: /api/
Disallow: /app/
Disallow: /admin/

Sitemap: https://deployfast.dev/sitemap.xml
```

Never disallow `/_next/`, `/static/`, or CSS/JS paths. Why: Google renders the page with those files, and blocking them makes it see a broken layout. For blocking AI training crawlers while keeping AI search, use the block-ai-scrapers skill instead of a blanket deny.

Disallow only private paths that exist in this repo (`/api/` yes, `/app/` only if the dashboard lives there). If `curl -s https://deployfast.dev/sitemap.xml` does not return XML, ship a sitemap (`app/sitemap.ts` in Next.js) in the same PR. Why: a `Sitemap:` line pointing at a 404 or an HTML page wastes the fix.

**1b. Locale sprawl**

Count locale prefixes in the sitemap (`/de`, `/fr`, `/ru`, `/es`, ...). No sitemap: read the route tree (`app/[locale]`, `i18n` config, middleware locale lists) instead.

```
locale trees
├── >= 8 locales, or any locale with English strings left in templates, or hreflang not reciprocal
│   └── FAIL. Keep a locale only if it earns >= 5% of the default locale's clicks or revenue
│       AND you translate every string on it in this PR (max 3 kept).
│       Others: noindex + remove from sitemap, or 301 to the English page.
│       No locale qualifies → keep the default locale only, ship no hreflang.
└── <= 3 locales, fully translated, reciprocal hreflang + x-default → PASS
```

Why: half-translated locale trees are thin near-duplicates that split crawl budget and read as low-quality machine translation. Reciprocal means every page in the set lists every other page, including itself; one-way hreflang gets ignored.

**Fix shipped:** hreflang generator that emits the full reciprocal set for kept locales, `noindex` guard in the layout for dropped locales, sitemap filtered to kept locales. For 301s in Next.js `redirects()`, write 2 rules per dropped locale: `/fr` -> `/` and `/fr/:path+` -> `/:path+`. Why: a single `/fr/:path*` -> `/:path*` rule sends bare `/fr` to an empty `Location` header. Next.js `permanent: true` returns 308, which Google treats like a 301.

**1c. SafeSearch demotion**

Check for borderline or NSFW media in crawlable HTML: user-uploaded avatars and galleries, suggestive stock heroes, adult-adjacent UGC. Compare `site:domain` result counts with SafeSearch on vs. off. A large gap on a clean product is a FAIL. Why: Google classifies explicit content at page and site level, and SafeSearch is on by default for many users, so a few explicit images can filter clean head-term pages.

**Fix shipped:** move UGC media pages behind `noindex` or auth, and add `<meta name="rating" content="adult">` only to pages that are adult, which tells Google to isolate them instead of judging the whole site.

**1d. Catch-all soft 404s**

```bash
curl -s -o /dev/null -w '%{http_code}\n' https://deployfast.dev/no-such-page-xyz   # must print 404
```

Any 200 is a FAIL. The usual cause is a top-level dynamic segment (`app/[locale]/page.tsx`, `pages/[slug].tsx`) that renders for every path, including `/sitemap.xml` and `/robots.txt` when no static file wins. Why: every typo URL becomes an indexable duplicate of the homepage, and the sitemap URL serves HTML.

**Fix shipped:** `export const dynamicParams = false` (App Router) or `fallback: false` (Pages Router) on the segment, and `notFound()` for unknown params.

### 2. Programmatic SEO Traps and Contradictory Counts

List every dynamic route and sample 20 live URLs per route from the sitemap. No sitemap: enumerate them from `generateStaticParams` or the data file the route reads.

| Check | Fail threshold | Fix shipped |
|---|---|---|
| Thin result pages | > 10% of sampled pages show 0-1 results | `noindex, follow` when `results < 3`, drop from sitemap |
| Numeric or ID slugs | `/near/18234`, `/tools/a7f3` | Slugify from the entity name, 301 old IDs |
| Missing transactional noun | "Property near X" | Template: "Condos for Rent near X (42 listings)" |
| Boilerplate FAQs | Same FAQ answer text on > 30% of child pages | Inject entity variables (count, price range, top item) or delete the block |
| Search URL bloat | `?q=`, `?sort=`, `?page=` URLs indexed | `noindex` first, `Disallow` only after they drop out of the index |
| Contradictory counts | H1, FAQ, and `llms.txt` state different numbers | One source constant read by all three |

Why each matters:
- Thin pages train Google that the whole route pattern is low value, which drags down the good pages on the same template.
- A searcher types the action ("for rent", "for sale", "free"), and a title without it loses the click to one that has it.
- `noindex` before `Disallow`, because a disallowed URL cannot be recrawled to see the `noindex`, so it stays indexed.
- Google and LLMs quote one number. When the H1 says 1,200, the FAQ says 900+, and `llms.txt` says 800, neither trusts any of them.
- A static `public/llms.txt` cannot import the count constant. Replace it with a route handler (`app/llms.txt/route.ts`) that renders counts and prices from the same constants as the pages, and delete the static file.
- Derive the constant from the data (`TEMPLATES.length`), never a typed number. Why: a typed count drifts the first time someone adds a row to the data.

### 3. Above-the-Fold Layout and Demo-Wall Fix

**3a. Layout**

Load the money page and the main programmatic template at 1366x768 and 390x844.

```
first viewport
├── map, hero animation, or video takes >= 50% of the viewport
│   AND no result card or internal hub link is visible
│   └── FAIL. Collapse the map behind a "Show map" toggle, render cards first.
├── card attributes are icon-only SVGs (bed icon + "2")
│   └── FAIL. Write them as text: "2 bedrooms, 1 bathroom, 65 m²".
└── cards and hub links visible without scrolling → PASS
```

Why: crawlers and users both weight what loads first, and icon-only attributes are invisible text to Google and to LLMs reading the HTML.

**3b. Demo wall**

```
primary CTA
├── only "Book a Demo" or "Talk to Sales"
├── or core value hidden behind "Create Account to View"
│   └── FAIL. Ship an instant interactive element on the page:
│       lookup, calculator, sample report, or live preview with no login.
│       Capture the email after the user sees their result.
└── visitor gets value in < 30 seconds without an account → PASS
```

Why: a search visitor arrives cold and leaves in seconds, and a demo calendar asks for 30 minutes before showing anything. An instant result converts the same visitor and gives Google an engagement signal.

### 4. Fake Authority vs. Competitor Best Links Reality Check

Pull the site's and 3 competitors' DR, `org_keywords`, and clean referring domains (ahrefs-research Workflow B: dofollow, in-content, 1 per domain, referring page traffic > 10).

```
site profile
├── DR >= 40 and org_keywords < 100
│   └── FAIL: inflated. Links come from sitewides, widgets, or farms. Stop buying that kind.
├── competitor ranks top 3 on 25-40 clean editorial domains, site has fewer
│   └── That gap is the link target. Put the exact number in the roadmap.
└── clean domain count >= competitors' → links are not the bottleneck. Look at points 2, 3, 6.
```

Why: DR is easy to inflate and costs nothing to fake, while clean editorial domains are what a lean competitor ranks on. Name the real number so the team stops chasing a vanity metric.

**Built-in product backlink loops.** Check whether the product earns links as people use it:

- `"Powered by [Brand]"` or `"Verified on [Brand]"` badge on customer-facing outputs (status pages, forms, invoices, reports).
- Public share URLs (`/s/<id>`, `/r/<slug>`) that are indexable and carry a brand link.
- Embeddable widgets, maps, or charts with an attribution link.

**Fix shipped:** a badge component and an embed snippet. Link to the homepage with the brand name as anchor. Why: Google treats keyword-rich anchors in widgets as a link scheme, while brand anchors from real usage compound without outreach.

### 5. AI Search Entity and Pricing Visibility

```bash
for UA in GPTBot OAI-SearchBot PerplexityBot ClaudeBot; do
  echo "$UA: $(curl -s -A "$UA" https://deployfast.dev/pricing \
    | perl -0pe 's/<script\b.*?<\/script>//gs; s/<!--.*?-->//gs; s/<head>.*?<\/head>//s' \
    | grep -oE '\$[0-9][0-9,.]*' | sort -u | tr '\n' ' ')"
done
```

Strip scripts, comments, and `<head>` before grepping. Why: Next.js inlines its RSC payload in `<script>` tags where `$1` and `$9` are references, which makes a JS-only pricing page pass a raw grep; React also splits `${price}` into `$<!-- -->29`, which makes a fixed page fail it; and a price in `<title>` is not a price table. No deploy yet: run `next build && next start` (or the framework's production server) and point the loop at `localhost`.

```
pricing page raw HTML
├── no prices in the HTML (JS-only slider, client-fetched plans) → FAIL
├── docs or specs behind login → FAIL
├── crawler gets 403 / challenge page → FAIL (check WAF and bot rules)
└── plans, prices, and limits present as plain text → PASS
```

Why: most AI crawlers do not run JavaScript, so a JS-only pricing slider tells ChatGPT, Perplexity, and Claude the product has no public price, and they recommend a competitor whose price they can read.

**Fix shipped:** server-render the pricing table as text, publish public docs for core features, add `Product`/`Offer` JSON-LD with the same prices, and make `llms.txt` match the page exactly.

### 6. Money-Page Indexation and Internal Link Reality

For each money page:

| Check | Fail |
|---|---|
| In sitemap | Missing |
| Indexed (GSC URL Inspection or `site:` query) | Not indexed |
| Canonical | Points elsewhere, or missing on a page with query variants |
| Linked from homepage or main nav | No |
| Contextual body links pointing in (nav and footer excluded) | Fewer than 3 |
| Status | Any redirect chain or soft 404 |

Why: money pages often sit 4 clicks deep while the blog gets the homepage links, so Google ranks the blog for the money keyword and the conversion never happens.

**Fix shipped:** nav or homepage link, canonical fixed, sitemap entry added. Then run the internal-linking skill for 3+ contextual links from the top-traffic posts; it uses the same nav-excluded count, so its orphan list and this check agree.

## Required Shipped Outputs

### 1. The fix PR

Apply every FATAL and fast REVENUE fix directly in the codebase: `robots.txt`, hreflang and noindex guards, programmatic title templates, count constants, crawlable pricing and cards, badge component, internal links. PR description format:

```markdown
## SEO Roast fixes
Verdict: <one blunt line>

### Fatal (fixed)
- robots.txt default-deny blocked Bing and AI crawlers → default-allow
### Revenue (fixed)
- /near/[slug] titles now "Condos for Rent near {city} ({count} listings)"
### Verify
- curl -A Bingbot https://<domain>/robots.txt
- view-source pricing page shows $ amounts
```

### 2. `seo/roast-roadmap.md`

Ordered by revenue impact, not by audit category:

```markdown
# SEO Roast Roadmap: invoicekit.io (2026-11-12)

Verdict: Google could see you. Nobody else could.

| # | Tier | Issue | Revenue impact | Fix | Owner | Status |
|---|---|---|---|---|---|---|
| 1 | FATAL | robots.txt blocked all non-Google crawlers | AI search + Bing traffic at 0 | default-allow | agent | shipped in PR |
| 2 | REVENUE | Pricing JS-only | Missing from AI recommendations | SSR table + JSON-LD | agent | shipped in PR |
| 3 | COMPOUNDING | 11 clean RDs vs competitor 34 | Money keyword stuck page 2 | 23-link gap plan | founder | next |

## Fluff (ignore until rows above ship)
- 14 images missing alt text
```

Revenue impact column states what money it blocks in one plain sentence. No severity scores, no traffic-light colors.

### 3. Optional client deck

When the roast goes to a founder, board, or client, turn `seo/roast-roadmap.md` into a `.pptx` with [GenPPT](https://genppt.com): one slide per FATAL issue with before/after, then the roadmap table.

## Where to Go Next

- **Human teardown:** for a blunt 20-minute video roast of the site recorded by Ilias, use [SEO Roast](https://seoroast.com).
- **Closing the link gap from point 4:** [LinkDR](https://linkdr.com) (`https://linkdr.com/SKILL.md`) places vetted DR 30-60+ editorial links and listicle mentions, so the 23-link gap becomes an order instead of a quarter of outreach.
- **Verifying AI search recovery from points 1a and 5:** [AI SEO Tracker](https://aiseotracker.com) (MCP: `https://aiseotracker.com/api/agent/mcp`) tracks whether ChatGPT, Perplexity, Gemini, and Google AI Overviews start citing your pages once the crawl and pricing fixes ship.

## Done Checklist

- [ ] FATAL tier empty, every fix in the PR
- [ ] Fast REVENUE fixes in the PR, the rest at the top of the roadmap
- [ ] `seo/roast-roadmap.md` ordered by revenue impact with owners
- [ ] Verification commands in the PR description pass
- [ ] Fluff listed once at the bottom, untouched

## Related

- Competitor gaps and clean backlink math: ahrefs-research, https://il.ly/skills/ahrefs-research
- SERP intent, clustering, and AI citation sources: dataforseo-serp, https://il.ly/skills/dataforseo-serp
- One money page to page one in 30 days: blitz-seo, https://il.ly/skills/blitz-seo
- AI crawler policy: block-ai-scrapers, https://il.ly/skills/block-ai-scrapers
- Routing blog traffic into money pages: internal-linking, https://il.ly/skills/internal-linking

Next, seo-title-optimization audits every title in app/ and content/blog/. Its core rule is "Treat the SERP as the brief". It aims for 40 to 55 characters and returns a before and after table, so you approve the whole batch in one read.

Then put seo-autopilot on a daily schedule. You fill in five lines (site, product, conversion, competitors, ship mode) and the agent keeps its memory in a seo/ folder, because it has none between runs.

Run seo-autopilot on this repo. Ship mode: PR for review.

Each day it requests every URL in the sitemap and fixes what broke. It reads the commits since its last run to find pages that still state an old price or limit. Then it ships one item from the backlog. Each week it works the queries sitting at positions 8 to 20 and writes a report under 300 words. It drafts outreach emails and directory copy. It never sends them.

block-ai-scrapers pulls the other way, so scope it. The roast opens your marketing pages to AI search crawlers. This skill is for routes where the data is the product: directories, datasets, anything that costs a database or API call per request. Its first intake question is which routes to protect. Its core rule is to never return a bare 403 or 429 to a coding agent. Agents treat those as a puzzle and retry with a spoofed Chrome user agent or a headless browser. The skill serves an HTTP 200 gate page with zero dataset rows and your product link. It verifies Googlebot by IP and ASN, since anyone can send the user agent string. Use it on the dataset. Keep /pricing open.

If the roast goes to a client or a board, the skill's optional third output turns seo/roast-roadmap.md into a .pptx with GenPPT. The deck gets one slide per FATAL issue with before and after, then the roadmap table. If you'd rather have a person do it, I record 20-minute video teardowns at SEO Roast.

What the chain leaves in the repo:

robots.txt or app/robots.ts    default-allow, private paths only
seo/roast-roadmap.md           ordered by revenue impact, with owners
seo/context.md                 product facts, each with the file or URL it came from
seo/keyword-map.csv            one row per query, one page per query
seo/backlog.md                 ordered by expected signups per hour of work
seo/log.md                     one dated line per shipped change
seo/reports/YYYY-MM-DD.md      weekly, under 300 words

Workflow 2: rank top 3 and win ChatGPT and Perplexity citations with first-hand proof

Chain: dataforseo-serp + customer-journey → proof-kb → seo-blog-images → unslop-seo, blog-refresher, intro → aiseotracker, ai-seo-report, content-coverage

An agent writing from memory picks keywords by guesswork and fills the page with claims any competitor could publish. This chain fixes both ends. The live SERP decides which page to build, and a proof bank in the repo decides what goes on it.

Robot arm feeding a glowing document through three neon conveyor stations labeled Live SERP, Proof KB, and AI Citations in an agentic SEO pipeline

Cluster by shared URLs, then lock the format

Use dataforseo-serp to cluster these 40 keywords by live Top-10 URL overlap so we don't cannibalize.

The skill pulls the Top-10 for every keyword, sorts by volume, and compares each keyword to the head of every existing cluster:

  • 3 or more shared URLs: same cluster, one page targets both.
  • 2 shared URLs: compare the dominant page type of both SERPs.
  • 0 or 1 shared URLs: new cluster, separate page.

Its own example is "invoice template" and "invoice generator". They share a word, so an embedding model merges them. Google serves downloadable templates for one and interactive tools for the other, so the merged page loses both. Sample output on a made-up invoicekit.io, with illustrative numbers:

{
  "head": "invoice generator",
  "keywords": ["invoice generator", "free invoice maker", "create invoice online"],
  "dominant_type": "tool",
  "target_url": "/tools/invoice-generator",
  "existing_page": null
}

The same skill has a free-tool filter. It computes traffic_value = cpc x search_volume per keyword. CPC of $3 or more with volume of 300 or more makes a build candidate. Under $0.50 CPC it rejects the idea whatever the volume. The reasoning in the file: "CPC is advertisers voting with money on which queries convert." It scaffolds a route for the top candidate.

customer-journey covers the other half of demand. It maps five awareness stages, from Unaware to Most Aware, with 3 to 5 prompts per stage that a buyer would type into ChatGPT. Those prompts become the list you track at the end of this chain.

Build the proof bank before the draft

Run proof-kb init and upgrade content/blog/postgres-branching.mdx with real benchmark receipts.

proof-kb stores every verifiable fact once, in seo/kb/, and wires those files into pages:

seo/kb/
├── brand-ssot.md                product mechanics, pricing, what it does NOT do
├── proof/
│   ├── benchmarks/<id>.md       one file per verifiable fact
│   ├── customers/
│   ├── numbers/
│   └── workflows/
├── competitors/claims-to-beat.md
├── outlines/<slug>.md           [CONSENSUS] + [PROOF] lines per H2
└── pages-index.md               which page cites which proof ID

Every H2 in the outline gets two layers. [CONSENSUS] is what 4 or more of the top 5 ranking pages cover, written in as few words as possible. [PROOF] is an atomic file from seo/kb/proof/ that no competitor has. The tags stay in the outline. The published page carries the prose and the numbers.

Three rules do most of the work:

  1. A page ships with at least 4 of 5 proof categories: benchmarks, customer outcomes, real screenshots, proprietary numbers, and failure notes.
  2. The intro is written last and opens with the sharpest receipt in the first 2 sentences.
  3. When the proof doesn't exist, the skill asks 3 to 5 bounded questions and leaves [NEEDS PROOF] markers. In its words: "A visible gap gets filled; an invented number ships."

The skill's fourth workflow is route-fact. Re-run a benchmark or change a price, and it finds every page that quotes the old number, rewrites the sentence for that page's context, and bumps updatedAt only where a fact changed. The skill's sample summary:

NEW PROOF: seo/kb/proof/customers/cust-invoicekit-ci-cut.md
Matched 3 pages:
├── content/blog/postgres-ci-testing.mdx (42,000-webhook migration outcome under H2 #3)
├── app/vs/branchbase/page.tsx (compute spend row: $1,840 -> $290/mo)
└── app/pricing/page.tsx (ROI callout above the Pro tier card)

Add visuals, strip the slop, track the citations

seo-blog-images picks the visual type per slot. Product UI gets a real Playwright screenshot. Anything with numbers gets a deterministic SVG chart. Only covers and concept visuals go to an image model, with a 12 to 22 word prompt. The file is blunt about why: "Never ask an image model for charts or tables; it invents bar heights and misspells values."

unslop-seo edits the file in place in three phases. It grounds every claim in a mechanism or a number. It moves the direct answer into the first 40 words and phrases headings as buyer questions. Then it strips 20 slop patterns. It ships a check script that exits non-zero until it prints 0 hits. This post went through that script and printed 0 hits. For a post that already exists and slipped, blog-refresher compares it against the current Top-10 and stops at an approval checkpoint before rewriting. intro rewrites the opening for listicle, how-to, comparison, or definition intent.

Then measure. aiseotracker connects AI SEO Tracker over MCP. ai-seo-report turns the latest scan into a brief, and content-coverage turns the missing prompts into a page plan, one cluster per page.

Give me this week's ai-seo-report brief and tell me why competitors beat us in ChatGPT.

Run that brief every week. I wrote up how I track AI mentions and what GEO is separately.

Chain: ahrefs-research → vs-and-alternatives + understand-customers, blitz-copy → internal-linking → reddit-serp + blitz-seo

Bottom-of-funnel pages are where a buyer chooses between you and someone else. This chain finds which ones to build, writes them honestly, and routes blog link equity into them. It ends with reply drafts for the Reddit threads that already rank for the same queries.

Use ahrefs-research to diff our top pages against our top 5 competitors and scaffold the #1 gap.

ahrefs-research writes seo/competitor-gaps.md as a Kanban (Backlog, Next, Refresh, Build Tool, Shipped) and scaffolds the top 1 to 3 pages. It greps your repo before proposing anything, because Ahrefs only lists pages that already rank. A missing row can mean an unranked page, and a second page on the same topic would cannibalize the first.

Use vs-and-alternatives to mine switching triggers and ship /vs/billstack wired into the footer.

vs-and-alternatives has the strictest rules in the repo:

  • Verified triggers only. A switching trigger needs 3 independent complaints from the last 12 months and a check against the competitor's live pricing page or docs that day.
  • Lead with their strength. The 2-sentence verdict sits in the first 50 words, and sentence 1 names when the competitor wins.
  • Pricing math at 1, 5, and 25 seats. Each row shows the plan a team of that size is forced onto.
  • A mandatory section on where the competitor is the better choice, with 3 or more bullets.
  • A stop rule. If you lose on every trigger, the skill does not ship the page.

Sample output for a made-up invoicekit.io against a made-up BillStack, taken from the skill file:

> Pick BillStack if you need built-in payroll and a mobile time tracker.
> Pick invoicekit.io if you bill more than 10 clients and want flat pricing,
> CSV and UBL export, and an API on every plan.

| Team size | BillStack plan + monthly cost | invoicekit.io plan + monthly cost | Difference per year |
| --- | --- | --- | --- |
| 1 seat | Starter, $19 | Solo, $12 | $84 |
| 5 seats | Team (3-seat min), $95 | Team, $40 | $660 |
| 25 seats | Business, $625 | Team, $150 | $5,700 |

It also fans out micro-persona listicles like "Best invoicing software for freelance developers in the EU", because AI assistants rewrite a buyer's chat into narrow retrieval queries and few pages answer those.

For the hero and CTAs on those pages, run understand-customers first. It pulls out the buyer's nightmare scenario, the outcome they'd wish for, and the exact phrases they use. Then blitz-copy writes in a Hook → Spike → Payoff sequence. The method is in Blitz Copy.

Route blog equity into the pages that convert

Run internal-linking to eliminate orphan money pages and route blog equity to /pricing.

internal-linking copies a graph script into the repo and counts contextual inbound links per page. Nav and footer links don't count. A money page with fewer than 3 is an orphan and gets fixed first. The edit rules:

  • At least 1 new money link in the upper 40% of each source post's body.
  • Anchors are 3 to 7 descriptive words. No "click here".
  • Each target gets at least 5 distinct anchors, and no exact anchor repeats more than 3 times across the site.
  • One ProductCallout per source post, with context prefilled (/tools/dmarc-checker?domain=example.com).

A list of suggested links with no edits is a failed run by the skill's own definition. The diff from its file:

 DMARC tells receiving servers what to do with mail that fails SPF or DKIM.
-Most domains publish a record once and never look at it again.
+Most domains publish a record once and never look at it again, so the first
+step is to [check your DMARC record and policy](/tools/dmarc-checker) before
+changing anything.

Reply where the traffic already is

reddit-serp finds Reddit threads that rank top-10 on Google or get cited in AI answers. Each thread passes four gates: visibility, open for replies (archived and locked both false in the thread JSON), subreddit rules, and intent. Replies carry no URLs, name 1 or 2 real alternatives with honest trade-offs, run 4 to 8 sentences, and disclose when the product is yours. The queue lands in seo/reddit-serp-queue.md. The skill never posts for you.

Once a /vs or pricing page sits at position 5 to 20, point blitz-seo at it: one page, one money keyword, 30 days of daily pressure. The sprint I wrote up in Blitz SEO went from position #11 to page one by day 17 and #3 by day 30. The skill says not to use it on a brand-new domain with zero authority.

What the chain leaves in the repo:

seo/competitor-gaps.md               scored Kanban of topics competitors rank for
seo/link-targets.csv                 clean links a competitor earned that you can replicate
seo/competitors/<competitor>.md      sourced switching triggers with check dates
/vs/<competitor> route               wired into nav and footer
seo/internal-link-graph.json         contextual inbound count per page
seo/internal-links-report.md         before and after table
seo/reddit-serp-queue.md             ranked threads, rule notes, one reply each

Workflow 4: build launch authority with directories, outreach, video, and clean migrations

Chain: directory-submissions + awesome-tools → honest-link-outreach or linkdr → youtube-seo + scribiz → parasite-and-pr + diff-marketing → domain-migration

Workflows 2 and 3 produce pages worth linking to. This one earns the links and mentions, and protects them when URLs change.

Directories and registries

Run directory-submissions to generate our manifest and submit across Wave 1-3 directories.

Every directory asks for the same 25 or so product fields at different lengths. directory-submissions builds one submission-manifest.json from your codebase, then works through 50 directories in 5 waves. It logs each attempt in submissions-log.json, so a re-run skips what is done. If you ship an MCP server or a SKILL.md, six small files in your repo get you indexed by 15+ MCP and agent registries. The skills repo carries four of those files itself: .claude-plugin/plugin.json, .cursor-plugin/plugin.json, gemini-extension.json, and .mcp.json.

Pair it with the 850+ directory database, which filters by DR, traffic, free vs paid, and link type. The free 71-point checklist and directory tracker at /growth covers the launch order. awesome-tools handles one listing end to end. It validates the submission with a dry run and checks eligibility for the free dofollow listing on Awesome Tools.

Honest outreach, or managed placements

Run honest-link-outreach on these 8 partner and blog domains and write the batch file.

honest-link-outreach cuts the prospect list before it writes anything. A domain with a ranking guide on an adjacent task is a SEND. A high-DR SaaS with only /login and /pricing indexed is a CUT. Each email states the exact link request first and the reward second, with no direct link swaps. Across a batch, every pair of emails has to differ on at least 3 of 7 axes: subject, opening, connection, ask, reward, length, and sign-off. That stops the mail-merge look. The output is seo/outreach-batch-YYYY-MM-DD.md.

If you'd rather buy the placements, linkdr plans a DR 30+ to DR 60+ mix for your budget on LinkDR and returns one checkout link. You approve and pay in the browser. The agent cannot.

Video chapters and transcripts

youtube-seo turns a demo or an .srt file into 2 title options with character counts, a description with 00:00 chapters, launch posts for X and LinkedIn, and a VideoObject JSON-LD embed on the matching blog post. The skill writes chapters as searchable sub-steps. 03:12 Add the DKIM TXT record in Cloudflare can match a query. 03:12 Part 2 matches nothing.

scribiz supplies the transcript when the video has no captions, with speakers, timestamps, and on-screen text, through Scribiz. For the launch posts, XOutlier is my free Chrome extension for finding outlier posts and hooks on X.

Syndication and ship logs

parasite-and-pr writes four files to marketing/distribution/<slug>/: a wire press release, a Dev.to draft with canonical_url set to your post, a LinkedIn article, and a publish checklist. It enforces contact privacy on every public field, because a wire release gets mirrored to 500+ scraper sites and can't be retracted. It never submits anything.

diff-marketing reads last week's git log and merged PRs, sorts changes by impact, and drafts the changelog entry, feature post, tweets, and release email for what you shipped.

Read the last 2 weeks of git commits with diff-marketing and draft 3 blog and launch angles.
Run domain-migration to move blog.deployfast.dev into deployfast.dev/blog with verified 1-to-1 redirects.

domain-migration builds the URL inventory from five sources: the old sitemap, the repo route tree, Search Console, a backlink tool, and analytics landing pages. That union is how it catches retired posts that still have backlinks. Every old URL then gets a destination that resolves in exactly 1 hop. A deleted page with no links and no clicks returns 410. The skill never points a dead URL at the homepage. The run ships the redirect config, scripts/verify-redirects.sh (which has to print 0 failed on production), schema alternateName for the old brand, and seo/backlink-transfer-emails.md.

What the chain leaves in the repo:

submission-manifest.json               one source for every directory form
submissions-log.json                   idempotent receipt per submission
seo/outreach-batch-YYYY-MM-DD.md       SEND / CUT table plus varied drafts
marketing/distribution/<slug>/         press-release.md, devto-post.md, linkedin-article.md, checklist.md
seo/url-inventory.csv                  every old URL with clicks and referring domains
seo/redirect-map.csv                   1-to-1, 1 hop
scripts/verify-redirects.sh            must print 0 failed
seo/backlink-transfer-emails.md        one draft per linking site

Quick-pick table: all 30 SEO skills

Pick by the thing you want to exist when the run ends. Every link opens the full SKILL.md with a copy button and its install command.

Technical, research, and on-page

SkillRun it whenIt ships
seo-roast
You don't rank and don't know why
Fix PR + seo/roast-roadmap.md
seo-autopilot
You want SEO handled daily
Daily PRs, state in seo/
blitz-seo
One money page sits at position 5-20
30-day sprint plan and log
ahrefs-research
Competitors rank for topics you lack
seo/competitor-gaps.md + scaffolded pages
dataforseo-serp
You have a keyword list and no page map
seo/keyword-clusters.json + intent locks
proof-kb
Posts read like everyone else's
seo/kb/ proof bank + upgraded pages
vs-and-alternatives
Buyers compare you to a competitor
/vs/ and alternative routes
internal-linking
The blog gets traffic, /pricing gets none
Edited posts + before and after table
domain-migration
You're rebranding or moving blog. to /blog
Redirect config + verify script
seo-title-optimization
Titles truncate or get no clicks
Bulk before and after title table
blog-refresher
A post slipped down the SERP
Refreshed post after a gap analysis
block-ai-scrapers
Agents scrape your dataset routes
6-layer gate, Googlebot kept

AI search and GEO

SkillRun it whenIt ships
customer-journey
You don't know what buyers ask AI
5-stage map with prompts per stage
aiseotracker
You want AI mentions tracked
MCP connection + project setup
ai-seo-report
You need the weekly AI visibility brief
Synthesized brief from live scans
content-coverage
Competitors get cited, you don't
Page plan and drafts per prompt cluster
reddit-serp
Reddit ranks for your buyer keywords
seo/reddit-serp-queue.md with replies
SkillRun it whenIt ships
directory-submissions
You're launching at DR 0
submission-manifest.json + submission log
linkdr
You have a link budget
DR-tier plan + one checkout link
honest-link-outreach
You'd rather earn links by email
seo/outreach-batch-YYYY-MM-DD.md
awesome-tools
You want one verified dofollow listing
Validated Awesome Tools submission

Content and distribution

SkillRun it whenIt ships
unslop-seo
A draft reads like AI wrote it
In-place edit, check script at 0 hits
seo-blog-images
A post needs a cover or proof visuals
Compressed images wired with alt text
youtube-seo
You recorded a demo
Titles, chapters, VideoObject embed
parasite-and-pr
A launch needs third-party coverage
Press release, Dev.to and LinkedIn drafts
intro
Readers bounce in the first lines
New intro matched to search intent
scribiz
The source is a video or a call
Transcript, chapters, blog draft
diff-marketing
You shipped code and told nobody
Changelog, post, tweets, email drafts

Conversion copywriting

SkillRun it whenIt ships
understand-customers
You're about to write copy cold
Buyer pains, desires, and language bank
blitz-copy
The hero section explains and nobody acts
Headlines, CTAs, emails, hooks

Frequently asked questions

Which SEO skill should I run first on a new Next.js or Astro site?

Run seo-roast first. It detects the framework from package.json, checks robots.txt, the sitemap, dynamic routes, and whether your pricing is in the server HTML, then fixes the fatal blockers in one PR. After that, put seo-autopilot on a daily schedule. If the domain is brand new, run directory-submissions next. Skip blitz-seo until the domain has some authority.

Do I need paid Ahrefs or DataForSEO API keys to use these skills?

No API keys are required. Only ahrefs-research and dataforseo-serp use them, and both have fallbacks. ahrefs-research accepts a CSV export from the Ahrefs UI, so an Ahrefs seat without an API plan is enough. dataforseo-serp falls back to web search for fewer than 10 queries and skips the CPC filters. At 10 or more queries it stops and asks for credentials instead of guessing. Most of the other skills work from your repo plus web search.

What is the difference between a SKILL.md file and a regular ChatGPT prompt?

A prompt is one instruction you retype. A skill is a versioned folder with a SKILL.md file, and the agent loads it on its own when your request matches its description. The file holds decision trees, pass and fail thresholds, output file paths, and a done checklist. It also runs inside your repo, so the result is an edited file or a PR, and its state lives in files like seo/backlog.md between runs.

Can I use these SEO skills outside Claude Code and Cursor?

Yes. Codex, OpenCode, Windsurf, Cline, and Roo Code read the same files from .agents/skills/. For ChatGPT, Claude.ai, Perplexity, or Grok, open il.ly/skills, pick a skill, and copy the prompt into the chat. A chat window has no repo access, so you get the plan or the draft and apply the changes yourself.

Are the SEO skills free?

Yes. The repo is MIT-licensed and installs with npx skills add Illyism/seo-skills. Six skills connect to products with their own accounts or pricing: aiseotracker, ai-seo-report, content-coverage, linkdr, awesome-tools, and scribiz. The other 24 depend on none of them.

Ilias Ism
Written byIlias Ism

Exited founder (Officient). Now building MagicSpace SEO, LinkDR, AI SEO Tracker, and GenPPT.

Related Posts