Proactive and schedule-driven; read-only against the public web, with a single
Slack channel as the only output.
Step 0 — Orient and resume
cat .kortix/memory/competitor-watch-log.md 2>/dev/null || echo "(no ledger yet — first run)"
Read the last snapshot recorded for each tracked page. If this is the first
run ever, there is nothing to diff against — fetch, store the snapshot, and
skip reporting (nothing to compare yet).
Step 1 — Load the watch list
The watch list lives in {{watch_list}} (competitor name → URL, one per line,
e.g. Acme — pricing: https://acme.com/pricing). Treat it as the source of
truth for exactly which pages to fetch this run — no more, no less.
Step 2 — Fetch each tracked page
Fetch every URL in the watch list over plain HTTP(S) GET. No auth, no
credentials — these are public pages.
curl -sL --max-time 20 "$URL"
If a fetch fails (timeout, 404, page moved), note it in the ledger as a
blocker for next run rather than failing the whole sweep.
Step 3 — Normalize before comparing
Strip what varies without meaning anything: nav, footer, ads, timestamps,
session-specific query params, whitespace. Reduce each page to its meaningful
text content (main content area, changelog entries, pricing table rows)
before computing a diff or hash.
Step 4 — Diff against the last snapshot
Compare the normalized content to the snapshot stored in
.kortix/memory/competitor-watch-log.md for that URL. A byte-identical
normalized page is "no change" — move on without reporting it.
Step 5 — Filter cosmetic from meaningful
Not every text diff is worth a Slack message. Report:
- A pricing tier, price point, or plan name that changed.
- A new changelog entry or shipped feature.
- A rewritten headline, tagline, or positioning statement on a landing page.
Drop:
- Typo fixes, formatting, reflowed layout with the same words.
- Date/time stamps, view counts, or other page furniture.
- Reordering of existing content with no wording change.
When in doubt whether a diff is meaningful, err toward including it —
under-reporting defeats the point of the watch.
Step 6 — Compose and post the summary
One message to {{slack_channel}} per run:
- Something changed: a short bullet per meaningful change — competitor, what
changed, and the page it happened on. Keep it scannable, not a raw diff
dump.
- Nothing changed: a single brief line ("No meaningful competitor changes
today.") or skip the post entirely per the project's preference — never
post per-page "no change" noise.
Step 7 — Update the ledger
Update .kortix/memory/competitor-watch-log.md with today's normalized
snapshot for every fetched page (so the next run has something to diff
against) and a dated log line of what was reported or skipped.