Blog Cannibalization
AgriciDaniel/claude-blog
Detect keyword cannibalization across blog posts by extracting primary keywords from titles and headings, clustering semantically similar targets, and flagging posts competing for the same search…
A skill your agent uses when publishing SEO blog articles to qaskills.sh, e.g.
$ npx skills add PramodDutta/qaskills --skill publish-seo-batch -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install PramodDutta/qaskills publish-seo-batch --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/publish-seo-batch .claude/skills/publish-seo-batch && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "publish-seo-batch" agent skill from https://github.com/PramodDutta/qaskills/tree/main/.claude/skills/publish-seo-batch into .claude/skills/publish-seo-batch/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "publish-seo-batch", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/PramodDutta/qaskills/tree/main/.claude/skills/publish-seo-batchType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add PramodDutta/qaskills --skill publish-seo-batch -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install PramodDutta/qaskills publish-seo-batch --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .agents/skills && cp -r skills-src/.claude/skills/publish-seo-batch .agents/skills/publish-seo-batch && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "publish-seo-batch" agent skill from https://github.com/PramodDutta/qaskills/tree/main/.claude/skills/publish-seo-batch into .agents/skills/publish-seo-batch/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "publish-seo-batch", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add PramodDutta/qaskills --skill publish-seo-batch -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install PramodDutta/qaskills publish-seo-batch --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/.claude/skills/publish-seo-batch .cursor/skills/publish-seo-batch && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "publish-seo-batch" agent skill from https://github.com/PramodDutta/qaskills/tree/main/.claude/skills/publish-seo-batch into .cursor/skills/publish-seo-batch/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "publish-seo-batch", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/PramodDutta/qaskills.git --path .claude/skills/publish-seo-batch--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add PramodDutta/qaskills --skill publish-seo-batch -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install PramodDutta/qaskills publish-seo-batch --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/.claude/skills/publish-seo-batch .gemini/skills/publish-seo-batch && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "publish-seo-batch" agent skill from https://github.com/PramodDutta/qaskills/tree/main/.claude/skills/publish-seo-batch into .gemini/skills/publish-seo-batch/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "publish-seo-batch", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install PramodDutta/qaskills publish-seo-batchInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add PramodDutta/qaskills --skill publish-seo-batch -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .github/skills && cp -r skills-src/.claude/skills/publish-seo-batch .github/skills/publish-seo-batch && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "publish-seo-batch" agent skill from https://github.com/PramodDutta/qaskills/tree/main/.claude/skills/publish-seo-batch into .github/skills/publish-seo-batch/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "publish-seo-batch", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add PramodDutta/qaskills --skill publish-seo-batch -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install PramodDutta/qaskills publish-seo-batch --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/PramodDutta/qaskills.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/.claude/skills/publish-seo-batch .opencode/skills/publish-seo-batch && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "publish-seo-batch" agent skill from https://github.com/PramodDutta/qaskills/tree/main/.claude/skills/publish-seo-batch into .opencode/skills/publish-seo-batch/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "publish-seo-batch", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
publish-seo-batchA skill your agent uses when publishing SEO blog articles to qaskills.sh, e.g.
Publish SEO Batch is an agent skill from PramodDutta/qaskills. Use when publishing SEO blog articles to qaskills.sh, e.g. "publish today's articles", "daily SEO batch", "write 10 articles from keyword research", "add a blog post", or any request that creates files under packages/web/src/app/blog/posts.
Its SKILL.md is about 2.2k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.
It sits in Writing & Content, covering Blog and article writing and Keyword research. The repository describes itself as: QA Skills Directory QA Skills is a curated directory of testing-specific skills for AI coding agents (Claude Code, Cursor, Copilot, etc.). The licence is MIT.
10 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 1d2a092. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
gitcurlpnpmpython3From the folder's file list and the shell code blocks in SKILL.md.
Hosts in commands or code, which the agent is likely to contact:
qaskills.shbing.comapi.indexnow.orgFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Publish SEO Batch loads about 2.2k tokens when it runs. Until then it costs about 65 tokens; SKILL.md has 793 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from PramodDutta/qaskills at commit 1d2a092, republished under its MIT licence (© PramodDutta). 793 words, ~2,157 tokens.
.claude/skills/publish-seo-batch/SKILL.md (or your agent's skills folder).The daily content pipeline: source topics -> dedup slugs -> write posts -> register -> build -> commit -> deploy -> prove live -> ping IndexNow. Default batch size is 10 unless the user says otherwise. Every step has a check; a batch is not "published" until step 8 passes, then step 9 nudges the search engines.
git -C /Users/promode/qaskills status --short # note pre-existing WIP; you will NOT stage it
date +%F # today's date, used in every post and the commit messagePre-existing modified/untracked files are the user's WIP. Leave them alone.
Saved GSC reports in docs/seo/KEYWORD-OPPORTUNITIES-*.md are historical and fully published; do not source topics from them. Instead:
docs/seo/KEYWORD-OPPORTUNITIES-YYYY-MM.md and include it in the commit.Batch arrays are spread into the registries LAST, so a colliding slug silently replaces a real article. This has shipped a stub over a full article before.
cd /Users/promode/qaskills
for s in slug-one slug-two; do
hits=$(grep -rn "$s" packages/web/src/app/blog/posts/ | grep -v "$s-something-longer" | wc -l)
echo "$s: $hits hits"
doneAny hit (filename, posts map key, postList entry, batch array entry): choose a different slug or drop the topic. Also scan titles in posts/index.ts for near-duplicate topics; a second article on the same query cannibalizes the first.
File: packages/web/src/app/blog/posts/<slug>.ts
import type { BlogPost } from './index';
export const post: BlogPost = {
title: 'Primary Keyword In Natural Title',
description: 'Meta description, 140-170 chars, contains the keyword, states the payoff.',
date: 'YYYY-MM-DD', // today
category: 'Guide', // Guide | Reference | Tutorial | Comparison | AI Testing | API Testing | Migration | BDD | Performance
content: `
# Same Title As Above
Opening paragraphs that answer the query directly...
`,
};Per-article bar (all required):
title/blog/<existing-slug>); verify each target exists in posts/index.ts before linking${ in prose unless intentionally interpolating; escape as \${ if literal## Frequently Asked Questions section (3-4 ### Question? H3s with short answers) as the LAST H2. It counts toward the word bar and src/lib/extract-faqs.ts turns it into FAQPage JSON-LD for AI-search citation. Without it, articles tend to land short of 1200 words.packages/web/src/app/blog/posts/index.ts needs three edits per post:
import { post as camelCaseName } from './<slug>'; (with the other imports)posts map entry: '<slug>': camelCaseName, placed BEFORE the batch ...Object.fromEntries spreadspostList entry: { slug: '<slug>', ...camelCaseName }, placed before the batch spreads at the endMissing 1 or 2 = the page 404s. Missing 3 = invisible on /blog and absent from the sitemap. Do not touch sitemap.ts; it derives from postList.
cd /Users/promode/qaskills
# exactly 2 quoted occurrences per slug in index.ts (map key + postList)
for s in slug-one slug-two; do
c=$(grep -c "'$s'" packages/web/src/app/blog/posts/index.ts)
[ "$c" -eq 2 ] || echo "REGISTRATION WRONG: $s count=$c"
done
# no em dashes in the new files
grep -l '—' packages/web/src/app/blog/posts/<each-new-slug>.ts && echo "EM DASH FOUND"
# build must pass
pnpm --filter @qaskills/shared build && pnpm --filter @qaskills/web buildFix and re-run until all three are clean. Build failure in a post file is almost always an unescaped backtick or ${ in the template literal.
git -C /Users/promode/qaskills add \
packages/web/src/app/blog/posts/<slug-one>.ts \
packages/web/src/app/blog/posts/<slug-two>.ts \
packages/web/src/app/blog/posts/index.ts
git -C /Users/promode/qaskills diff --cached --stat # only your files
git -C /Users/promode/qaskills commit -m "feat: publish 10 SEO articles (YYYY-MM-DD) from keyword research"
git -C /Users/promode/qaskills push origin mainExplicit paths only. No trailers, no footers, no em dash in the message.
REQUIRED SUB-SKILL: ship-prod. Follow it exactly (worktree if the tree is dirty, explicit project IDs, its verification checklist).
for s in slug-one slug-two; do
code=$(curl -s -o /dev/null -w '%{http_code}' "https://qaskills.sh/blog/$s")
echo "$s: $code"
done
curl -s https://qaskills.sh/sitemap.xml | grep -c '<one-new-slug>' # >= 1Every slug must return 200 and appear in the sitemap. Report the checked URLs in the final summary.
After the new slugs are confirmed live (step 8), notify IndexNow so Bing and the other participating engines crawl them fast. Submit only the NEW slugs, not the whole sitemap. The verification key file is already hosted at https://qaskills.sh/f1e4781767e4472e9061ad0f853449d3.txt (committed in packages/web/public/); do not regenerate it.
# Build the payload from just this batch's new slugs
python3 - "$@" <<'PY'
import json, sys
slugs = ["slug-one", "slug-two"] # replace with this batch's new slugs
urls = [f"https://qaskills.sh/blog/{s}" for s in slugs]
json.dump({
"host": "qaskills.sh",
"key": "f1e4781767e4472e9061ad0f853449d3",
"keyLocation": "https://qaskills.sh/f1e4781767e4472e9061ad0f853449d3.txt",
"urlList": urls,
}, open("/tmp/indexnow-batch.json", "w"))
print("urls:", len(urls))
PY
curl -s -o /dev/null -w 'Bing IndexNow: %{http_code}\n' -X POST 'https://www.bing.com/indexnow' \
-H 'Content-Type: application/json; charset=utf-8' --data @/tmp/indexnow-batch.json
curl -s -o /dev/null -w 'IndexNow.org: %{http_code}\n' -X POST 'https://api.indexnow.org/indexnow' \
-H 'Content-Type: application/json; charset=utf-8' --data @/tmp/indexnow-batch.json200 or 202 means accepted. A 403 SiteVerificationNotCompleted means the key file was not reachable; confirm the txt URL returns the bare key as text/plain and retry. This is a fire-and-forget hint, not a gate: a non-200 here does not un-publish the batch, but report it. Google is not an IndexNow participant; it discovers the posts through the sitemap and robots.txt as before.
| Symptom | Cause | Fix |
|---|---|---|
Build: Unexpected token / template error in a post | Unescaped backtick or ${ in content | Escape as \` and \${ |
| Article 404 live | Missing posts map entry, or deploy did not actually run | Step 5 count check, then re-run ship-prod verification |
| Article absent from /blog and sitemap | Missing postList entry | Add it, rebuild, redeploy |
| An OLD article changed content | New slug collided with a batch-array slug | Rename the new slug, restore, redeploy |
| Sitemap grep = 0 but page is 200 | Deployed stale HEAD or sitemap cached | Confirm commit is in HEAD, redeploy, re-check |
git add -A or staging files you did not create© PramodDutta, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in .claude/skills/publish-seo-batch of PramodDutta/qaskills.
Open the folder on GitHubat commit 1d2a092
Publish SEO Batch next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Publish SEO Batch this skillPramodDutta/qaskills | 235 | — | ~2.2k | Automated safety check: Pass | MIT | |
| Blog CannibalizationAgriciDaniel/claude-blog | 2.3k | 1 repos | ~2.2k | Automated safety check: Pass | MIT | |
| Article Writingericrisco/rsc-harness | 180 | — | ~2.9k | Automated safety check: Pass | MIT | |
| Ink Briefjeremylongshore/tons-of-skills-marketplace | 2.8k | — | ~1.2k | Automated safety check: Notes | MIT | |
| Blog Post CounterInfrasity-Labs/dev-gtm-claude-skills | 136 | — | ~3.9k | Automated safety check: Pass | MIT | |
| SEO Keyword ResearchVarnan-Tech/opendirectory | 674 | — | ~1.8k | Automated safety check: Pass | MIT |
AgriciDaniel/claude-blog
Detect keyword cannibalization across blog posts by extracting primary keywords from titles and headings, clustering semantically similar targets, and flagging posts competing for the same search…
ericrisco/rsc-harness
A skill your agent uses when writing one long-form article end to end — answer-first lede, question-shaped headings, plus its on-page surface (title, meta, slug, FAQ, Article/FAQPage JSON-LD) — or…
jeremylongshore/tons-of-skills-marketplace
Content brief generator — takes a topic or keyword and produces a complete content brief with target keyword, search intent, recommended structure, internal link targets, word count, CTA, and…
Infrasity-Labs/dev-gtm-claude-skills
Counts and compares blog posts across a target and competitors, audits content freshness via sitemap lastmod dates, and maps competitor organic keywords (US, non-branded, informational) against the…
Varnan-Tech/opendirectory
SEO keyword research workflow for blog generation using Google Trends data.
sickn33/agentic-awesome-skills
Writes search-intent-led long-form articles with answer-first structure, FAQ coverage, internal links, and conversion paths for SEO and AEO.
PramodDutta/qaskills
A skill your agent uses when adding or editing QA skills in seed-skills/ or getting them onto the live qaskills.sh catalog, e.g.
PramodDutta/qaskills
A skill your agent uses when deploying qaskills.sh to production, verifying whether a deploy landed, or when a push to main did not show up on the live site, e.g.
PramodDutta/qaskills
Comprehensive RESTful API testing patterns covering HTTP methods, status codes, request/response validation, authentication, error handling, and contract testing.
PramodDutta/qaskills
The complete QA skill for Claude Code — turn Claude into an expert QA engineer that picks the right test type, writes reliable Playwright, Cypress, and pytest tests, eliminates flaky tests, enforces…
PramodDutta/qaskills
End-to-end testing skill using Cypress for web applications, covering custom commands, network intercepts, fixtures, cy.session, and component testing patterns.
PramodDutta/qaskills
Make Claude Code write and maintain end-to-end tests like a senior SDET — Playwright and Cypress flows with stable locators, the Page Object Model, fixtures, reused auth state, network mocking, and…
Categories
A skill your agent uses when publishing SEO blog articles to qaskills.sh, e.g. Publish SEO Batch is an agent skill from PramodDutta/qaskills.g.
Publish SEO Batch fits situations like: publishing SEO blog articles to qaskills.sh; tasks that involve Blog and article writing; tasks that involve Keyword research.
Run `npx skills add PramodDutta/qaskills --skill publish-seo-batch -a claude-code`. Or copy the skill folder (.claude/skills/publish-seo-batch in PramodDutta/qaskills) into .claude/skills/publish-seo-batch in your project. Claude Code loads it when a task matches its description.
Run `npx skills add PramodDutta/qaskills --skill publish-seo-batch -a codex`. Or copy the skill folder (.claude/skills/publish-seo-batch in PramodDutta/qaskills) into .agents/skills/publish-seo-batch in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add PramodDutta/qaskills --skill publish-seo-batch -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/publish-seo-batch, .gemini/skills/publish-seo-batch, .github/skills/publish-seo-batch and .opencode/skills/publish-seo-batch in your project.
Going by SKILL.md and its folder, Publish SEO Batch needs the command-line tools its instructions call (git, curl, pnpm and python3). Our summary lists: Python 3.
SKILL.md names 3 domains. In commands or code: qaskills.sh, bing.com and api.indexnow.org; the agent is likely to contact these when it follows the instructions. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Publish SEO Batch is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 2.2k tokens (SKILL.md is roughly 8.6k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Publish SEO Batch: Blog Cannibalization (AgriciDaniel/claude-blog, 2.3k stars), Article Writing (ericrisco/rsc-harness, 180 stars), Ink Brief (jeremylongshore/tons-of-skills-marketplace, 2.8k stars) and Blog Post Counter (Infrasity-Labs/dev-gtm-claude-skills, 136 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
PramodDutta (a GitHub user) maintains it in PramodDutta/qaskills, which has 235 GitHub stars. The repository holds 11 skills in this directory. The repository was last updated on October 4, 2026.
Source: PramodDutta/qaskills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.