SKILL.md
SEO Drift Monitor
You cannot prove a deploy broke SEO without a snapshot from before the deploy. Capture a baseline when the page is known good, diff against it after every change, and classify what moved.
Operations
| Request | Operation |
|---|---|
| "baseline this page" | Capture snapshot, save to seo-baselines/ |
| "compare" / "did anything break" | Fetch current state, diff against latest baseline |
| "history" | List stored baselines and past comparison results for the URL |
What a baseline captures
Fetch the URL and record all of these in one JSON file:
| Field | Content |
|---|---|
url, captured_at | Normalized URL, ISO timestamp |
status_code | HTTP status (capture even 4xx/5xx, status is a tracked field) |
title, meta_description | Exact text |
canonical, meta_robots | href and content values |
h1, h2, h3 | Arrays, in document order |
schema | All JSON-LD blocks, parsed |
open_graph | og:* tag map |
html_hash, schema_hash | SHA-256 of body and of serialized schema |
cwv | Core Web Vitals if a PageSpeed key is available, else null |
Storage: seo-baselines/<host>/<path-slug>.json, one file per capture, timestamp in the filename. Keep them in the repo so history rides along with deploys.
URL normalization before matching: lowercase scheme and host, strip default ports, sort query parameters, drop UTM parameters, strip trailing slash.
Baseline workflow
- Validate the URL. Refuse private IPs, loopback, and cloud metadata endpoints.
- Fetch the page over HTTPS with TLS verification on.
- Extract every field in the table above.
- Compute the hashes.
- Write the JSON file and report the path plus a one-line summary of captured elements.
Compare workflow
- Load the most recent baseline for the normalized URL (or a specific file if the user names one). None found: say so and offer to create one, do not compare against nothing.
- Fetch and parse the current state the same way.
- Apply the comparison rules. Read references/comparison-rules.md for the full rule set with severities and fixes.
- Report every triggered rule: field, old value, new value, severity, recommended action. Save the comparison result next to the baseline as
<name>.compare.json. - Route follow-ups to siblings: schema changes to claude-seo-schema, CWV or canonical or noindex issues to claude-seo-technical, title/meta/OG changes to claude-seo-page.
Severity meanings: CRITICAL is an SEO-breaking change, act immediately. WARNING needs investigation within a week. INFO is awareness, may be intentional.
Verification
After capturing a baseline, run python3 -c "import json,sys; d=json.load(open(sys.argv[1])); print(d['title'], d['status_code'])" <file>. Expect the real page title and status printed with no exception. If it fails, the snapshot is malformed, recapture before relying on it.
Good vs bad
Good: Pre-deploy baseline, post-deploy compare, report reads "canonical changed from self to staging URL: CRITICAL, restore before traffic drops." Bad: Traffic dropped, no baseline exists, and the report guesses at what "probably changed". Without a snapshot you have opinions, not diffs. Capture a baseline now so next time you have evidence.
Footguns
- Comparing different URL variants.
example.com/pageandexample.com/page?utm_source=xmust normalize to the same key or you get false CRITICAL diffs. Always normalize before matching. - Baseline captured during an incident. A snapshot of a 500 page becomes your "known good". Check
status_codeis 200 before treating a baseline as the reference for regressions. - Missing CWV treated as regression. If the baseline has
cwv: null, skip CWV rules instead of flagging a change. - Fetching through redirects silently. Record the final URL and status chain. A new 301 on the page is itself a finding, not transparent plumbing.
Completion checklist
- [ ] URL validated and normalized before fetch
- [ ] All baseline fields captured, hashes computed
- [ ] Snapshot file written under
seo-baselines/and verified parseable - [ ] Compare runs the full rule set, not just fields that look interesting
- [ ] Every finding has old value, new value, severity, action
- [ ] Sibling skill recommended for each CRITICAL finding
Any box unchecked: not done. Fix or say so.