/semrush-baseline — SEMrush quarterly snapshot
Pulls a refreshed SEMrush snapshot for a given site and writes it as sites/{site}/semrush-baseline-YYYY-MM-DD.md for trend comparison over time. The 7th skill in the toolkit — targeted by the 3 quarterly-semrush-baseline cron entries in .claude/schedules.yml.
Inputs
Required (asked at start if not given):
- Site — must match a folder under
sites/[name]/. The skill reads itssite-info.mdKeyword tool default + SEMrush Position Tracking campaign ID.
Optional:
--cronflag — cron mode (no AskUserQuestion; escalate to_inbox/on errors).
Workflow
Step 0 — Cron-mode detection (if invoked with --cron)
If the invocation contains --cron, this skill runs in cron mode (no user available). Required behavior:
- Idempotency check: if
sites/{site}/semrush-baseline-YYYY-MM-DD.mdfor today already exists, exit cleanly withexit: "idempotent-skip". - Escalation contract: any decision that would normally prompt the user (missing site-info, SEMrush API errors that persist, missing API key) MUST be escalated by writing an item to
sites/{site}/_inbox/viascripts/lib/cron-mode.mjswriteInboxItem(...)and exiting withexit: "escalated". Do NOT useAskUserQuestionin cron mode. - Defaults: when a choice would normally be asked, default to
site-info.mdvalues. If site-info is silent, escalate per (2). - Audit log: ALWAYS write one line to the audit log on exit — success (
shipped), escalation (escalated), idempotent skip (idempotent-skip), or failure (failed). - Backoff: at the start of every cron-mode run, call
checkBackoff({ routine })fromscripts/lib/audit-log.mjs. If true, the routine has hit the 3-strike threshold — write_inbox/routine-disabled-{site}-quarterly-semrush-baseline.md, runscripts/sync-schedules.mjs --pause-routine={site}-quarterly-semrush-baseline, and exit.
Step 1 — Read context
CLAUDE.mdsites/{site}/site-info.md— Keyword tool + SEMrush Position Tracking campaign IDsites/{site}/notes.mdCurrent state- Previous baseline (if any) — most recent
sites/{site}/semrush-baseline-*.mdfor comparison
If site-info.md Keyword tool (default) is not SEMrush (case-insensitive), skip with exit: "idempotent-skip" and audit log entry "site not configured for SEMrush."
If SEMRUSH_API_KEY is not set in .env, escalate to _inbox/ and exit.
Step 2 — Pull SEMrush data
Via scripts/semrush.mjs helper (if exists) or direct SEMrush API:
- Domain overview (
domain_ranksendpoint): Authority Score (AS), organic traffic, organic keywords count, paid traffic, total backlinks - Top 10 organic keywords (
domain_organicendpoint): sorted by position × volume - Top 5 organic competitors (
domain_organic_organicendpoint) - Position Tracking campaign delta (if campaign ID present in site-info): current rankings vs. previous fetch
Step 3 — Write baseline file
Save to sites/{site}/semrush-baseline-YYYY-MM-DD.md:
# SEMrush baseline — {site} — YYYY-MM-DD
routine_version: 1.0
Generated: YYYY-MM-DDThh:mm:ssZ
## Overview
| Metric | Current | vs. previous baseline |
|---|---|---|
| Authority Score | N | ±N |
| Organic traffic / mo | N | ±N% |
| Organic keywords | N | ±N |
| Backlinks (total) | N | ±N |
| Referring domains | N | ±N |
## Top 10 organic keywords
| Rank | Keyword | Volume | Position | URL |
| ... |
## Top 5 organic competitors
| Domain | Common kws | Competition % | AS |
| ... |
## Position Tracking campaign delta
(if campaign ID present in site-info.md)
| Keyword | Position now | Position last quarter | Δ |
| ... |
## Notable changes vs. previous baseline
- {one-line summary of biggest moves, e.g., "AS 0 → 5 (+5)"}
- {ranking moves >5 positions}
- {keyword count delta}
## Notes
Cron next fire: {next Q-start date from schedules.yml}
Step 4 — Update site-info.md Backlinks section
In cron mode: append a one-line note to the ## Backlinks (snapshot) section with the new date + AS + RD count. Do NOT overwrite existing content; this is an append-only audit trail.
Step 5 — Audit log
Call appendRun({ routine: "{site}-quarterly-semrush-baseline", routineVersion: "1.0", site, durationSec, exit: "shipped", filesTouched: [baseline-file-path, "sites/{site}/site-info.md"], escalations: [] }).
Call recordSuccess({ routine: "{site}-quarterly-semrush-baseline" }).
Routine versioning + idempotency contract
This skill participates in cruise-control via --cron mode. When invoked by cron:
Stamp
routine_versionin every output (semrush-baseline-YYYY-MM-DD.mdfrontmatter line + audit log line +_inbox/item frontmatter if escalating). Currentroutine_version: 1.0.Idempotency: safe to run twice on the same day — if today's
semrush-baseline-YYYY-MM-DD.mdexists, exit withidempotent-skip. SEMrush API costs apply per call, so this matters.
Reference: docs/specs/2026-05-16-agents-cruise-control-design.md § Operational hardening O3.
Refusal conditions
- Site folder doesn't exist
site-info.mdmissingKeyword toolin site-info is notSEMrushSEMRUSH_API_KEYmissing in.env- (Cron mode only) backoff threshold reached — auto-pause + exit per Step 0