Metadata lint
Audits HTML head metadata against a priority-ordered rule set and proposes minimal, scoped fixes. The output is the audit report — not a refactor, not a strategy doc. Pair with /website-pm-score (broader page audit) or /aeo-strategy (search-visibility strategy) to act on the findings.
Sourced from ibelick/ui-skills under MIT (Julien Thibeaut, 2026). Adapted to the Genesys Phase 4 SKILL.md schema; substantive content preserved.
Design-contract exemption note: This skill carries primitive: website but is NOT a design-output skill (the design-production.md applies to skills that produce visual deliverables — landing pages, wireframes, dashboards, decks). Metadata-lint produces a text audit report listing HTML head violations and code-level fixes; there is no DESIGN.md token consumption, no visual surface, no design-cycle phases to walk. The validator's design-contract warning is an expected false positive driven by the primitive: website taxonomy heuristic.
Triggers
Run when:
- Adding or changing page titles, descriptions, canonical URLs, robots directives
- Implementing Open Graph or Twitter card metadata
- Setting favicons, app icons, manifest, theme-color
- Building shared SEO components or layout metadata defaults
- Adding structured data (JSON-LD)
- Changing locale, alternate languages, or canonical routing
- Shipping new pages, marketing pages, or shareable links
Do NOT run for:
- Strategic decisions about what TO put in metadata (that's
/aeo-strategy or /messaging)
- Whole-page audits — use
/website-pm-score instead; metadata-lint is the head-tags slice
Inputs
| Input |
Required |
Notes |
| HTML file path or live URL |
Yes |
One target per run; loop the skill for multi-page audits |
| Brand context |
Recommended |
Read projects/consulting/{client}/CLAUDE.md if reviewing client work — title format + voice should match |
| Existing metadata system |
Inferred from code |
Next.js metadata API, react-helmet, manual <head>, Astro frontmatter — match the project's pattern |
Workflow
- Identify pages with missing or incorrect metadata (titles, descriptions, canonical, OG tags)
- Audit against the priority rules below — fix critical issues (duplicates, indexing) first
- Ensure title, description, canonical, and og:url all agree with each other
- Verify social cards render correctly on a real URL, not localhost
- Keep diffs minimal and scoped to metadata only — do not refactor unrelated code
Rule categories by priority
| Priority |
Category |
Impact |
| 1 |
Correctness and duplication |
Critical |
| 2 |
Title and description |
High |
| 3 |
Canonical and indexing |
High |
| 4 |
Social cards |
High |
| 5 |
Icons and manifest |
Medium |
| 6 |
Structured data |
Medium |
| 7 |
Locale and alternates |
Low-medium |
| 8 |
Tool boundaries |
Critical |
Quick reference
1. Correctness and duplication (critical)
- Define metadata in one place per page; avoid competing systems
- Do not emit duplicate
title, description, canonical, or robots tags
- Metadata must be deterministic — no random or unstable values
- Escape and sanitize any user-generated or dynamic strings
- Every page must have safe defaults for title and description
2. Title and description (high)
- Every page must have a title
- Use a consistent title format across the site (e.g.,
{Page} — {Brand})
- Keep titles short and readable; avoid stuffing
- Shareable or searchable pages should have a meta description
- Descriptions must be plain text — no markdown, no quote spam
3. Canonical and indexing (high)
- Canonical must point to the preferred URL for the page
- Use
noindex only for private, duplicate, or non-public pages
- Robots meta must match actual access intent
- Previews or staging pages should be
noindex by default when possible
- Paginated pages must have correct canonical behavior
4. Social cards (high)
- Shareable pages must set Open Graph title, description, and image
- Open Graph and Twitter images must use absolute URLs
- Prefer correct image dimensions and stable aspect ratios
og:url must match the canonical URL
- Use a sensible
og:type, usually website or article
- Set
twitter:card appropriately, summary_large_image by default
5. Icons and manifest (medium)
- Include at least one favicon that works across browsers
- Include
apple-touch-icon when relevant
- Manifest must be valid and referenced when used
- Set
theme-color intentionally to avoid mismatched UI chrome
- Icon paths should be stable and cacheable
6. Structured data (medium)
- Do not add JSON-LD unless it clearly maps to real page content
- JSON-LD must be valid and reflect what is actually rendered
- Do not invent ratings, reviews, prices, or organization details
- Prefer one structured data block per page unless required
7. Locale and alternates (low-medium)
- Set the
html lang attribute correctly
- Set
og:locale when localization exists
- Add
hreflang alternates only when pages truly exist
- Localized pages must canonicalize correctly per locale
8. Tool boundaries (critical)
- Prefer minimal changes — do not refactor unrelated code
- Do not migrate frameworks or SEO libraries unless requested
- Follow the project's existing metadata pattern (Next.js metadata API, react-helmet, manual head, Astro frontmatter, etc.)
Common fixes
<!-- Missing title: add one with consistent format -->
<!-- before --> <head><meta name="description" content="..." /></head>
<!-- after --> <head><title>Pricing — Acme</title><meta name="description" content="..." /></head>
<!-- og:url disagrees with canonical: align them -->
<!-- before -->
<link rel="canonical" href="https://acme.com/pricing" />
<meta property="og:url" content="https://acme.com/pricing/" /> <!-- trailing slash -->
<!-- after --> both URLs match exactly
<!-- Open Graph image is relative: must be absolute -->
<!-- before --> <meta property="og:image" content="/og.png" />
<!-- after --> <meta property="og:image" content="https://acme.com/og.png" />
<!-- Robots tag wrong on staging: add noindex -->
<!-- before --> (no robots tag on staging.acme.com)
<!-- after --> <meta name="robots" content="noindex,nofollow" />
// Next.js 14+ metadata API — single source of truth per page
export const metadata = {
title: "Pricing — Acme",
description: "...",
alternates: { canonical: "https://acme.com/pricing" },
openGraph: {
title: "Pricing — Acme",
description: "...",
url: "https://acme.com/pricing", // matches canonical
images: ["https://acme.com/og.png"], // absolute
type: "website",
},
twitter: { card: "summary_large_image" },
};
Metadata lint — {page-or-url}
Date: 2026-05-01
Critical (P1) — must-fix before ship
- [Rule 1.2 duplication]
<title> defined in both layout.tsx:12 AND page.tsx:8 — emit one source of truth
Fix: remove page-level title; rely on layout default with metadata export
High (P2) — fix this cycle
- [Rule 4.3 OG image] og:image is relative
/og.png — must be absolute
Fix: prefix with site origin or move to env var SITE_URL
Medium (P3) — backlog
- [Rule 6.2 JSON-LD] Organization schema missing
address despite render of contact info
Fix: add address field or remove the schema block
Verified clean
- ✓ Title format consistent
- ✓ Canonical agrees with og:url
- ✓ robots:noindex correctly absent on production
---
## Review guidance (gate 1 — quick review)
- Fix critical issues first (duplicates, canonical, indexing)
- Ensure title, description, canonical, and og:url agree
- Verify social cards on a real URL, not localhost
- Prefer stable, boring metadata over clever or dynamic
- Keep diffs minimal and scoped to metadata only
---
## Self-roast checklist
Before delivering the audit report, ask:
- Did the lint catch ALL duplicate `<title>` / `<meta name="description">` / canonical / robots tags?
- Did `og:url` match the canonical exactly (trailing slashes, protocol, subdomain)?
- Was the social card actually tested on a real URL (LinkedIn / Twitter card validator), not just inspected locally?
- Did fixes stay scoped to metadata? (No drive-by refactors of unrelated head tags or layout components.)
- For multi-page audits: is the title format consistent across pages?
If any answer is "no" or "didn't check", re-run that section before shipping the report.
---
## Cross-references
- Broader page audit (perf + a11y + content + metadata) → `/website-pm-score`
- AI search visibility strategy + citation gap planning → `/aeo-strategy`
- Source skill (MIT) → [ibelick/ui-skills/skills/fixing-metadata](https://github.com/ibelick/ui-skills/blob/main/skills/fixing-metadata/SKILL.md)
---
1---2name: metadata-lint3description: <!-- Sourced from ibelick/ui-skills (MIT). https://github.com/ibelick/ui-skills/blob/main/skills/fixing-metadata/SKILL.md. See../../../meta/catalog/design-reviewer/NOTICE.md for the MIT attribution block. -->4---56<!-- Sourced from ibelick/ui-skills (MIT). https://github.com/ibelick/ui-skills/blob/main/skills/fixing-metadata/SKILL.md. See../../../meta/catalog/design-reviewer/NOTICE.md for the MIT attribution block. -->78# Metadata lint910Audits HTML head metadata against a priority-ordered rule set and proposes minimal, scoped fixes. The output is the audit report — not a refactor, not a strategy doc. Pair with `/website-pm-score` (broader page audit) or `/aeo-strategy` (search-visibility strategy) to act on the findings.1112Sourced from [ibelick/ui-skills](https://github.com/ibelick/ui-skills/blob/main/skills/fixing-metadata/SKILL.md) under MIT (Julien Thibeaut, 2026). Adapted to the Genesys Phase 4 SKILL.md schema; substantive content preserved.1314> **Design-contract exemption note:** This skill carries `primitive: website` but is NOT a design-output skill (the `design-production.md` applies to skills that produce visual deliverables — landing pages, wireframes, dashboards, decks). Metadata-lint produces a text audit report listing HTML head violations and code-level fixes; there is no DESIGN.md token consumption, no visual surface, no design-cycle phases to walk. The validator's design-contract warning is an expected false positive driven by the `primitive: website` taxonomy heuristic.1516---1718## Triggers1920Run when:21- Adding or changing page titles, descriptions, canonical URLs, robots directives22- Implementing Open Graph or Twitter card metadata23- Setting favicons, app icons, manifest, theme-color24- Building shared SEO components or layout metadata defaults25- Adding structured data (JSON-LD)26- Changing locale, alternate languages, or canonical routing27- Shipping new pages, marketing pages, or shareable links2829Do NOT run for:30- Strategic decisions about what TO put in metadata (that's `/aeo-strategy` or `/messaging`)31- Whole-page audits — use `/website-pm-score` instead; metadata-lint is the head-tags slice3233---3435## Inputs3637| Input | Required | Notes |38|---|---|---|39| HTML file path or live URL | Yes | One target per run; loop the skill for multi-page audits |40| Brand context | Recommended | Read `projects/consulting/{client}/CLAUDE.md` if reviewing client work — title format + voice should match |41| Existing metadata system | Inferred from code | Next.js metadata API, react-helmet, manual `<head>`, Astro frontmatter — match the project's pattern |4243---4445## Workflow46471. Identify pages with missing or incorrect metadata (titles, descriptions, canonical, OG tags)482. Audit against the priority rules below — fix critical issues (duplicates, indexing) first493. Ensure title, description, canonical, and og:url all agree with each other504. Verify social cards render correctly on a real URL, not localhost515. Keep diffs minimal and scoped to metadata only — do not refactor unrelated code5253---5455## Rule categories by priority5657| Priority | Category | Impact |58|---|---|---|59| 1 | Correctness and duplication | Critical |60| 2 | Title and description | High |61| 3 | Canonical and indexing | High |62| 4 | Social cards | High |63| 5 | Icons and manifest | Medium |64| 6 | Structured data | Medium |65| 7 | Locale and alternates | Low-medium |66| 8 | Tool boundaries | Critical |6768---6970## Quick reference7172### 1. Correctness and duplication (critical)7374- Define metadata in one place per page; avoid competing systems75- Do not emit duplicate `title`, `description`, `canonical`, or `robots` tags76- Metadata must be deterministic — no random or unstable values77- Escape and sanitize any user-generated or dynamic strings78- Every page must have safe defaults for title and description7980### 2. Title and description (high)8182- Every page must have a title83- Use a consistent title format across the site (e.g., `{Page} — {Brand}`)84- Keep titles short and readable; avoid stuffing85- Shareable or searchable pages should have a meta description86- Descriptions must be plain text — no markdown, no quote spam8788### 3. Canonical and indexing (high)8990- Canonical must point to the preferred URL for the page91- Use `noindex` only for private, duplicate, or non-public pages92- Robots meta must match actual access intent93- Previews or staging pages should be `noindex` by default when possible94- Paginated pages must have correct canonical behavior9596### 4. Social cards (high)9798- Shareable pages must set Open Graph title, description, and image99- Open Graph and Twitter images must use absolute URLs100- Prefer correct image dimensions and stable aspect ratios101- `og:url` must match the canonical URL102- Use a sensible `og:type`, usually `website` or `article`103- Set `twitter:card` appropriately, `summary_large_image` by default104105### 5. Icons and manifest (medium)106107- Include at least one favicon that works across browsers108- Include `apple-touch-icon` when relevant109- Manifest must be valid and referenced when used110- Set `theme-color` intentionally to avoid mismatched UI chrome111- Icon paths should be stable and cacheable112113### 6. Structured data (medium)114115- Do not add JSON-LD unless it clearly maps to real page content116- JSON-LD must be valid and reflect what is actually rendered117- Do not invent ratings, reviews, prices, or organization details118- Prefer one structured data block per page unless required119120### 7. Locale and alternates (low-medium)121122- Set the `html lang` attribute correctly123- Set `og:locale` when localization exists124- Add `hreflang` alternates only when pages truly exist125- Localized pages must canonicalize correctly per locale126127### 8. Tool boundaries (critical)128129- Prefer minimal changes — do not refactor unrelated code130- Do not migrate frameworks or SEO libraries unless requested131- Follow the project's existing metadata pattern (Next.js metadata API, react-helmet, manual head, Astro frontmatter, etc.)132133---134135## Common fixes136137```html138<!-- Missing title: add one with consistent format -->139<!-- before --> <head><meta name="description" content="..." /></head>140<!-- after --> <head><title>Pricing — Acme</title><meta name="description" content="..." /></head>141142<!-- og:url disagrees with canonical: align them -->143<!-- before -->144<link rel="canonical" href="https://acme.com/pricing" />145<meta property="og:url" content="https://acme.com/pricing/" /> <!-- trailing slash -->146<!-- after --> both URLs match exactly147148<!-- Open Graph image is relative: must be absolute -->149<!-- before --> <meta property="og:image" content="/og.png" />150<!-- after --> <meta property="og:image" content="https://acme.com/og.png" />151152<!-- Robots tag wrong on staging: add noindex -->153<!-- before --> (no robots tag on staging.acme.com)154<!-- after --> <meta name="robots" content="noindex,nofollow" />155```156157```jsx158// Next.js 14+ metadata API — single source of truth per page159export const metadata = {160 title: "Pricing — Acme",161 description: "...",162 alternates: { canonical: "https://acme.com/pricing" },163 openGraph: {164 title: "Pricing — Acme",165 description: "...",166 url: "https://acme.com/pricing", // matches canonical167 images: ["https://acme.com/og.png"], // absolute168 type: "website",169 },170 twitter: { card: "summary_large_image" },171};172```173174---175176# Metadata lint — {page-or-url}177Date: 2026-05-01178179## Critical (P1) — must-fix before ship180- [Rule 1.2 duplication] `<title>` defined in both layout.tsx:12 AND page.tsx:8 — emit one source of truth181 Fix: remove page-level title; rely on layout default with `metadata` export182183## High (P2) — fix this cycle184- [Rule 4.3 OG image] og:image is relative `/og.png` — must be absolute185 Fix: prefix with site origin or move to env var SITE_URL186187## Medium (P3) — backlog188- [Rule 6.2 JSON-LD] Organization schema missing `address` despite render of contact info189 Fix: add `address` field or remove the schema block190191## Verified clean192- ✓ Title format consistent193- ✓ Canonical agrees with og:url194- ✓ robots:noindex correctly absent on production195```196197---198199## Review guidance (gate 1 — quick review)200201- Fix critical issues first (duplicates, canonical, indexing)202- Ensure title, description, canonical, and og:url agree203- Verify social cards on a real URL, not localhost204- Prefer stable, boring metadata over clever or dynamic205- Keep diffs minimal and scoped to metadata only206207---208209## Self-roast checklist210211Before delivering the audit report, ask:212213- Did the lint catch ALL duplicate `<title>` / `<meta name="description">` / canonical / robots tags?214- Did `og:url` match the canonical exactly (trailing slashes, protocol, subdomain)?215- Was the social card actually tested on a real URL (LinkedIn / Twitter card validator), not just inspected locally?216- Did fixes stay scoped to metadata? (No drive-by refactors of unrelated head tags or layout components.)217- For multi-page audits: is the title format consistent across pages?218219If any answer is "no" or "didn't check", re-run that section before shipping the report.220221---222223## Cross-references224225- Broader page audit (perf + a11y + content + metadata) → `/website-pm-score`226- AI search visibility strategy + citation gap planning → `/aeo-strategy`227- Source skill (MIT) → [ibelick/ui-skills/skills/fixing-metadata](https://github.com/ibelick/ui-skills/blob/main/skills/fixing-metadata/SKILL.md)228229---230