SEO tune — make an existing site findable by search AND by AI
Three layers, one pass:
- SEO (classic search — Yandex, Google): robots.txt, sitemap.xml, canonical
URLs, a real
<title> + meta description, Open Graph / Twitter cards.
- AEO (AI answer engines — so your page is quotable): structured data
(JSON-LD), FAQ blocks with direct question→answer pairs.
- GEO (LLM / agent discovery): a deliberate AI-crawler robots policy, IndexNow so
new pages get picked up fast, and (optional, experimental)
llms.txt.
This skill tunes a site that already exists. It doesn't generate a blog from
scratch (that's a bigger, separate tool). Point it at a folder of built HTML, or a
running site, and it fills the gaps.
Step 0 — ask for the site's basics (never hardcode)
Before touching anything, get these from the user and keep them in a scratch note
(you'll reuse them). Nothing here is baked into the skill — it's all theirs:
SITE_URL — the canonical origin, e.g. https://example.com
BRAND — the site / author name
LANG — primary language (e.g. ru, en)
- Analytics IDs, IF they use them (Yandex Metrika counter, GA4 id) — optional
- IndexNow key — you'll generate one with them in
references/indexnow.md
Step 1 — audit (report, then STOP)
Walk the site (the built HTML files, or fetch the live pages) and check each item.
Report a checklist [есть]/[нет] first, then STOP and wait for the owner's explicit
approval before you change anything. Do not proceed to Step 2 until they say go.
Presence is not enough — check that each page is effectively indexable and that its
canonical is correct, or the audit will "pass" a site that is actually invisible to
search or silently collapsing into one URL. A Disallow: /, an all-noindex site, or a
site where every page canonicals to the homepage must FAIL this audit, not pass it.
| Layer |
Check |
Where |
| SEO |
robots.txt exists, points to the sitemap, and does NOT block indexing (see effective indexability) |
/robots.txt |
| SEO |
sitemap.xml lists only the desired indexable canonical URLs, absolute <loc> |
/sitemap.xml |
| SEO |
every page has a unique, real <title> and <meta name="description"> |
<head> |
| SEO |
every page has exactly ONE absolute, correct <link rel="canonical"> (see canonical correctness) |
<head> |
| SEO |
Open Graph (og:title + og:type + og:image + og:url; og:image:alt when an image is set) + twitter:card |
<head> |
| AEO |
article pages carry Article/BlogPosting JSON-LD |
references/jsonld-recipes.md |
| AEO |
Q&A / how-to pages carry FAQPage/HowTo JSON-LD (AEO / AI engines only — no Google rich result) |
same |
| AEO |
home page carries the truthful site-subject type (Organization/Person/LocalBusiness/…) + WebSite JSON-LD |
same |
| GEO |
llms.txt exists (optional, experimental — see note) |
references/llms-txt.md |
| GEO |
robots.txt reflects the owner's chosen AI-crawler policy (allow OR intentionally block) |
references/llms-txt.md |
| GEO |
IndexNow key file is published and pages get pinged on publish |
references/indexnow.md |
Effective indexability (presence ≠ indexable — do not skip)
A file that merely exists can still be fully blocked. For each page, verify it is
actually indexable:
- robots.txt rules that apply to the REAL crawler.
robots.txt is
most-specific-group-wins (RFC 9309): work out the group Googlebot / YandexBot actually
match, not just the * group. Disallow: / — under * OR under the engine's own
user-agent — means the site is blocked. FAIL it.
- HTML
noindex: <meta name="robots" content="noindex"> (or a googlebot /
yandex-specific meta) removes the page from the index even if robots.txt allows
crawling.
- HTTP
noindex: an X-Robots-Tag: noindex response header does the same,
invisibly. Check the response headers, not just the HTML.
- Final HTTP status: the URL must return a final
200 — not a redirect chain, a
4xx/5xx, or a login / paywall. A canonical or sitemap URL that 301s or 404s is a bug.
- Rendered content: the main content must actually be present after render. For a
JS-heavy site, an empty HTML shell that never hydrates has nothing to index — confirm
the real content is in what a crawler receives.
Sources: Google robots meta / noindex,
Yandex robots.txt.
Canonical correctness (presence ≠ correct)
<link rel="canonical"> is a strong consolidation signal — a wrong one can collapse a
whole multi-page site into a single URL. For each page verify:
- Exactly one canonical, and it is an absolute URL on your one chosen origin.
- The canonical URL is itself indexable (returns 200, not
noindex, not redirected).
- It matches this page's content — a page's canonical should point to itself (or a
genuine duplicate), never to an unrelated page.
- BUG to flag: every page carrying the SAME canonical (typically → the homepage).
This tells search engines every page IS the homepage and de-indexes the rest. This is
exactly the kind of existing tag that must be FIXED, not preserved — "don't break what
works" does not apply to a page-collapsing canonical.
- Built-file → public-URL mapping: do not mechanically append the file path to
SITE_URL. /about/index.html on disk is usually the public /about/; handle
trailing slashes, query parameters, localized (i18n / hreflang) variants and redirected
URLs deliberately, not by string concatenation.
Sources: Google canonicalization,
Yandex canonical.
Step 2 — generate what's missing (only after approval)
For each gap, use the recipe file, filling in the user's real SITE_URL/BRAND:
- robots.txt / sitemap.xml — generate the sitemap from only the desired indexable
canonical URLs (see the sitemap rules + template below).
<lastmod> is optional and
should reflect a real content change; a build mtime that bumps on every deploy is as
misleading as now, so omit it rather than fake it.
<head> tags — unique real title + a description that summarizes the page (aim
~140–160 chars as an editorial heuristic — there is no fixed Google limit and the
snippet is trimmed per device/query). Canonical = the page's real public URL on your
one origin (mind the built-file mapping caveat above). OG image per-page if you have
one, else a site default.
- JSON-LD —
references/jsonld-recipes.md. Pick the TRUTHFUL subject type for the
home page (Organization only if the site is an organization; Person for a personal
site; LocalBusiness/OnlineStore where those fit). One
<script type="application/ld+json"> per block in <head>.
- llms.txt —
references/llms-txt.md (optional, experimental).
- IndexNow —
references/indexnow.md (generate the key, publish the key file, ping
once on every publish — one endpoint fans out to the others).
sitemap.xml — generation rules + template
Include only the URLs you want indexed: the canonical, indexable pages. Exclude
redirects, noindex pages, duplicates, 404s, login and purely technical pages.
- Absolute
<loc> URLs on your one chosen origin, canonical-consistent (the same URL you
set as <link rel="canonical">).
- UTF-8 encoding, an XML declaration, the sitemap namespace, and XML-escaped entities
(
& → &, < → <, …).
- Max 50,000 URLs / 50 MB per file; beyond that, split into multiple sitemaps and add
a sitemap index.
<lastmod> is optional; if present, use a W3C-datetime value that reflects a real
content change (not now, not a deploy mtime).
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/</loc>
<lastmod>2026-07-05</lastmod>
</url>
<url>
<loc>https://example.com/blog/first-post/</loc>
<lastmod>2026-07-05</lastmod>
</url>
</urlset>
Sources: Google build a sitemap,
Yandex sitemap format.
Rules
- Truthful metadata only. Description must match the page; JSON-LD fields must match
visible content. Mismatched / misleading structured data can lose a page its
rich-result eligibility or trigger a structured-data manual action — but Google states
this does not change normal web ranking, and Yandex simply ignores markup it can't
trust rather than penalizing it. So mark up honestly for eligibility; there is no
"ranking penalty" for a bad block, only lost eligibility.
Google structured-data policies.
- The user's own IDs/keys/domain — always. Never invent analytics IDs or reuse
someone else's IndexNow key. If they don't use analytics, leave it out.
- Don't break what works. Read a page's existing
<head> before editing; add missing
tags, don't duplicate ones already there. Exception: an actively harmful existing
tag — a page-collapsing canonical, a stray noindex, a Disallow: / — is a bug to fix,
not "what works" to preserve.
- One canonical origin. Pick
https:// + one host (www or bare, not both) and be
consistent across canonical, sitemap and OG.
Files
references/jsonld-recipes.md — copy-paste JSON-LD for the common page types.
references/llms-txt.md — llms.txt + the AI-crawler allowlist (GEO).
references/indexnow.md — IndexNow key + ping (fast indexing on Yandex & Bing).
1---2name: seo-tune3description: Audit and tune ANY existing site (static HTML, Astro, Next.js, WordPress export...) for search + AI discovery: SEO (Yandex & Google), AEO (AI answer engines), GEO (LLM/agent discovery). The agent checks robots.txt, sitemap.xml, canonical, meta/OG tags, JSON-LD, llms.txt and IndexNow, then generates whatever is missing. Use when the user says: optimize my site for search / SEO / чтобы находили в поиске / хочу в Яндекс и Google / AI-ответы. Tunes an existing site — it does not build one.4---56# SEO tune — make an existing site findable by search AND by AI78Three layers, one pass:910- **SEO** (classic search — Yandex, Google): robots.txt, sitemap.xml, canonical11 URLs, a real `<title>` + meta description, Open Graph / Twitter cards.12- **AEO** (AI answer engines — so your page is *quotable*): structured data13 (JSON-LD), FAQ blocks with direct question→answer pairs.14- **GEO** (LLM / agent discovery): a deliberate AI-crawler robots policy, IndexNow so15 new pages get picked up fast, and (optional, experimental) `llms.txt`.1617This skill **tunes a site that already exists**. It doesn't generate a blog from18scratch (that's a bigger, separate tool). Point it at a folder of built HTML, or a19running site, and it fills the gaps.2021## Step 0 — ask for the site's basics (never hardcode)2223Before touching anything, get these from the user and keep them in a scratch note24(you'll reuse them). Nothing here is baked into the skill — it's all theirs:2526- `SITE_URL` — the canonical origin, e.g. `https://example.com`27- `BRAND` — the site / author name28- `LANG` — primary language (e.g. `ru`, `en`)29- Analytics IDs, IF they use them (Yandex Metrika counter, GA4 id) — optional30- IndexNow key — you'll generate one with them in `references/indexnow.md`3132## Step 1 — audit (report, then STOP)3334Walk the site (the built HTML files, or fetch the live pages) and check each item.35Report a checklist `[есть]/[нет]` first, then **STOP and wait for the owner's explicit36approval before you change anything.** Do not proceed to Step 2 until they say go.3738Presence is not enough — check that each page is **effectively indexable** and that its39canonical is **correct**, or the audit will "pass" a site that is actually invisible to40search or silently collapsing into one URL. A `Disallow: /`, an all-`noindex` site, or a41site where every page canonicals to the homepage must **FAIL** this audit, not pass it.4243| Layer | Check | Where |44|---|---|---|45| SEO | `robots.txt` exists, points to the sitemap, and does NOT block indexing (see effective indexability) | `/robots.txt` |46| SEO | `sitemap.xml` lists only the desired indexable canonical URLs, absolute `<loc>` | `/sitemap.xml` |47| SEO | every page has a unique, real `<title>` and `<meta name="description">` | `<head>` |48| SEO | every page has exactly ONE absolute, correct `<link rel="canonical">` (see canonical correctness) | `<head>` |49| SEO | Open Graph (`og:title` + `og:type` + `og:image` + `og:url`; `og:image:alt` when an image is set) + `twitter:card` | `<head>` |50| AEO | article pages carry `Article`/`BlogPosting` JSON-LD | `references/jsonld-recipes.md` |51| AEO | Q&A / how-to pages carry `FAQPage`/`HowTo` JSON-LD (AEO / AI engines only — no Google rich result) | same |52| AEO | home page carries the truthful site-subject type (`Organization`/`Person`/`LocalBusiness`/…) + `WebSite` JSON-LD | same |53| GEO | `llms.txt` exists (optional, experimental — see note) | `references/llms-txt.md` |54| GEO | robots.txt reflects the owner's chosen AI-crawler policy (allow OR intentionally block) | `references/llms-txt.md` |55| GEO | IndexNow key file is published and pages get pinged on publish | `references/indexnow.md` |5657### Effective indexability (presence ≠ indexable — do not skip)5859A file that merely exists can still be fully blocked. For each page, verify it is60**actually indexable**:6162- **robots.txt rules that apply to the REAL crawler.** `robots.txt` is63 most-specific-group-wins (RFC 9309): work out the group Googlebot / YandexBot actually64 match, not just the `*` group. `Disallow: /` — under `*` OR under the engine's own65 user-agent — means the site is blocked. FAIL it.66- **HTML `noindex`:** `<meta name="robots" content="noindex">` (or a `googlebot` /67 `yandex`-specific meta) removes the page from the index even if robots.txt allows68 crawling.69- **HTTP `noindex`:** an `X-Robots-Tag: noindex` response header does the same,70 invisibly. Check the response headers, not just the HTML.71- **Final HTTP status:** the URL must return a final `200` — not a redirect chain, a72 `4xx/5xx`, or a login / paywall. A canonical or sitemap URL that 301s or 404s is a bug.73- **Rendered content:** the main content must actually be present after render. For a74 JS-heavy site, an empty HTML shell that never hydrates has nothing to index — confirm75 the real content is in what a crawler receives.7677Sources: [Google robots meta / noindex](https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag),78[Yandex robots.txt](https://yandex.com/support/webmaster/en/controlling-robot/robots-txt).7980### Canonical correctness (presence ≠ correct)8182`<link rel="canonical">` is a strong consolidation signal — a wrong one can collapse a83whole multi-page site into a single URL. For each page verify:8485- **Exactly one** canonical, and it is an **absolute** URL on your one chosen origin.86- The canonical URL is itself **indexable** (returns 200, not `noindex`, not redirected).87- It **matches this page's content** — a page's canonical should point to itself (or a88 genuine duplicate), never to an unrelated page.89- **BUG to flag:** every page carrying the SAME canonical (typically → the homepage).90 This tells search engines every page IS the homepage and de-indexes the rest. This is91 exactly the kind of existing tag that must be FIXED, not preserved — "don't break what92 works" does not apply to a page-collapsing canonical.93- **Built-file → public-URL mapping:** do not mechanically append the file path to94 `SITE_URL`. `/about/index.html` on disk is usually the public `/about/`; handle95 trailing slashes, query parameters, localized (i18n / hreflang) variants and redirected96 URLs deliberately, not by string concatenation.9798Sources: [Google canonicalization](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls),99[Yandex canonical](https://yandex.com/support/webmaster/en/robot-workings/canonical).100101## Step 2 — generate what's missing (only after approval)102103For each gap, use the recipe file, filling in the user's real `SITE_URL`/`BRAND`:104105- **robots.txt / sitemap.xml** — generate the sitemap from only the desired indexable106 canonical URLs (see the sitemap rules + template below). `<lastmod>` is optional and107 should reflect a real content change; a build mtime that bumps on every deploy is as108 misleading as `now`, so omit it rather than fake it.109- **`<head>` tags** — unique real title + a description that summarizes the page (aim110 ~140–160 chars as an editorial heuristic — there is no fixed Google limit and the111 snippet is trimmed per device/query). Canonical = the page's real public URL on your112 one origin (mind the built-file mapping caveat above). OG image per-page if you have113 one, else a site default.114- **JSON-LD** — `references/jsonld-recipes.md`. Pick the TRUTHFUL subject type for the115 home page (`Organization` only if the site is an organization; `Person` for a personal116 site; `LocalBusiness`/`OnlineStore` where those fit). One117 `<script type="application/ld+json">` per block in `<head>`.118- **llms.txt** — `references/llms-txt.md` (optional, experimental).119- **IndexNow** — `references/indexnow.md` (generate the key, publish the key file, ping120 once on every publish — one endpoint fans out to the others).121122## sitemap.xml — generation rules + template123124Include **only the URLs you want indexed**: the canonical, indexable pages. Exclude125redirects, `noindex` pages, duplicates, 404s, login and purely technical pages.126127- Absolute `<loc>` URLs on your one chosen origin, canonical-consistent (the same URL you128 set as `<link rel="canonical">`).129- UTF-8 encoding, an XML declaration, the sitemap namespace, and XML-escaped entities130 (`&` → `&`, `<` → `<`, …).131- Max **50,000 URLs / 50 MB** per file; beyond that, split into multiple sitemaps and add132 a sitemap index.133- `<lastmod>` is **optional**; if present, use a W3C-datetime value that reflects a real134 content change (not `now`, not a deploy mtime).135136```xml137<?xml version="1.0" encoding="UTF-8"?>138<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">139 <url>140 <loc>https://example.com/</loc>141 <lastmod>2026-07-05</lastmod>142 </url>143 <url>144 <loc>https://example.com/blog/first-post/</loc>145 <lastmod>2026-07-05</lastmod>146 </url>147</urlset>148```149150Sources: [Google build a sitemap](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap),151[Yandex sitemap format](https://yandex.com/support/webmaster/en/controlling-robot/sitemap).152153## Rules154155- **Truthful metadata only.** Description must match the page; JSON-LD fields must match156 visible content. Mismatched / misleading structured data can lose a page its157 rich-result eligibility or trigger a structured-data manual action — but Google states158 this does not change normal web ranking, and Yandex simply ignores markup it can't159 trust rather than penalizing it. So mark up honestly for eligibility; there is no160 "ranking penalty" for a bad block, only lost eligibility.161 [Google structured-data policies](https://developers.google.com/search/docs/appearance/structured-data/sd-policies).162- **The user's own IDs/keys/domain — always.** Never invent analytics IDs or reuse163 someone else's IndexNow key. If they don't use analytics, leave it out.164- **Don't break what works.** Read a page's existing `<head>` before editing; add missing165 tags, don't duplicate ones already there. **Exception:** an actively harmful existing166 tag — a page-collapsing canonical, a stray `noindex`, a `Disallow: /` — is a bug to fix,167 not "what works" to preserve.168- One canonical origin. Pick `https://` + one host (www or bare, not both) and be169 consistent across canonical, sitemap and OG.170171## Files172173- `references/jsonld-recipes.md` — copy-paste JSON-LD for the common page types.174- `references/llms-txt.md` — llms.txt + the AI-crawler allowlist (GEO).175- `references/indexnow.md` — IndexNow key + ping (fast indexing on Yandex & Bing).