sahin.io

All skills and agents

seo-audit

The SEO rulebook for sahin.io/angel-investments, with the exact thresholds (title 30–60 characters, description 70–160, one H1, 300-word floor for programmatic pages, Core Web Vitals, image, link, schema and sitemap rules) and the build audit that enforces them (scripts/seo-aio-audit.mjs, baseline data/seo-aio-audit-baseline.json). Use before adding or changing any public page, title, description, heading, schema, internal link or image; when the deploy gate reports a new seo-aio-audit violation; and whenever the owner asks for an SEO audit, SEO review or ranking improvements.

Source file
.claude/skills/seo-audit/SKILL.md

SEO audit

Adapted from the two most used open SEO skill packs, both MIT licensed: claude-seo (Copyright (c) 2026 agricidaniel) and marketingskills (Copyright (c) 2025 Corey Haines). Thresholds below are theirs unless marked "site". AI-search rules (crawlers, answer-first writing, citations, freshness) are in the ai-search-optimization skill. How a page's head and JSON-LD are built is in seo-head-and-schema.

Run it

npx tsx scripts/gate.ts                  # runs it inside "SEO validation"
node scripts/seo-aio-audit.mjs           # after a build (dist/cloudflare)
node scripts/seo-aio-audit.mjs --report  # every violation, not only new ones
node scripts/seo-aio-audit.mjs --update-baseline   # after fixing old debt

The audit reads every indexable route in dist/cloudflare/seo-route-manifest.json and fails on a violation that is not in data/seo-aio-audit-baseline.json. The baseline is the old debt: it may only shrink. Fix a new violation rather than adding it to the baseline. Only add one when the owner accepts it, and say so in the commit message.

For the live site, use the seo-aio-auditor agent (read-only).

Rules the audit enforces

Rule id Check Threshold
html-size Googlebot reads only the first 2 MB of HTML ≤ 2,000,000 bytes
canonical One absolute, self-referencing canonical equals the route's canonical URL
title-length <title> 30–60 characters (fitPageTitle budget)
description-length meta description 70–160 characters; aim for 120–160
title-duplicate / description-duplicate unique across indexable pages no repeats
h1-count headings exactly one <h1>
heading-skip heading outline no skipped level (h2 → h4)
thin-content main-content words (programmatic floor) ≥ 300 words
img-alt every <img> has alt (alt="" only for decoration) 100%
img-dimensions width and height on every <img> 100%
favicon-link <link rel="icon"> in the head present
jsonld JSON-LD parses, one @graph per page exactly one block
deprecated-schema no HowTo, SpecialAnnouncement, ClaimReview, CourseInfo, EstimatedSalary, LearningVideo, VehicleListing none
article-fields Article has headline, image, author, datePublished, dateModified all present
article-og-type Article pages use og:type article match
date-consistency the page entity's dateModified equals the sitemap <lastmod> same day
orphan at least one link from another indexable page ≥ 1 inbound

The AI-search rules (h1-early, article-citations, visible-date, robots-ai-crawlers) are explained in ai-search-optimization.

Rules checked by hand

Technical

  • Redirects: one hop at most, 301 for permanent moves (server/publicRouting.ts).
  • URLs: lowercase, hyphens, no content in query strings, one trailing-slash policy, under 100 characters (public-url-conventions).
  • Title, description, canonical, robots and JSON-LD are in the server HTML, never added by JavaScript (Astro static output does this; keep it that way).
  • No history.pushState that hijacks the back button. It became a Google spam policy on 2026-04-13.
  • Touch targets at least 24×24 CSS px (WCAG 2.2); viewport without maximum-scale or user-scalable=no.

Performance (field data, 75th percentile; FID is retired, use INP)

Metric Good
LCP ≤ 2.5 s
INP ≤ 200 ms
CLS ≤ 0.1

Lighthouse lab numbers stand in when CrUX has no data.

On-page

  • Title: query first, brand last, important words in the first 50 characters, aligned with the H1. No year or "free" unless the page delivers it.
  • Description: does not repeat the title, no templated "title + stock CTA".
  • The page's main query appears in the first 100 words.
  • Quick wins are pages ranking 8–20 in Search Console (pnpm gsc:report). Change one page's title at a time and wait 3–4 weeks before judging.

Content and E-E-A-T

  • Who, How, Why: a visible author (Sahin, linked to /about), how the page was made (data source, date), and a reason a person would want it.
  • Visible "Updated" date that matches dateModified (see ai-search-optimization).
  • Readability: sentences of 15–20 words, paragraphs of 2–4 sentences.
  • Word count is not a ranking factor, but under 300 words on a programmatic page means it adds nothing a list row does not.

Programmatic pages (companies, investors, categories, founders, news)

  • Each page must be worth publishing on its own: unique facts, not the same paragraph with the name swapped. Under 40% unique text is thin; under 30% is a stop.
  • Never noindex a page to fix it (owner rule, 2026-10-16, standing-rules). Make it unique: sourced facts, a summary written from its own data, a different angle.
  • Records with more than 80% of the same fields are duplicates: give each its own facts and angle.
  • Two families on the same slugs (/sectors/{slug} and /market/{slug}) must each answer a different question, both indexed.
  • Roll out more than 100 new pages in batches and review a 5–10% sample.
  • Each page links 3–5 related pages plus its breadcrumb trail.

Schema

  • JSON-LD only, in the server HTML, matching what the page shows.
  • Use: WebSite, Person, ProfilePage, Organization, Article, BreadcrumbList, ItemList, CollectionPage, Dataset.
  • FAQPage rich results are gone for sites like this one (claude-seo and marketingskills report full retirement on 2026-05-07). Keep FAQPage only where the questions are visible; it is harmless and AI engines read it.
  • HowTo (2023) and the sitelinks search box (2024) are retired; never add them.
  • Validate a changed page with the Rich Results Test and validator.schema.org.

Links

  • Descriptive anchor text, never "click here".
  • Hub and spoke: the hub links every spoke, every spoke links back, and related spokes link each other.
  • Long articles: 5–10 internal links; cite 2–3 authoritative external sources.

Images

  • Alt text 10–125 characters that describe the image.
  • Weight: thumbnails under 50 KB, content images under 100 KB, hero under 200 KB. AVIF or WebP first.
  • loading="lazy" only below the fold, never on the LCP image; the LCP image gets fetchpriority="high".

Sitemap and indexing

  • Only 200-status, canonical, indexable URLs (buildCanonicalSitemap).
  • lastmod is the date the page's content last changed, not the build date.
  • Under 50,000 URLs and 50 MB per file.
  • IndexNow runs after each deploy (scripts/indexnow-submit.ts).
  • Compare indexed against intended pages monthly in Search Console.

Report format

Rank findings by impact. For each: the URL in full (sahin.io/angel-investments/...), what was seen, the rule and threshold, and the file that produces it.