agentleFS
JoviDeCroockJoviDeCroock/pracht/skills/audit-seo/SKILL.md

audit-seo

Skill106 starsChanged 7 months agoMITView on GitHub

Audit SEO per pracht route (`head()` titles, descriptions, Open Graph, canonicals, robots) and generate a `sitemap.xml` from the route manifest. Use for "audit SEO", "check meta tags", "generate a sitemap", "check OG cards", "review robots.txt".

3 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

8 rules. About 0 are common, 0 are distinctive, and 8 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    If absent, recommend creating public/robots.txt:

    line 79
  2. Very specific:

    No accidental Disallow: / (full-site block).

    line 92
  3. Very specific:

    Write each URL in the app's canonical spelling: /about/ under trailingSlash: "always", /about otherwise (the root is always /).

    line 110
  4. Very specific:

    Default <changefreq> from the route's revalidate policy: timeRevalidate → weekly if > 86400s, daily if > 3600s, hourly otherwise.

    line 112
  5. Very specific:

    If the user asks, scaffold JSON-LD via the head() export's native script field — HeadMetadata supports script?: HeadScriptDescriptor[], …

    line 126
  6. Very specific:

    No shell-level custom <script> JSX is needed.

    line 143
  7. Very specific:

    Use the resolved manifest — shell head() inheritance matters.

    line 159
  8. Very specific:

    Never auto-write sitemap.xml to the deployed site without user confirmation.

    line 160

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Pracht Audit SEO

pracht owns the document. Per-route SEO lives in the head() export returning { title?, lang?, meta?, link?, script? }. This skill audits coverage and generates the static SEO artifacts.

Step 1: Inventory

MCP: if pracht dev-mcp is registered, prefer its inspect_*, doctor, and verify tools to the CLI.

pracht inspect routes --json

Prerequisite: pracht inspect needs a vite config with the pracht plugin wired up; run from the app root.

For every route file, read the head() export (and the shell's head() for inherited values).

Step 2: Per-route checklist

For each route, capture presence and quality:

FieldExpected
title30-60 chars, unique per route
meta description70-160 chars, unique per route
meta og:titlePresent (often = title)
meta og:descriptionPresent
meta og:imageAbsolute URL, ≥ 1200×630
meta og:urlAbsolute, canonical
meta twitter:cardsummary_large_image for content
link canonicalAbsolute URL
script (JSON-LD)Optional; see Step 6
langSet on root or via shell

Skip SPA-only / non-indexable routes (admin, dashboard) — flag as "noindex candidate" if they don't already declare it.

Step 3: Cross-route checks

  • Duplicate titles across routes — list collisions.
  • Duplicate descriptions — same.
  • Missing canonical on any route that has any ?query variants.
  • Duplicate trailing-slash URLs. With the default pracht({ trailingSlash: "ignore" }) every page answers at /about and /about/. Recommend "always" or "never", which redirects the other spelling with a 308, or a canonical link on every page. Canonicals, og:url, and sitemap entries must use the spelling in dist/server/routing.json.
  • Missing OG image — most common issue; recommend a default image at shell level so every route inherits one.

Step 4: robots.txt

robots.txt MUST be served at the origin root (/robots.txt) — crawlers never look anywhere else. pracht API routes are always mounted under /api/ (a src/api/robots.ts handler serves /api/robots, never /robots.txt), so an API handler cannot provide it. The workable option is the static asset:

  • public/robots.txt (Vite static asset, served at /robots.txt).

If absent, recommend creating public/robots.txt:

User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Sitemap: https://<domain>/sitemap.xml

If present, validate:

  • A Sitemap: line referencing an existing endpoint (see Step 5 — if the sitemap is an API route, this must point at /api/sitemap).
  • No accidental Disallow: / (full-site block).
  • Path patterns match real routes (cross-reference with the manifest).
  • Flag any src/api/robots.ts found in the repo as warn: it is dead weight at /api/robots and does not serve /robots.txt.

Step 5: sitemap

Generate (or recommend generating) a sitemap from the route manifest:

  • Include routes by indexability, not prefetch strategy: public render: "ssg"/"isg" routes (and public SSR routes worth indexing), minus routes under auth middleware, minus routes declaring a robots/noindex meta. (prefetch is a client navigation hint — orthogonal to indexability; do not use it as a criterion.)
  • Skip dynamic-segment routes unless getStaticPaths resolved them at build time — pull resolved paths from the prerender output, which is laid out as dist/client/<route>/index.html (clean URLs; e.g. /about → dist/client/about/index.html).
  • Write each URL in the app's canonical spelling: /about/ under trailingSlash: "always", /about otherwise (the root is always /).
  • Default <changefreq> from the route's revalidate policy: timeRevalidate → weekly if > 86400s, daily if > 3600s, hourly otherwise.

Offer two output forms:

  1. Static public/sitemap.xml regenerated at build time via a small script (served at /sitemap.xml).
  2. A pracht API route at src/api/sitemap.ts that emits XML on each request from the inspected manifest. It is served at /api/sitemap (API routes always mount under /api/), so the robots Sitemap: line must point at https://<domain>/api/sitemap.

Step 6: Structured data (optional)

If the user asks, scaffold JSON-LD via the head() export's native script field — HeadMetadata supports script?: HeadScriptDescriptor[], where each descriptor takes attributes plus children for the inline body:

export function head() {
  return {
    script: [
      {
        type: "application/ld+json",
        children: JSON.stringify({ "@context": "https://schema.org", ... }),
      },
    ],
  };
}

No shell-level custom <script> JSX is needed. This is opt-in — do not push it on every audit.

Step 7: Report

RouteSeverityTitleDescriptionOG imageCanonicalVerdict

Primary severity per finding: error (site blocked by robots, auth-gated route in sitemap), warn (missing title/description/OG image/canonical on an indexable route), info (nice-to-haves like JSON-LD). Keep the complete/partial/missing verdict as a secondary per-route rollup, grouped by verdict.

Rules

  1. Use the resolved manifest — shell head() inheritance matters.
  2. Never auto-write sitemap.xml to the deployed site without user confirmation; offer the file as a draft.
  3. Recommend a default OG image at the shell level — single highest-leverage fix.
  4. Auth-gated routes should NOT appear in sitemaps.
  5. Cross-reference with tune-render-mode — SSG routes are the sitemap candidates; SSR routes need decision per case.

$ARGUMENTS

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.