From cca43cbe5aa068cd0cb3db681ca1919e957d26f3 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:16:02 +0200 Subject: [PATCH 1/8] chore(agents): remove stale tracked seo-analyzer.md.bak + ignore *.bak MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pre-split (SEO/GEO) backup, 1097 diff lines vs live agent — dead weight committed by accident. *.bak now gitignored (Editors block). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- .gitignore | 1 + agents/seo-analyzer.md.bak | 868 ------------------------------------- 2 files changed, 1 insertion(+), 868 deletions(-) delete mode 100644 agents/seo-analyzer.md.bak diff --git a/.gitignore b/.gitignore index b2af458..c3a222e 100644 --- a/.gitignore +++ b/.gitignore @@ -118,6 +118,7 @@ desktop.ini *.swp *.swo *~ +*.bak .idea/ .vscode/ diff --git a/agents/seo-analyzer.md.bak b/agents/seo-analyzer.md.bak deleted file mode 100644 index 31b59ba..0000000 --- a/agents/seo-analyzer.md.bak +++ /dev/null @@ -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 : -RENDERING : -HOSTING : -HTACCESS : -ROBOTS.TXT : -SITEMAP.XML : -ANALYTICS : -CMP COOKIES : -LEGAL PAGES : -JSON-LD : -``` - ---- - -## 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 project (). -Activity: -Stack detected: - -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: ) -``` - ---- - -## 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="" - -# 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/" | 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 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: `"" "" 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: "" -site: -``` - -Identify mentions not yet converted to backlinks. List opportunities. - ---- - -## STEP 6 — COMPETITIVE ANALYSIS `[FULL only]` - -### Local competition (if local business) - -Search via web_search: ` ` (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: -STATUS: PASS | FAIL | PARTIAL -LAW: -RISK: -FIX: AUTO () | USER () -``` - ---- - -## 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 () -Technical : XX/20 -On-page : XX/20 -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 -Legal : XX/20 -───────────────────────── -GLOBAL (weighted): XX.X/20 () -``` - -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. — - A2. — - ... - -BATCH B — SMALL FEATURES (N items, no confirmation needed) - B1. — files: - B2. — files: - ... - -BATCH C — IMAGE PIPELINE (N images) - - -BATCH D — STRUCTURAL CHANGES (N items, NEEDS CONFIRMATION) - D1. — impact: - D2. — impact: - ... - -BATCH E — CONTENT REMOVAL (N items, NEEDS CONFIRMATION) - E1. — reason: - ... - -BATCH F — USER ACTIONS (N items, documented in SEO.md) - F1. — tool/link: - ... -``` - -**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: . - File: - Current state: - Expected state: - 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: . - Files to create/modify: - Technical context: - Business context: - Requirements: - 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 -o - -# For each image missing dimensions: -# identify -format "%wx%h" → then edit the 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. — impact: - D2. — impact: - -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 `` in layouts. `@astrojs/sitemap`. - Redirects in `astro.config.mjs` or `_redirects`. -- **Nuxt**: `useHead()` or `nuxt.config`. `@nuxtjs/sitemap`. -- **Static HTML / PHP**: edit `` 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: -AGENT: -FILE: -CHANGE: -REASON: -VERIFIED: -``` - -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 — - -**Date** : -**Version** : v (incremented on each run) -**Agent** : seo-analyzer -**URL** : -**Score global** : XX.X / 20 - ---- - -## 0. Alertes majeures (conformite legale et risques) - - -## 1. Notes globales (/20 par axe + ponderee) - - -## 2. Audit technique - - - -## 3. Audit on-page - - -## 4. Audit SEO local / NAP - - -## 5. Audit presence externe (GMB, reseaux sociaux, citations) - - -## 6. Analyse concurrentielle - - -## 7. Optimisation GEO / IA - - -## 8. Plan d'action — QUICK WINS (< 7 jours) - - -## 9. Plan d'action — MOYEN TERME (1-3 mois) - - -## 10. Plan d'action — LONG TERME (3-6 mois) - - -## 11. Actions utilisateur requises - - - -## 12. Recommandations gratuites (outils, methodes, budget 0 EUR) - - -## 13. Synthese 90 jours — objectifs realistes - - -## 14. Annexe — informations impossibles a auditer automatiquement - - -## 15. Log des modifications appliquees par l'agent - - ---- - -## Historique - - - -``` - -**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 : -FRAMEWORK : -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 : - -PROCHAINE ETAPE : -``` - ---- - -## 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 `` 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. From 6d72d0adc82437a2c846d8467f75d44222affa8d Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:16:02 +0200 Subject: [PATCH 2/8] =?UTF-8?q?fix(session-start):=20truthful=20banner=20?= =?UTF-8?q?=E2=80=94=20derive=20ALWAYS=5FON,=20label=20graphify,=20greedy?= =?UTF-8?q?=20split?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ALWAYS_ON derived from settings.json:enabledPlugins (true entries) minus toggle-owned names — the hardcoded pair under-reported newly enabled plugins (pr-review-toolkit enabled yet invisible). LRN-005. - Display 'graphify' (the CLI/skill name); graphifyy stays the pipx package name everywhere it IS the package. - Overflow split = greedy width-fill: the fixed 3-name cut overflowed line 1 and printed an empty line 2 with 3 long names. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- hooks/session-start.sh | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/hooks/session-start.sh b/hooks/session-start.sh index 016061b..d74f759 100644 --- a/hooks/session-start.sh +++ b/hooks/session-start.sh @@ -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 From 3a9b9e584d627ce74e5d4275f8e18f331adeaeb8 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:16:16 +0200 Subject: [PATCH 3/8] fix(install-plugins): gate success messages on real outcomes; drop plugin-dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - gstack + graphify blocks printed unconditional ok after || warn — misleading-success (LRN-071 class). ok now gated on tracked outcome, loud warn otherwise. - plugin-dev install dropped (audit #14): installed 2026-06-23, never enabled, pure disk weight; uninstalled from the machine, reinstall deliberately if plugin authoring becomes a need. - Summary block truthfulness: header no longer claims 'start OFF' for plugins committed enabled; pr-review-toolkit token estimate ~300 → ~2.2k (measured, 6 agent descriptions); ui-ux ~400 → ~780 (measured); graphifyy row names the CLI (graphify). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- install-plugins.sh | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/install-plugins.sh b/install-plugins.sh index 587c5d7..2810f4d 100644 --- a/install-plugins.sh +++ b/install-plugins.sh @@ -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)" From ed2408e742a823e4c4541f7c1b488ed8385d40dd Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:16:16 +0200 Subject: [PATCH 4/8] =?UTF-8?q?fix(design-hook):=20tighten=20trigger=20reg?= =?UTF-8?q?ex=20=E2=80=94=20cut=20ultra-generic=20tokens?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit page/pages/form/menu/card/carte/style/look/screen/interface/color/shadow fired on a large share of non-UI prompts (~200 tokens of reminder each; measured 6 fires during a pure config audit, including on task notifications). Specific compounds stay: formulaire, styling, stylesheet, styliser, écran, couleur, palette… FR aesthetic words kept. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- hooks/design-toolchain-reminder.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/hooks/design-toolchain-reminder.sh b/hooks/design-toolchain-reminder.sh index a05b9da..6664483 100755 --- a/hooks/design-toolchain-reminder.sh +++ b/hooks/design-toolchain-reminder.sh @@ -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' From 45a387c1dd04a31bb9fe1c2ba57947ebf215a503 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:16:36 +0200 Subject: [PATCH 5/8] feat(update-all): bun self-upgrade + documented non-update exclusions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Step 6.5: bun upgrade (guarded). Deliberate exclusions documented in place: magic MCP (npx @latest resolves at invocation), graphify claude install (rewrites curated configs — BDR-028 territory, manual only), gsd (lock-pinned: make update reinstalls the pin, note added to plugins.lock.json so the no-op is explicit). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- plugins.lock.json | 2 +- update-all.sh | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/plugins.lock.json b/plugins.lock.json index 853fb7e..ef55a07 100644 --- a/plugins.lock.json +++ b/plugins.lock.json @@ -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", diff --git a/update-all.sh b/update-all.sh index 621e8ed..0eed297 100644 --- a/update-all.sh +++ b/update-all.sh @@ -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..." From 9e534241f91434ea55bd53c2c85da74a9d4c26a0 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:16:36 +0200 Subject: [PATCH 6/8] feat(settings): deny-list hardening pass (audit #20) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - rm -r / rm -fr denied (only -rf was; flag-order variants passed). - python3 -c / python -c ask → deny: aligned with node -e / perl -e / ruby -e (arbitrary-interpreter class was incoherently split). - git push + denied (refspec force carried no flag). - --force-with-lease un-over-blocked: --force* split into --force / --force *, so the safer variant now falls to the git push ASK gate. Deny 99 → 105, ask 19 → 18. Second curtain unchanged (auto-mode classifier, BDR-004). doctor's deny sentinel tracks HEAD (LOT 1). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- settings.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/settings.json b/settings.json index 8ecbde7..cba2210 100644 --- a/settings.json +++ b/settings.json @@ -63,9 +63,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 --force *)", "Bash(git push -f*)", + "Bash(git push * +*)", "Bash(git reset --hard*)", "Bash(git clean -fd*)", "Bash(sudo rm*)", @@ -156,6 +160,8 @@ "Bash(source /dev/stdin)", "Bash(mkfifo *)", "Bash(node -e *)", + "Bash(python3 -c *)", + "Bash(python -c *)", "Bash(xargs * .env*)", "Bash(tar * .env*)", "Bash(zip * .env*)", @@ -177,7 +183,6 @@ "WebFetch", "Bash(xargs *)", "Bash(sed *)", - "Bash(python3 -c *)", "Bash(git stash pop*)", "Bash(git stash drop*)", "Bash(git stash clear)" From a0d092ca9f2099832a943ded120185de193e14b7 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:16:36 +0200 Subject: [PATCH 7/8] chore(make): declare onboard in .PHONY Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e86fd7a..dd9e79a 100644 --- a/Makefile +++ b/Makefile @@ -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}' From a73dff4edfcf52d3d067c2147fb4ba5a3b18f8f9 Mon Sep 17 00:00:00 2001 From: Bastien Chanot Date: Thu, 2 Jul 2026 14:29:53 +0200 Subject: [PATCH 8/8] feat(settings): rtk-wrapped allowlist + .env deny mirrors (audit #11 companion) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rtk hook no longer auto-allows (audit-bugs branch): rewritten commands are evaluated natively. Allow rules match the original forms (grep *, ls *) not the rewritten ones — without explicit rules every rewrite would fall to the classifier. Added the read-only rtk-wrapped family, bare + absolute-path forms (the hook emits absolute paths when PATH lacks the cargo dir): grep, ls, cat, head, tail, wc, diff, git status/log/diff/show/branch. NOT find (rtk find could carry -exec rm — native find-deny rules would not match the rtk prefix). Deny mirrors guard the bypass the allowlist would open on hand-written 'rtk cat .env'-class commands: cat/grep/head/tail × .env, both prefixes. Residual: exotic quoting may evade the mirrors — second curtain stays the auto-mode classifier (BDR-004). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_016zA3Qh2Q1QpcGXzXxKeDHR --- settings.json | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/settings.json b/settings.json index cba2210..238b37f 100644 --- a/settings.json +++ b/settings.json @@ -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)", @@ -165,7 +191,15 @@ "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 *)",