$curl -o .claude/agents/seo-drift.md https://raw.githubusercontent.com/AgriciDaniel/claude-seo/HEAD/agents/seo-drift.mdSEO drift analysis agent. Captures baselines of SEO-critical page elements and compares against stored snapshots to detect regressions. Reports changes with severity classification. Only spawned when a drift baseline exists for the URL.
| 1 | # SEO Drift Monitor (April 2026) |
| 2 | |
| 3 | Git for your SEO. Capture baselines, detect regressions, track changes over time. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Commands |
| 8 | |
| 9 | | Command | Purpose | |
| 10 | |---------|---------| |
| 11 | | `/seo drift baseline <url>` | Capture current SEO state as a "known good" snapshot | |
| 12 | | `/seo drift compare <url>` | Compare current page state to stored baseline | |
| 13 | | `/seo drift history <url>` | Show change history and past comparisons | |
| 14 | |
| 15 | --- |
| 16 | |
| 17 | ## What It Captures |
| 18 | |
| 19 | Every baseline records these SEO-critical elements: |
| 20 | |
| 21 | | Element | Field | Source | |
| 22 | |---------|-------|--------| |
| 23 | | Title tag | `title` | `parse_html.py` | |
| 24 | | Meta description | `meta_description` | `parse_html.py` | |
| 25 | | Canonical URL | `canonical` | `parse_html.py` | |
| 26 | | Robots directives | `meta_robots` | `parse_html.py` | |
| 27 | | H1 headings | `h1` (array) | `parse_html.py` | |
| 28 | | H2 headings | `h2` (array) | `parse_html.py` | |
| 29 | | H3 headings | `h3` (array) | `parse_html.py` | |
| 30 | | JSON-LD schema | `schema` (array) | `parse_html.py` | |
| 31 | | Open Graph tags | `open_graph` (dict) | `parse_html.py` | |
| 32 | | Core Web Vitals | `cwv` (dict) | `pagespeed_check.py` | |
| 33 | | HTTP status code | `status_code` | `fetch_page.py` | |
| 34 | | HTML content hash | `html_hash` (SHA-256) | Computed | |
| 35 | | Schema content hash | `schema_hash` (SHA-256) | Computed | |
| 36 | |
| 37 | --- |
| 38 | |
| 39 | ## How Comparison Works |
| 40 | |
| 41 | The comparison engine applies **17 rules across 3 severity levels**. Load |
| 42 | `references/comparison-rules.md` for the full rule set with thresholds, |
| 43 | recommended actions, and cross-skill references. |
| 44 | |
| 45 | ### Severity Levels |
| 46 | |
| 47 | | Level | Meaning | Response Time | |
| 48 | |-------|---------|---------------| |
| 49 | | **CRITICAL** | SEO-breaking change, likely traffic loss | Immediate | |
| 50 | | **WARNING** | Potential impact, needs investigation | Within 1 week | |
| 51 | | **INFO** | Awareness only, may be intentional | Review at convenience | |
| 52 | |
| 53 | --- |
| 54 | |
| 55 | ## Storage |
| 56 | |
| 57 | All data is stored locally in SQLite: |
| 58 | |
| 59 | ``` |
| 60 | ~/.cache/claude-seo/drift/baselines.db |
| 61 | ``` |
| 62 | |
| 63 | ### Tables |
| 64 | |
| 65 | - **baselines**: Captured snapshots with all SEO elements |
| 66 | - **comparisons**: Diff results with triggered rules and severities |
| 67 | |
| 68 | URL normalization ensures consistent matching: lowercase scheme/host, strip |
| 69 | default ports (80/443), sort query parameters, remove UTM parameters, strip |
| 70 | trailing slashes. |
| 71 | |
| 72 | --- |
| 73 | |
| 74 | ## Command: `baseline` |
| 75 | |
| 76 | Captures the current state of a page and stores it. |
| 77 | |
| 78 | **Steps:** |
| 79 | 1. Validate URL (SSRF protection via `google_auth.validate_url()`) |
| 80 | 2. Fetch page via `scripts/fetch_page.py` |
| 81 | 3. Parse HTML via `scripts/parse_html.py` |
| 82 | 4. Optionally fetch CWV via `scripts/pagespeed_check.py` (use `--skip-cwv` to skip) |
| 83 | 5. Hash HTML body and schema content (SHA-256) |
| 84 | 6. Store snapshot in SQLite |
| 85 | |
| 86 | **Execution:** |
| 87 | ```bash |
| 88 | claude-seo run drift_baseline.py <url> |
| 89 | claude-seo run drift_baseline.py <url> --skip-cwv |
| 90 | ``` |
| 91 | |
| 92 | **Output:** JSON with baseline ID, timestamp, URL, and summary of captured elements. |
| 93 | |
| 94 | --- |
| 95 | |
| 96 | ## Command: `compare` |
| 97 | |
| 98 | Fetches the current page state and diffs it against the most recent baseline. |
| 99 | |
| 100 | **Steps:** |
| 101 | 1. Validate URL |
| 102 | 2. Load most recent baseline from SQLite (or specific `--baseline-id`) |
| 103 | 3. Fetch and parse current page state |
| 104 | 4. Run all 17 comparison rules |
| 105 | 5. Classify findings by severity |
| 106 | 6. Store comparison result |
| 107 | 7. Output JSON diff report |
| 108 | |
| 109 | **Execution:** |
| 110 | ```bash |
| 111 | claude-seo run drift_compare.py <url> |
| 112 | claude-seo run drift_compare.py <url> --baseline-id 5 |
| 113 | claude-seo run drift_compare.py <url> --skip-cwv |
| 114 | ``` |
| 115 | |
| 116 | **Output:** JSON with all triggered rules, old/new values, severity, and actions. |
| 117 | |
| 118 | After comparison, offer to generate an HTML report: |
| 119 | ```bash |
| 120 | claude-seo run drift_report.py <comparison_json_file> --output drift-report.html |
| 121 | ``` |
| 122 | |
| 123 | --- |
| 124 | |
| 125 | ## Command: `history` |
| 126 | |
| 127 | Shows all baselines and comparisons for a URL. |
| 128 | |
| 129 | **Execution:** |
| 130 | ```bash |
| 131 | claude-seo run drift_history.py <url> |
| 132 | claude-seo run drift_history.py <url> --limit 10 |
| 133 | ``` |
| 134 | |
| 135 | **Output:** JSON array of baselines (newest first) with timestamps and comparison summaries. |
| 136 | |
| 137 | --- |
| 138 | |
| 139 | ## Cross-Skill Integration |
| 140 | |
| 141 | When drift is detected, recommend the appropriate specialized skill: |
| 142 | |
| 143 | | Finding | Recommendation | |
| 144 | |---------|----------------| |
| 145 | | Schema removed or modified | Run `/seo schema <url>` for full validation | |
| 146 | | CWV regression | Run `/seo technical <url>` for performance audit | |
| 147 | | Title or meta description changed | Run `/seo page <url>` for content analysis | |
| 148 | | Canonical changed or removed | Run `/seo technical <url>` for indexability check | |
| 149 | | Noindex added | Run `/seo technical <url>` |