From claude-seo
Groups keywords by Google SERP overlap to design hub-and-spoke content clusters with internal link matrices and interactive visualizations.
npx claudepluginhub agricidaniel/claude-seo --plugin claude-seoThis skill uses the workspace's default tool permissions.
SERP-overlap-driven keyword clustering for content architecture. Groups keywords
Guides strict Test-Driven Development (TDD): write failing tests first for features, bugfixes, refactors before any production code. Enforces red-green-refactor cycle.
Guides systematic root cause investigation for bugs, test failures, unexpected behavior, performance issues, and build failures before proposing fixes.
Guides A/B test setup with mandatory gates for hypothesis validation, metrics definition, sample size calculation, and execution readiness checks.
SERP-overlap-driven keyword clustering for content architecture. Groups keywords by how Google actually ranks them (shared top-10 results), not by text similarity. Designs hub-and-spoke content clusters with internal link matrices and generates interactive cluster map visualizations.
Scripts: Located at the plugin root scripts/ directory.
| Command | What it does |
|---|---|
/seo cluster plan <seed-keyword> | Full planning workflow: expand, cluster, architect, visualize |
/seo cluster plan --from strategy | Import from existing /seo plan output |
/seo cluster execute | Execute plan: create content via claude-blog or output briefs |
/seo cluster map | Regenerate the interactive cluster visualization |
Expand the seed keyword into 30-50 variants using WebSearch:
Deduplication: Normalize variants (lowercase, strip articles), remove exact duplicates. Target: 30-50 unique keyword variants. If under 30, run a second expansion pass with the top PAA questions as seeds.
This is the core differentiator. Load references/serp-overlap-methodology.md for
the full algorithm.
Process:
| Shared Results | Relationship | Action |
|---|---|---|
| 7-10 | Same post | Merge into single target page |
| 4-6 | Same cluster | Group under same spoke cluster |
| 2-3 | Interlink | Place in adjacent clusters, add cross-links |
| 0-1 | Separate | Assign to different clusters or exclude |
Optimization: With 40 keywords, full pairwise = 780 comparisons. Instead:
DataForSEO integration: If DataForSEO MCP is available, use serp_organic_live_advanced
instead of WebSearch for SERP data. Run python scripts/dataforseo_costs.py check serp_organic_live_advanced --count N
before each batch. If "status": "needs_approval", show cost estimate and ask user.
If "status": "blocked", fall back to WebSearch.
Classify each keyword into one of four intent categories:
| Intent | Signals | Include in Clusters? |
|---|---|---|
| Informational | how, what, why, guide, tutorial, learn | Yes |
| Commercial | best, top, review, comparison, vs, alternative | Yes |
| Transactional | buy, price, discount, coupon, order, sign up | Yes |
| Navigational | brand names, specific product names, login | No (exclude) |
Remove navigational keywords from clustering. Flag borderline cases for manual review. Keywords can have mixed intent (e.g., "best CRM software" is both commercial and informational) -- classify by dominant intent.
Load references/hub-spoke-architecture.md for full specifications.
Design the cluster structure:
| Intent Pattern | Template Options |
|---|---|
| Informational (broad) | ultimate-guide |
| Informational (how) | how-to |
| Informational (list) | listicle |
| Informational (concept) | explainer |
| Commercial (compare) | comparison |
| Commercial (evaluate) | review |
| Commercial (rank) | best-of |
| Transactional | landing-page |
Set word count targets:
Cannibalization check — No two posts share the same primary keyword. If SERP overlap is 7+, merge those keywords into a single post targeting both.
Design the bidirectional linking structure:
| Link Type | Direction | Requirement |
|---|---|---|
| Spoke to pillar | spoke -> pillar | Mandatory (every spoke) |
| Pillar to spoke | pillar -> spoke | Mandatory (every spoke) |
| Spoke to spoke (within cluster) | spoke <-> spoke | 2-3 links per post |
| Cross-cluster | spoke -> spoke (other cluster) | 0-1 links per post |
Rules:
Generate the link matrix as a JSON adjacency list:
{
"links": [
{ "from": "pillar", "to": "cluster-0-post-0", "type": "mandatory", "anchor": "keyword" },
{ "from": "cluster-0-post-0", "to": "pillar", "type": "mandatory", "anchor": "keyword" }
]
}
Generate cluster-map.html using the template at templates/cluster-map.html.
CLUSTER_DATA JSON object from the cluster plan:
{
pillar: { title, keyword, volume, template, wordCount, url },
clusters: [{ name, color, posts: [{ title, keyword, volume, template, wordCount, url, status }] }],
links: [{ from, to, type }],
meta: { totalPosts, totalClusters, totalLinks, estimatedWords }
}
CLUSTER_DATA placeholder in the template with the actual JSONcluster-map.html in a browser to explore the interactive cluster map."When invoked with --from strategy:
/seo plan output in the current directory (search for
files matching *SEO*Plan*, *strategy*, *content-strategy*)If no strategy file is found, prompt the user: "No existing SEO plan found in the
current directory. Run /seo plan first, or provide a seed keyword for fresh clustering."
When /seo cluster execute is invoked:
Test: Does ~/.claude/skills/blog/SKILL.md exist?
If claude-blog IS installed:
references/execution-workflow.md for the full algorithmcluster-plan.json from the current directoryblog-write skill with cluster context:
If claude-blog is NOT installed:
cluster-briefs/ directory as individual markdown filescluster-briefs/."Post-execution quality report. Run automatically after /seo cluster execute or
on demand via analysis of the output directory.
| Metric | Target | How Measured |
|---|---|---|
| Coverage | 100% | Posts written / posts planned |
| Link Density | 3+ per post | Count internal links per post |
| Orphan Pages | 0 | Posts with < 1 incoming link |
| Cannibalization | 0 conflicts | Check for duplicate primary keywords |
| Image Count | 1+ per post | Posts with at least one image |
| Pillar Links | 100% | All spokes link to pillar and vice versa |
| Cross-Links | 80%+ | Recommended spoke-to-spoke links implemented |
| Content Gaps | 0 | Planned posts that were skipped or incomplete |
When /seo cluster map is invoked:
cluster-plan.json from the current directorycluster-map.html with updated statusesAll outputs are written to the current working directory:
| File | Description |
|---|---|
cluster-plan.json | Machine-readable cluster plan (full data) |
cluster-plan.md | Human-readable cluster plan summary |
cluster-map.html | Interactive SVG visualization |
cluster-briefs/ | Content briefs (if no claude-blog) |
cluster-scorecard.md | Post-execution quality report |
| Skill | Relationship |
|---|---|
seo-plan | Import source: strategy import reads seo-plan output |
seo-content | Quality check: E-E-A-T validation of generated content |
seo-schema | Schema markup: Article, BreadcrumbList, ItemList for cluster pages |
seo-dataforseo | Data source: SERP data when DataForSEO MCP is available |
seo-google | Reporting: generate PDF report of cluster plan and scorecard |
After cluster planning or execution completes, offer:
"Generate a PDF report? Use /seo google report"
| Error | Cause | Resolution |
|---|---|---|
| "No seed keyword provided" | Missing argument | Prompt user for seed keyword or URL |
| "Insufficient keyword variants" | Expansion yielded < 15 keywords | Run second expansion pass with PAA questions |
| "SERP data unavailable" | WebSearch and DataForSEO both failing | Retry after 30s; if persistent, use intent-only clustering with warning |
| "No strategy file found" | --from strategy but no plan exists | Prompt user to run /seo plan first |
| "cluster-plan.json not found" | Execute without planning | Prompt user to run /seo cluster plan first |
| "claude-blog not installed" | Execute attempted without blog skill | Generate content briefs instead; suggest installation |
| "DataForSEO budget exceeded" | Cost check returned "blocked" | Fall back to WebSearch; inform user |
| "Duplicate primary keywords" | Cannibalization detected | Merge affected posts or reassign keywords |
| "Orphan page detected" | Post missing incoming links | Add links from nearest cluster siblings |
| "Resume state corrupted" | Mismatch between plan and output | Rebuild state from output directory scan |
python scripts/fetch_page.py (SSRF protection via validate_url())