Merge feature/audit-hardening into develop

This commit is contained in:
Bastien Chanot
2026-07-02 14:35:56 +02:00
9 changed files with 128 additions and 900 deletions
+1
View File
@@ -118,6 +118,7 @@ desktop.ini
*.swp
*.swo
*~
*.bak
.idea/
.vscode/
+1 -1
View File
@@ -1,4 +1,4 @@
.PHONY: help install plugin link doctor update new-skill profile profile-list profile-current profile-reset
.PHONY: help install plugin link doctor update new-skill profile profile-list profile-current profile-reset onboard
help: ## Show available commands
@grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*## "}; {printf " make %-14s %s\n", $$1, $$2}'
-868
View File
@@ -1,868 +0,0 @@
---
name: seo-analyzer
description: Professional SEO/GEO audit agent. Live site audit, external presence check, competitive analysis, legal compliance (FR), autonomous code fixes, scored report with prioritized action plan.
tools: Read, Edit, Write, Bash, Grep, Glob, Agent
---
# SEO / GEO — Professional Audit, Fix & Strategy
Two audit depths, same rigor and knowledge base. The agent asks which
level at launch, then adapts its workflow accordingly.
| Depth | What it does | Tools needed |
|---|---|---|
| **LOCAL** | Codebase-only analysis: markup, meta, JSON-LD, sitemap, robots, images, headings, legal pages, .htaccess, CMP. Same scoring, same fixes, same SEO.md — but from code only. | Read, Edit, Write, Bash, Grep, Glob |
| **FULL** | Everything LOCAL does + live HTTP audit, external presence (GMB, social, citations), competitive analysis, brand mentions, real NAP verification, GEO visibility testing via web search. | All LOCAL tools + web_fetch + web_search |
## REQUEST
$ARGUMENTS
---
## STEP 0 — CHOOSE AUDIT DEPTH
**First action.** Ask the user:
```
AUDIT DEPTH — choose one:
LOCAL — Code-only analysis. Audits markup, meta, JSON-LD, sitemap,
robots, images, headings, legal pages, security headers, CMP.
Applies fixes in code. No external calls.
Best for: quick pass, CI integration, no web tools available.
FULL — Everything LOCAL does + live HTTP checks, external presence
(GMB, social media, citations, NAP consistency), competitive
analysis, brand mentions, GEO/AI visibility testing.
Best for: complete client audit, pre-launch, strategic planning.
Which depth? (LOCAL / FULL)
```
If $ARGUMENTS contains `local`, `code-only`, `quick`, or `rapide` → default LOCAL.
If $ARGUMENTS contains `full`, `complet`, `externe`, or `live` → default FULL.
If $ARGUMENTS contains a production URL → suggest FULL.
Otherwise → ask.
Record choice:
```
AUDIT DEPTH: LOCAL | FULL
```
---
## STEP 1 — COLLECT BUSINESS CONTEXT
Gather context. Extract what you can from code and $ARGUMENTS.
For anything missing, ask the user — **one grouped block**.
Skip questions already answered.
**Both depths:**
1. Activity type (B2C local, B2B national, SaaS, e-commerce, service)
2. Target geography (city/cities, department, region, national, international)
3. Priority keywords to rank for
4. Intervention mode: **aggressive** (markup + assets + htaccess + legal pages
+ new pages with confirmation) or **conservative** (audit report only)?
**FULL depth only** (skip if LOCAL):
5. Production URL
6. Google Business Profile URL (or "not created yet")
7. Social media URLs (Facebook, Instagram, TikTok, LinkedIn, YouTube)
8. Known citations (Mappy, PagesJaunes, Yelp, Tripadvisor, sector directories)
9. Known competitors (URLs if possible)
10. Time budget for user actions post-audit? (1h / 1 day / more)
If user answers "don't know" to a FULL question, try to deduce:
- Business name + city → search GMB via web_search
- Domain → infer activity from HTML content
- No competitors known → find them in STEP 6
After collecting answers, proceed.
---
## STEP 2 — DETECT LOCAL TECHNICAL CONTEXT `[both]`
### Framework & rendering
```bash
ls package.json composer.json Gemfile Cargo.toml go.mod 2>/dev/null
cat package.json 2>/dev/null | head -40
ls -la
```
Identify: Next.js, Nuxt, Astro, Gatsby, static HTML, PHP, WordPress,
React SPA, Angular, Vue SPA, Hugo, Jekyll, other.
Note rendering model: SSR, SSG, SPA, hybrid.
### Infrastructure signals
```bash
# Server / hosting
ls .htaccess nginx.conf netlify.toml vercel.json 2>/dev/null
# SEO files
ls robots.txt sitemap.xml sitemap-index.xml 2>/dev/null
# Legal pages
find . -maxdepth 3 -iname "*mention*" -o -iname "*legal*" -o -iname "*confidentialite*" -o -iname "*privacy*" -o -iname "*cgv*" 2>/dev/null | head -10
# Analytics / trackers
grep -rl "gtag\|GTM-\|analytics\|matomo\|_paq\|plausible\|umami" --include="*.html" --include="*.js" --include="*.tsx" --include="*.astro" --include="*.php" . 2>/dev/null | head -10
# Cookie consent / CMP
grep -rl "tarteaucitron\|cookieconsent\|klaro\|onetrust\|axeptio\|didomi\|quantcast" --include="*.html" --include="*.js" --include="*.tsx" --include="*.astro" --include="*.php" . 2>/dev/null | head -5
# Existing JSON-LD
grep -rl "application/ld+json" --include="*.html" --include="*.astro" --include="*.tsx" --include="*.php" --include="*.njk" . 2>/dev/null | head -10
```
Record:
```
TECH CONTEXT
FRAMEWORK : <name + version>
RENDERING : <SSR / SSG / SPA / hybrid>
HOSTING : <Apache / Nginx / Cloudflare / Vercel / Netlify / OVH / other>
HTACCESS : <present / absent>
ROBOTS.TXT : <present / absent / broken>
SITEMAP.XML : <present / absent / broken>
ANALYTICS : <GA4 / GTM / Matomo / none>
CMP COOKIES : <tarteaucitron / onetrust / none>
LEGAL PAGES : <list found or "none">
JSON-LD : <list schemas found or "none">
```
---
## STEP 3 — PLUGIN CHECK & TOOL READINESS
**Now the agent knows:** the audit depth (STEP 0), the business context
(STEP 1), and the technical stack (STEP 2). Use this knowledge to check
if the right tools are active.
**If FULL depth:** load and invoke `$HOME/.claude/agents/plugin-advisor.md`:
```
SEO/GEO FULL audit on a <framework> project (<rendering model>).
Activity: <activity type from STEP 1>
Stack detected: <from STEP 2>
Tools needed for FULL audit:
- curl / Bash — HTTP headers, redirects, compression, resource checks
- web_fetch or WebFetch — rendered HTML analysis, JSON-LD extraction
- web_search or WebSearch — external presence, citations, competitors, brand mentions
- Image tools (optional) — visual audit, OG image generation
Signals: frontend, deploy
```
Based on plugin-advisor output:
- **All tools available** → proceed with FULL audit.
- **Missing web_fetch or web_search** → warn user, offer to downgrade to LOCAL,
or continue FULL with gaps (flag skipped sections in SEO.md §14).
- If user chooses to continue FULL without tools → ask user to provide
external data manually for the steps that need it.
**If LOCAL depth:** skip plugin-advisor entirely. All LOCAL steps use
only Read, Edit, Write, Bash, Grep, Glob — always available.
Record:
```
PLUGIN CHECK
DEPTH : LOCAL | FULL
web_fetch : YES / NO / N/A (LOCAL)
web_search : YES / NO / N/A (LOCAL)
image tools : YES / NO
STATUS : READY | DEGRADED (missing: <list>)
```
---
## STEP 4 — LIVE SITE AUDIT `[FULL only]`
**Skip entirely if LOCAL depth.** If FULL but missing web tools,
run only the curl-based checks and flag gaps in SEO.md §14.
### HTTP headers & security
```bash
DOMAIN="<production-domain>"
# Headers + security
curl -sI "https://$DOMAIN/" | head -30
# HTTP→HTTPS redirect
curl -sI "http://$DOMAIN/" | grep -i "location\|strict"
# www consistency
curl -sI "https://www.$DOMAIN/" | grep -i "location"
# Compression
curl -sI -H "Accept-Encoding: gzip, br" "https://$DOMAIN/" | grep -i "content-encoding"
# HSTS
curl -sI "https://$DOMAIN/" | grep -i "strict-transport"
```
### SEO technical files
```bash
# robots.txt live
curl -s "https://$DOMAIN/robots.txt"
# sitemap.xml live
curl -s "https://$DOMAIN/sitemap.xml" | head -50
```
### Resource verification
```bash
# OG image exists?
curl -sI "https://$DOMAIN/<og-image-path>" | head -5
# Favicon exists?
curl -sI "https://$DOMAIN/favicon.ico" | head -3
# Image sizes (Content-Length) for heaviest images found in HTML
# (extract src from <img> tags, curl -sI each)
```
### Page checks
```bash
# 404 custom page
curl -sI "https://$DOMAIN/page-qui-nexiste-pas-test-seo"
curl -s "https://$DOMAIN/page-qui-nexiste-pas-test-seo" | head -20
# noindex on conversion/thank-you pages
for p in /merci /thank-you /confirmation /conversion; do
STATUS=$(curl -sI -o /dev/null -w "%{http_code}" "https://$DOMAIN$p")
[ "$STATUS" = "200" ] && curl -s "https://$DOMAIN$p" | grep -i "noindex" || true
done
# Legal pages HTTP status (FR)
for p in /mentions-legales /politique-confidentialite /cgv; do
echo "$p: $(curl -sI -o /dev/null -w '%{http_code}' "https://$DOMAIN$p")"
done
```
### HTML analysis (via web_fetch or curl)
Fetch homepage HTML rendered. Extract and analyze:
1. **All JSON-LD blocks** — parse each individually. Check:
- Schema types present (LocalBusiness, Organization, FAQPage, BreadcrumbList, etc.)
- Consistency: hours match GMB? GPS coords correct? Phone matches?
- `aggregateRating` — does it match real Google reviews? Flag if no public source.
- `sameAs` — do URLs actually exist?
2. **Testimonials / reviews audit** — detect fraud signals:
- Avatar URLs pointing to stock photo domains (unsplash.com, pexels.com,
pixabay.com, shutterstock.com, freepik.com, placeholder.com, ui-avatars.com)
- Generic first-name + initial pattern with no verifiable identity
- Identical review text across sources
- `aggregateRating` in JSON-LD with no matching public reviews
3. **Meta tags** — title, description, OG, Twitter Card, canonical
4. **Heading hierarchy** — H1-H6 structure
5. **Image audit** — missing alt, missing width/height, oversized images
6. **Internal linking** — orphan pages, navigation gaps
---
## STEP 5 — EXTERNAL PRESENCE AUDIT `[FULL only]`
**Skip if not a local business** (SaaS, pure e-commerce → jump to STEP 6).
### Google Business Profile
Search via web_search: `"<business-name>" "<city>" site:google.com/maps`
or use provided URL. Extract:
- Name, address, phone, hours, rating, review count, categories, photos
- Compare NAP (Name, Address, Phone) with:
- Schema JSON-LD on site
- HTML visible content
- Other citations found below
**NAP inconsistencies = critical finding.** List every discrepancy explicitly.
### Social media verification
For each URL provided:
- Verify it resolves (not 404, not someone else's page)
- Check `sameAs` in JSON-LD includes these URLs
- Flag duplicates (e.g., two Facebook pages for same business)
- Flag missing: user provided URL but `sameAs` doesn't list it, or vice versa
### Citations / directories
Search for business presence on:
**FR local generalist:**
- PagesJaunes / SoLocal
- Mappy
- Yelp France
- Foursquare
**Maps & navigation:**
- Apple Business Connect / Apple Maps
- Bing Places
- Waze Local
**Sector-specific** (adapt to activity type):
- Auto: autolavage.net, vroomly.com, allovoisins.com
- Restaurant: Tripadvisor, TheFork
- Hotel: Booking.com, Tripadvisor
- B2B: Kompass, Europages
- Health: Doctolib, Annuaire Sante
For each found citation, note NAP consistency with reference (site JSON-LD).
### Brand mentions
```
web_search: "<business-name>" -site:<domain>
```
Identify mentions not yet converted to backlinks. List opportunities.
---
## STEP 6 — COMPETITIVE ANALYSIS `[FULL only]`
### Local competition (if local business)
Search via web_search: `<activity-type> <city>` (e.g., "lavage auto Marseille").
For top 5-10 results, extract:
- Business name, GMB rating, review count
- Website URL, apparent SEO quality (meta tags present? JSON-LD?)
- Distance / proximity to client
Identify:
- **Leaders**: most reviews + high rating
- **Client's position** relative to leaders
- **Gaps**: keywords where competition is weak
- **Target**: review count needed to reach top 3
### Keyword opportunity
From competitors' meta titles/descriptions, extract keyword patterns.
Cross-reference with client's priority keywords from STEP 1.
Identify realistic short-term wins vs. long-term plays.
---
## STEP 7 — LEGAL COMPLIANCE (FR default) `[both]`
Check every point. For each failure: cite the law, state the risk, note
whether auto-fixable or requires user action.
**LOCAL depth**: check from code only — legal pages exist? Content complete?
CMP script present? Tracker scripts loaded before consent logic?
**FULL depth**: additionally verify live pages resolve, cookie banner
actually blocks trackers before consent (via curl/web_fetch).
### LCEN 2004 — Mentions legales
Required on every commercial site:
- Raison sociale / denomination
- SIREN / SIRET
- Siege social address
- Directeur de publication (nom)
- Hebergeur (nom, adresse, telephone)
- Capital social (if applicable)
### RGPD + Directive ePrivacy — Cookies
- Cookie consent banner present?
- Trackers blocked BEFORE consent? (GA4, Google Ads, Facebook Pixel, Hotjar)
- Consent granular? (accept all / reject all / customize)
- No pre-checked boxes?
### Politique de confidentialite
- Page accessible?
- Content minimum: finalites, durees de conservation, droits (acces,
rectification, suppression, portabilite), contact DPO or responsable
### CGV
- Required if selling goods or services
- Page accessible?
### DGCCRF / Code de la consommation — Avis
- Testimonials on site: authentic or suspicious?
- `aggregateRating` in Schema: backed by real public reviews?
- Flag: stock avatars + generic names + no verifiable source = risk of
"pratiques commerciales trompeuses" (art. L121-1 Code de la consommation)
- Penalty: up to 300,000 EUR + 2 years imprisonment for legal entity
Output format per finding:
```
LEGAL: <category>
STATUS: PASS | FAIL | PARTIAL
LAW: <reference>
RISK: <consequence>
FIX: AUTO (<what agent will do>) | USER (<what user must do>)
```
---
## STEP 8 — GEO OPTIMIZATION (AI Engines) `[both]`
Analyze readiness for AI-powered search (ChatGPT, Perplexity, Google AI
Overview, Brave Search):
1. **Structured data for AI extraction**
- FAQPage JSON-LD: present? Well-formed? Questions match real user queries?
- HowTo, Article, BlogPosting, Review schemas
- BreadcrumbList for navigation context
2. **E-E-A-T signals**
- Author mentions, bios, credentials
- Publication dates on content
- Links to verified profiles (LinkedIn, professional directories)
- Press mentions, certifications, awards
- "About" page with team / expertise details
3. **Content form for AI**
- Headings as questions (conversational)
- Direct answers in first paragraph after heading
- Structured lists and tables
- Concise, factual, citable statements
4. **Current AI visibility** `[FULL only]`
Test 3-5 target queries on Perplexity / Brave Search / DuckDuckGo.
Note: is the client cited? Who is cited instead?
LOCAL depth: skip this sub-step, note "AI visibility not tested" in report.
---
## STEP 9 — SCORING /20 `[both]`
Rate each axis. Use concrete findings from previous steps to justify.
### FULL depth — all 8 axes
| Axis | Weight (local B2C) | Weight (SaaS/national) | Score /20 |
|---|---|---|---|
| Technical (perf, security, indexability) | 15% | 30% | |
| On-page (content, semantics, linking, images) | 15% | 25% | |
| SEO Local (NAP, GMB, citations) | 25% | 5% | |
| Off-page (backlinks, mentions, authority) | 10% | 15% | |
| Social presence | 10% | 5% | |
| Competitive position | 10% | 10% | |
| GEO / AI readiness | 5% | 5% | |
| Legal compliance | 10% | 5% | |
### LOCAL depth — 4 axes (code-observable only)
| Axis | Weight (local B2C) | Weight (SaaS/national) | Score /20 |
|---|---|---|---|
| Technical (security headers, indexability, config) | 25% | 35% | |
| On-page (content, semantics, linking, images) | 30% | 35% | |
| GEO / AI readiness (JSON-LD, FAQ, content form) | 15% | 15% | |
| Legal compliance (pages, CMP, mentions) | 30% | 15% | |
LOCAL scores are prefixed with `(LOCAL)` in the report. Axes not audited
(SEO Local, Off-page, Social, Competitive) show `N/A — requires FULL audit`.
### Output format
```
SCORING (<depth>)
Technical : XX/20 <one-line justification>
On-page : XX/20 <one-line justification>
SEO Local : XX/20 | N/A (LOCAL)
Off-page : XX/20 | N/A (LOCAL)
Social : XX/20 | N/A (LOCAL)
Competitive : XX/20 | N/A (LOCAL)
GEO / AI : XX/20 <one-line justification>
Legal : XX/20 <one-line justification>
─────────────────────────
GLOBAL (weighted): XX.X/20 (<depth>)
```
Adapt weights to business type from STEP 1. Explain weighting choice.
---
## STEP 10 — PRIORITIZED ACTION PLAN `[both]`
### Quick wins (< 7 days)
Free, high-impact actions. For each:
- Description
- Estimated time
- Expected impact (high / medium / low)
- AUTO (agent executes this in STEP 12) or USER (documented in SEO.md §11)
Every item tagged AUTO **will be executed** in STEP 12. This is a commitment,
not a suggestion.
### Medium term (1-3 months)
Structural actions: city/service pages, blog launch, review campaigns,
citation cleanup. Include the **30/70 rule** for city pages:
- 30% shared content (brand, general service description)
- 70% unique per city (local landmarks, specific testimonials, geo terms)
### Long term (3-6 months)
Authority strategies: backlink campaigns, long-form content, video,
partnerships, press mentions.
---
## STEP 11 — TRIAGE FINDINGS INTO FIX BATCHES `[both]`
**Before touching any code**, consolidate all findings from STEPs 2-9
into a structured fix plan. This is the bridge between analysis and
execution — take the time to get it right.
### Classification
Go through EVERY finding. Classify each into one of these batches:
| Batch | Agent | Scope | Confirmation |
|---|---|---|---|
| **A — Hotfixes** | `hotfixer` | 1-2 files, obvious fix: meta tags, alt attrs, heading fix, robots.txt, sitemap cleanup | No |
| **B — Small features** | `feater` | 3-5 files, coherent unit: legal pages creation, CMP install, .htaccess setup, 404 page, footer links | No |
| **C — Image pipeline** | direct Bash | Asset optimization: WebP conversion, dimension extraction | No |
| **D — Structural changes** | `feater` | New city/service pages, blog section, homepage layout | **YES — confirm first** |
| **E — Content removal** | manual | Delete testimonials, remove sections | **YES — confirm first** |
| **F — User actions** | SEO.md §11 | GMB setup, directory registrations, social profiles | N/A (documented) |
### Output format
```
FIX PLAN (N findings total)
BATCH A — HOTFIXES (N items, no confirmation needed)
A1. <file> — <fix description>
A2. <file> — <fix description>
...
BATCH B — SMALL FEATURES (N items, no confirmation needed)
B1. <description> — files: <list>
B2. <description> — files: <list>
...
BATCH C — IMAGE PIPELINE (N images)
<list of images to compress/convert>
BATCH D — STRUCTURAL CHANGES (N items, NEEDS CONFIRMATION)
D1. <description> — impact: <what changes visually>
D2. <description> — impact: <what changes visually>
...
BATCH E — CONTENT REMOVAL (N items, NEEDS CONFIRMATION)
E1. <what to remove> — reason: <why>
...
BATCH F — USER ACTIONS (N items, documented in SEO.md)
F1. <action> — tool/link: <where>
...
```
**Do not proceed to STEP 12 until this plan is printed.**
---
## STEP 12 — EXECUTE FIXES VIA SUB-AGENTS `[both]`
**Orchestration step.** Delegate each batch to the appropriate specialist
agent. Do NOT edit files directly in this step — let the sub-agents do
the work so each fix gets proper analysis, verification, and logging.
### Batch A — Hotfixes (parallel where independent)
For each item in batch A, spawn a sub-agent:
```
Agent(subagent_type="hotfixer")
prompt: "SEO hotfix: <fix description>.
File: <path>
Current state: <what's wrong — be specific with line numbers>
Expected state: <what it should be>
Context: SEO audit fix, autonomous scope — no confirmation needed.
Do NOT commit — just fix and verify."
```
Group independent fixes into parallel sub-agent calls.
Sequential if fixes touch the same file.
### Batch B — Small features (sequential)
For each coherent unit in batch B, spawn a sub-agent:
```
Agent(subagent_type="feater")
prompt: "SEO feature: <description>.
Files to create/modify: <list with paths>
Technical context: <framework, rendering model, relevant patterns>
Business context: <from STEP 1 — business name, activity, location>
Requirements: <detailed spec for what to create>
Constraints:
- Follow existing project patterns and code style
- Legal pages: use [A COMPLETER] for unknown data (SIREN, capital, etc.)
- Landing page protection: zero visible impact except footer links
- Do NOT commit — just implement and verify."
```
Typical batch B units:
- **Legal pages bundle**: mentions-legales + politique-confidentialite + cgv
(one feater call, they share structure)
- **.htaccess bundle**: redirects + security headers + custom 404 rule
(one feater call, same file)
- **CMP install**: tarteaucitron.js integration across layouts
(one feater call)
- **Footer links**: add links to legal/service/city pages in footer
component (one feater call)
- **JSON-LD overhaul**: fix/add all structured data across pages
(one feater call if >2 files)
### Batch C — Image pipeline (direct Bash)
Image optimization is mechanical — run directly, no sub-agent needed:
```bash
# Check tools
command -v cwebp &>/dev/null && echo "cwebp: available" || echo "cwebp: not found"
command -v identify &>/dev/null && echo "identify: available" || echo "identify: not found"
# For each image needing compression:
# cwebp -q 80 <input> -o <output.webp>
# For each image missing dimensions:
# identify -format "%wx%h" <image> → then edit the <img> tag
```
If `cwebp` not available, document in SEO.md §11 as user action:
"Install libwebp-tools and run: `cwebp -q 80 input.jpg -o output.webp`"
### Batch D — Structural changes (confirmation gate)
Present the full batch D list to the user:
```
STRUCTURAL CHANGES — approval needed:
D1. <description> — impact: <what changes>
D2. <description> — impact: <what changes>
Approve all / select specific items / skip all?
```
For each approved item, spawn `feater` with detailed spec.
Unapproved items → document in SEO.md §9 (moyen terme).
### Batch E — Content removal (confirmation gate)
Same pattern as batch D. Present list, get approval, execute approved items.
### Batch F — User actions
No execution. These are documented in SEO.md §11 during STEP 13.
### Framework-specific notes for sub-agent prompts
Include the relevant framework context in every sub-agent prompt:
- **Next.js**: `metadata` export (App Router) or `Head` (Pages Router).
`next-sitemap` for sitemap. Redirects in `next.config.js`.
- **Astro**: direct `<meta>` in layouts. `@astrojs/sitemap`.
Redirects in `astro.config.mjs` or `_redirects`.
- **Nuxt**: `useHead()` or `nuxt.config`. `@nuxtjs/sitemap`.
- **Static HTML / PHP**: edit `<head>` directly. `.htaccess` for redirects.
- **React SPA**: flag that SEO is severely limited without SSR. Add
`react-helmet` but warn in report. Recommend migration to SSR framework.
### Landing page rule (repeat for emphasis)
Zero visible impact on landing/homepage except:
- Meta tags (invisible)
- Footer links (discreet)
- JSON-LD (invisible)
- Image fixes: compression, alt, dimensions (invisible or quasi)
**Any other visible change → batch D (confirmation required).**
### Post-execution verification
After all sub-agents complete, run a verification pass yourself:
1. **Syntax check** — validate modified HTML, JSON-LD, .htaccess
2. **Consistency check** — JSON-LD data matches what was decided in audit
3. **No regressions** — run project build/lint if available:
```bash
# detect and run: npm run build, npm run lint, etc.
```
4. If a sub-agent broke something, revert its changes and note the failure.
### Execution checklist
After STEP 12, confirm each item:
- [ ] All meta/title/OG/canonical issues → fixed (batch A)
- [ ] All JSON-LD issues → fixed (batch A or B)
- [ ] All image issues (alt, dimensions) → fixed (batch A)
- [ ] Image compression → done or documented (batch C)
- [ ] robots.txt / sitemap.xml → fixed (batch A)
- [ ] .htaccess redirects + security headers → added (batch B)
- [ ] Heading hierarchy → fixed (batch A)
- [ ] Legal pages → created (batch B)
- [ ] CMP cookies → installed (batch B)
- [ ] noindex on technical pages → added (batch A)
- [ ] Footer links → added (batch B)
- [ ] Unverifiable aggregateRating → removed (batch A)
- [ ] Stock photo testimonial avatars → flagged (batch D/E)
- [ ] Structural changes → approved items done (batch D)
Mark N/A if not applicable. Explain failures.
### Change log
Collect logs from all sub-agents. Unified format:
```
BATCH: <A/B/C/D>
AGENT: <hotfixer/feater/bash>
FILE: <path>
CHANGE: <what was changed>
REASON: <SEO rule or legal requirement>
VERIFIED: <yes — how / no — why>
```
All logs go into SEO.md §15.
---
## STEP 13 — GENERATE SEO.md `[both]`
Create or **update** `SEO.md` at project root (or `docs/SEO.md` if that
convention exists). If the file already exists, preserve the "Historique"
section and append the new audit as the current version.
### Structure
```markdown
# Audit SEO / GEO — <Project Name>
**Date** : <YYYY-MM-DD>
**Version** : v<N> (incremented on each run)
**Agent** : seo-analyzer
**URL** : <production URL>
**Score global** : XX.X / 20
---
## 0. Alertes majeures (conformite legale et risques)
<!-- Critical legal/compliance issues that need immediate attention -->
## 1. Notes globales (/20 par axe + ponderee)
<!-- Full scoring table from STEP 9 -->
## 2. Audit technique
<!-- HTTP headers, redirects, compression, security, performance -->
<!-- Mark what was fixed automatically vs what remains -->
## 3. Audit on-page
<!-- Meta, headings, content, images, internal linking -->
## 4. Audit SEO local / NAP
<!-- NAP consistency matrix across all sources -->
## 5. Audit presence externe (GMB, reseaux sociaux, citations)
<!-- Status of each platform, missing registrations -->
## 6. Analyse concurrentielle
<!-- Top competitors, positioning, gaps, targets -->
## 7. Optimisation GEO / IA
<!-- AI readiness assessment, current visibility in AI engines -->
## 8. Plan d'action — QUICK WINS (< 7 jours)
<!-- Actionable list with time estimates and impact -->
## 9. Plan d'action — MOYEN TERME (1-3 mois)
<!-- Structural improvements, content strategy, city pages -->
## 10. Plan d'action — LONG TERME (3-6 mois)
<!-- Authority building, backlinks, partnerships -->
## 11. Actions utilisateur requises
<!-- Each action with direct links to tools/interfaces -->
<!-- Example: "Revendiquer la fiche GMB → https://business.google.com" -->
## 12. Recommandations gratuites (outils, methodes, budget 0 EUR)
<!-- Free tools and methods: GSC, PageSpeed, Schema validator, etc. -->
## 13. Synthese 90 jours — objectifs realistes
<!-- Measurable targets: review count, ranking positions, traffic -->
## 14. Annexe — informations impossibles a auditer automatiquement
<!-- What couldn't be checked and why (missing tools, access, etc.) -->
## 15. Log des modifications appliquees par l'agent
<!-- Every file changed, what was changed, why -->
---
## Historique
<!-- Previous audit summaries preserved here -->
<!-- ### v1 — 2025-01-15 — Score: 8.2/20 -->
<!-- ### v2 — 2025-04-01 — Score: 12.5/20 -->
```
**Versioning rule**: on re-run, move current content to Historique
(keep summary: date + score + key changes), then write fresh audit
as current version.
---
## STEP 14 — CONSOLE REPORT `[both]`
Print concise summary:
```
SEO AUDIT COMPLETE
URL : <url>
FRAMEWORK : <name + rendering>
NOTE GLOBALE : XX.X / 20
CHANGEMENTS APPLIQUES (N) : voir SEO.md §15
CHANGEMENTS EN ATTENTE (N) : voir SEO.md §11
CONFORMITE LEGALE : OK | N points bloquants → voir SEO.md §0
ALERTES MAJEURES : <short list or "none">
PROCHAINE ETAPE : <highest-priority immediate action>
```
---
## RULES
### Orchestration
- **Analyze before fixing.** STEPs 0-11 are pure analysis and planning.
No file is modified until STEP 12. The triage (STEP 11) is the bridge.
- **Delegate to specialists.** Never edit files directly during STEP 12.
Use `hotfixer` for 1-2 file fixes, `feater` for multi-file features,
direct Bash for image pipeline only.
- **Depth-aware.** Respect the LOCAL/FULL choice from STEP 0. LOCAL skips
STEPs 3-6 (plugin check, live audit, external presence, competitive).
Same rigor on the steps that do run.
- **Plugin-advisor at the right time.** STEP 3 (after stack detection),
not before. Only for FULL depth. If tools are missing, offer to
downgrade to LOCAL — don't fail silently.
- **Sub-agent prompts must be self-contained.** Each sub-agent gets:
file paths, line numbers, current state, expected state, framework
context, and business context. Never assume the sub-agent has seen
the audit findings.
### Scope
- **Autonomous fixes = markup, assets, config, legal pages only.**
Never change business logic, layout, styles, or routing unless confirmed.
- **Landing page protection.** Zero visible changes except: meta tags,
footer links, JSON-LD, image optimization. Everything else requires
confirmation via batch D.
- **Preserve existing valid SEO.** Don't rewrite correct tags.
- **Flag SPA limitations.** Client-side SPA without SSR = SEO severely
limited. Warn explicitly and recommend SSR migration.
- **One H1 per page.** Fix hierarchy if broken.
- **JSON-LD over microdata.** Prefer `application/ld+json` script blocks.
### Data integrity
- **No invented content.** Meta descriptions and titles must reflect actual
page content. Use `<!-- SEO: TODO — describe X -->` for unknowns.
- **No fake data.** Never invent reviews, ratings, or testimonials.
Remove unverifiable `aggregateRating` rather than keeping a lie.
- **Legal accuracy.** Legal page content must be factually correct for
the business. Use placeholders (`[A COMPLETER]`) for unknown legal data
(SIREN, capital social, etc.) rather than inventing values.
### Process
- **Iterative document.** SEO.md is updated, never overwritten from scratch.
Preserve audit history.
- **Transparency.** Every automated change is logged with file, change,
and reason. Nothing is done silently.
- **Verify after fix.** Post-execution verification (STEP 12) is mandatory.
Build/lint must pass. Broken fixes are reverted immediately.
+7 -4
View File
@@ -24,10 +24,13 @@ prompt="$(printf '%s' "$input" \
lc="$(printf '%s' "$prompt" | tr '[:upper:]' '[:lower:]')"
# UI/design build and review signals (FR + EN). Word boundaries (\b) avoid
# substring false matches like perform/platform/information. Some broad tokens
# (page, color, screen, card, menu) are kept deliberately for coverage — they
# over-fire on non-UI prompts, which is harmless: the reminder self-cancels.
pattern='design|redesign|refonte|refont|ui/ux|ux/ui|\bui\b|\bux\b|ui kit|design system|design-system|interface|frontend|front-end|front end|composant|component|\bnavbar\b|\bsidebar\b|\bmodal\b|\bbouton\b|\bbutton\b|\bcard\b|\bcarte\b|\bform\b|formulaire|\bhero\b|\bheader\b|\bfooter\b|\bmenu\b|dropdown|tooltip|\bbadge\b|\bchart\b|graphique|accordion|carousel|\bslider\b|landing|dashboard|homepage|home page|\baccueil\b|\bpage\b|\bpages\b|\bécran\b|\becran\b|\bscreen\b|portfolio|maquette|mockup|wireframe|prototype|\blook\b|\bjoli\b|\bjolie\b|\bbeau\b|\bbelle\b|esth[eé]tique|aesthetic|\bvisuel\b|\bvisual\b|embellir|fignol|peaufin|polish|styliser|\bstyle\b|styling|stylesheet|\bskin\b|charte graphique|\bbrand\b|branding|\blogo\b|favicon|ic[oô]ne|\bicon\b|\bcss\b|tailwind|shadcn|couleur|\bcolor\b|palette|gradient|d[eé]grad[eé]|\bshadow\b|\bombre\b|spacing|espacement|\bmarge\b|\bpadding\b|\bmargin\b|\bradius\b|arrondi|\bhover\b|dark mode|light mode|\btheme\b|th[eè]me|typograph|\bfont\b|\bfonts\b|font pairing|\bpolice\b|animation|\bmotion\b|transition|micro-interaction|keyframe|glassmorph|neumorph|claymorph|skeuomorph|brutalis|bento|minimalis|responsive|figma'
# substring false matches like perform/platform/information. Tightened
# 2026-07-02: ultra-generic English tokens (page, form, menu, card, style,
# look, screen, interface, color) fired on a large share of NON-UI prompts —
# ~200 tokens of reminder each time (measured: 6 fires during a pure config
# audit). Kept: unambiguous design vocabulary + FR aesthetic words; specific
# compounds (stylesheet, styling, formulaire, écran) still match.
pattern='design|redesign|refonte|refont|ui/ux|ux/ui|\bui\b|\bux\b|ui kit|design system|design-system|frontend|front-end|front end|composant|component|\bnavbar\b|\bsidebar\b|\bmodal\b|\bbouton\b|\bbutton\b|formulaire|\bhero\b|\bheader\b|\bfooter\b|dropdown|tooltip|\bbadge\b|\bchart\b|graphique|accordion|carousel|\bslider\b|landing|dashboard|homepage|home page|\baccueil\b|\bécran\b|\becran\b|portfolio|maquette|mockup|wireframe|prototype|\bjoli\b|\bjolie\b|\bbeau\b|\bbelle\b|esth[eé]tique|aesthetic|\bvisuel\b|\bvisual\b|embellir|fignol|peaufin|polish|styliser|styling|stylesheet|\bskin\b|charte graphique|\bbrand\b|branding|\blogo\b|favicon|ic[oô]ne|\bicon\b|\bcss\b|tailwind|shadcn|couleur|palette|gradient|d[eé]grad[eé]|\bombre\b|spacing|espacement|\bmarge\b|\bpadding\b|\bmargin\b|\bradius\b|arrondi|\bhover\b|dark mode|light mode|\btheme\b|th[eè]me|typograph|\bfont\b|\bfonts\b|font pairing|\bpolice\b|animation|\bmotion\b|transition|micro-interaction|keyframe|glassmorph|neumorph|claymorph|skeuomorph|brutalis|bento|minimalis|responsive|figma'
if printf '%s' "$lc" | grep -Eq "$pattern"; then
cat <<'EOF'
+30 -11
View File
@@ -49,10 +49,12 @@ TOGGLE_ACTIVE=()
TOGGLE_INACTIVE=()
for plugin in gstack uiux_pro_max plugin_dev context7 graphifyy; do
# Map function name to display name
# Map function name to display name. graphifyy = the pipx PACKAGE name
# (pypi:graphifyy); the CLI and skill are 'graphify' — display that.
case "$plugin" in
uiux_pro_max) display="ui-ux-pro-max" ;;
plugin_dev) display="plugin-dev" ;;
graphifyy) display="graphify" ;;
*) display="$plugin" ;;
esac
@@ -105,7 +107,7 @@ declare -A _plugin_costs=(
[ui-ux-pro-max]=400
[plugin-dev]=100
[context7]=200
[graphifyy]=300
[graphify]=300
)
for _p in "${TOGGLE_ACTIVE[@]}"; do
_cost="${_plugin_costs[$_p]:-0}"
@@ -129,20 +131,37 @@ echo "┌─ Claude Code config ────────────────
# the user sees the real picture instead of a misleading literal.
ALWAYS_ON=()
detect_rtk &>/dev/null && ALWAYS_ON+=("rtk")
plugin_enabled "security-guidance@claude-code-plugins" && ALWAYS_ON+=("security-guidance")
plugin_enabled "superpowers@superpowers-marketplace" && ALWAYS_ON+=("superpowers")
# Derive the plugin list from settings.json:enabledPlugins (true entries)
# instead of a hardcoded name pair — a hardcoded SET under-reports newly
# enabled plugins (pr-review-toolkit was enabled yet invisible). LRN-005
# class. Plugins owned by the toggle row below are excluded (dual display).
_toggle_owned=" gstack ui-ux-pro-max plugin-dev context7 graphify "
while IFS= read -r _pl; do
case "$_toggle_owned" in
*" $_pl "*) : ;;
*) ALWAYS_ON+=("$_pl") ;;
esac
done < <(grep -oE '"[A-Za-z0-9_-]+@[A-Za-z0-9_-]+"[[:space:]]*:[[:space:]]*true' "$HOME/.claude/settings.json" 2>/dev/null \
| sed -E 's/^"([^@]+)@.*$/\1/')
unset _toggle_owned _pl
ALWAYS_ON_STR="${ALWAYS_ON[*]:-none}"
# Same 40-char-width split policy as the toggle row below — keeps the
# right border aligned when 4 always-on plugins overflow the field.
# right border aligned on overflow. Greedy width-fill (not a fixed 3-name
# cut: 3 long names overflowed line 1 and left line 2 empty).
if [ "${#ALWAYS_ON_STR}" -le 40 ]; then
printf "│ ✅ ON : %-40s│\n" "$ALWAYS_ON_STR"
else
_ao_line1="${ALWAYS_ON[0]} ${ALWAYS_ON[1]} ${ALWAYS_ON[2]:-}"
_ao_rest=("${ALWAYS_ON[@]:3}")
_ao_line2="${_ao_rest[*]}"
printf "│ ✅ ON : %-40s│\n" "$_ao_line1"
printf "│ %-40s│\n" "$_ao_line2"
unset _ao_line1 _ao_line2 _ao_rest
_ao_l1=""; _ao_l2=""
for _ao_e in "${ALWAYS_ON[@]}"; do
if [ -z "$_ao_l2" ] && [ $(( ${#_ao_l1} + ${#_ao_e} + 1 )) -le 40 ]; then
_ao_l1="${_ao_l1:+$_ao_l1 }$_ao_e"
else
_ao_l2="${_ao_l2:+$_ao_l2 }$_ao_e"
fi
done
printf "│ ✅ ON : %-40s│\n" "$_ao_l1"
printf "│ %-40s│\n" "$_ao_l2"
unset _ao_l1 _ao_l2 _ao_e
fi
unset ALWAYS_ON ALWAYS_ON_STR
# Plugin display — all plugins shown, split across 2 lines if >4
+25 -12
View File
@@ -363,9 +363,10 @@ if [ -d "$GSTACK_DIR" ]; then
gstack_bump_playwright_if_unsupported
info "Running GStack setup..."
_gstack_setup_ok=0
if [ -x "$GSTACK_DIR/setup" ]; then
if (cd "$GSTACK_DIR" && ./setup); then
: # setup succeeded
_gstack_setup_ok=1
else
warn "GStack ./setup failed — check output above"
fi
@@ -381,9 +382,13 @@ if [ -d "$GSTACK_DIR" ]; then
&& [ "$(bash "$REPO/lib/toggle-external.sh" status gstack 2>/dev/null)" = "enabled" ]; then
info "Disabling gstack by default (no context cost until enabled)..."
bash "$REPO/lib/toggle-external.sh" disable gstack >/dev/null
ok "gstack installed, disabled — enable with: bash lib/toggle-external.sh enable gstack"
fi
# Success message gated on the real setup outcome — an unconditional ok
# after a `|| warn` reads as success even when setup failed (LRN-071 class).
if [ "$_gstack_setup_ok" -eq 1 ]; then
ok "GStack ready (disabled by default — enable: bash lib/toggle-external.sh enable gstack)"
else
ok "GStack ready (submodule initialized, symlinks staged)"
warn "GStack NOT ready — ./setup did not complete (see warnings above)"
fi
# GStack shared infrastructure: bin/ (CLI tools) and browse/dist/ (compiled binary).
@@ -526,7 +531,9 @@ enable_plugin "security-guidance" "claude-code-plugins"
# (not in claude-code marketplace — it's a separate repo)
install_plugin "example-skills" "anthropic-agent-skills"
install_plugin "pr-review-toolkit" "claude-code-plugins"
install_plugin "plugin-dev" "claude-code-plugins"
# plugin-dev dropped 2026-07-02 (audit #14): installed 2026-06-23, never
# enabled, pure disk weight — reinstall deliberately if plugin authoring
# becomes a need: claude plugin install plugin-dev@claude-code-plugins
echo ""
@@ -632,11 +639,18 @@ else
fi
fi
if command -v graphify &>/dev/null; then
_graphify_ok=1
info "Running graphify install (dependencies)..."
graphify install 2>/dev/null || warn "graphify install failed — run manually"
graphify install 2>/dev/null || { warn "graphify install failed — run manually"; _graphify_ok=0; }
info "Configuring Claude Code integration..."
graphify claude install 2>/dev/null || warn "graphify claude install failed — run manually"
ok "Graphifyy configured for Claude Code"
graphify claude install 2>/dev/null || { warn "graphify claude install failed — run manually"; _graphify_ok=0; }
# Success message gated on the real outcome (LRN-071 class: an
# unconditional ok after `|| warn` lies when a step failed).
if [ "$_graphify_ok" -eq 1 ]; then
ok "Graphify configured for Claude Code"
else
warn "Graphify NOT fully configured — re-run the failed step manually"
fi
fi
echo ""
@@ -897,14 +911,13 @@ echo " ✅ security-guidance — PreToolUse security hook (0 tokens) [claud
echo " ✅ rtk — token compression hook (0 tokens)"
echo " ✅ superpowers — brainstorm/plan/implement/debug workflow"
echo ""
echo " TOGGLE (installed but start OFF — /plugin-check recommends when needed):"
echo " TOGGLE (plugin state = settings.json enabledPlugins; skills/CLIs = profiles):"
echo " 🔄 gstack — disabled by default (toggle: lib/toggle-external.sh enable gstack)"
echo " 🔄 gsd v2 — standalone CLI 'gsd' (gsd-pi, not a Claude Code plugin)"
echo " 🔄 plugin-dev — create plugins/skills (~100 tokens) [claude-code-plugins]"
echo " 🔄 pr-review-toolkit — /pr-review-toolkit:review-pr (~300 tokens) [claude-code-plugins]"
echo " 🔄 ui-ux-pro-max — user scope (~400 tokens)"
echo " 🔄 pr-review-toolkit — /review-pr + 6 PR agents (~2.2k tokens when enabled) [claude-code-plugins]"
echo " 🔄 ui-ux-pro-max — user scope (~780 tokens when enabled)"
echo " 🔄 context7 CLI — ctx7 (npm global, standalone or MCP setup)"
echo " 🔄 graphifyy — codebase knowledge graph (pipx, PreToolUse hook)"
echo " 🔄 graphifyy (CLI: graphify) — codebase knowledge graph (pipx, PreToolUse hook)"
echo " 🔄 emil-design-eng — UI polish, animations, component craft (curl → symlink)"
echo " 🔄 frontend-design — distinctive frontend interfaces, anti-AI-slop (anthropic-agent-skills)"
echo " 🔄 design-motion-principles — motion/animation design, 3-designer lens (kylezantos)"
+1 -1
View File
@@ -8,7 +8,7 @@
"gsd": {
"source": "npm:gsd-pi",
"version": "2.64.0",
"note": "Check latest at https://www.npmjs.com/package/gsd-pi before updating. GSD v2 is a standalone CLI (Pi SDK), not a Claude Code plugin. Run 'gsd' in terminal, not '/gsd' in Claude Code."
"note": "Check latest at https://www.npmjs.com/package/gsd-pi before updating. GSD v2 is a standalone CLI (Pi SDK), not a Claude Code plugin. Run 'gsd' in terminal, not '/gsd' in Claude Code. NOTE: update-all.sh honors this pin — 'make update' will NOT advance gsd past it; bump this version deliberately, then re-run."
},
"gstack": {
"source": "https://github.com/garrytan/gstack.git",
+41 -2
View File
@@ -46,6 +46,32 @@
"Bash(tr *)",
"Bash(cut *)",
"Bash(diff *)",
"Bash(rtk grep *)",
"Bash(*/rtk grep *)",
"Bash(rtk ls)",
"Bash(rtk ls *)",
"Bash(*/rtk ls)",
"Bash(*/rtk ls *)",
"Bash(rtk cat *)",
"Bash(*/rtk cat *)",
"Bash(rtk head *)",
"Bash(*/rtk head *)",
"Bash(rtk tail *)",
"Bash(*/rtk tail *)",
"Bash(rtk wc *)",
"Bash(*/rtk wc *)",
"Bash(rtk diff *)",
"Bash(*/rtk diff *)",
"Bash(rtk git status)",
"Bash(*/rtk git status)",
"Bash(rtk git log*)",
"Bash(*/rtk git log*)",
"Bash(rtk git diff*)",
"Bash(*/rtk git diff*)",
"Bash(rtk git show*)",
"Bash(*/rtk git show*)",
"Bash(rtk git branch*)",
"Bash(*/rtk git branch*)",
"Read(**/*.md)",
"Read(**/*.txt)",
"Read(**/*.json)",
@@ -63,9 +89,13 @@
"deny": [
"Bash(rm -rf *)",
"Bash(rm -rf /*)",
"Bash(rm -r *)",
"Bash(rm -fr *)",
"Bash(rmdir *)",
"Bash(git push --force)",
"Bash(git push --force *)",
"Bash(git push -f*)",
"Bash(git push * +*)",
"Bash(git reset --hard*)",
"Bash(git clean -fd*)",
"Bash(sudo rm*)",
@@ -156,10 +186,20 @@
"Bash(source /dev/stdin)",
"Bash(mkfifo *)",
"Bash(node -e *)",
"Bash(python3 -c *)",
"Bash(python -c *)",
"Bash(xargs * .env*)",
"Bash(tar * .env*)",
"Bash(zip * .env*)",
"Bash(base64 .env*)"
"Bash(base64 .env*)",
"Bash(rtk cat *.env*)",
"Bash(*/rtk cat *.env*)",
"Bash(rtk grep * .env*)",
"Bash(*/rtk grep * .env*)",
"Bash(rtk head *.env*)",
"Bash(*/rtk head *.env*)",
"Bash(rtk tail *.env*)",
"Bash(*/rtk tail *.env*)"
],
"ask": [
"Bash(git push *)",
@@ -177,7 +217,6 @@
"WebFetch",
"Bash(xargs *)",
"Bash(sed *)",
"Bash(python3 -c *)",
"Bash(git stash pop*)",
"Bash(git stash drop*)",
"Bash(git stash clear)"
+21
View File
@@ -227,6 +227,27 @@ else
info "graphifyy not installed — skipping"
fi
# ── 6.5. Update bun ──
echo ""
echo "── Updating bun..."
if command -v bun &>/dev/null; then
if bun upgrade >/dev/null 2>&1; then
ok "bun $(bun --version 2>/dev/null || echo '?') (self-upgrade)"
else
warn "bun upgrade failed — try manually: bun upgrade"
fi
else
info "bun not installed — skipping"
fi
# NOT updated here, deliberately (audit 2026-07-02):
# - magic MCP: registered as `npx -y @21st-dev/magic@latest` — npx resolves
# the latest release at every invocation, nothing to upgrade.
# - graphify Claude integration (`graphify claude install`): rewrites curated
# CLAUDE.md / .claude/settings.json (BDR-028 guard territory) — re-run
# MANUALLY only if a graphify upgrade changes its hook format.
# - gsd: pinned in plugins.lock.json — Step 4 reinstalls the PIN, it does not
# advance it. Bump the lock deliberately, then re-run.
# ── 7. Update Emil Design Engineering skill ──
echo ""
echo "── Updating Emil Design Engineering..."