source-watch
Local, deterministic change-monitoring for the web sources your agent depends on. (init/check a sources.yml; flags content/title/new/gone changes, HIGH on watch keywords.)
- Stars
- 0
- Language
- Python
- Created
- Jul 30, 2026
- Updated
- Jul 30, 2026
Introduction
source-watch
Local, deterministic change-monitoring for the web sources your agent depends on.
本地的、确定性的「信源变更监控」工具:给 Agent 一份信源清单,
init建基线,check精准报告「哪些信源变了、正文改了哪几段、是否命中你关心的关键词、哪些 404 了」。

Before / After
Before — Your agent quotes an external page (library changelog, rival pricing, API docs, a regulation page) but has no idea it changed. It either re-fetches the whole noisy page every time (slow, buried in nav/ads/timestamps) or answers from stale context.
After — You keep a sources.yml. source-watch tells the agent exactly what
moved, in a diff it can parse, and flags the changes you care about as HIGH.
No more guessing whether the page is current.
What it does
init— baseline every source: noise-reduced body text + title + fingerprint.check— re-fetch and classify each source ascontent/title/new/gone.- Noise reduction — strips
script/style/nav/footer/header, optional CSSselector, defaults to the longest text block. - Severity — any change whose text matches a
watchkeyword/regex is flagged HIGH. - Output —
WATCH_REPORT.md(human) +watch-state.json(machine-readable baseline and last report, so an agent can read it directly). - Offline-friendly —
file://sources and a pure-stdlib fetcher; zero third-party dependencies.
Install
Clone into your agent's skills directory. No pip install required.
Codex
git clone https://github.com/whaojie797-design/source-watch ~/.codex/skills/source-watch
Claude Code
git clone https://github.com/whaojie797-design/source-watch ~/.claude/skills/source-watch
Cursor
git clone https://github.com/whaojie797-design/source-watch ~/.cursor/skills/source-watch
Quick start
# 1. describe what to watch
cp sources.example.yml sources.yml
# edit urls / selectors / watch keywords
# 2. baseline
python scripts/watch.py init --config sources.yml --store .watchstore
# 3. later: what changed?
python scripts/watch.py check --config sources.yml --store .watchstore
# 4. acknowledge the change and re-baseline
python scripts/watch.py check --config sources.yml --store .watchstore --update
sources.yml:
sources:
- name: next-changelog
url: https://nextjs.org/changelog
selector: "main article"
watch:
- "breaking"
- "deprecat"
- name: rival-pricing
url: https://example.com/pricing
watch: ["price", "plan"]
Sample report (real)
$ python scripts/watch.py init --config sources.yml --store .ws
[BASE] next-changelog — 124 chars, fingerprint 2b299333df8099b6
[BASE] rival-pricing — 88 chars, fingerprint 7c1ae0b4f2c9d3e1
[BASE] acme-docs — 220 chars, fingerprint 9412af520f24141e
Baseline saved: .ws/watch-state.json (3 sources)
$ python scripts/watch.py check --config sources.yml --store .ws
[HIGH] next-changelog — content — matched: breaking
[OK] rival-pricing — unchanged
[UNREACHABLE] acme-docs — file not found: .../simple.html
3 sources watched · 1 changed · 1 HIGH · 1 unreachable
WATCH_REPORT.md (excerpt):
## HIGH
### next-changelog — content
- url: file:///.../changelog.html
- matched: breaking
- diff:
@@
- Fix: improved caching for static assets.
+ BREAKING: removed legacy config format, migrate before upgrading.
How it works
- Fetch each
url(urllibfor http(s), direct read forfile://). - Extract body text with
html.parser, dropping noise tags; optionalselectornarrows the region, with silent full-document fallback if it matches nothing. - Hash the normalized body →
fingerprint. Compare to the baseline. - Classify the delta and, if
watchpatterns hit, raise severity to HIGH. - Write
WATCH_REPORT.md+ updatewatch-state.json(baseline + last report).
Everything is deterministic and offline-capable; the test suite runs entirely
against local file:// fixtures.
Limitations
- It compares fetched, extractable text. Pages that render content purely via
JavaScript (no server HTML) need a pre-rendered snapshot or a
selectorover static markup. file://sources are great for offline docs and tests, but can't see live sites.- The "longest text block" heuristic is a reasonable default, not a full reader; use
selectoron noisy pages for precision. watchmatches on the new body text only (not the diff) — keep patterns specific.
License
MIT © 2026 whaojie797-design