Skip to content
Back to skills

Seo Cluster

ASecurity

SERP-overlap semantic topic clustering for content architecture — groups keywords into hub-and-spoke clusters (one pillar + supporting spokes) with an internal-link matrix and intent labels. The free path clusters keywords by actual shared Google results (SERPs acquired via WebSearch, clustered deterministically by serp_cluster.py); DataForSEO/Semrush deepen it with live bulk SERPs and keyword volume/CPC/difficulty. Trigger when the user says "topic cluster", "content cluster", "semantic clus...

  • 9 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added August 31, 2026
developmentpythongo

Works with

  • mcp

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned August 31, 2026

npx -y skills add ZachArticulateV/designer-pro-and-seo --skill seo-cluster --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Seo Cluster?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Seo Cluster
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/zacharticulatev-seo-cluster/badge)](https://www.skillsdirectory.com/skills/zacharticulatev-seo-cluster)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: seo-cluster
description: SERP-overlap semantic topic clustering for content architecture — groups keywords into hub-and-spoke clusters (one pillar + supporting spokes) with an internal-link matrix and intent labels. The free path clusters keywords by actual shared Google results (SERPs acquired via WebSearch, clustered deterministically by serp_cluster.py); DataForSEO/Semrush deepen it with live bulk SERPs and keyword volume/CPC/difficulty. Trigger when the user says "topic cluster", "content cluster", "semantic clustering", "pillar page", "hub and spoke", "content architecture", "keyword grouping", or "cluster plan".
---

# seo-cluster

**Family:** seo
**Status:** Stable

## Purpose

Plan content architecture as **hub-and-spoke clusters**: one pillar page per
cluster, supporting spoke articles linking to and from it, with an internal-link
matrix that specifies anchor text. Keywords are grouped by **SERP overlap** — if
Google returns the same pages for two keywords, they belong on one page; if it
returns different pages, they need separate pages. That shared-result signal, not
word or embedding similarity, is the only one that predicts whether a single URL can
rank for the group (see `references/seo-cluster/serp-overlap-method.md`). The pillar
is the most SERP-central keyword; the spokes specialize under it
(`references/seo-cluster/hub-and-spoke.md`).

## Triggers

- "topic cluster" / "content cluster" / "semantic clustering"
- "pillar page" / "hub and spoke" / "content architecture"
- "keyword grouping" / "cluster plan"

## Inputs

- Seed keywords (or a single seed to expand into a keyword set)
- Cluster-size / overlap threshold; region / language; SERP depth (top-N)

## Steps

1. **Expand seeds** into a keyword set (modifiers, questions, related terms).
2. **Acquire SERPs (this is the acquisition step, not the script).** For each
   keyword, gather the top-ranked URLs into a SERP blob — a JSON object
   `{keyword: [ranked urls]}`. Free path: read SERPs with **WebSearch**. Tier-1
   path: pull bulk live SERPs from a DataForSEO / Semrush MCP when connected.
3. **Cluster deterministically** over that blob:
   ```
   python3 "${CLAUDE_PLUGIN_ROOT}/scripts/seo/serp_cluster.py" \
     --serps serps.json --threshold 3 --top 10 --human
   ```
   `serp_cluster.py` computes pairwise SERP overlap, clusters by shared-URL
   single-linkage at the chosen threshold, classifies each keyword's intent, picks
   the pillar, and emits the internal-link matrix. It **never fetches** anything and
   runs fully offline; it is the deterministic post-processor over the supplied blob.
4. **Review roles** — confirm the pillar (broad/head) and spokes (specific/long-tail)
   per cluster; split any visibly mixed-intent or over-merged cluster (the chaining
   caveat in the method reference).
5. **Render** the cluster map: drop the script's JSON into
   `skills/seo-cluster/templates/cluster-map.html` (replace the
   `/*__SERP_CLUSTER_JSON__*/ null` sentinel — the marker plus the `null` after it — so
   both the template and the injected result stay valid JS) for an interactive
   hub-and-spoke view, plus the link matrix (CSV/markdown). Hand each pillar/spoke to
   `seo-content-brief` to brief the page.

## Capability routing

This skill follows the plugin's capability-tier cascade
(`references/CAPABILITY-TIERS.md`) and always returns a cluster plan:

1. **Tier 1 — DataForSEO / Semrush MCP.** When connected, pull live bulk SERPs per
   keyword (and, separately, keyword volume / CPC / difficulty) to feed clustering at
   scale and to prioritize the resulting pillars.
2. **Tier 2 — built-in (the default).** Otherwise acquire SERPs with **WebSearch**
   and cluster them with `serp_cluster.py` — deterministic SERP-overlap clustering,
   intent labels, pillar selection, and the internal-link matrix, with no key and no
   network in the script. This is the product.
3. **Tier 4 — guided.** If no SERP data can be gathered at all, deliver a manual
   keyword-grouping checklist (group by intent + obvious shared theme) and name
   DataForSEO / Semrush as the way to add live SERPs + volume.

```capability-routing
capability:   serp-keywords
tier1:        DataForSEO / Semrush MCP (live bulk SERPs + keyword volume/CPC/difficulty)
tier1_signal: DATAFORSEO_USERNAME | DATAFORSEO_PASSWORD
tier2:        serp_cluster.py (SERP-overlap clustering over a WebSearch-acquired SERP blob, no key)
tier2_yields: hub-and-spoke clusters + intent labels + internal-link matrix, zero spend
tier3:        none
tier3_signal: none
tier4:        manual keyword-grouping checklist; add DataForSEO/Semrush for live bulk SERPs + volume
needs_tier1:  keyword search volume, CPC, keyword difficulty
```

Always end by stating which tier ran and what volume/SERP-scale data a higher tier
would add.

## Outputs

| Output | What it contains | Format | Quality bar (how it is scored) |
|---|---|---|---|
| Cluster map | Each keyword → its cluster, with pillar vs spoke and an intent label per keyword | JSON (default) + interactive `cluster-map.html` | Every keyword is placed (a clustered member or a flagged singleton); clustering is deterministic — the same blob reproduces it byte-for-byte |
| Hub-and-spoke plan | One pillar + its spokes per cluster, pillar chosen by SERP centrality | JSON `clusters[]` / ASCII `--human` | Exactly one pillar per cluster; every **direct** spoke shares ≥ threshold URLs with the pillar; a member pulled in only through a single-linkage chain (< threshold with the pillar) is flagged `bridged` and never gets a below-threshold pillar link; mixed-intent clusters surfaced for a split |
| Internal-link matrix | Directed links (spoke→pillar, pillar→spoke, spoke→2–3 siblings, and a bridged spoke→its bridge) with anchor text per link | JSON `link_matrix[]` (CSV/markdown on request) | Every direct spoke links up to its pillar with the pillar keyword as anchor; a bridged spoke links up to the member it actually co-ranks with (≥ threshold), never the pillar; sibling links chosen by overlap, capped at 3 |
| Tier line + needs_tier1 | Which tier ran + the never-fabricate fields a higher tier would add | one sentence + list | States the tier honestly; volume/CPC/difficulty ship as `needs_tier1`, never a synthesized number |

Filed to: the user's project workspace (never the plugin). Keyword volume, CPC, and
difficulty are never-fabricate fields — emitted as a labeled `needs_tier1` list until
a DataForSEO / Semrush MCP is connected.

## Error Handling

| Condition | Detection | Behavior (degrade, never fail) | User-facing message |
|---|---|---|---|
| DataForSEO / Semrush MCP absent | the MCP tool is not exposed or errors | acquire SERPs with WebSearch and cluster with `serp_cluster.py` | "Ran Tier 2 (WebSearch SERPs + serp_cluster.py). Add DataForSEO/Semrush for bulk live SERPs + volume." |
| No SERP data obtainable | WebSearch unavailable / blocked | fall back to the manual intent+theme grouping checklist (Tier 4) | "Couldn't gather SERPs — grouped by intent/theme instead; connect a SERP source for overlap-true clusters." |
| Bad / empty SERP blob | `serp_cluster.py` validates: non-object, value not a list, empty, or unparseable JSON → JSON `{"error"}` + non-zero exit | report the validation error; do not invent clusters | "--serps must be a JSON object {keyword: [ranked urls]} — here is the expected shape." |
| Everything is a singleton | script returns clusters=[] with all keywords in `singletons` | report it honestly; suggest lowering `--threshold` or supplying deeper SERPs | "No keywords shared ≥ N results — lower the threshold or add more keywords/top-N depth." |
| Volume/CPC/difficulty requested but no Tier-1 | only the free tier ran | deliver clusters + `needs_tier1` list | "Clusters are ready; volume/CPC/difficulty need a DataForSEO/Semrush MCP (listed in needs_tier1)." |

Every row degrades to a real deliverable — a cluster plan or an honest grouping —
never an empty failure.

## Dependencies

- `scripts/seo/serp_cluster.py` (required) — Python 3.10+, standard library only;
  deterministic, offline SERP-overlap clustering over a supplied blob
- `references/seo-cluster/serp-overlap-method.md`,
  `references/seo-cluster/hub-and-spoke.md` (method + architecture knowledge)
- `seo-content-brief` (optional — briefs each pillar/spoke page)
- Optional: DataForSEO / Semrush MCP (live bulk SERPs + volume/CPC/difficulty)

## Notes

Be explicit about which tier ran. The free path clusters by **real SERP overlap**
(SERPs acquired via WebSearch) — the accurate method — and is the product;
DataForSEO / Semrush only deepen it with scale and the volume/CPC/difficulty numbers
the free path honestly lists under `needs_tier1`. Embedding-only clustering is
deliberately avoided: it produces topically-broad groups Google does not recognize
as one page (see `references/seo-cluster/serp-overlap-method.md`).

Related: `design-research` dispatches `seo-cluster` during its fan-in (one-directional
graph — `seo-cluster` does not depend back on it).

Files in this skill

  • SKILL.md8.9 KB
  • templates/cluster-map.html9.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.