skills/seo/SKILL.md
Audit or fix SEO issues for a single website or page. Checks meta tags, structured data, technical SEO, content quality, i18n, and AI readiness using only WebFetch — no external APIs. Pass a URL and mode (audit or fix) as parameters.
npx skillsauth add psquared-development/psquared-skills seoInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Announce:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SEO Analysis starting. Parsing parameters... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This skill expects: /seo <url> [mode]
https://psquared.dev, https://inboxmate.psquared.dev)audit (default) or fix
audit — analyze and report findings, don't touch any filesfix — analyze, report, AND apply fixes directly to source filesIf no URL is provided, ask the user.
When the URL matches a known psquared site, use the local source files for the fix mode:
| Domain | Source path (relative to psquared-websites) | Framework |
|--------|----------------------------------------------|-----------|
| psquared.dev / www.psquared.dev | apps/psquared/ | Nuxt 3 |
| inboxmate.psquared.dev | apps/inboxmate/ | Static HTML |
| ki-linz.at / www.ki-linz.at | apps/ki-linz/ | Astro 5 |
| agenthub.psquared.dev | apps/agenthub/ | Static HTML |
The monorepo lives at /Users/martinpammesberger/Documents/psquared/psquared-websites/.
For unknown URLs, only audit mode is available (no local source to fix).
Announce:
Discovering pages for [domain]...
WebFetch: [url]/robots.txt
Record:
Disallow rules? List them.Sitemap: directive?Try in order:
Sitemap: directive[url]/sitemap.xml[url]/sitemap-index.xml[url]/sitemap_index.xmlIf a sitemap is found, extract all page URLs. If not, fall back to crawling:
Announce:
Found [N] pages to analyze.
Limit: Analyze a maximum of 30 pages per site. If more are found, prioritize: homepage, main navigation pages, then remaining by URL depth.
Announce:
[1/N] Analyzing [page URL]...
For each discovered page, use WebFetch to fetch the HTML, then check all categories below.
| Check | What to look for | Severity |
|-------|-----------------|----------|
| <title> | Present, 30-60 chars, unique across site, contains relevant keywords | HIGH |
| <meta name="description"> | Present, 120-160 chars, unique across site, compelling | HIGH |
| <link rel="canonical"> | Present, points to correct URL (no trailing slash mismatch, no http/https mismatch) | HIGH |
| <meta property="og:title"> | Present, matches or supplements <title> | MEDIUM |
| <meta property="og:description"> | Present, matches or supplements meta description | MEDIUM |
| <meta property="og:image"> | Present, valid URL, image exists | MEDIUM |
| <meta property="og:url"> | Present, matches canonical | MEDIUM |
| <meta property="og:type"> | Present (website, article, etc.) | LOW |
| <meta name="twitter:card"> | Present (summary_large_image preferred) | LOW |
| <meta name="twitter:title"> | Present | LOW |
| <meta name="twitter:description"> | Present | LOW |
| <meta name="viewport"> | Present with width=device-width | HIGH |
| Check | What to look for | Severity |
|-------|-----------------|----------|
| Single H1 | Exactly one <h1> per page | HIGH |
| H1 content | Contains primary keyword, descriptive, not just a logo | HIGH |
| Heading order | No skipped levels (H1 -> H3 without H2) | MEDIUM |
| Heading keywords | Headings include relevant terms for the page topic | LOW |
| Check | What to look for | Severity |
|-------|-----------------|----------|
| Alt text | All <img> tags have non-empty alt attribute | HIGH |
| Alt quality | Alt text is descriptive, not just "image" or filename | MEDIUM |
| Lazy loading | Images below fold use loading="lazy" | LOW |
| Width/height | Images specify dimensions (prevents CLS) | LOW |
Look for <script type="application/ld+json"> blocks.
| Check | What to look for | Severity |
|-------|-----------------|----------|
| Presence | At least one JSON-LD block on homepage | HIGH |
| Valid JSON | Block parses without errors | HIGH |
| @type appropriate | Organization/LocalBusiness for homepage, Article for blog posts, Product for product pages, FAQPage for FAQ sections | MEDIUM |
| Required fields | Each schema type has its required properties populated | MEDIUM |
| Contact info | Organization schema includes url, name, contactPoint or email | LOW |
Recommended schema types per page:
| Page type | Schema |
|-----------|--------|
| Homepage | Organization or LocalBusiness |
| Blog post | Article with author, datePublished, headline |
| Product/service page | Product or Service |
| FAQ section | FAQPage with Question + Answer items |
| Contact page | LocalBusiness with address, telephone |
| Check | What to look for | Severity | |-------|-----------------|----------| | Broken links | Internal links that return 404 (sample up to 10 per page) | HIGH | | Link text | Descriptive anchor text, not "click here" or "read more" | MEDIUM | | Orphan pages | Pages not linked from any other page | MEDIUM | | Navigation consistency | Main nav present on all pages | LOW |
| Check | What to look for | Severity |
|-------|-----------------|----------|
| <html lang> | Present and correct | HIGH |
| Hreflang tags | <link rel="alternate" hreflang="x"> for each language variant | HIGH (if multilingual) |
| Self-referencing hreflang | Each page includes hreflang pointing to itself | MEDIUM |
| x-default | hreflang="x-default" present | MEDIUM |
| Consistency | Hreflang tags are reciprocal (page A points to B, B points back to A) | HIGH |
Skip i18n checks for sites that are clearly single-language only.
| Check | What to look for | Severity |
|-------|-----------------|----------|
| HTTPS | Site uses HTTPS | HIGH |
| Mobile viewport | Viewport meta tag present | HIGH |
| Charset | <meta charset="utf-8"> present | MEDIUM |
| Favicon | <link rel="icon"> present | LOW |
| CSS/JS blocking | Critical CSS inline or preloaded | LOW |
| 404 page | /404 or similar returns custom page (not default server error) | LOW |
| Check | What to look for | Severity |
|-------|-----------------|----------|
| Thin content | Page has < 300 words of visible text (excluding nav/footer) | MEDIUM |
| Duplicate titles | Same <title> used on multiple pages | HIGH |
| Duplicate descriptions | Same meta description on multiple pages | HIGH |
| Text/HTML ratio | Very low text-to-markup ratio | LOW |
| Check | What to look for | Severity |
|-------|-----------------|----------|
| llms.txt | [url]/llms.txt exists with site summary for AI crawlers | LOW |
| Structured answers | Content has clear Q&A patterns, definition lists, or summary paragraphs that AI can extract | LOW |
| Content accessibility | Key information in HTML text (not trapped in images/JS-only renders) | MEDIUM |
| Check | What to look for | Severity |
|-------|-----------------|----------|
| X-Frame-Options | Present in response headers | LOW |
| X-Content-Type-Options | nosniff | LOW |
| Referrer-Policy | Present | LOW |
| HTTPS redirect | HTTP redirects to HTTPS | MEDIUM |
Fetch headers via WebFetch response. If headers aren't accessible, skip this section.
Announce:
Analysis complete. Compiling results...
For each page, count findings by severity:
| Grade | Criteria | |-------|----------| | A | 0 HIGH issues, max 2 MEDIUM | | B | 0 HIGH issues, 3+ MEDIUM | | C | 1-2 HIGH issues | | D | 3-4 HIGH issues | | F | 5+ HIGH issues |
Average the per-page grades. Also flag site-wide issues:
Rank all findings by impact:
Announce:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SEO Audit Complete: [domain] Overall Grade: [A-F] Pages analyzed: [N] Critical: [N] issues Important: [N] issues Nice to have: [N] issues ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Then output a detailed report with:
| Item | Status | |------|--------| | robots.txt | Present / Missing | | sitemap.xml | Present ([N] URLs) / Missing | | Structured data | Present on [N]/[total] pages / Missing | | Hreflang | Correct / Issues / N/A | | HTTPS | Yes / No |
For each page (sorted worst to best):
[Page URL] — Grade: [X]
| Issue | Severity | Details |
|-------|----------|---------|
| Missing meta description | HIGH | No <meta name="description"> found |
| ... | ... | ... |
Numbered list of the top 10 most impactful fixes, ordered by effort-to-impact ratio.
Skip this step entirely if mode is
audit.
Announce:
Applying fixes to source files in [source path]...
If the URL matches a site in the Site Registry, locate the source files and apply fixes.
apps/psquared/)| Fix target | Where to edit |
|------------|--------------|
| Global meta tags | nuxt.config.js → app.head |
| Per-page meta | pages/*.vue → useHead() or useSeoMeta() composable |
| OG image | public/ directory + meta tag reference |
| Structured data | nuxt.config.js → app.head.script with type: 'application/ld+json', or per-page useHead() |
| Sitemap config | nuxt.config.js → @nuxtjs/sitemap module config |
| robots.txt | public/robots.txt or nuxt.config.js → @nuxtjs/robots module |
Read the existing
nuxt.config.jsand relevant page files before making any edits. Follow existing patterns.
apps/ki-linz/)| Fix target | Where to edit |
|------------|--------------|
| Global meta tags | src/layouts/*.astro → <head> section |
| Per-page meta | Page frontmatter + <head> in layout |
| Structured data | Inline <script type="application/ld+json"> in layout or page |
| Sitemap config | astro.config.mjs → @astrojs/sitemap integration |
| robots.txt | public/robots.txt |
apps/inboxmate/, apps/agenthub/)| Fix target | Where to edit |
|------------|--------------|
| Meta tags | Directly in <head> of each .html file |
| Structured data | Add <script type="application/ld+json"> block in <head> |
| robots.txt | Create robots.txt in the app root |
| Sitemap | Create sitemap.xml in the app root |
Announce:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SEO Fixes Applied: [domain] Overall Grade: [before] → [after] Fixed: - [file]: [what was changed] - [file]: [what was changed] Remaining (manual fix needed): - [issue]: [why it couldn't be auto-fixed] Run `/seo [url] audit` to verify. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
tools
Generate a polished psquared client offer as a multi-page PDF (title, project description, screenshots, Angebot/pricing, AGB). Walks the user through gathering inputs (or accepts a JSON config), renders branded HTML templates with Playwright in two passes (title page edge-to-edge + body pages with margins and pagination), then merges with pdf-lib.
data-ai
Create email drafts for approved InboxMate demos. Verifies all demos are ready, pulls contacts from CRM, creates CRM tasks, and creates draft emails via the notification service. Run after /review-demos has processed all pending demos.
development
Run SEO audit or fix across all psquared websites autonomously. Dispatches parallel agents for psquared.dev, inboxmate.psquared.dev, ki-linz.at, and agenthub.psquared.dev, then presents a combined report. Pass mode (audit or fix) as parameter.
testing
Verify all InboxMate demo agents are properly configured — checks greetings, quick questions, knowledge, colors, and CRM linkage. Run after batch demo creation or before sending outreach.