codebase-seo
Audit, then GEO review, then apply fixes. Next.js / TypeScript defaults; follow whatever
the repo already uses. ${CLAUDE_SKILL_DIR} is this skill's directory — the working
directory is the user's project, so address bundled files through it.
| Flag | Phase | Writes code |
|---|---|---|
--audit | 1 — technical SEO | no |
--geo | 2 — AI-citation readiness | no |
--fix | 3 — apply findings already in context | yes |
--full | 1 → 2 → 3 (default) | yes |
--routes /,/pricing narrows scope; default is every route.
Setup
- Prefer a local path and a live URL. Each catches what the other cannot.
- Read
.agents/product-marketing.mdor.claude/product-marketing.mdif either exists. Ask only what it does not answer. --fixneeds reports in context. If absent, run--full.
Scripts
Needs curl and Node 18+, nothing to install. Run these before reading source: they produce
the evidence, source inspection explains it. Each exits non-zero on an error-level finding.
Add --json to the Node scripts for structured output.
bash "${CLAUDE_SKILL_DIR}/scripts/redirect-trace.sh" example.com /pricing /blog
node "${CLAUDE_SKILL_DIR}/scripts/extract-jsonld.mjs" https://example.com/pricing
node "${CLAUDE_SKILL_DIR}/scripts/audit-meta.mjs" https://example.com/pricing
node "${CLAUDE_SKILL_DIR}/scripts/audit-meta.mjs" out/pricing.html --base https://example.com
Pass real routes to redirect-trace.sh — loops often hide on deep paths, not on /.
All three read server-rendered HTML only. Client-injected JSON-LD is invisible to them, as
it is to web_fetch. Never write "no schema found" on a script's say-so; confirm in a browser.
Phase 1 — technical audit (--audit)
Read ${CLAUDE_SKILL_DIR}/references/technical-audit.md and work its checklist. Run the
scripts first, then use source to locate and explain each finding.
Report per finding:
File: app/page.tsx:37-41
Severity: Critical | High | Medium | Low
Root cause: <one sentence>
Impact: <what breaks in search, social, or AI citation>
Fix: <minimal change, file + line>
Effort: <5 min | 30 min | product decision>
Group by severity, then close with a table: # | Finding | Severity | Effort | Blocks release?
Phase 2 — GEO review (--geo)
Read ${CLAUDE_SKILL_DIR}/references/geo.md. JSON-LD to copy:
${CLAUDE_SKILL_DIR}/references/schema-recipes.md.
Check bot access first — if the crawlers are blocked, nothing else in this phase matters.
Two claims to never make: that schema types have a citation-yield ranking "per Princeton research" (that study tested content tactics, not schema), and any projected traffic lift. Neither is observable from a codebase, and inventing them discredits the real findings.
Group output as Schema gaps, Content opportunities, Architecture decisions.
Phase 3 — fix (--fix)
Applies the Phase 1 and Phase 2 findings. Edit the working tree and stop — no git add,
no git commit. Review and commit belong to the user.
- Match the repo's framework, file layout, and spelling. Do not impose a dialect.
- Name the exact file and line before each edit. Minimal change, no drive-by refactors, no
any. - Wire schema fields to real data sources; never hardcode a value that drifts.
- Never invent an
aggregateRating. Remove it and list it under "needs real data". - Skip i18n architecture, copy outside schema descriptions, and anything the report marks as needing product input.
Host redirects — hard rule. An app-level www↔apex, http↔https, or trailing-slash
redirect that duplicates one the hosting platform already performs will ping-pong, produce
ERR_TOO_MANY_REDIRECTS, and take the site down. Leave host canonicalisation to the
platform. Fix a loop by removing the app-level redirect, never by adding another. When
canonical and landed host merely disagree, change the metadata to match the host actually
served — not the redirect to match the metadata.
Batch 1: every Critical, High, and Medium finding from Phase 1, in severity order. Batch 2: the Phase 2 schema work.
Verify before reporting done. Never claim success on the strength of the edits alone.
- The project builds (
npm run build, or whatever the repo uses). extract-jsonld.mjslints clean against the built HTML or a dev server.audit-meta.mjspasses on every changed route.redirect-trace.sh, if any redirect was touched.
Report any step you could not run, and why.
Output sections: Changed (by batch), Verification, Needs a product decision, Needs real data.