A Claude Code skill and slash command that catches when a fact you cite has changed at the source, verifies your local citation still matches the baseline, shows you what is now out of date, and fixes scoped files once you approve.
Most page monitors stop at "this page changed." fact-drift reads the actual value, checks the files where you cite it, and updates approved stale citations after you sign off.
Your content quotes numbers from other people's websites: a government limit, a quota, a price, a deadline. Those numbers change, and nobody tells you. The source page updates, your article does not, and you find out when a reader does. Tools that watch pages can say "this page changed," but they cannot tell you the number went from 60 to 80, or which of your files now needs fixing.
Anywhere your content repeats a fact that lives on a page you do not control:
- Help guides and knowledge bases that quote government rules, fees, or deadlines, like visa, tax, or benefits guides. When a threshold changes, the skill flags the guide and offers to fix it.
- Developer docs that pin versions ("requires Node 20+", "tested on Python 3.12"). Keep install and compatibility notes in step with upstream releases.
- Pricing and comparison pages that cite a competitor's price or plan limits. When they change their pricing, your "X vs Y" page stops being quietly wrong.
- Compliance and policy pages that track regulations: tax rates, minimum wage, filing deadlines, reporting limits.
- Affiliate and review roundups that cite specs, prices, or ratings from product pages, the kind that goes stale the moment a product changes.
- API and integration docs that reference a third party's rate limits, endpoints, or end-of-life dates.
A run that catches a change looks like this:
# fact-drift snapshot, 2026-05-28
| Target | Status | Current | Baseline |
| python-latest-stable | OK | 3.14.5 | 3.14.5 |
| node-latest-stable | DRIFT | 26.1.0 | 24.9.0 |
| kubernetes-latest-stable | OK | 1.36.1 | 1.36.1 |
DRIFT node-latest-stable 24.9.0 -> 26.1.0
Found "24.9.0" in 2 files:
docs/install.md:12
README.md:40
Update both to "26.1.0"? [y/n]
Install as a plugin (recommended). In Claude Code:
/plugin marketplace add https://github.com/hwajongpark/fact-drift
/plugin install fact-drift@fact-drift
Or install as a standalone skill:
git clone https://github.com/hwajongpark/fact-drift
cp -r fact-drift/skills/fact-drift ~/.claude/skills/fact-drift
mkdir -p ~/.claude/commands
cp fact-drift/commands/fact-drift.md ~/.claude/commands/fact-drift.mdThen point it at your sources and run it:
# Copy the example config from the repo into your project, then add your targets
cp examples/rules.config.example.json ./rules.config.json
# Capture a baseline (first run)
/fact-drift --update-baseline
# Later, check for drift
/fact-driftYou give it a list. Each item is one fact: the web page it lives on, a plain-English note for what to pull ("find the latest version number"), and the files where you cite it.
When it runs, it opens each page, extracts the value with an exact source quote, compares the value to what it saw last time, and checks that your configured citation files still contain the expected value. If something changed, it shows you the old value, the new value, the source quote, and every scoped file that still has the old one. You check that list, and if it looks right, it updates the approved matches. Nothing changes until you say yes.
Under the hood it checks all the pages at once, so a long list still finishes fast.
One entry per fact. The included examples/rules.config.example.json tracks the latest stable versions of Python, Node.js, and Kubernetes, so it runs out of the box.
{
"targets": [
{
"id": "python-latest-stable",
"name": "Python latest stable release",
"url": "https://en.wikipedia.org/wiki/Python_(programming_language)",
"extract": "From the infobox, return the latest stable release version of Python. Return only the version string.",
"citation_files": ["docs/requirements.md"],
"notes": "Our setup docs pin a minimum Python version; bump them when a new stable lands."
}
]
}Want a real-world example? examples/advanced-korea-gov.config.json tracks Korean government pages. Some of those need a full browser, so it also shows how the skill handles pages it cannot read.
Plain words, not code, to find the value. I tell it what to look for in plain English, like "find the latest version number." The other option is to point at an exact spot in the page's code. That is faster, but it breaks the moment someone redesigns the page, even when the number is still sitting right there. Plain words keep working through a redesign. Worth the small extra cost.
It remembers the last value, so it can spot a change. To know a number changed, you have to know what it was before. The first run writes down each value, where it found it, and the exact source quote. Every run after that compares now against last time. No memory, no way to catch a change. In CI, commit fact-drift-baseline/ or restore it before running the check.
It checks your content even when the source has not changed. A source can still match the baseline while your docs drifted by hand. OK means the upstream value matches the baseline and your configured citation scope still contains that value.
It does the fixing, you do the deciding. The point is not to hand you a to-do list, it is to do the boring work. When a value changes, it finds stale matches in the citation scope, prepares the edits, and applies them once you approve. It does the finding and the typing; you make the call.
It always shows the plan before it touches anything. Nothing changes until you have seen exactly what will change. A number like "60" can mean five different things across your files, and you are the one who knows which should actually update. So it searches the configured citation scope, shows you every match first, and lets you drop the ones that should stay.
It runs free on Claude Code. It uses the Claude Code plan you already have, so every check costs nothing and anyone with Claude Code can run it. The catch: it reads pages the simple way, so pages that need a full browser (heavy JavaScript, logins) will not work, and it says so plainly. Most pages are fine.
The trick is not the check, it is everything around it. Honestly, underneath this is just "go read a page," something you could do by hand. What makes it useful is the rest: a fixed list so you never forget a number, a saved history so it can spot changes, scoped edits after approval, and a check you can put on a schedule so drift gets caught without you remembering. It turns "remember to check this and fix it where cited" into a single yes.
fact-drift is a command, so you schedule it the way you schedule any command: point a timer at it. A weekly GitHub Action that runs the check and fails if any target is NEW, DRIFT, ERROR, or CONTENT_MISMATCH:
# .github/workflows/fact-drift.yml
name: fact-drift
on:
schedule:
- cron: "0 8 * * 1" # 08:00 UTC every Monday
workflow_dispatch: {}
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Requires committed fact-drift-baseline/ files, or a previous step that restores them.
# Runs Claude Code headlessly; see Claude Code's headless/CI docs for auth.
- run: npx @anthropic-ai/claude-code -p "/fact-drift --ci"Two things to know before you rely on it:
- Schedule the check, approve the fixes. fact-drift never edits a file without showing you the plan first, so an unattended run detects drift and fails/reports it; you run
--applyto approve the edits. Fixing a target hands-off is a choice you make per target, not the default. - Keep the baseline available to CI. If CI starts without
fact-drift-baseline/, targets areNEW, not verified. Commit the baseline directory or restore it before the check. - Only pages that load as plain text are good schedule targets. A page behind heavy JavaScript or a login returns ERROR on the cheap path. Schedule the targets that fetch cleanly; for the JS-walled ones, run a real browser (a separate path) or schedule a staleness reminder and re-check them by hand.
- It does not change anything without your approval. You see every edit before it touches a file, and you can drop any of them.
- It does not handle pages behind a login, or pages that need heavy JavaScript to load. If a page will not load as plain text, that target reports ERROR and needs a real browser, which is a separate path.
- It does not commit to git. It edits the files and updates the baseline; committing is yours.
- It does not treat an unreadable page as a valid baseline.
NOT_FOUNDandERRORfail closed.
Contributions are welcome. Bug reports (a page it misreads) and useful real-world target configs help most. If you have a config for a public source worth tracking, a pull request adding it alongside examples/advanced-korea-gov.config.json gives the next person a head start.
