Triage
Score every site in `sites/` by SEO opportunity and recommend the top 3 to focus investment on. Considers revenue potential, current authority, technical health, content gap, and conversion potential. Outputs a ranked list with rationale. Use when the user types `/triage` or asks "which sites should I focus on."From its SKILL.md
npx -y skills add mkreindel/seo-toolkit-template --skill triageAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
4 things to look at
- skips confirmationTells the agent to proceed without asking first, 1 time: "when a choice would normally be asked, default to `site-info.md` / `goals.md` values".
- reads credentialsReads from 1 credential source: `GSC_OAUTH_REFRESH_TOKEN`.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 1 command, including `scripts/sync-schedules.mjs --pause-routine={name}`.
SKILL.md
10.3 KB, ~2.6k tokens by cl100k_base, as published. Nobody here has run it
/triage — Portfolio prioritization
Helps the user pick which sites in their portfolio deserve SEO investment this quarter. With 20+ managed sites and limited time, this is the highest-leverage decision.
Inputs
Optional:
- Time horizon —
quarter(default),month,year. Adjusts how forward-looking opportunities are weighted. - Capacity — number of sites the user can realistically focus on (default: 3).
- Filter — optionally limit to sites matching a tag in
notes.md(e.g., "client-work", "personal", "high-revenue").
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: see this skill's "Routine versioning + idempotency contract" section. If today's output already exists, exit cleanly with
exit: "idempotent-skip". Write one line to the audit log viascripts/lib/audit-log.mjsappendRun({ exit: "idempotent-skip", ... }). -
Escalation contract: any decision that would normally prompt the user (missing required file, voice anti-AI failure, schema validation failure, keyword cannibalization, etc.) MUST be escalated by writing an item to
sites/{site}/_inbox/viascripts/lib/cron-mode.mjswriteInboxItem(...). After writing, exit cleanly withexit: "escalated". Do NOT useAskUserQuestionin cron mode. -
Defaults: when a choice would normally be asked, default to
site-info.md/goals.mdvalues. If both are silent on the required choice, 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-{name}.md, runscripts/sync-schedules.mjs --pause-routine={name}, and exit.
Step 1 — Read context (Rule 1)
Load every sites/[name]/site-info.md and notes.md. If any site is missing required files, flag it but don't fail.
Step 2 — Score each site on five dimensions
For each site, compute a score 0–10 on each dimension:
Dimension 1: Revenue potential (weight: 30%)
- 10 = real revenue source, money-keyword rankings would meaningfully grow income
- 7 = active business, ranking gains help but aren't transformative
- 4 = side project, lifestyle business, low monetization
- 1 = vanity site, internal tool, no revenue intent
Read from site-info.md → Business → "What they do" + Conversion → "What counts as a conversion" + recent revenue notes.
Dimension 2: Current authority (weight: 20%)
Score based on site-info.md SEO baseline:
- 10 = > 10K monthly organic visits, DR > 40, indexed > 500 pages
- 7 = 1K–10K visits, DR 20–40, indexed 100–500
- 4 = 100–1K visits, DR < 20, indexed 20–100
- 1 = new site, < 100 visits, < 20 pages indexed
Higher-authority sites compound faster — investment pays off sooner.
Dimension 3: Technical health (weight: 15%)
From most recent /audit results in site-info.md:
- 10 = all 8 non-negotiables pass, Lighthouse mobile ≥ 90, no Tier 1 gaps on top pages
- 7 = minor fixes needed (1–2 non-negotiables fail or floor < score < 90)
- 4 = significant gaps (CSR Lovable site without prerender, missing schema, Lighthouse < 70)
- 1 = fundamentally broken (no sitemap, blocked by robots, manual action, mostly thin content)
Critical filter: a site scoring 1 here gets prioritized for technical fixes regardless of other dimensions, because content investment is wasted on a broken foundation.
Dimension 4: Content gap / opportunity (weight: 20%)
- 10 = strong keyword research done (high-value keywords identified), competitors rank for terms this site doesn't, clear content path forward
- 7 = some opportunity, partial keyword research
- 4 = saturated niche or thin opportunity
- 1 = no opportunity (already #1 for everything relevant, or topic is dead)
Read from keywords.csv row count + competitor analysis in notes.md if present.
Dimension 5: Conversion potential (weight: 15%)
- 10 = clear conversion path documented (CTAs, form, booking system) + tracking working
- 7 = partial setup, conversions counted but not optimized
- 4 = weak CTAs, no tracking, no clear path
- 1 = no conversion infrastructure (rankings would generate traffic but no revenue capture)
Read from site-info.md → Conversion section.
Step 3 — Compute weighted score
Total = (Revenue × 0.30) + (Authority × 0.20) + (Technical × 0.15) + (ContentGap × 0.20) + (Conversion × 0.15)
Score range: 1.0 to 10.0.
Step 4 — Apply filters and special rules
- Critical technical issue (Dimension 3 = 1): site jumps to top of "fix first" list, separate from main ranking.
- Hard pause flag in
site-info.md: site removed from ranking entirely. - Filter argument: restrict ranking to sites matching the tag.
- Architecture gap (
SEO_GUIDE.mdSection 2.6): any site withservice-business: trueAND > 3 rows inservice-keywords.csvAND noarchitecture.mdgets an inline flag in its rationale:⚠️ Missing transactional architecture — required before next /service run.This doesn't change the score but surfaces the planning blocker so it's visible at the recommendation stage.
Step 4.5 — Compute goal-progress per site (T2-J)
For each site in sites/*:
- Read
sites/{site}/goals.md. Parse the## Success metricssection into a list of{metric, target}pairs. - For each metric, attempt to measure the current value:
- "Blog count: N+ new posts" → count entries in
used-keywords.mdshipped since quarter-start (parse the "Shipped — blog posts" section). - "Primary keyword rank: top-N for X" → if SEMrush API configured, query Position Tracking; otherwise mark
cannot-measure-automatically. - "Backlinks: ≥N total in Referring Domains" → if SEMrush API configured, query backlinks endpoint.
- "GSC indexed pages: ≥N" → query GSC API coverage endpoint (uses GSC_OAUTH_REFRESH_TOKEN).
- "Sitemap grows from N → M URLs" → diff live sitemap.xml count against the target.
- Free-text metrics (e.g., "GBP reviews: ≥5 by end of month") → mark
cannot-measure-automatically; user fills in monthly.
- "Blog count: N+ new posts" → count entries in
- Compute "% to target" where possible:
current / target * 100, clamped to 100% for the "exceeded" case. - Assign visual indicator:
- ✅ on track (>= 80%)
- ⚠️ behind (50–79%)
- ⏸️ off-track (< 50%)
- 🔵 exceeded (> 100%)
- ❓ cannot-measure-automatically (free-text or API unavailable)
Step 5 — Generate ranked list + rationale
Output format:
# Portfolio triage — [date]
**Capacity:** [N] sites | **Horizon:** [quarter/month/year]
## Fix-first (technical issues blocking content investment)
| Site | Score | Critical issue |
|------|-------|---------------|
| [name] | 1.0 (Dim 3) | [e.g., CSR Lovable site, no sitemap] |
## Top [N] for SEO investment this [horizon]
### 1. [site-name] — total score: [X.X]
- **Revenue potential:** [score]/10 — [one sentence rationale]
- **Authority:** [score]/10 — [details]
- **Technical:** [score]/10 — [recent audit summary]
- **Content gap:** [score]/10 — [keyword opportunity summary]
- **Conversion:** [score]/10 — [conversion infrastructure status]
- **Recommended next 3 actions:** [bulleted, specific — if `Architecture gap` flag is present, "Create `architecture.md` from `templates/architecture.md`" is action #1]
### 2. [site-name] — total score: [X.X]
[same structure]
### 3. [site-name] — total score: [X.X]
[same structure]
## Park (don't invest this [horizon])
[remaining sites, listed with one-sentence reason]
## Suggested cadence across the top 3
- **Site 1 (highest score):** [N posts/week + service pages + off-page actions]
- **Site 2:** [allocation]
- **Site 3:** [allocation]
Aggregate publishing across the 3 should fit the user's realistic weekly capacity.
## Goal-progress per site (T2-J)
For each site, list each goals.md success metric with current value and indicator:
### [site-name]
- ✅ Blog count: 5 / 8 posts (63%)
- ⚠️ Primary keyword rank: SEMrush API rate-limited this run (recheck next cycle)
- ⏸️ Backlinks: 3 / 7 (43%) — accelerate before quarter-end
- 🔵 GSC indexed pages: 18 / 17 (106% — exceeded)
- ❓ GBP reviews: 2 / 5 (free-text metric; manual verification)
Step 6 — Save results
Write to triage-[YYYY-MM-DD].md at the toolkit root (gitignored if user prefers). Don't overwrite previous triages — keep a history for trend analysis.
Step 7 — Quarterly re-run reminder
If most recent triage was > 90 days ago, flag this. If ≤ 90 days, note "Last triage: [date] — re-run only if portfolio composition changed."
Routine versioning + idempotency contract
This skill participates in cruise-control via --cron mode. When invoked by cron:
-
Stamp
routine_versionin every output (the_triage/YYYY-MM.mdcross-site summary frontmatter, per-sitenotes.mdtriage-rank entry, the audit log line viascripts/lib/audit-log.mjs). Currentroutine_version: 1.0. -
Idempotency: this skill MUST be safe to run twice in the same month without producing duplicate work. Implementation: check whether
_triage/{YYYY-MM}.mdalready exists for the current month; if so, exit cleanly withexit: "idempotent-skip". The monthly summary is meant to be generated once on the 1st of the month. -
Goal-progress computation (T2-J from spec): the cron-mode run reads each site's
goals.mdand computes "% to target" per success metric, integrated into the per-site recommendation in the triage output.
Reference: docs/specs/2026-05-16-agents-cruise-control-design.md § Operational hardening O3 + § T2-J.
Refusal conditions
sites/folder is empty (no managed sites).- All sites have
hard pauseflag (nothing to rank).
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.