agentsclimarketplace

Seo audit

Skill silvio-l/skills/skills/seo-audit

My personal Claude Code skills. Engineering process, context hygiene, and AI-agent maintenance — straight from my .claude directory.

Install
npx -y skills add silvio-l/skills --skill seo-audit

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Local-first, free-tier SEO + GEO/AEO audit: brand scan, entity/citability signals, JSON-LD schema, external probes (Lighthouse/GSC/PageSpeed), /100 scored report, optional --push. Use when you need an SEO audit, /seo-audit, GEO-Audit, Schema-Check.

SKILL.md

14.8 KB, ~3.8k tokens by cl100k_base, as published. Nobody here has run it

seo-audit — Local-First SEO Audit

You are the auditor. You inventory the repo, scan the built HTML for brand-consistency violations, synthesize the findings into a prioritized list, and write a single Markdown report. You do not fix the findings — that is the user's call after they read the report.

Where things live

ConcernFile
Inventory phase — framework / pages / SEO assets / app-store / domain docinventory.md
Brand-consistency phase — glossary parser, scanner, suppression rulesbrand.md
GEO/AEO scan phase — entity page, citable prose, FAQ, heading structure, llms.txtgeo.md
Schema/JSON-LD audit phase — presence, required fields, deprecated types, sameAsschema.md
External-probes phase — seven adapters, parallel runner, live-smokeprobes.md
Push phase — IndexNow, Bing Webmaster, llms.txt; confirmation flowpush.md
Setup-Onboarding phase — --doctor / --setup <tool> / --verifysetup.md
Synthesis phase — weights, score formula, dedup, tiebreaker, headline scoresynthesis.md
Report phase — sections, template, diff mode, Strategisch/Technisch splitreport.md
Report template (Markdown)templates/report.md
Dispatcher (single entry point)scripts/audit.py
Glossary parserscripts/glossary_parser.py
HTML scannerscripts/brand_scan.py
Inventory scannerscripts/inventory.py
GEO/AEO scannerscripts/geo_scan.py
Schema/JSON-LD scannerscripts/schema_scan.py
Positioning-brief loader (--brief)scripts/positioning_brief.py
External-probes adaptersscripts/probes/
Push adapters (IndexNow / Bing / llms.txt)scripts/push/
Setup-Onboarding (doctor + wizards + verify)scripts/setup/
Synthesis (pure logic)scripts/synthesis.py

Read the phase doc when you enter that phase. SKILL.md is the always-on layer — keep it minimal.

Quick start

S=~/.claude/skills/seo-audit/scripts/audit.py

# Audit the current repo, write into .scratch/seo-audit/.
python3 "$S" --root .

# Audit a different repo, custom dist, diff against the prior report.
python3 "$S" --root ~/code/whispaste --dist ~/code/whispaste/build \
             --report-dir ~/code/whispaste/.scratch/seo-overhaul \
             --compare-last

The dispatcher prints the absolute path of the written report on stdout. Open that file and verify it before declaring the run done — confirm it actually contains all four canonical sections (per report.md) and the findings table; exit 0 alone is not proof the report is well-formed. Only then read it back to summarize for the user.

Phase order

  1. Inventoryinventory.py walks the repo root. Output drives the report header and tells downstream phases where the built HTML lives.
  2. Brand scanglossary_parser.py reads the first Begriff | Stattdessen | Grund table from CONTEXT.mdCLAUDE.mdREADME.md. brand_scan.py matches every term case-insensitively against dist/ (or --dist) on a word-boundary, excluding <script> / <style> blocks. Per-file frontmatter flag contrastiveVocabulary: true and per-section <!-- seo-audit:contrastive --> markers suppress matches.
  3. GEO/AEO scangeo_scan.py checks entity/citability signals: About-page presence, citable prose blocks (≥ 60 chars), FAQ/Q&A structures, heading structure (H1 count, hierarchy, pseudo-headings), and llms.txt / llms-full.txt presence. All checks are offline; findings carry dimension=geo. Heavy checks (prose, FAQ) are skipped under --quick.
  4. Schema/JSON-LD scanschema_scan.py extracts all <script type="application/ld+json"> blocks, validates JSON, checks required-field completeness for 7 core types (via versioned REQUIRED_FIELDS_V1), flags deprecated types (DEPRECATED_TYPES_V1), and checks sameAs social-profile consistency. All checks are offline; findings carry dimension=schema. Files with contrastiveVocabulary: true in an HTML comment are excluded.
  5. Positioning brief (optional)positioning_brief.py loads brand context from --brief <path>, or auto-discovers from <root>/.seo/positioning.md or a <!-- seo:brief --> fenced section in CONTEXT.md. The brief is never used by finding-producing phases — it only flows into the report's recommendation section.
  6. External probes — run when --url <url> is passed. Seven adapters (Lighthouse, pa11y, W3C, Schema.org validator, Observatory, GSC, PageSpeed) fan out concurrently. Requires network.
  7. Synthesissynthesis.py dedups (key: file_path, line_number, match, category, dimension), scores each finding by severity × user_impact / fix_effort, computes a per-dimension breakdown and a /100 headline score via versioned DIMENSION_WEIGHTS_V1, and sorts deterministically.
  8. Reportaudit.py renders templates/report.md with the synthesis output and writes .scratch/<feature>/seo-audit-<YYYY-MM-DD>.md. Recommendations are split into Strategisch (track=strategic, content/entity decisions) and Technisch (track=technical, automatable fixes) sections, with copy-paste-ready fix snippets for JSON-LD and llms.txt findings.

Arguments

FlagDefaultBehaviour
--root <path>requiredRepository root to audit.
--dist <path><root>/distDirectory of built HTML to scan.
--report-dir <path><root>/.scratch/seo-auditOutput directory.
--brief <path>nonePath to a Markdown positioning brief. Provides brand context for the recommendation section only — never affects findings or score. Auto-discovered from <root>/.seo/positioning.md or a <!-- seo:brief --> fenced section in CONTEXT.md when absent or unreadable.
--quickoffSkip heavy per-file GEO checks (prose analysis) and the site-wide FAQ scan; skip the heavy probes (Lighthouse, pa11y).
--url <url>noneRun external probes against this live URL. Repeatable. Requires network.
--pushoffEnable push module (IndexNow, Bing Webmaster, llms.txt). Opt-in; the agent confirms each operation with the user before firing it.
--dry-runoffOnly valid with --push: render the push plan to stdout without performing any submissions or writes.
--compare-lastoffDiff against the most recent prior report in --report-dir.
--doctoroffSetup-Onboarding diagnostic — read-only env / file / probe inspection. Mutually compatible with --verify. See setup.md.
--setup <tool>noneSingle-tool setup wizard. Valid tools: indexnow, pagespeed, bing, gsc. Not combinable with --doctor / --verify. See setup.md.
--verifyoffOne minimal probe call per configured tool, returning per-tool OK/4xx/5xx status. Mutually compatible with --doctor. See setup.md.
--forceoffForce-regenerate setup artefacts (currently only honoured by --setup indexnow).

Definition of Done (single source of truth)

A seo-audit run is DONE only when all of the following hold:

  1. The inventory section identified a framework (or unknown with a reason).
  2. A glossary was loaded — or the report explicitly notes "no glossary found".
  3. The brand scan produced a deterministic finding list — running it twice over the same input yields byte-identical results.
  4. Suppression markers (<!-- seo-audit:contrastive -->, contrastiveVocabulary: true frontmatter flag) were honoured by both the brand scan and the schema scan.
  5. The GEO/AEO scan ran over the same --dist directory and produced findings with dimension=geo. Two runs over identical input yield byte-identical results.
  6. The Schema/JSON-LD scan ran over the same --dist directory and produced findings with dimension=schema. Two runs over identical input yield byte-identical results.
  7. The synthesis output carries a /100 headline_score and a per-dimension dimensions_breakdown (one score per dimension in DIMENSION_WEIGHTS_V1). The findings are sorted by score desc, with the (file_path, line_number, match, dimension) tiebreaker.
  8. The report file exists under <report-dir>/seo-audit-<YYYY-MM-DD>.md with these canonical sections: Executive Summary (headline score + dimensions breakdown), Findings nach Kategorie, Diff zum letzten Lauf, Empfehlungen (Strategisch / Technisch / Fix-Snippets).
  9. The positioning brief (if loaded) appears only in the Positionierungs-Kontext subsection of the report — it never alters the finding list, scores, or synthesis output.
  10. Recommendations are split: Strategisch (du entscheidest) lists findings with track=strategic (content/entity decisions the human must make); Technisch (umsetzbar) lists track=technical findings (automatable one-file or copy-paste fixes).
  11. Fix snippets (copy-paste-ready JSON-LD blocks, llms.txt skeleton) are present in the report for every finding whose fix is deterministically derivable from the finding data.
  12. If --url is omitted, no external network call is made (the entire brand/GEO/schema pipeline stays fully offline). If --url is supplied, the probe layer runs and its findings flow through the same synthesis pipeline.
  13. If --push is passed, no submission or file write happens until the agent has asked the user, per operation, and received an explicit confirmation. The script never prompts; the agent does. --push --dry-run is side-effect-free.

Push confirmation flow (binding for the agent)

When the user passes --push, the dispatcher prints a structured plan to stdout. Before executing any operation, you (the agent) must:

  1. Read the plan back to the user in plain prose — name each module, show what would be submitted, and surface every warning and first_setup_hint.
  2. Ask once per module: "Should I run the IndexNow push to <host>?" — wait for an explicit yes/no.
  3. Only call push.execute_all(plans, clients=..., confirmations=...) with confirmations[module] = True for the modules the user confirmed. Modules the user declined stay False and are skipped silently.
  4. If a module's plan is ready: False, do not even ask — read the reason / first_setup_hint to the user and move on.

The script intentionally has no input() call. That keeps the confirmation in your conversational control where it belongs.

Free-tier discipline

This skill is strictly local-first. Without --url, the pipeline makes zero network calls. With --url, the seven probe adapters run through npx or curl against public endpoints with the quotas documented below.

Free-Tier — was kostet was?

ToolCostQuota / dayWhat happens past quota
GEO/AEO scanner (geo_scan.py)free, runs locallyn/a — local HTML walkn/a
Schema/JSON-LD scanner (schema_scan.py)free, runs locallyn/a — local HTML walkn/a
Positioning-brief loader (positioning_brief.py)free, local file readn/a — localn/a
Lighthouse (npx lighthouse)free, runs locallyn/a — bound only by local CPUn/a
pa11y (npx pa11y)free, runs locallyn/a — localn/a
W3C Nu validator (validator.w3.org/nu/)free, no API keyno published hard cap; "polite use" — the documented guidance is ≤ 1 request/sec (W3C Nu docs)requests rejected with HTTP 429 until the rate drops
Schema.org validator (validator.schema.org)free, no published API contractno published quota — polite-use conventionresponse throttled / shape may change without notice
Mozilla HTTP Observatory (http-observatory.security.mozilla.org/api/v1/)free, no keyno published hard cap; results cached server-side for 24h per host (Observatory docs)rescans before the 24h cache window return cached results
Google Search Console API (mcp__gsc__*)free with a verified GSC property1 200 queries / minute, 30 000 queries / day per project (GSC API quotas)HTTP 429 / quota-exceeded — wait until the next day
Google PageSpeed Insights APIfree with API key25 000 requests / day, 240 requests / 100 s / user (PSI API quotas)HTTP 429 — adapter logs the error and contributes []
IndexNow (api.indexnow.org)free, no provider key — user generates and self-hosts the key fileno published per-day cap; one POST submits a batch of URLs (IndexNow docs)malformed requests rejected; missing key file → HTTP 4xx
Bing Webmaster URL Submission APIfree, BING_WEBMASTER_API_KEY from Webmaster Tools10 URLs / day default for unverified sites; 10 000 / day for verified (Bing docs)HTTP 4xx; the skill clips the batch via a local date-rolled counter (BING_DAILY_LIMIT env overrides)
llms.txt / llms-full.txt (local file)free; generated locallyn/a — purely local file writen/a

Push (IndexNow, Bing Webmaster, llms.txt) is opt-in via --push and confirmed per operation. See push.md.

Limitations (v1)

  • HTML-only scanning. The scanner reads .html/.htm files under --dist. SPA-rendered content that only shows up after JS execution is invisible. Slice 02's Lighthouse adapter will cover that.
  • One glossary table per doc. The parser picks the first table whose header reads Begriff | Stattdessen | Grund. If a project needs multiple tables, split them across the candidate files (CONTEXT.md wins over CLAUDE.md wins over README.md).
  • Markdown report only. No HTML or PDF output. The report is designed to be skimmed in an editor and diffed in git.

Keep looking

Skills are one crate of 327,069. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.