seo
SEO Audit & Fix
Announce:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SEO Analysis starting. Parsing parameters... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Parameters
This skill expects: /seo <url> [mode]
- url — the site to audit (e.g.
https://psquared.dev,https://inboxmate.psquared.dev) - mode —
audit(default) orfixaudit— analyze and report findings, don't touch any filesfix— analyze, report, AND apply fixes directly to source files
If no URL is provided, ask the user.
Site Registry
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).
STEP 0 — Discover Pages
Announce:
Discovering pages for [domain]...
0a — Fetch robots.txt
WebFetch: [url]/robots.txt
Record:
- Does it exist?
- Are there
Disallowrules? List them. - Is there a
Sitemap:directive? - Are important paths accidentally blocked?
0b — Fetch sitemap
Try in order:
- URL from robots.txt
Sitemap:directive [url]/sitemap.xml[url]/sitemap-index.xml[url]/sitemap_index.xml
If a sitemap is found, extract all page URLs. If not, fall back to crawling:
- Fetch the homepage
- Extract all internal links (same domain)
- Follow one level deep to discover subpages
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.
STEP 1 — Analyze Each Page
Announce:
[1/N] Analyzing [page URL]...
For each discovered page, use WebFetch to fetch the HTML, then check all categories below.
1a — Meta Tags
| 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 |
1b — Heading Hierarchy
| 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 |
1c — Images
| 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 |
1d — Structured Data (JSON-LD)
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 |
1e — Internal Links & Navigation
| 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 |
1f — i18n & Hreflang
| 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.
1g — Technical SEO
| 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 |
1h — Content Quality
| 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 |
1i — AI & GEO Readiness
| 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 |
1j — Security Headers (SEO-adjacent)
| 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.
STEP 2 — Score & Compile
Announce:
Analysis complete. Compiling results...
2a — Per-Page Scores
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 |
2b — Site-Wide Score
Average the per-page grades. Also flag site-wide issues:
- Missing robots.txt or sitemap → HIGH
- No structured data on any page → HIGH
- No hreflang on multilingual site → HIGH
- Duplicate titles/descriptions across pages → HIGH
2c — Priority Ranking
Rank all findings by impact:
- Critical — blocks indexing or causes major SEO harm (missing title, blocked in robots.txt, broken canonical)
- Important — significant improvement potential (missing OG tags, no structured data, duplicate descriptions)
- Nice to have — polish items (alt text quality, llms.txt, security headers)
STEP 3 — Report (audit mode)
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:
Site Overview
| 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 |
Page-by-Page Results
For each page (sorted worst to best):
[Page URL] — Grade: [X]
| Issue | Severity | Details |
|---|---|---|
| Missing meta description | HIGH | No <meta name="description"> found |
| ... | ... | ... |
Top Priorities
Numbered list of the top 10 most impactful fixes, ordered by effort-to-impact ratio.
STEP 4 — Fix (fix mode only)
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.
Framework-specific fix strategies
Nuxt 3 (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.
Astro 5 (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 |
Static HTML (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 |
Fix rules
- Read before writing. Always read the full file before editing. Follow existing code patterns and style.
- One fix at a time. Apply each fix individually using the Edit tool.
- Don't break things. If a fix requires understanding complex component logic, flag it in the report instead of guessing.
- Don't over-optimize. Fix real issues found in the audit. Don't add things that weren't flagged.
- Preserve existing good SEO. If something is already correct, don't touch it.
- Track what you changed. Keep a list of every file edited and what was changed.
After fixing
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. ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
More from psquared-development/psquared-skills
inboxmate-demo
Set up a personalized InboxMate demo chatbot for a sales prospect. Use when asked to create a demo, set up an InboxMate playground, or prepare a chatbot demo. Guides the full pipeline: research company, scrape content, call MCP, deliver playground URL.
33check-outreach-status
Check status of sent demo outreach emails and monitor follow-up draft status. Follow-up drafts are created by /setup-email-drafts — this skill only monitors. Run periodically after /setup-email-drafts has been used.
23refurbish-demos
Upgrade demo agent knowledge — clears old summaries, scrapes real pages via MCP Tavily (advanced mode), falls back to WebFetch, fixes icons, republishes. Pass campaignId or 'all-sent' as parameter.
8analyse-inboxmate
Reference guide for understanding the InboxMate ecosystem - architecture, repos, pipeline, CRM states, metrics, and how to query each system. Use when starting any InboxMate-related work.
8sanity-check
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.
7plan-campaign
Plan an outreach campaign. Groups OK_TO_SEND demos (no campaign yet) into a named campaign with an offer text and deadline, creates the campaign in CRM, and links the selected opportunities to it. Run after /review-demos and before /setup-email-drafts.
7