seo-audit
Skill7 starsChanged 28 days agoMITView on GitHub
SEO/GEO site audit covering 13 dimensions with 6 critical gates. Scans source code, templates, and config files across meta tags, structured data, AI crawlers, content quality, GEO readiness, performance, and optional live Core Web Vitals. Framework-aware: Astro, Next.js, Hugo, WordPress, React, plain HTML. Flags: full (default), [path], --live-url <url>, --quick, --content-only, --geo, --profile <marketing|docs|blog|ecommerce|app-shell>, --content-profile auto|marketing|docs|blog|ecommerce|app-shell, --live-sample-bots <default|all|bot1,bot2>, --persist-backlog.
185 other projects use a version of this.
Adopted by
Most recently taken up by
- nisarth/claude-skills-storetheir own version, first seen Nov 8, 2026
- alpit-patel/seo-aeo-geo-kittheir own version, first seen Nov 8, 2026
- foverse/seoversetheir own version, first seen Nov 8, 2026
- insight68/Skillstheir own version, first seen Nov 8, 2026
- figueroaignacio/ignaciofigueroa.devtheir own version, first seen Nov 8, 2026
- ftzi/livespectheir own version, first seen Nov 8, 2026
Used with
Projects with it also use openseo-review-web-content, openseo-release-notes and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
JwuthriSkillopenseo-review-web-content
Write and review content for the OpenSEO website (web/) — blog posts, guides, feature pages, FAQs. Distills the philosophy for on-brand, useful, accurate content. Use whenever adding or editing user-facing prose in web/content or web/src.
Also in 5 projects that use this
JwuthriSkillopenseo-release-notes
Cut an OpenSEO release — bump the version, draft user-facing release notes from commits since the last tag, run a review + subagent-verification pass, and open a "release: vX.X.X" PR. Use when the user asks to prepare a release, bump the version, or write release notes.
Also in 6 projects that use this
nicepkgSkillcommunity-led-growth
Expert in community-led growth (CLG) - leveraging user communities to drive acquisition, retention, and expansion. Covers building developer communities, user groups, ambassador programs, and turning customers into advocates. Knows the difference between community as a feature vs community as a growth engine, and how to measure community ROI. Use when "community-led, CLG, ambassador program, champion program, user community, developer community, word of mouth, user group, " mentioned.
Also in 5 projects that use this
nicepkgSkillph-community-outreach
Engage Reddit, Indie Hackers, Hacker News and other communities for Product Hunt launches. Use this skill to identify relevant communities, craft appropriate posts, and drive cross-platform engagement without appearing spammy.
Also in 5 projects that use this
xfstudioSkillmicro-saas-launcher
Expert in launching small, focused SaaS products fast - the indie hacker approach to building profitable software. Covers idea validation, MVP development, pricing, launch strategies, and growing to sustainable revenue. Ship in weeks, not months. Use when: micro saas, indie hacker, small saas, side project, saas mvp.
Also in 5 projects that use this
akii-technologies-ltdSkillkeyword-clustering
Cluster and organize keywords into topical groups for SEO. Use when the user asks to "cluster keywords", "group keywords", "organize keywords", "keyword mapping", "topic clusters", "keyword grouping", "build a content plan", "pillar pages", "topical authority", "semantic clustering", or pastes a list of keywords.
Also in 12 projects that use this
- +4 more from nicepkg
- +2 more from Jwuthri
Other versions185 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 185
- coreyhaines31/marketingskills★ 59ksame name
- anthropics/knowledge-work-plugins★ 35ksame name
- every-app/open-seo★ 27ksame name
- AgriciDaniel/claude-seo★ 20ksame name
- trycompai/crm★ 12ksame name
- Ryze-AI-Adgent/open-seo-mcp-skills★ 8.4ksame name
- TheCraigHewitt/seomachine★ 7.5ksame name
- legions-developer/evilcharts★ 3.2ksame name
- MaxMiksa/Auto-Company★ 3.2ksame name
- MaxMiksa/Autonomous-Company★ 3.2ksame name
175 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository58 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- a11y-auditSkill
- agent-benchmarkSkill
- api-auditSkill
- architectureSkill
- backlogSkill
- benchmarkSkill
- brainstormSkill
- buildSkill
- canarySkill
- ci-auditSkill
- code-auditSkill
- container-auditSkill
- content-auditSkill
- content-expandSkill
- content-fixSkill
- content-migrationSkill
- context-auditSkill
- db-auditSkill
- debugSkill
- dependency-auditSkill
- deploySkill
- design-reviewSkill
- designSkill
- docsSkill
- env-auditSkill
- executeSkill
- fix-testsSkill
- geo-auditSkill
- geo-fixSkill
- incidentSkill
- infra-auditSkill
- leadsSkill
- mutation-testSkill
- pentestSkill
- performance-auditSkill
- planSkill
- presentationSkill
- profile-sessionSkill
- receive-reviewSkill
- refactor-radarSkill
- refactorSkill
- release-docsSkill
- retroSkill
- reviewSkill
- security-auditSkill
- seo-fixSkill
- shipSkill
- skill-evalSkill
- structure-auditSkill
- test-auditSkill
- tests-performanceSkill
- ui-design-teamSkill
- using-zuvoSkill
- worktreeSkill
- write-articleSkill
- write-e2eSkill
- write-testsSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
49 rules. 0 are common, 21 are distinctive, and 28 are very specific to this project.
0
Common
Most of the 167 edited versions we read keep these.
21
Distinctive
This author's own choices. Worth a look.
28
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 60
Read these files before any work begins:
- Distinctive: line 87
If any file is missing, STOP.
- Very specific: line 91
Read ../../shared/includes/env-compat.md for agent dispatch patterns, path resolution, and progress tracking across all supported platforms.
- Very specific: line 115
Use the deterministic preload helper FIRST: Run ~/.zuvo/compute-preload seo-audit "$PWD".
- Very specific: line 121
Read ../../shared/includes/codesift-setup.md for the full initialization sequence.
- Very specific: line 123
Summary: Run the CodeSift setup from codesift-setup.md at skill start.
- Very specific: line 131
Read ../../shared/includes/live-probe-protocol.md for the full consent gate, rate limiting rules, error escalation thresholds, and HTTP …
- Distinctive: line 133
All live probing in this skill follows that shared protocol.
- Very specific: line 167
Default: full (no --live-url).
- Very specific: line 223
When --live-url is provided, check for browser tools:
- Very specific: line 240
If --live-sample-bots is set:
- Distinctive: line 284
Claude Code: Use the Task tool to run all three in parallel:
- Distinctive: line 311
Cursor: No agent dispatch. Execute each agent's analysis sequentially yourself, maintaining identical output format.
- Distinctive: line 314
If native agent dispatch is unavailable, run the three agent analyses sequentially yourself, preserve the same report sections, and note …
- Distinctive: line 322
If an agent fails or times out:
- Distinctive: line 324
If retry fails: log the error, proceed with results from successful agents, note the gap in the report
- Distinctive: line 328
After all agents complete:
- Distinctive: line 333
If any dimension is missing (agent failed): mark as "INSUFFICIENT DATA" in scoring
- Very specific: line 341
Read ../../shared/includes/seo-check-registry.md as the single source of truth for owner_agent, layer, enforcement, and evidence_mode.
- Very specific: line 349
Only blocking checks may produce overall FAIL or PROVISIONAL.
- Very specific: line 356
Use ../../shared/includes/seo-bot-registry.md for the canonical live sample order and class semantics
- Very specific: line 362
When code suggests Cloudflare, WAF, CDN, or host-layer overrides, the result may be PROVISIONAL or INSUFFICIENT DATA until live probing …
- Very specific: line 372
Use ../../shared/includes/seo-page-profile-registry.md as the D9 default contract
- Very specific: line 375
If content is CMS-backed or inaccessible from the repo, downgrade to advisory, N/A, or INSUFFICIENT DATA, not hard failure
- Distinctive: line 399
Use these specific queries for SEO-relevant searches:
- Distinctive: line 427
Verify JSON-LD and meta tags in both:
- Very specific: line 437
When --live-sample-bots is provided, or when live mode already has enough coverage to test representative bots safely, sample up to N bots …
- Very specific: line 448
If live bot probing is unavailable, emit a Bot Policy Matrix from source-only evidence and mark live-dependent rows as PROVISIONAL.
- Distinctive: line 453
Check up to 50 internal links and 100 external links.
- Distinctive: line 457
If browser tools available, capture screenshots at 3 breakpoints (1440, 768, 375).
- Distinctive: line 465
All 6 gates MUST have explicit status:
- Very specific: line 485
Only blocking checks and critical gates control FAIL vs PROVISIONAL.
- Distinctive: line 550
Before generating the report, verify:
- Very specific: line 554
Critical Gate Completeness: All 6 gates have explicit PASS/FAIL/INSUFFICIENT DATA with evidence.
- Distinctive: line 555
Evidence Completeness: Every FAIL finding has file:line or INSUFFICIENT DATA note.
- Very specific: line 556
Priority Math: Verify 3D priority calculation (SEO * 0.4) + (Business * 0.4) + ((4 - Effort) * 0.2).
- Very specific: line 559
Blocking Semantics: Only checks marked blocking in seo-check-registry.md are allowed to create overall FAIL or PROVISIONAL.
- Distinctive: line 600
Every finding in the execution plan uses this structure:
- Very specific: line 654
Before generating JSON, read ../../shared/includes/audit-output-schema.md for the schema contract.
- Very specific: line 656
After saving the markdown report, also save structured JSON findings for downstream consumption by zuvo:seo-fix and CI pipelines.
- Very specific: line 764
After the audit report is generated, run cross-model validation to catch score inflation and gate inconsistency.
- Very specific: line 772
Record the verdicts: after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, …
- Very specific: line 774
If adversarial-review is not in PATH: ~/.zuvo/adversarial-review (stable.
- Distinctive: line 776
Wait for complete output. Then:
- Very specific: line 807
If gate_status = FAIL → VERDICT = INCOMPLETE.
- Distinctive: line 813
Run: <ISO-8601-Z> seo-audit <project> <N-critical> <N-total> <VERDICT> - <N>-dimensions <NOTES> <BRANCH> <SHA7> <INCLUDES> <TIER>
- Very specific: line 818
Follow the retrospective protocol from retrospective.md.
- Distinctive: line 820
If gate check skips: print "RETRO: skipped (trivial session)" and proceed.
- Very specific: line 822
After printing this block, append the Run: line value (without the Run: prefix) to the log file path resolved per run-logger.md.
“Common” is measured: kept by at least 6 in 10 of the 167 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
zuvo:seo-audit — SEO/GEO Site Audit
Hybrid code-level and optional live site audit for search engine optimization and generative engine optimization. Examines source code, templates, and config files across 13 dimensions. Optional live mode adds Core Web Vitals measurement, broken link detection, and rendered DOM verification.
Scope: Pre-launch readiness, periodic SEO health, GEO optimization, content scaling preparation, post-redesign verification.
Out of scope: Code quality (zuvo:code-audit), security vulnerabilities (zuvo:security-audit), deep performance profiling (zuvo:performance-audit).
Mandatory File Loading
Read these files before any work begins:
../../shared/includes/codesift-setup.md-- CodeSift discovery and tool selection../../shared/includes/env-compat.md-- Agent dispatch and environment adaptation../../shared/includes/seo-bot-registry.md-- Canonical AI/search bot taxonomy and live-probe scope../../shared/includes/seo-page-profile-registry.md-- Profile-aware D9/D10 thresholds and downgrades../../shared/includes/seo-fix-registry.md-- Canonical fix_type, safety, params (before Phase 6.2 JSON output)../../shared/includes/audit-output-schema.md-- JSON output contract (before Phase 6.2)../../shared/includes/seo-check-registry.md-- Canonical check slugs and enforcement layers (agents MUST use)../../shared/includes/run-logger.md-- Run logging contract../../shared/includes/retrospective.md-- Retrospective protocol
Print the checklist:
CORE FILES LOADED:
1. codesift-setup.md -- [READ | MISSING -> STOP]
2. env-compat.md -- [READ | MISSING -> STOP]
3. seo-bot-registry.md -- [READ | MISSING -> STOP]
4. seo-page-profile-registry.md -- [READ | MISSING -> STOP]
5. seo-fix-registry.md -- [READ | MISSING -> STOP]
6. audit-output-schema.md -- [READ | MISSING -> STOP]
7. seo-check-registry.md -- [READ | MISSING -> STOP]
8. run-logger.md -- [READ | MISSING -> STOP]
9. retrospective.md -- [READ | MISSING -> STOP]If any file is missing, STOP.
Environment Compatibility
Read ../../shared/includes/env-compat.md for agent dispatch patterns, path resolution, and progress tracking across all supported platforms.
MANDATORY TOOL CALLS — SEO Audit Validity Gate
INVALID if any tool below is skipped. "DEFERRED", "N/A", "--quick" NOT valid reasons.
| Tool | Trigger | Skip allowed? |
get_file_tree | Always | NO — locate sitemap.xml, robots.txt, llms.txt, /pages/ |
search_text | Always | NO — meta tags, JSON-LD, OpenGraph, canonical |
search_patterns | Always | NO — SEO anti-patterns (missing meta, malformed schema) |
scan_secrets | Always | NO — API keys in client code |
audit_scan | Always | NO — compound check |
nextjs_metadata_audit | Next.js detected | NO when Next.js |
| Astro/framework tools | Astro/framework detected | NO when matches |
Forbidden: nextjs_metadata_audit: skipped (when Next), codesift: unavailable (when deferred), retrospective: skipped — REJECTED.
POSTAMBLE: report on disk → retro appended → ~/.zuvo/append-runlog exit 0. Every SEO finding needs path/to/file.ext:LINE (verify-audit gate).
Mandatory-tools-acknowledgment: I will run get_file_tree + search_text + search_patterns + scan_secrets + audit_scan + nextjs_metadata_audit (when Next.js) + framework tools for this SEO audit. Every finding will cite a `path/to/file.ext:LINE` resolving in the current tree.Use the deterministic preload helper FIRST. Run ~/.zuvo/compute-preload seo-audit "$PWD". Math gate enforced.
CodeSift Integration
Read ../../shared/includes/codesift-setup.md for the full initialization sequence.
Summary: Run the CodeSift setup from codesift-setup.md at skill start. Use CodeSift for structured data discovery, meta tag pattern search, and component analysis when available. Fall back to Grep/Read/Glob if unavailable.
Safety Gates (NON-NEGOTIABLE)
GATE 1 -- Live Audit Consent
Read ../../shared/includes/live-probe-protocol.md for the full consent gate,
rate limiting rules, error escalation thresholds, and HTTP method restrictions.
All live probing in this skill follows that shared protocol.
GATE 2 -- Read-Only Audit
This audit is read-only against source code.
Allowed write targets:
zuvo/audits/for the report file (.mdand.json)memory/backlog.mdandmemory/findings/(written bybacklog-add) only when--persist-backlogis explicitly enabled
FORBIDDEN:
- Writing to any source/production file
- Modifying application code (suggest fixes in report, do not apply)
- Installing packages or modifying dependencies
Phase 0: Parse $ARGUMENTS and Stack Detection
0.1 Arguments
| Argument | Behavior | |||||
full (default) | All 13 dimensions, code-only | |||||
[path] | Audit specific directory or module | |||||
--live-url <url> | Code audit + live audit (CWV, broken links, rendered DOM) | |||||
--quick | Critical gates only -- fast pass/fail (CG1-CG6) | |||||
--content-only | Content-focused audit: D7, D9, D10 | |||||
--geo | GEO-focused audit: D3, D5, D9, D10 | |||||
| `--profile <marketing | docs | blog | ecommerce | app-shell>` | Canonical flag for overriding the D9/D10 content heuristics profile | |
| `--content-profile auto | marketing | docs | blog | ecommerce | app-shell` | Legacy alias for --profile; accept for backward compatibility |
| `--live-sample-bots <default | all | bot1,bot2>` | In live mode, probe representative bots or an explicit subset from seo-bot-registry.md and emit a Bot Policy Matrix | |||
--persist-backlog | Record prioritized findings through backlog-add (Phase 7) |
Default: full (no --live-url).
0.2 Stack Detection
Detect the web framework from project config files:
# Portable web framework detection (BSD/GNU compatible)
ASTRO=$(find . -maxdepth 3 -name "astro.config.*" 2>/dev/null | wc -l)
NEXT=$(find . -maxdepth 3 -name "next.config.*" 2>/dev/null | wc -l)
HUGO=$(find . -maxdepth 2 \( -name "hugo.toml" -o -name "hugo.yaml" \) 2>/dev/null | wc -l)
WP=$(find . -maxdepth 3 -name "wp-config.php" 2>/dev/null | wc -l)
REACT=$(rg -l "from ['\"]react['\"]" . -g '*.tsx' -g '*.jsx' 2>/dev/null | head -5 | wc -l || grep -rl "from 'react'" . --include="*.tsx" --include="*.jsx" 2>/dev/null | head -5 | wc -l || true)Also detect (with heuristics):
Content format:
markdown— directories namedcontent/,posts/,blog/,pages/containing*.mdor*.mdxdatabase— WordPress detected, or CMS config found (e.g.,strapi,payload,sanity)none— no content directories found
SEO files:
robots.txt— checkpublic/robots.txt,static/robots.txt, or framework route (src/pages/robots.txt.ts,app/robots.ts)sitemap— checkpublic/sitemap*.xml, framework config (@astrojs/sitemapin config,app/sitemap.ts), or generated outputllms.txt— checkpublic/llms.txtllms-full.txt— checkpublic/llms-full.txtor framework-equivalent static output
Deploy platform:
vercel.jsonor.vercel/→ Vercelnetlify.tomlor_headers+_redirects→ Netlifywrangler.tomlor_worker.js→ Cloudflare.htaccess→ Apachenginx.confor/etc/nginx/refs → Nginx- None detected → Unknown
Store results:
DETECTED_STACK = [astro | nextjs | hugo | wordpress | react | html]
CONTENT_FORMAT = [markdown | database | none]
CONTENT_PROFILE = [auto | marketing | docs | blog | ecommerce | app-shell]Print:
Stack: [framework] | Content: [format] | Profile: [profile] | Deploy: [platform]
SEO files: robots.txt [found/MISSING] | sitemap [found/MISSING] | llms.txt [found/MISSING] | llms-full.txt [found/MISSING]
Mode: [full/quick/content-only/geo] | Live: [url or "code-only"]Phase 1: MCP Tool Inventory (live mode only)
Skip if no --live-url. Code agents use only Grep/Read/Glob/Bash.
When --live-url is provided, check for browser tools:
Check 1: chrome-devtools OR playwright -> DOM inspection, screenshots
Check 2: lighthouse (optional) -> CWV measurement
Check 3: accessibility-scanner (optional) -> WCAG auditFor each missing tool that is relevant, inform the user of the capability gap and suggest installation.
CWV fallback chain:
- chrome-devtools evaluate_script -> Performance API
- Bash:
npx lighthouse <url> --output json --chrome-flags="--headless" - SKIP: "No CWV measurement tools available. D8-live = INSUFFICIENT DATA."
Set availability flags and proceed.
If --live-sample-bots is set:
default= probe one bot per class (training,search/retrieval,user-proxy) usingseo-bot-registry.mdall= probe everylive_test=yesbot from the registrybot1,bot2= only probe canonicalbot_keyvalues explicitly listed by the user
Phase 2: Code Audit (Parallel Agent Dispatch)
Dispatch follows ../../shared/includes/execution-policy.md through env-compat. Reuse existing
authorization within that policy; session restrictions take precedence. Run each required gate
and report its actual independence or an unmet requirement.
Dispatch 3 agents in parallel. Each agent evaluates its assigned dimensions independently.
Dimension grouping
| Group | Agent | Dimensions | Shared data |
| A (Technical) | agents/seo-technical.md | D1, D4, D5, D11, D12, D13 | Config files, robots.txt, head templates |
| B (Content) | agents/seo-content.md | D7, D9, D10 | Content files, markdown/HTML pages |
| C (Assets) | agents/seo-assets.md | D2, D3, D6, D8 | Layout templates, asset files, build config |
Mode-aware dimension filtering
Based on the mode from Phase 0, determine which agents to dispatch:
| Mode | Agents dispatched | Dimensions active |
full (default) | All 3 | D1-D13 |
--quick | Technical + Assets | Blocking gates only (CG1-CG6), no non-blocking dimension scoring |
--content-only | Content only | D7, D9, D10 |
--geo | Technical + Content + Assets | D3, D5, D9, D10 |
Pass mode, selected_dimensions, and content_profile to each dispatched
agent as input parameters. Agents MUST skip dimensions not in their
selected_dimensions list.
Agent dispatch
Refer to ../../shared/includes/env-compat.md for dispatch patterns per environment.
Claude Code: Use the Task tool to run all three in parallel:
Agent 1: SEO Technical (Group A)
model: "sonnet"
type: "Explore"
instructions: read agents/seo-technical.md
input: detected_stack, [config file paths from Phase 0], codesift_repo, mode, selected_dimensions, content_profile
Agent 2: SEO Content (Group B)
model: "sonnet"
type: "Explore"
instructions: read agents/seo-content.md
input: detected_stack, [content directory paths], codesift_repo, mode, selected_dimensions, content_profile
Agent 3: SEO Assets (Group C)
model: "sonnet"
type: "Explore"
instructions: read agents/seo-assets.md
input: detected_stack, [layout/template paths], codesift_repo, mode, selected_dimensions, content_profile<!-- PLATFORM:CODEX -->Codex: Define TOML agents per env-compat.md patterns. Each agent runs in read-only sandbox.
<!-- /PLATFORM:CODEX --><!-- PLATFORM:CURSOR -->Cursor: No agent dispatch. Execute each agent's analysis sequentially yourself, maintaining identical output format.
<!-- /PLATFORM:CURSOR -->If native agent dispatch is unavailable, run the three agent analyses sequentially yourself, preserve the same report sections, and note the fallback mode in the final audit header.
Waiting for results
Collect all 3 agent reports before proceeding to Phase 3 (live audit) or Phase 4 (scoring).
If an agent fails or times out:
- Retry once with same inputs
- If retry fails: log the error, proceed with results from successful agents, note the gap in the report
Merge logic (before Phase 4)
After all agents complete:
- Concatenate findings arrays from all 3 agents
- Assign stable finding IDs using format
{dimension}-{check}(e.g.,D4-sitemap-exists,D3-json-ld-ssr). These IDs are deterministic across runs for the same codebase — unlike sequential F1/F2 which shift when findings change. Also assign display-order numbers (F1, F2, ...) for human-readable reports, but--findingfiltering in seo-fix uses the stable ID. - Each agent returns raw check statuses per dimension -- main agent calculates numeric scores in Phase 4
- Evaluate critical gates: CG1-CG4, CG6 from blocking Technical checks; CG5 from blocking Assets checks
- If any dimension is missing (agent failed): mark as "INSUFFICIENT DATA" in scoring
Agent vs main scoring boundary: Agents return raw check statuses (PASS/PARTIAL/FAIL/INSUFFICIENT DATA) per check. The main agent calculates all numeric scores in Phase 4 using the status-to-value mapping. Agents do NOT calculate dimension scores themselves.
Dimension constraints (normative -- agents MUST follow)
Enforcement model (normative)
Read ../../shared/includes/seo-check-registry.md as the single source of truth
for owner_agent, layer, enforcement, and evidence_mode.
blocking: can produce overallFAILorPROVISIONALscored: affects dimension and overall scores, but cannot alone flip the overall resultadvisory: prioritized and reported, but excluded from pass/fail logic
Only blocking checks may produce overall FAIL or PROVISIONAL. Heuristic,
advisory, or content-inaccessible findings must never create a blocking result
without direct evidence.
For fix_type identifiers and safety classifications, agents MUST use ../../shared/includes/seo-fix-registry.md as the canonical source.
D5 — AI crawler policy:
- Use
../../shared/includes/seo-bot-registry.mdfor the canonical live sample order and class semantics - "Conscious decision" = explicit, non-contradictory policy for relevant bots or bot classes, with evidence that policy is intentional rather than accidental
- Deep robots analysis must look for problematic rules such as
/*.js*,/*.pdf$, and/*.feed* - When code suggests Cloudflare, WAF, CDN, or host-layer overrides, the result
may be
PROVISIONALorINSUFFICIENT DATAuntil live probing confirms policy - llms.txt in D5: check presence and crawler accessibility only (is it served? is it blocked?)
D7 — Internal linking (code-only caveat):
- In code-only mode, orphan detection is limited to static analysis (route files without inbound
<a>or<Link>references). Report as "potential orphan risk", not definitive orphan. - Full orphan confirmation requires live crawl or route graph analysis (--live-url mode).
D9 — Content quality (measurable heuristics):
- Use
../../shared/includes/seo-page-profile-registry.mdas the D9 default contract - Thin-content thresholds are profile-aware, not globally fixed at 300 words
- If content is CMS-backed or inaccessible from the repo, downgrade to
advisory,N/A, orINSUFFICIENT DATA, not hard failure - Answer-first and chunkability must follow the active profile rather than a universal requirement
D10 — GEO/AI readiness:
- llms.txt in D10: evaluate content quality and structure (not presence — that's D5)
- Separate llms proposal compliance from best-practice richness:
llms.txtpresence/access belongs to D5, whilellms-full.txtquality and companion richness belong to D10 - E-E-A-T signals: check for
author,datePublished,dateModifiedfields in frontmatter/schema, plus citation/source references - Freshness is heuristic and should remain
advisoryunless direct blocking evidence exists elsewhere
D13 — Monitoring (advisory checks):
- "Search Console setup indicators" is advisory only — cannot be confirmed from repo in most cases. Score as INSUFFICIENT DATA in code-only mode unless verification meta tag or DNS TXT record is present in config.
D11 — Security and Technical (CG3 + CG4):
- CG3 (HTTPS active): In code-only mode, report INSUFFICIENT DATA unless deploy config explicitly proves TLS (e.g.,
vercel.jsonwith forceSSL,netlify.tomlwith force_ssl, Cloudflare always-HTTPS). Absence ofhttp://refs is not proof of HTTPS. - CG4 (Canonical present): Check for
<link rel="canonical">or framework equivalent (Next.jsalternates.canonical, Astro canonical in layout) at layout/template level. Must be a real check with evidence, not inferred from "no canonical issues found".
CodeSift query patterns (when available)
Use these specific queries for SEO-relevant searches:
search_text(repo, "canonical", file_pattern="*.{astro,tsx,html,php}")
search_text(repo, "application/ld+json", file_pattern="*.{astro,tsx,html}")
search_text(repo, "og:image", file_pattern="*.{astro,tsx,html}")
search_text(repo, "robots", file_pattern="*.{txt,ts,js,toml,yaml}")
search_text(repo, "sitemap", file_pattern="*.{ts,js,mjs,toml,yaml}")
search_text(repo, "hreflang", file_pattern="*.{astro,tsx,html}")
search_text(repo, "noindex", file_pattern="*.{astro,tsx,html,ts}")
search_text(repo, "font-display", file_pattern="*.css")
search_text(repo, "llms.txt")For framework-specific deep analysis, see agent instruction files which contain per-framework search patterns (Next.js Metadata API, Astro frontmatter, Hugo partials, WordPress hooks).
Phase 3: Live Audit (only if --live-url)
Runs in parallel with Phase 2 code agents in environments that support it.
3.1 Core Web Vitals
Measure LCP, CLS, and INP using the available tool chain. Record measurement source (Lighthouse, Performance API, or N/A).
3.2 Source and Rendered Verification
Verify JSON-LD and meta tags in both:
- Initial HTML source / raw response body -- fetch without JS execution (curl or equivalent). This is the SSR proof for CG5.
- Rendered DOM after page execution -- confirms tags are visible post-hydration.
Rendered DOM alone is NOT sufficient evidence for CG5. JSON-LD injected client-side only after hydration = CG5 FAIL.
Also check that meta tags are rendered correctly and OG images are accessible.
3.3 Live Bot Matrix Sampling
When --live-sample-bots is provided, or when live mode already has enough
coverage to test representative bots safely, sample up to N bots from
seo-bot-registry.md using HEAD/GET requests with spoofed user-agents.
For each sampled bot, record:
- bot key and class
- verification mode (
source,live,merged) - response status code
- whether robots policy and live behavior agree
- any Cloudflare / WAF / CDN override suspicion
If live bot probing is unavailable, emit a Bot Policy Matrix from source-only
evidence and mark live-dependent rows as PROVISIONAL.
3.4 Broken Link Check
Check up to 50 internal links and 100 external links. Record status codes.
3.5 Visual Verification
If browser tools available, capture screenshots at 3 breakpoints (1440, 768, 375). Check for mobile rendering issues.
Phase 4: Scoring
4.1 Evaluate Critical Gates
All 6 gates MUST have explicit status:
CG1: Sitemap exists -- from D4
CG2: Googlebot not blocked -- from D5
CG3: HTTPS active -- from D11 (code-only: INSUFFICIENT DATA unless deploy config like `vercel.json`, `netlify.toml`, or force-https proves TLS)
CG4: Canonical tags present -- from D11
CG5: JSON-LD server-side rendered -- from D3
CG6: AI crawler policy conscious -- from D5Critical gate statuses:
PASS-- evidence confirms gate is satisfiedFAIL-- evidence confirms gate is not satisfiedINSUFFICIENT DATA-- static analysis is inconclusive and no live verification is available
Scoring rules:
- Any blocking critical gate =
FAIL-> overall result =FAILregardless of score - Any blocking critical gate =
INSUFFICIENT DATA-> overall result =PROVISIONALuntil live/source verification is completed PROVISIONALdoes not block CI gates (it is not a FAIL) but flags incomplete assurance- Only
blockingchecks and critical gates controlFAILvsPROVISIONAL.scoredandadvisoryfindings may lower scores, but they never override the overall result on their own.
4.2 Dimension Scores
Check status → numeric value:
| Status | Value | Notes |
| PASS | 1.0 | Evidence confirms check passes |
| PARTIAL | 0.5 | Partially satisfied or minor issues |
| FAIL | 0.0 | Evidence confirms check fails |
| INSUFFICIENT DATA | excluded | Not counted in denominator |
Per-dimension: score = (sum of check values / count of non-excluded checks) * 100
N/A rules per dimension (exclude from overall score):
| Dimension | N/A when |
| D6 (Images) | No <img> elements in codebase |
| D7 (Internal Linking) | Single-page site (no subpages) |
| D12 (Internationalization) | Single-language site (no hreflang, no i18n config) |
| D13 (Monitoring) | Static export with no analytics config — mark as advisory |
| D9 (Content Quality) | No content corpus (no markdown/blog/pages directories) |
4.3 Overall Score
Dimension weights:
D1: 10% D2: 5% D3: 12% D4: 8% D5: 8% D6: 5% D7: 7%
D8: 10% D9: 15% D10: 10% D11: 5% D12: 3% D13: 2%
Active weights = sum of weights where dimension is NOT N/A
Overall = sum(dimension_score * weight) / active_weights * 1004.4 Sub-Scores
Each normalized to 0-100:
SEO Score: D1 + D2 + D4 + D6 + D7 + D8 + D11 + D12 (weighted)
GEO Score: D3 + D5 + D9 + D10 (weighted)
Tech Score: D4 + D8 + D11 + D12 + D13 (weighted)4.5 Grade Assignment
A (>= 85): Production-ready SEO+GEO. Strong across all dimensions.
B (70-84): Good foundation. Optimization opportunities identified.
C (50-69): Significant gaps. Prioritized fixes needed before scaling.
D (< 50): Major issues. SEO/GEO blocking growth.
Result overrides:
- Any blocking critical gate = FAIL -> result = "FAIL" (regardless of tier)
- Any blocking critical gate = INSUFFICIENT DATA -> result = "PROVISIONAL"
Tier is always calculated from score: A/B/C/D.Phase 5: Report Validation
Before generating the report, verify:
- Count Consistency: Total checks = sum of all dimension checks. No check counted twice.
- Score Math: Recalculate overall from dimension scores * weights. Must match within 0.1.
- Critical Gate Completeness: All 6 gates have explicit PASS/FAIL/INSUFFICIENT DATA with evidence.
- Evidence Completeness: Every FAIL finding has file:line or INSUFFICIENT DATA note.
- Priority Math: Verify 3D priority calculation
(SEO * 0.4) + (Business * 0.4) + ((4 - Effort) * 0.2). - Finding Numbering: F-IDs are sequential (F1, F2, ...) with no gaps or duplicates.
- Summary Consistency: findings_count in executive summary matches actual finding count in report body.
- Blocking Semantics: Only checks marked
blockinginseo-check-registry.mdare allowed to create overallFAILorPROVISIONAL.
Fix any discrepancies before presenting to user.
Phase 6: Report
Executive Summary
SEO/GEO AUDIT -- [project name]
----
SEO: [N]/100 [HEALTHY / NEEDS ATTENTION / AT RISK / CRITICAL]
GEO: [N]/100 [same scale]
Tech: [N]/100 [same scale]
----Health scale: HEALTHY (80+), NEEDS ATTENTION (60-79), AT RISK (40-59), CRITICAL (<40).
Full Report Sections
- Header -- project, date, stack, mode (code / code+live), content profile
- Critical Gates -- 6 gates, PASS/FAIL/INSUFFICIENT DATA with evidence
- Dimension Scores -- D1-D13 table with score, weight, weighted contribution
- Overall Score + Tier
- Sub-Scores -- SEO, GEO, Tech (each /100)
- Strengths -- explicit PASS findings worth preserving
- Bot Policy Matrix -- source/live/merged bot evidence with per-bot status
- Source vs Render Diff -- raw response vs rendered DOM mismatches for JSON-LD and meta tags
- Quick Wins -- findings with Priority >= 2.0 AND Effort = EASY
- Full Execution Plan -- all findings sorted by priority descending
- Content Table -- per-page/content-type coverage, word counts, answer-first rate (if content scanned)
- GEO Readiness Panel -- 7 dimensions (llms.txt, AI crawlers, chunkability, structured HTML, citation readiness, E-E-A-T, freshness)
- Fix Coverage Summary -- safe/moderate/dangerous/no-template counts from the shared fix registry
- Manual Check Recommendations -- informational only, not scored
- CI-Parseable Summary --
SEO-AUDIT-RESULT: PASS|FAIL|PROVISIONAL score=NN tier=X critical=none|CG-N
Finding Format (stable across runs)
Every finding in the execution plan uses this structure:
[F-ID] [Dimension] [Severity] [Confidence]
Issue: [one-line description]
Evidence: [file:line or "code-only inference"]
Why it matters: [SEO/GEO/business impact in one sentence]
Fix: [actionable instruction]
Priority: [N.N] (SEO=[1-3] × Biz=[1-3] × Effort=[1-3])
Enforcement: [blocking | scored | advisory]
Layer: [core | hygiene | geo | visibility-deferred]
ETA: [minutes or "n/a"]
Confidence scale:
HIGH = direct source evidence (file:line confirms the finding)
MEDIUM = inferred from config or indirect signals
LOW = heuristic or absence-based (e.g., file not found)
See also `../../shared/includes/seo-fix-registry.md` for the canonical confidence definitions.3D Priority Calculation
For each finding:
SEO Impact: HIGH(3) / MEDIUM(2) / LOW(1)
Business Impact: HIGH(3) / MEDIUM(2) / LOW(1)
Fix Effort: EASY(1) / MEDIUM(2) / HARD(3)
Priority = (SEO * 0.4) + (Business * 0.4) + ((4 - Effort) * 0.2)
Range: 1.0 - 3.0
Quick Win = Priority >= 2.0 AND Effort = EASYAssignment rubric (to ensure consistent scoring):
| Factor | 3 (HIGH) | 2 (MEDIUM) | 1 (LOW) |
| SEO Impact | Blocks indexation, rich results, or crawlability (CG fail) | Degrades ranking signals or social sharing | Cosmetic or minor optimization |
| Business Impact | Affects homepage, landing pages, or money pages | Affects secondary pages or non-revenue content | Affects low-traffic or internal pages |
| Fix Effort | 1-2 files, config change or additive insert | 3-5 files, template modification, testing needed | 6+ files, architecture change, or content creation |
Save Report
mkdir -p audit-resultsSave to: zuvo/audits/seo-audit-YYYY-MM-DD.md — at the project root (zuvo/ resolves via git rev-parse --show-toplevel; override $ZUVO_OUTPUT_DIR. See ../../shared/includes/report-output-location.md).
Auto-increment if a report for today already exists: seo-audit-YYYY-MM-DD-2.md, seo-audit-YYYY-MM-DD-3.md, etc.
Phase 6.2: JSON Output
Before generating JSON, read ../../shared/includes/audit-output-schema.md for the schema contract. For fix_type values and safety classifications, reference ../../shared/includes/seo-fix-registry.md.
After saving the markdown report, also save structured JSON findings for downstream consumption by zuvo:seo-fix and CI pipelines.
File: zuvo/audits/seo-audit-YYYY-MM-DD.json
Auto-increment with -N suffix if same-day file exists (same convention as .md).
Schema: See ../../shared/includes/audit-output-schema.md for the full schema definition.
Serialize from Phase 4 scoring results:
{
"version": "1.1",
"skill": "seo-audit",
"timestamp": "[current ISO 8601]",
"project": "[working directory absolute path]",
"args": "[arguments from Phase 0]",
"stack": "[detected stack from Phase 0]",
"result": "[PASS, FAIL, or PROVISIONAL from critical gate evaluation]",
"score": {
"overall": [0-100],
"tier": "[A/B/C/D]",
"sub_scores": {
"seo": [0-100],
"geo": [0-100],
"tech": [0-100]
}
},
"critical_gates": [
{ "id": "CG1", "name": "Sitemap exists", "status": "PASS|FAIL", "evidence": "..." },
{ "id": "CG3", "name": "HTTPS active", "status": "INSUFFICIENT DATA", "evidence": "Code-only mode, cannot verify HTTPS" }
],
"findings": [
{
"id": "D4-sitemap-exists",
"display_id": "F1",
"dimension": "D4",
"check": "sitemap-exists",
"status": "FAIL",
"severity": "HIGH",
"enforcement": "blocking",
"layer": "core",
"seo_impact": 3,
"business_impact": 3,
"effort": 1,
"priority": 2.8,
"confidence_reason": "No sitemap config or generated sitemap found in source tree",
"evidence": "...",
"file": null,
"line": null,
"fix_type": "sitemap-add",
"fix_safety": "MODERATE",
"fix_params": { "framework": "astro", "site_url": "https://example.com" },
"eta_minutes": 15,
"bot_scope": null
}
],
"bot_matrix": [
{
"bot_key": "gptbot",
"status": "BLOCKED",
"evidence": "public/robots.txt:12",
"verification_mode": "code"
}
],
"summary": {
"findings_count": { "total": 13, "critical": 3, "high": 4, "medium": 4, "low": 2 },
"quick_wins": 6,
"fixable": { "safe": 5, "moderate": 4, "dangerous": 2, "no_template": 2 }
}
}Nullability: findings[].fix_type, findings[].fix_safety, and findings[].fix_params are nullable. Set to null for findings that have no auto-fix template (content quality, E-E-A-T, etc.). Consumers MUST check for null before using these fields.
The findings[].fix_type, findings[].fix_safety, and findings[].fix_params fields enable zuvo:seo-fix to apply automated fixes without re-scanning the codebase.
Phase 7: Backlog and Next Steps
Backlog Persistence (optional)
Activated with --persist-backlog flag.
Record each finding that meets at least one of these conditions through backlog-add, one call per finding (../../shared/includes/backlog-protocol.md "Filing from a skill"; the conditions are this audit's own selection, while the bars, the dedupe and the confidence routing are the protocol's and are not restated here):
- Priority >= 2.0
- Any Critical Gate = FAIL
A Generic write per finding: ~/.zuvo/backlog-add --repo "$R" --class <C> --conf <N> --source seo-audit --file "$F" --line <n> [--anchor "$A"] [--evidence "$E"] --title "$T" when a repository file causes it (a template, a config, a content file). A finding on a live page or host with no repository file causing it (a response header, a status code, a rendered tag) takes --target "$U" --evidence "$E" in place of --file, --line and --anchor, whatever the class: ~/.zuvo/backlog-add --repo "$R" --class <C> --conf <N> --source seo-audit --target "$U" --evidence "$E" --title "$T", U the page URL or the host. A live defect that a repository file causes is filed by that file (the file form), with the URL in --evidence "$E"; the target form is only for a finding with no repository file causing it. <N> is your confidence that the finding is real. This audit files CQ or BUG only: <C> is CQ for a failed check and BUG only when the finding names the input and the wrong output; BUG takes --anchor "$A", copied from the line that shows the defect ("The location rule"). T starts with the finding's check ID, <check-id>: <title> (e.g. sitemap-exists), so a later run can find the entry. A check that fails for the whole file is a whole-file finding: --line 1, a "Whole file: ..." title (after the check ID), and no --anchor; a whole-file BUG is filed at the line that shows the defect instead, with --anchor "$A" copied from it, never at line 1. Assign "$R" and "$T" before each call, "$F" only for a file finding, "$U" and "$E" only for a target finding (or "$E" alone when a file record carries the URL as evidence), "$A" only when you pass --anchor, as "Free text goes through a variable" in that section says; an empty value you pass is a bug, and backlog-add refuses a missing required field (REFUSED missing-field:<f>). Report the B- or F-id each call prints and Recorded: N (backlog: a, ledger: b) ("The report line" in backlog-protocol.md), plus each NOT PERSISTED (<reason>) by name; on a non-zero exit act on the protocol's exit table, and never append by hand.
An open entry is closed, never removed (Closing, not removing), when this run re-read its cited code and found it fixed. Close each open entry with the same file (or target) and the same title check ID whose cited code this run re-read and found fixed (for a file entry, its line and anchor); leave every other entry with that file and check ID open. A target (live-page) entry is closed only by a later live audit that re-reads the page, never by a source-file patch alone. A legacy entry written in the old {file}|{dimension}|{check} fingerprint format is matched by that fingerprint's file and check segments.
Recording findings through backlog-add commits and stages nothing. This audit lists the wrote= paths backlog-add printed as Backlog writes: <path>, ... (Backlog writes: none when there are none), in its report for the user when it runs standalone, and in its report for the calling skill's closing commit to carry when another skill runs it (backlog-protocol.md "Filing from a skill", Committing what backlog-add wrote).
Next-Action Routing
| Audit Result | Proposed Action | Why |
| Any CG = FAIL | Fix critical gate first | CG failures block all optimization |
| GEO Score < 50 | Add llms.txt + AI crawler rules + content structure | Highest GEO ROI |
| SEO Score < 60 | Fix meta tags + canonical + sitemap gaps | Foundation issues |
| Content < 300 words avg | Expand thin content | Content quality drives all signals |
| D3 < 50 (Structured Data) | Add/fix JSON-LD schemas | Schema markup boosts citations |
| Tier A (>= 85) | Periodic re-audit or add --live-url for CWV data | Maintain and measure |
Phase 7b: Adversarial Review on Audit Report (MANDATORY — do NOT skip)
After the audit report is generated, run cross-model validation to catch score inflation and gate inconsistency. Point --files at the report you just wrote — do NOT run the literal placeholder (it matches nothing and burns a pass).
REPORT="zuvo/audits/seo-audit-$(date +%F).md" # the report this run wrote
[ -f "$REPORT" ] && ~/.zuvo/adversarial-review --mode audit --files "$REPORT" \
|| echo "adversarial: report not found — write it first"Record the verdicts after triage: every finding is fixed, rejected (a false positive) or deferred — record each by its ID: in ONE call, ~/.zuvo/adversarial-review --record-disposition ID-1 fixed --record-disposition ID-2 rejected …, per ../../shared/includes/adversarial-loop.md Step 4.9 (the review lists its IDs on stderr).
If adversarial-review is not in PATH: ~/.zuvo/adversarial-review (stable; the versioned cache path breaks after any release)
Wait for complete output. Then:
- CRITICAL (FAIL gate not in verdict, severity mismatch, score inflation) → fix in report before delivery
- WARNING (N/A abuse, skipped check, insufficient evidence) → append to Known Gaps section
- INFO → ignore
SEO-AUDIT COMPLETE
Overall: [N]/100 -- Tier [A/B/C/D] | Result: [PASS/FAIL/PROVISIONAL] SEO: [N]/100 | GEO: [N]/100 | Tech: [N]/100 Critical gates: [N PASS] / [N FAIL] / [N INSUFFICIENT DATA] Findings: [N critical] / [N total]
Validity Gate (REQUIRED — print BEFORE Run line, AFTER retro append + append-runlog)
VALIDITY GATE
required_tool_calls:
get_file_tree: [<N> | NOT_CALLED]
search_text: [<N> | NOT_CALLED]
search_patterns: [<N> | NOT_CALLED]
scan_secrets: [<N> | NOT_CALLED]
audit_scan: [<N> | NOT_CALLED]
nextjs_metadata_audit: [<N> | not_required | NOT_CALLED]
postamble:
retros_log_appended: [yes(bytes_added=N) | NOT_APPENDED]
retros_md_appended: [yes(entry_count=N) | NOT_APPENDED]
verify_audit_pass: [yes(<verified>/<total>) | NOT_RUN | REJECTED]
gate_status: [PASS | FAIL]If gate_status = FAIL → VERDICT = INCOMPLETE. Append the Run line via the retro-gated wrapper (NOT direct >> runs.log):
printf '%b\n' "$RUN_LINE" | ~/.zuvo/append-runlogRun: <ISO-8601-Z> seo-audit <project> <N-critical> <N-total> <VERDICT> - <N>-dimensions <NOTES> <BRANCH> <SHA7> <INCLUDES> <TIER>
Retrospective (REQUIRED)
Follow the retrospective protocol from retrospective.md.
Gate check → structured questions → TSV emit → markdown append.
If gate check skips: print "RETRO: skipped (trivial session)" and proceed.
After printing this block, append the Run: line value (without the Run: prefix) to the log file path resolved per run-logger.md.
VERDICT: PASS (0 critical findings), WARN (1-3 critical), FAIL (4+ critical).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

