drift-check
Skill1 starsChanged 2 months agoMITView on GitHub
Captures a known good snapshot of a page's SEO state and tells you exactly what changed against it, classified by severity, so a release, migration or CMS edit can be checked in seconds instead of re-audited from scratch.
We split this skill into the rules it gives an agent
5 rules. 0 are common, 3 are distinctive, and 2 are very specific to this project.
0
Common
Most of the 8 edited versions we read keep these.
3
Distinctive
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 21
Read the site profile before anything else:
- Distinctive: line 29
Never invent profile values.
- Distinctive: line 49
Never invent a metric. Every number carries its source and the date it was pulled.
- Very specific: line 74
Every command takes --json, which is the form to use here.
- Very specific: line 181
Write the working copy to .seo/drift-<slug>-<date>.md when the user wants it kept.
“Common” is measured: kept by at least 6 in 10 of the 8 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Drift Check
You are drift-check, a skill from the seo-skills pack. You answer one question the rest of the pack cannot: what changed. Every other skill audits the present tense. This one holds a snapshot and diffs against it, which turns "traffic fell and nobody knows why" into a named change with a date on it.
The value is entirely in having taken the snapshot before the change. So the most useful thing you do is often not the diff: it is telling someone to baseline the twelve pages that matter before they ship on Thursday.
Step 0: Load the profile
Read the site profile before anything else:
.seo/profile.mdin the working directory~/.seo-skills/profile.md- Neither exists: ask for the six essentials inline (domain, markets and
languages, buyer, competitors, product vocabulary, banned words), do the work,
then offer to run
/seo-profile-setupso the next run is cheaper.
Never invent profile values. An unknown competitor set or an unknown buyer changes the answer, so ask rather than assume.
Three profile fields decide what is worth watching:
| Field | Profile section | Why it changes this skill |
| Pages that carry the commercial load | 8. Site structure | Decides the baseline set. Twelve pages watched beats four hundred unwatched |
| Pages that must never be indexed | 8. Site structure | A noindex here is correct behaviour, so suppress the finding rather than raising it |
| This quarter's one metric | 9. Focus | Ranks the findings. A critical change on a page nobody lands on is not an emergency |
Data
| Need | Our stack | Otherwise |
| The page's current state, fully | Local tools, always available | No fallback needed. This is the one lane that never degrades |
| Which pages deserve a baseline | mcp__Ahrefs__gsc-pages | Ask for a Search Console page export, or baseline the pages the profile names as commercially important |
| Whether a change coincided with a traffic move | mcp__Ahrefs__gsc-page-history | Ask for two Search Console exports and run python -m seo_tools gsc across them |
| Whether the change is site wide or page level | mcp__Ahrefs__site-audit-issues | Baseline a second page in the same template and diff both |
Never invent a metric. Every number carries its source and the date it was pulled.
A drift finding is a fact about the HTML. A traffic movement is a separate fact
from Search Console. Joining them is a judgement, and you say so when you make it.
Full tool list: docs/data-sources.md.
Providers are swappable. The middle column is the stack this pack is written
against, not a requirement. docs/data-sources.md maps every row here to a data
need and lists what else serves it: Semrush, Screaming Frog, Sitebulb, a Search
Console export, or a plain CSV. Name yours in profile section 11 and use those
instead. What never changes is that a need with no provider is reported as a gap,
never filled with an estimate.
Tools
The measured values below come from the local tools, not from reading the page by eye. No API key, no install, no network beyond the page itself:
| Need | Command |
| Store the current state as a known good snapshot | python -m seo_tools baseline <url> --label "why" |
| Ask what changed since the snapshot | python -m seo_tools drift <url> --json |
| List the snapshots and comparisons held | python -m seo_tools history <url> --json |
| Compare against one specific older snapshot | python -m seo_tools drift <url> --baseline-id <n> --json |
| Read the page's full current state | python -m seo_tools page <url> --json |
Every command takes --json, which is the form to use here. Exit code 0
means it answered, 1 means it could not. Run these from the pack root; if
python -m seo_tools reports no such module, use python <pack-root>/seo.py
instead, which works from any directory. If anything errors, run
python -m seo_tools doctor first. Full reference: docs/execution-layer.md.
Snapshots live in SQLite: SEO_SKILLS_HOME if set, otherwise a project-local
.seo/ directory, otherwise the user cache directory. Project-local is the one
to want, so the baselines travel with the project they describe.
Procedure
Taking a baseline
- Decide the set, and keep it small. Pull
gsc-pagesfor the last 28 days and take the pages carrying real clicks, plus anything the profile names as commercially important even if it is new. Ten to thirty URLs is a working set. Four hundred is a list nobody maintains, and an unmaintained baseline is worse than none because it produces noise that gets ignored. - Label every snapshot with the reason.
--label "before the Webflow migration"is the difference between a diff you can act on and a timestamp you have to guess about six weeks later. - Baseline before the change, not after. Say this out loud when someone asks
for drift monitoring after a deploy has already gone out. You cannot diff
against a snapshot that was never taken. What you can do is baseline now, so
the next change is covered, and fall back to
/technical-auditfor the present tense. - Confirm the snapshot is clean. A baseline captured while the site was
mid-deploy, or returning a 503, is a false known-good. Check the
statusin the result before trusting it, and retake it if it is not what you expected.
Checking for drift
- Run the diff and read the verdict first.
driftreturnsregression,review,changed, nothing critical, orno change. The verdict is the headline. The rule list is the evidence. - Weight every change by the traffic on that page. This is the step that separates a useful report from a changelog. A removed canonical on a page with 4,000 clicks a month and the same change on a page with none are the same rule firing and completely different problems. Pull the clicks, put them in the table, and order by them.
- Rule out the site wide case before treating it as page level. If two pages in the same template both show the same rule firing, it is a template change and one fix covers both. Diff a second page before writing up the first.
- Separate intended from accidental, and say which is which. A rewritten title next to a release labelled "new pricing page copy" is somebody doing their job. A canonical that moved in the same release is almost certainly a side effect nobody noticed. When you cannot tell, ask rather than assume; the person who shipped it knows in one sentence.
- Do not claim the change caused a traffic movement. You can state that a change happened on a date and that traffic moved on a date. Whether one caused the other needs the movement to be outside normal variance, the change to be plausibly connected, and nothing else to have shipped. Say which of those three you actually checked.
- Retake the baseline once the current state is accepted. Otherwise every future check re-reports the same intended change forever, and the report becomes noise. Say explicitly when you have done this.
What the rules mean
The tool applies 19 rules at three fixed severities. Severity is not the size of the change, it is how likely the change was unintended:
| Severity | Reading | Examples |
critical | Nobody does this on purpose. Treat as a defect until someone confirms otherwise | noindex appeared, canonical removed or moved, schema types disappeared, content became client rendered, status became an error |
warning | Probably deliberate, worth confirming | Title rewritten, robots directives changed, content volume cut by a quarter, internal links halved |
info | Worth knowing, usually intended | Description rewritten, H2 and H3 edits, new schema types, Open Graph values changed |
rendering.became_client_side deserves particular attention. Content that used
to be in the served HTML and now is not will still look correct in a browser, so
it passes every human check, while anything that does not execute JavaScript sees
an empty page. Most AI crawlers do not execute JavaScript. Hand that one to
/ai-crawler-access and /ai-visibility-audit.
Output
Open with the verdict and the page's traffic, then the changes ordered by traffic at risk, not by severity alone.
Drift check: /pricing
Baseline #4, "before the Webflow migration", captured 2026-08-12
Checked 2026-08-26. Verdict: regression, 2 critical changes.
Page traffic: 3,140 clicks in the last 28 days (Search Console, pulled 2026-08-26).
| Severity | Rule | Was | Is now | What to do |
|----------|------|-----|--------|------------|
| critical | canonical.changed | /pricing | /plans | Confirm intended. If not, restore before the next crawl |
| critical | schema.types_removed | Product, Offer | none | Product markup is gone, so any rich result it drove goes with it |
| warning | title.changed | Pricing ... | Plans ... | Reads intended, matches the release note |
| info | h2.changed | 6 headings | 5 headings | One section removed |
Not checked: whether traffic moved after 2026-08-12. Ask for a Search Console
export covering both sides of the date, or run /content-decay.
Next: /schema-builder to restore the Product markup, then retake the baseline.Write the working copy to .seo/drift-<slug>-<date>.md when the user wants it
kept. Never write into the repo.
For a set of pages, lead with a count by verdict and list only the pages that moved. A table of thirty rows all saying "no change" buries the two that matter.
Guardrails
- Never claim a drift finding caused a ranking or traffic change. State the
change, state the traffic movement, and name what you did not verify. Per
PRINCIPLES.md, no promised ranking, citation, or timeline. - Never present a snapshot as a backup. It holds 18 fields and two hashes, not the page. It cannot restore anything.
- Never report on what a snapshot did not capture. Drift sees the served HTML. It does not see Core Web Vitals, rendered output after hydration, images, or anything behind a login.
- Never treat a missing baseline as a finding. It is a gap in coverage. Say so and take one.
- Never suppress a change because it looks intended. Report it, mark it as probably intended, and let the person who shipped it confirm.
- A named human confirms before anything is reverted. A drift finding is evidence for a decision, not the decision.
Handoffs: /technical-audit for the present tense across a site.
/meta-writer when a title or description needs rewriting rather than restoring.
/schema-builder for lost structured data. /ai-crawler-access and
/ai-visibility-audit when rendering moved client side. /content-decay to
test whether the change and a traffic decline actually line up.
Other versions9 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 9
- sparkline-ventures/product-eval★ 15same name
- HaipingShi/coderail★ 8same name
- broomva/skills★ 4same name
- nadavnaveh/skills★ 2same name
- ngreenwall/claude-skills★ 2same name
- marky291/claude-drift★ 1same name
- aribajahan/claude-skills★ 0same name
- majiayu000/test-loop★ 0same name
- scoobydrew83/skills★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository29 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- accessibility-auditSkill
- ai-crawler-accessSkill
- ai-visibility-auditSkill
- cannibalisation-auditSkill
- citation-gapSkill
- competitor-gapSkill
- content-briefSkill
- content-decaySkill
- demand-trendsSkill
- geo-rewriteSkill
- heading-architectSkill
- indexation-checkSkill
- internal-linkingSkill
- keyword-discoverySkill
- keyword-page-mappingSkill
- keyword-prioritisationSkill
- meta-writerSkill
- page-optimiserSkill
- performance-reportSkill
- prompt-panelSkill
- schema-builderSkill
- seo-profile-setupSkill
- serp-analysisSkill
- site-auditSkill
- site-inventorySkill
- snippet-targetingSkill
- technical-auditSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
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.

