diff --git a/agents/seo-analyzer.md b/agents/seo-analyzer.md index 9c09f16..7233632 100644 --- a/agents/seo-analyzer.md +++ b/agents/seo-analyzer.md @@ -58,8 +58,8 @@ STEP 1-2 business/tech context is consumed by all later steps). ## STEP 0 — AUDIT DEPTH -**First action.** If a parent skill (`/seo` dispatcher) passed depth -in $ARGUMENTS, use it. Otherwise: +If a parent skill (`/seo` dispatcher) passed depth in $ARGUMENTS, use +it. Otherwise: ``` SEO AUDIT DEPTH — choose one: @@ -141,11 +141,10 @@ Record rendering: **SSR / SSG / SPA / hybrid / ISR**. ### CMS detection + SEO plugin presence (plugin-first strategy) -Before proposing any manual edit, detect if the site runs on a CMS -and whether a SEO plugin is already handling the heavy lifting. If a -CMS is detected WITHOUT a SEO plugin, the highest-priority quick win -is to install the appropriate plugin — editing theme files manually -is a last resort and creates maintenance debt. +Detect whether the site runs on a CMS and whether a SEO plugin is +already handling the heavy lifting; record the signals. The +plugin-first ranking policy (CMS without plugin → installation is the +top quick win) lives in STEP 10. ```bash # WordPress signals @@ -206,8 +205,7 @@ topology — TLS terminated upstream, the origin sees plain HTTP plus `/harden` reuses this agent for its entire config-hardening axis, so a wrong topology call scores a client's server config against a file that never ran. -geo-analyzer STEP 4 already carries the matching CDN/WAF-override check — -keep the two consistent. +(The same CDN/WAF-override check lives in geo-analyzer STEP 4.) ```bash # Server / hosting @@ -505,7 +503,7 @@ Fetch rendered HTML. Extract and analyze: ## STEP 5 — ON-PAGE AUDIT `[both]` -### Rendering gate — run this BEFORE anything else in STEP 5 (R2) +### Rendering gate (R2) — it gates every on-page check below ```bash bash ~/.claude/lib/seo-data/fetch.sh rendercheck --url "https://$DOMAIN/" @@ -599,9 +597,9 @@ doorway-page risk — the exact thing the 30/70 rule exists to catch — is invisible. Group by shared parent AND by shared slug prefix; if ≥3 URLs share a prefix of 2+ hyphen tokens, that is a family whatever the depth. -Sanity-check the grouping before trusting it: a site whose sitemap yields -almost as many families as URLs has probably defeated your heuristic, not -proved it has no templates. +A sitemap that yields almost as many families as URLs has probably +defeated the heuristic, not proved the site has no templates — say so +instead of trusting the grouping. **Sample by finding class, because the classes need opposite samples:** @@ -611,10 +609,9 @@ proved it has no templates. | **Duplication / 30-70 / cannibalisation** | **≥3 from the LARGEST family** | invisible with one page each. You cannot tell whether 25 city pages are 70% unique by reading one of them. | | Per-page content (title/description length, H1 wording) | spread across families + GSC position 4-10 quick wins | these vary per page even from one template. | -"One per template" is right for code and **wrong for the 30/70 rule** — a -rule this spec mandates in §9. Sampling one page per family makes that check -structurally impossible, so take the third page of the biggest family even -though it is "the same template". +The split is deliberate: one-per-family alone makes the §9 30/70 check +structurally impossible — hence ≥3 pages from the biggest family, even +though they share a template. An un-sampled family is an un-audited family. Name the ones you skipped. @@ -658,16 +655,11 @@ mapfile -t FEXCL < <(bash ~/.claude/lib/source-scope.sh findargs) find . "${FEXCL[@]}" -type f \( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.gif" \) -printf "%s %p\n" 2>/dev/null | sort -rn | head -20 ``` -**Why the guard, and why `find` specifically (C1a).** `grep` and `find` -disagree about this repo and you use both. Claude Code routes `grep` through -ugrep with `--ignore-files`, so it honours `.gitignore` and never descends -into a gitignored `dist/`. `find` honours nothing. Measured on a real Astro -repo: this command returned **92 images, 45 of them under `dist/`** — every -asset twice, source and generated copy, byte-identical. So "top 20 by size" -was ~10 real images dressed as 20, and a batch-C item -(`cwebp -q 80 -o .webp`) could target `dist/og-image.png`, whose -`.webp` the dispatcher's own `npm run build` then erases. The fix lands, -verification passes, nothing survives. +**Why the guard, and why `find` specifically (C1a).** Claude Code routes +`grep` through ugrep with `--ignore-files` (honours `.gitignore`); `find` +honours nothing. Measured on a real Astro repo: without the guard this +command returned 92 images, 45 under `dist/` — and a batch-C item built +on that targets an artifact the dispatcher's own `npm run build` erases. `FEXCL` MUST be consumed as a quoted array. `find . $FEXCL …` lets the shell glob `*/dist/*` against the CWD and hand the matches to find as search paths @@ -967,8 +959,9 @@ disagree, and `/client-handover` gates on 17/20. **N/A is not a zero** and the engine will not let it behave like one. - `status: "error"` → malformed findings. Fix them; never fall back to eyeballing a number. -- Run it twice on the same file before publishing. If the output moved, your - findings moved, and that is the thing to explain. +- The engine is deterministic: if you modified the findings JSON after + scoring, re-run and explain the move — a shifted score means shifted + findings, never engine noise. **Technical axis note:** CWV scored on CrUX field data (75th percentile, real users, from STEP 4) when available; otherwise lab PageSpeed @@ -1144,22 +1137,19 @@ For each: - Expected impact (high / medium / low) - AUTO (bundled in STEP 12, applied by the dispatcher) or USER (in SEO.md §11, with automation options) -AUTO items are a commitment, not a suggestion. +**CMS plugin first**: a CMS detected in STEP 2 without a SEO plugin +makes plugin installation the top quick win — +RankMath/Yoast/SEOPress (WordPress), Yoast SEO (Drupal), SEO Suite +Ultimate (Magento), Plug in SEO (Shopify) deliver meta + sitemap + +OG + breadcrumbs + JSON-LD in ~15 min of admin UI, where hand-editing +theme files first creates duplication, conflicts, and maintenance +debt. See `~/.claude/agents/resources/automation-catalog.md` CMS +plugins section for the exact install path per CMS. -**P0 rule — CMS plugin first**: if STEP 2 detected a CMS without a -SEO plugin, the FIRST quick win MUST be plugin installation. Reason: -installing RankMath/Yoast/SEOPress (WordPress), Yoast SEO (Drupal), -SEO Suite Ultimate (Magento), Plug in SEO (Shopify) takes ~15 min -via admin UI and delivers meta + sitemap + OG + breadcrumbs + JSON-LD -in one shot. Editing theme files by hand before this creates -duplication, conflicts, and maintenance debt. See -`~/.claude/agents/resources/automation-catalog.md` CMS plugins -section for the exact install path per CMS. - -**P0 rule — Bing Webmaster Tools**: on FULL audit, ALWAYS emit -"Submit site to Bing Webmaster Tools" as a user action — ChatGPT -Search uses the Bing index, so this is also a GEO signal. See -automation-catalog.md for IndexNow + Bing. +**Bing Webmaster Tools** (FULL audits): emit "Submit site to Bing +Webmaster Tools" as a user action — ChatGPT Search uses the Bing +index, so this is also a GEO signal. See automation-catalog.md for +IndexNow + Bing. ### Medium term (1-3 months) City/service pages (30/70 rule: 30% shared, 70% unique per city), @@ -1214,7 +1204,8 @@ BATCH F — USER ACTIONS (N items, documented in SEO.md §11 with automation cat ... ``` -Do not proceed to STEP 12 until this plan is printed. +Single-shot runs (no MODE line) print this plan before STEP 12 +serializes it; `MODE: judge` simply ends here. --- @@ -1306,18 +1297,19 @@ as the last line of the bundle — the dispatcher keys its apply step on it. Do NOT run any post-fix verification (build/lint, NAP consistency); the dispatcher does that after it applies. Your job ends at the sentinel. -### Bundle completeness checklist (did every finding reach the bundle?) +### Finding-class → tier routing (complete map: every finding lands in +exactly one tier; §11 mirrors USER ACTIONS) -- [ ] Meta/title/OG/canonical → AUTO (hotfixer) -- [ ] JSON-LD LocalBusiness/Organization → AUTO (hotfixer/feater) — detailed GEO schema → geo-analyzer -- [ ] Image alt/dimensions → AUTO (hotfixer); compression → AUTO (bash) or §11 if tools absent -- [ ] robots.txt / sitemap.xml → AUTO (hotfixer) — AI-bot directives → geo-analyzer -- [ ] .htaccess security headers, image/video sitemap, hreflang → AUTO (feater) -- [ ] Legal pages, CMP, footer links → AUTO (feater) -- [ ] Heading hierarchy, noindex on technical pages → AUTO (hotfixer) -- [ ] Unverifiable aggregateRating removal → AUTO (hotfixer); stock-photo testimonials → GATED (E) -- [ ] Structural / new pages → GATED (D) -- [ ] Video transcripts, GMB, directories → USER ACTIONS (§11) +- Meta/title/OG/canonical → AUTO (hotfixer) +- JSON-LD LocalBusiness/Organization → AUTO (hotfixer/feater) — detailed GEO schema → geo-analyzer +- Image alt/dimensions → AUTO (hotfixer); compression → AUTO (bash) or §11 if tools absent +- robots.txt / sitemap.xml → AUTO (hotfixer) — AI-bot directives → geo-analyzer +- .htaccess security headers, image/video sitemap, hreflang → AUTO (feater) +- Legal pages, CMP, footer links → AUTO (feater) +- Heading hierarchy, noindex on technical pages → AUTO (hotfixer) +- Unverifiable aggregateRating removal → AUTO (hotfixer); stock-photo testimonials → GATED (E) +- Structural / new pages → GATED (D) +- Video transcripts, GMB, directories → USER ACTIONS (§11) ### Framework-specific notes @@ -1339,23 +1331,6 @@ Carry the relevant note into each bundle item so the applier honors it: - **Ghost** — Native SEO strong (meta + OG + JSON-LD out of box). Usually no plugin needed; handle gaps via `default.hbs` edits. - **Wix / Squarespace / Webflow (hosted CMS)** — No theme file access. ALL SEO changes happen in the admin UI: meta, alt, sitemap, redirects, JSON-LD (partial). Agent emits detailed USER action list per panel to touch — cannot auto-apply anything. -### Landing page rule - -Zero visible change on landing/homepage except: -- Meta tags (invisible) -- Footer links (discreet) -- JSON-LD (invisible) -- Image fixes: compression, alt, dimensions (invisible or quasi) - -Anything else → batch D (confirmation). - -### Handoff to dispatcher - -Post-fix verification (build/lint, NAP consistency across JSON-LD / -visible / GMB, revert-on-break) and the §15 change log are the -DISPATCHER's responsibility, AFTER it applies the bundle at L1. You -emitted the bundle terminated by the sentinel — stop here. - --- ## STEP 13 — OUTPUT `[both]` @@ -1519,10 +1494,10 @@ PROCHAINE ETAPE : ### Process - **Every user action lists automation.** Mandatory from `~/.claude/agents/resources/automation-catalog.md`. -- **WebSearch on FULL** to validate tool landscape + cross-check - competitor state before emitting. +- **WebSearch on FULL when naming drifting externals** — tool + landscapes and competitor state shift; cross-check before a + recommendation names them. - **Iterative SEO.md.** Preserve Historique section. -- **Transparency.** Every automated change logged with file, change, - reason. -- **Dispatcher verifies.** Build/lint pass + revert-on-break happen in - the dispatcher after it applies the bundle — never in this agent. +- **Dispatcher verifies.** Build/lint pass, revert-on-break and the §15 + change log happen in the dispatcher after it applies the bundle — + never in this agent.