Content Refresh Skill
Detects content decay, prioritizes refresh candidates, generates briefs, and tracks refresh effectiveness.
Universal rule: no company, domain, or GSC property is ever hardcoded. Everything client-specific comes from clients/<slug>/client.json and the client context. GSC is the PREFERRED signal source, never a prerequisite: the skill degrades gracefully through the signal cascade below.
Commands
| Command | Purpose |
|---|---|
/content-refresh <client> |
Dashboard: queue, recent refreshes, tracking |
/content-refresh scan <client> |
Run decay scan (manual trigger) |
/content-refresh queue <client> |
Show prioritized refresh queue |
/content-refresh <client> [url] |
Check specific URL's refresh status |
/content-refresh report <client> |
Effectiveness report |
Client Parameters (resolve FIRST)
From clients/<slug>/client.json: domain, url, gsc_property, language. Data reserve: clients/<slug>/data/ (crawl + DataForSEO baseline written by seo-collect). Outputs: clients/<slug>/outputs/refresh/.
Signal Sources (cascade, never abort)
| Priority | Source | Signals available | Condition |
|---|---|---|---|
| 1 | GSC, via seo-monitoring (outputs/monitoring/: latest gsc-*.json export, snapshots, history; direct gsc-mcp query ONLY if monitoring has never run) |
clicks, impressions, CTR, positions per page (the full detection) | GSC access connected for this client |
| 2 | DataForSEO (client's data reserve data/dataforseo/, or labs ranked_keywords/historical_rank_overview live) |
positions and their evolution per page | DataForSEO creds |
| 3 | Crawl heuristics (data reserve data/crawl/, or sitemap) |
age (lastmod), dated content (year in URL/title/body), thin pages, content-type schedules | always available |
Announce which sources are active at scan start. With source 3 only, the scan still produces a useful queue (age + dated-content + schedule triggers); score-based traffic detection is marked "pending GSC connection".
Division of labor with seo-monitoring: monitoring SUMMARIZES performance (what happened) and is the ONLY skill that fetches GSC; THIS skill analyzes what can be optimized. All optimization detection (decay scoring, stagnation, thresholds) is computed HERE, from the data monitoring deposits (outputs/monitoring/: gsc exports, snapshots, history.json). Never re-fetch what monitoring already deposited; never expect monitoring to pre-compute signals.
Workflow Overview
SCAN → DETECT → PRIORITIZE → SYSTEM/LEGACY CHECK → CLASSIFY → BRIEF ROUTING → QUEUE
Tools (harness-aware)
In Claude Code, load via ToolSearch at workflow start (per available source):
ToolSearch: "select:mcp__gsc-mcp__get_search_analytics" # source 1, ONLY if no monitoring export exists
ToolSearch: "select:mcp__gsc-mcp__get_search_by_page_query" # source 1, same condition
ToolSearch: "select:mcp__dataforseo__serp_organic_live_advanced" # optional, competitor positions
In other harnesses: use the equivalent tools if exposed. Existing-content crawl uses crawl4ai (POST /md), fallback WebFetch.
Fallbacks: GSC unavailable → drop to source 2, then 3 (NEVER abort). DataForSEO unavailable → source 3. crawl4ai unavailable → proceed without content-level baseline.
Stage 1: Scan
Input: the client's URL inventory, from the best available source:
- The latest monitoring export (
outputs/monitoring/gsc-*.json,pagessection) when present; otherwise direct GSC query (90 days + 30 days, 150 rows,site_url= client'sgsc_property) - Otherwise: the client's crawl reserve (
data/crawl/<date>/) or sitemap
Apply exclusion rules (see references/decay-thresholds.md): non-content subdomains, non-article paths, utility pages.
Stage 2: Detect
Two parallel detection paths:
Path A: Score-Based Detection (requires source 1 or 2)
For each URL, calculate decay score using weighted signals with guardrails.
Traffic calculation (GSC):
previous_30d_avg = (90d_total - last_30d) / 2
change_pct = (last_30d - previous_30d_avg) / previous_30d_avg * 100
Guardrails (skip signal if not met):
- Traffic drop: only if baseline ≥20 clicks/month
- Position drop: only if starting position ≤20
With source 2 only: position-based signals only (position drop, stagnation), no traffic signals. Full threshold details: references/decay-thresholds.md
Path B: Hard Triggers (works with source 3 alone)
Bypass scoring for:
- Age >12 months (crawl lastmod / publication date)
- Dated content: year in URL, title, or body data older than current year (e.g. a "[topic] 2024" page in 2026)
- Content-type schedules (comparison: quarterly, pricing: monthly, statistics: quarterly)
- Cluster trigger (the cluster's money page or pillar was refreshed)
Stage 3: Prioritize
Priority Score = (Traffic Value × 0.5) + (Decay Severity × 0.5)
Traffic Value factors: peak monthly clicks (40%), keywords ranking count (30%), conversion potential/intent (30%). Without traffic data (source 3 only): rank by business value of the cluster (money-page proximity per linking-clusters.md) + trigger severity.
Sort by priority score, take top N (default: 20).
Stage 4: Classify
4a. System/Legacy Detection (Pre-Check)
Determine whether the content was produced by this system or predates it:
- Extract the slug from the URL
- Search the client's outputs:
clients/<slug-client>/outputs/content/*/for a brief or article matching the slug - Match found → system content (prior brief + metadata exist)
- No match → legacy content (pre-system, no prior context)
Legacy is a flag, not a tier override: the decay score still determines the tier; legacy only changes the brief generation method.
4b. Tier Classification
| Tier | Trigger | System Content Action | Legacy Content Action |
|---|---|---|---|
| Auto-fix | Only broken links OR stale proof points | Direct edit, no brief | Direct edit, no brief |
| Partial Update | 50-69% decay OR age-only trigger | Refresh brief (refresh-brief-template.md) | /content-brief --refresh [url] |
| Full Rewrite | ≥70% decay | /content-brief --refresh [url] |
/content-brief --refresh [url] |
| Consolidation | Multiple thin/overlapping pages on one topic | /content-brief --refresh [url] + redirect plan |
/content-brief --refresh [url] + redirect plan |
Why legacy Partial Updates use full briefs: the thin refresh template assumes prior system context. Legacy content has none, so it benefits from the full research of /content-brief --refresh.
Stage 5: Generate Brief (Routing Fork)
Path A: Refresh Brief Template (Partial Update, system content only)
Template: references/refresh-brief-template.md. Refresh briefs include all fields Article-creator requires (keyword, format, word count, outline, CTAs, links) and can be fed directly to /article-create.
Path B: Full Brief via Content Brief Creator (Full Rewrite, Consolidation, Legacy Partial Update)
Invoke /content-brief --refresh [url] (full 11-stage workflow with refresh modifications: skips cannibalization, crawls existing article as baseline, dual info-gain comparison, reuses slug, appends Refresh Context). See Content-brief-creator/SKILL.md.
Path C: Auto-fix (no brief)
Direct edits: replace broken links; update stale proof points from the CLIENT's context/proof-points.md (never from any other source). Log changes to outputs/refresh/auto-fixes.log.
Stage 6: Refresh Queue (orchestrator handoff)
Write the prioritized queue to clients/<slug>/outputs/refresh/queue.json, one entry per candidate:
{
"url": "...",
"slug": "...",
"refresh_tier": "partial_update",
"is_legacy": false,
"decay_score": 65,
"signal_sources": ["gsc"],
"baseline_metrics": { "position": 8, "clicks_30d": 450 },
"decay_signals": ["position_drop", "age"],
"brief_method": "refresh_template"
}
brief_method values: "refresh_template" | "full_brief_refresh" | "auto_fix".
The queue is the handoff point for whatever orchestrates the pipeline (human, or an orchestrator agent). This skill does not manage a board. Downstream flow: BRIEF → REDACTION → QA (Content-quality-evaluator) → PUBLISH.
Stage 7: Track Effectiveness
Capture baseline at refresh completion, snapshot at T+30/T+60/T+90 (requires source 1 or 2; with source 3 only, mark tracking "pending GSC connection").
Categories: Recovery (≥+10%), Stable (-10% to +10%), Failed (≤-10%).
Save to clients/<slug>/outputs/refresh/tracking.json.
Output Files (per client)
| File | Purpose |
|---|---|
clients/<slug>/outputs/refresh/scan-YYYY-MM-DD.json |
Scan results |
clients/<slug>/outputs/refresh/queue.json |
Current prioritized queue |
clients/<slug>/outputs/refresh/tracking.json |
Effectiveness tracking |
clients/<slug>/outputs/refresh/auto-fixes.log |
Minor auto-fixes log |
clients/<slug>/outputs/content/<date>/content-brief-[slug]-refresh-*.md |
Refresh briefs (via CBC) |
Stagnation Signal
Computed by the scan from the monitoring history (outputs/monitoring/history.json, positions over time) or GSC data. Content stable at position 7+ for 60+ days warrants optimization investigation:
| Position | Action |
|---|---|
| #7-10 stable | Flag for SERP analysis |
| #11-15 stable | Flag for optimization |
| #16-20 stable | Lower priority, monitor |
Investigation checklist: what do #1-6 have that this page doesn't? Missing sections? E-E-A-T gaps? Missing SERP features (FAQ, video)?