Install
$ agentstack add skill-antonioblago-peec-ai-skills-peec-cluster ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Content Cluster Builder
Role
Reduce a flat Peec prompt set to 4–8 strategic zones — each with a structural weakness in the competition, one measurable metric, and one "do exactly this now" action. Not keyword clusters. Not a content calendar.
A zone is coherent only when three axes line up:
Intent
↑
Visibility gap
↑
Demand signal
If a candidate zone fails any axis, it gets merged or dropped.
Input
project_id— Peec project- optional
date_range— default last 30 days - optional
target_zones— default 4–8 (skill picks the resolution) - optional
focus_funnel_stage— restrict to one stage
Output
One markdown zone map (schema in §Output schema), plus one Peec tag per zone (zone:) with all prompts retagged, so peec-report can measure zone lift later.
When to use
- ≥20 Peec prompts and the team has lost the overview
- After
@peec-setup, before@content-writeper article - Quarterly strategy refresh
- Before an investment conversation ("what is our AI content strategy?")
Do not use when:
- /growthloop/setupstate.json
If missing OR completedat missing OR phasescompleted lacks {competitors, prompts, topics, tags}: STOP. Output: "No Peec setup state found at /growthloop/setupstate.json. Run /peec-setup first." If completedat older than 90 days: WARN once, continue. Use peecprojectid from state — don't re-resolve via listprojects.
### 1. Pull prompt inventory + visibility state
mcp__peec-ai__listprompts(projectid) mcp__peec-ai__getbrandreport( projectid, startdate, enddate, dimensions=["promptid"], filters=[{field: "brandid", operator: "in", values: [ownbrandid]}] ) mcp_peec-ai__geturlreport( projectid, startdate, enddate, dimensions=["promptid"], filters=[{field: "gap", operator: "gt", value: 0}] )
Merge into one table:
`prompt_id | text | funnel_stage | topic | tags | own_visibility | gap_size | top_competitor_url | top_competitor_class`
### 2. Score each prompt on three axes
- **Intent density** (0–1): semantic overlap with other prompts in the same funnel stage. Compute via embedding cosine (e.g. `text-embedding-3-small`) or `mcp__visiblyai__classify_keywords` as a regex-based fallback.
- **Visibility gap** (0–1): `1 − own_visibility`, weighted by `gap_size / max_gap_size_in_project`.
- **Demand density** (0–1): count of `classification=DISCUSSION` source URLs for this prompt in `get_url_report`. High = real buyers are asking.
**Combined score** = `intent_density × visibility_gap × demand_density` (multiplicative — all three must be non-zero).
### 3. Cluster (embedding-based, not regex)
**Primary — `mcp__visiblyai__query_fanout` as semantic bridge** (≥v0.6.0):
for each prompt with score > median: mcp__visiblyai__queryfanout( url=owndomain, keyword=promptkeyword, language=setupstate.promptlanguage, # never default silently country=setupstate.targetcountry ) → fanoutqueries[] becomes the semantic fingerprint
Two prompts go in the same zone when their fan-out queries overlap ≥40%.
**Fallback — direct LLM instruction:**
Given these prompts with metadata (funnel stage, tags, visibility gap, demand signal), group them into 4–8 strategic content zones by:
- Same buying decision question (not merely similar keywords)
- Same funnel stage (or adjacent)
- Shared demand signal (same pain points from forum data)
- Shared structural leverage (same competitor type we can beat)
For each zone: name, 2-sentence thesis, prompt_ids, shared competitor weakness, one concrete "do exactly this now" action.
### 4. Validate each candidate zone
Four checks, all must pass:
1. **Coherence** — ≥3 prompts with ≥0.4 embedding similarity to zone centroid
2. **Funnel** — max 1 funnel stage of spread (Awareness + Consideration ok; Awareness + Decision not)
3. **Gap** — average `visibility_gap` of zone > 0.3
4. **Uniqueness** — each zone has a competitor type not won by another zone
Zones that fail get merged to nearest neighbor or dropped.
### 5. Extract 7 components per valid zone
| Component | Source |
|---|---|
| **Name** (≤40 chars) | synthesize from prompts |
| **Thesis** (2 sentences) | why this zone exists + why you win here |
| **Funnel span** | TOFU / MOFU / BOFU / Retention |
| **Top 5 prompts** | sorted by combined score |
| **Competitor structural weakness** | from `peec-content-intel`: what's missing across all competitors in this zone |
| **Target `page_type`** | **REQUIRED.** Picked from `setup_state.page_type_taxonomy`. Algorithm: (1) aggregate top-url classifications of competitors in the zone; (2) map to the closest allowed page_type via the matrix in `_shared/SETUP_STATE.md`; (3) if no mapping exists (zone competitors all `LISTICLE` but your taxonomy has no `comparison` or `pillar`) → switch the one-move to **outreach** not content. |
| **One-move action** | concrete verb, concrete artifact, concrete channel — no "analyze X", instead "publish `landing_page` at `/seo-retainer` with structure Z, pitch at D1, D2". Must reference the chosen `page_type` literally. |
**Page-type decision examples:**
| business_type | Zone top_cls histogram | Chosen page_type | One-move |
|---|---|---|---|
| b2b-service | PRODUCT_PAGE × 5, COMPARISON × 2 | `landing_page` | Build `/seo-retainer` LP + comparison block |
| b2b-service | LISTICLE × 5 (all "best X in Germany") | **no content match** | Switch to `/peec-outreach` — pitch for inclusion |
| b2c-ecommerce | PRODUCT_PAGE × 4, CATEGORY_PAGE × 3 | `collection` + `pdp` | Optimize collection `/shoes/running` + 3 high-intent PDPs |
| b2b-saas | ARTICLE × 3, HOW_TO × 2 | `use_case` | Build `/integrations/shopify-seo` use-case page |
| info-product | ARTICLE × 4, LISTICLE × 2 | `sales_page` | Long-form sales page with 7-step pitch |
| local-service | HOMEPAGE × 4 (local competitors) | `local_landing` | Build `/seo-agentur-koblenz` with NAP + GMB proof |
If all zones of a project end up with "switch to outreach" because nothing in the taxonomy matches competitor URL classifications → **flag a taxonomy mismatch P0 in the zone map**. That's a signal the `business_type` in `setup_state.json` is wrong.
### 6. Rank zones by potential impact
potentialimpact = sum(prompts.visibilitygap × prompts.demanddensity × funnelweight)
funnel_weight = {Awareness: 0.6, Consideration: 1.0, Decision: 1.5, Retention: 1.2}
### 7. Persist zones as Peec tags
For each validated zone:
mcp__peec-ai__createtag(projectid, name="zone:", color="") for each prompt in zone: mcp__peec-ai__updateprompt(projectid, promptid, tagids=[..., zonetagid])
This is the hook `peec-report` uses to track zone performance over time.
---
## Output schema
```markdown
# Content zones for ()
## Zone 1 (score 0.85):
**Thesis:**
**Funnel:** Consideration → Decision
**Prompts:** 7 (see appendix A)
**Target page_type:** `landing_page` *(validated against setup_state.page_type_taxonomy)*
**Competitor weakness:**
- None of the top-5 competitor URLs address
- 4 of 5 say nothing about
**ONE MOVE NOW:**
> Build `landing_page` at `/seo-retainer` with H2 outline ,
> then within 7 days pitch at , ,
> and answer .
**Success metric (measure after 6 weeks):**
Peec visibility across the 7 prompts: avg X% → Y%.
---
## Zone 2 (score 0.78): ...
Quick reference
| Step | Tool | |---|---| | Load prompts / topics / tags | mcp__peec-ai__list_prompts / list_topics / list_tags | | Visibility per prompt | mcp__peec-ai__get_brand_report(dimensions=["prompt_id"]) | | Gap per prompt | mcp__peec-ai__get_url_report(filters: gap>0) | | Semantic cluster signal | mcp__visiblyai__query_fanout or classify_keywords | | Pain density | mcp__peec-ai__get_url_content on reddit threads | | Persist zone | mcp__peec-ai__create_tag + update_prompt |
Done criteria (self-check before returning)
A zone map is only complete when:
- Every zone has a one-move action with a concrete verb
- Every zone has a structural competitor weakness (not "weak content" — "competitor X lacks pricing, competitor Y lacks FAQ block")
- Every zone is measurable (Peec tag exists, prompt_ids listed)
- ≤8 zones total — if the algorithm returns 12, merge or drop the weakest 4
Guardrails (do not do these)
- Do not cluster by keyword — "Neuro-SEO Blog" + "Neuro-SEO Shop" address different funnels and different buyers
- Do not ship a zone map where all zones are Awareness — Decision coverage is often more valuable than five Awareness clusters
- Do not create a zone without a named competitor weakness — if you can't name what they do wrong, the zone isn't real
- Do not return more than 8 zones — 12 zones means 12 half-finished topics; 5 zones means 5 topics you win
- Do not skip the tag persistence step — without tags,
peec-reporthas nothing to attribute against
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: AntonioBlago
- Source: AntonioBlago/peec-ai-skills
- License: MIT
- Homepage: https://antonioblago.de
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.