Install
$ agentstack add skill-antonioblago-peec-ai-skills-peec-setup ✓ 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
AI Visibility Setup
Role
Take a Peec AI project from empty (or broken) to operator-ready: correct competitors, full-funnel prompts, coherent taxonomy, GSC keyword mapping, forum-mined buyer language, and a categorized executable backlog the client can run for the next 2 weeks.
Input
project_id(resolved viamcp__peec-ai__list_projects)target_country— ISO 3166-1 alpha-2 (DE,AT,CH,US,UK, ...). DefaultDE. Drives SERP/GSC filters and forum source selection.prompt_language— ISO 639-1 (de,en,fr, ...). Default = lowercase oftarget_country(DE→de). Drives the language Peec prompts are authored in.- Optional:
secondary_languages— list, default[]. Used for multi-market projects (e.g. DE primary + EN secondary). - Optional:
offer_keywords(retainer, monthly, etc.),own_domain - Optional:
scope—full|audit|partial:|competitors_only|prompts_only|taxonomy_only(default: auto-detected from setup state, see Phase 0)
Resolving language/country at start:
- If state file exists with these fields → use them, skip the question.
- Else if user passed them as arguments → use those.
- Else infer from
own_domainTLD (.de→ DE/de,.at→ AT/de,.ch→ CH/de + ask de/fr,.com→ ASK). - Else ASK the user once before Phase 1: "Target country (ISO, e.g. DE)? Prompt language (ISO, e.g. de)?". Persist the answer in state.
Never silently default to EN/en when the project has no signal — this corrupts every downstream skill.
Output
A setup report with: before/after counts, funnel distribution (e.g. 5/5/5/5), the single hero prompt to win first, the refresh timeline (24h for fresh data), a categorized P0/P1/P2 backlog, and any user-preference memories saved. No dashboards.
When to use
- "Set up Peec for "
- "My Peec competitors are wrong / not real competitors"
- "Design prompts for my customer journey"
- "Map GSC keywords to my Peec prompts"
- "Restructure Peec topics / tags"
- Audit of an existing AI-visibility tracking setup
Prerequisites
- Peec AI MCP connected (
mcp__peec-ai__*) - Visibly AI MCP connected (
mcp__visiblyai__*) — optional, only for GSC - GSC + GA4 connected inside Visibly AI (check via
get_google_connections)
State
This skill owns the setup state file. See [_shared/SETUP_STATE.md](../shared/SETUPSTATE.md) for the full schema and protocol.
- Reads
/growth_loop/setup_state.jsonat Phase 0 to decide the run mode (full | audit | partial | skip). - Writes the same file at the end of Phase 9 with merged
phases_completedand a freshsnapshot.
All other skills in this repo refuse to run without this file — never bootstrap a setup from inside another skill.
Phase 0 — State check & mode selection
Always runs first. Cheap (single file read + at most one parallel Peec read in brownfield case). Determines whether the rest of the run is needed at all.
1. Read /growth_loop/setup_state.json
2. If state file MISSING:
2a. Live-detect Peec content (parallel reads):
list_brands(project)
list_prompts(project, limit=5)
list_topics(project)
list_tags(project)
2b. If Peec is empty (≤2 brands AND ≤4 prompts AND ≤0 topics):
→ mode = full (greenfield — proceed to Phase 1)
2c. If Peec is populated (≥3 brands OR ≥5 prompts OR ≥1 topic):
→ mode = import (brownfield — see "Import mode" below)
3. If state file PRESENT, branch on `completed_at`:
90 days ago → mode = full (warn: stale)
4. If user passed an explicit `scope`, that wins over auto-detection.
5. Print one line:
"Setup state: · age: N days · mode: "
import mode (brownfield) — runs entirely inside Phase 0
Per [_shared/SETUP_STATE.md §import mode](../shared/SETUPSTATE.md), this mode reconstructs setup_state.json from live Peec data without re-doing discovery.
1. Show user one line:
"Detected existing Peec setup: brands, prompts, topics, tags."
2. ASK three things at once (single user turn):
- "Import this as the setup state, or run full setup from scratch? [import/full]"
- "Target country (ISO, e.g. DE)?"
- "Prompt language (ISO, e.g. de)?"
3. If user picks `import`:
a. Infer completed_at (NEVER default to now silently):
read created_at from list_brands + list_prompts;
completed_at = min(created_at across first 5 brands AND first 5 prompts)
If unavailable → list_chats(limit=1, sort=asc).timestamp
If still unavailable → ASK user one bucket question
("when did you set this up? [today/past month/past quarter/past year/older]")
and map to a date.
b. Build state object:
phases_completed = inferred from non-empty buckets (brands≥3 → +competitors; etc.)
snapshot = the counts just read
completed_at = inferred per (a) above
imported_at = now (UTC)
last_audit_at = now
hero_prompt_id = null
target_country, prompt_language = from user answers in step 2
notes = "imported from existing Peec project on ;
original setup inferred at "
setup_version = "1.1"
c. **Persist immediately** — atomic write to /growth_loop/setup_state.json
(write to .tmp, then rename). Do not wait for any other phase.
d. Print:
"State imported: /growth_loop/setup_state.json (phases: X/7).
Inferred setup date: (~N days ago).
Run /peec-agent to pick the next move, or /peec-setup
partial:gsc_mapping to fill in skipped phases."
e. Exit Phase 0. Do NOT proceed to Phase 1 — import mode finishes here.
The user can now invoke any consumer skill; they will all read the freshly
written state. If they want missing phases (e.g. forum_mining never happened),
they explicitly call partial:.
4. If user picks `full`:
CONFIRM ONCE MORE: "Full setup will create new prompts/topics/tags alongside
the existing ones. Proceed? [yes/no]"
On yes → mode = full, proceed to Phase 1.
On no → exit cleanly.
skip mode behaviour: show the existing snapshot (counts, phases, heropromptid) and ask "Re-run anyway? [audit / partial: / full / no]". Do not auto-run.
audit mode behaviour: call list_brands / list_prompts / list_topics / list_tags and compare counts to snapshot. For each phase where drift > 20% (or a P0 red flag from Phase 1 reappears), re-run only that phase. Append last_audit_at on write.
partial: mode: jump straight to the named phase, skip everything else.
If mode == skip and user declines re-run, exit cleanly with a 3-line summary — no further phases.
Phase 0.5 — Business type, audience & page-type taxonomy
Always runs in full, import, and audit modes (only skipped in skip mode). These three fields gate every downstream content decision — a wrong business_type corrupts every brief /peec-content-intel and every zone one-move /peec-cluster emits.
1. Read setup_state.json. If business_type + audience + page_type_taxonomy are all present
AND setup_version == "1.2" → skip this phase, continue to Phase 1.
2. If any are missing, ASK the user in ONE turn:
"Before I build prompts, I need three things (all in one message is fine):
(a) Business type — pick one:
• b2b-service (freelancer, agency, consulting — you sell hours or retainers)
• b2c-ecommerce (D2C shop — you sell products, typically Shopify/WooCommerce)
• b2b-saas (software product with subscriptions)
• info-product (courses, memberships, digital products)
• local-service (physical location, catchment-area business)
• marketplace (multi-seller platform)
(b) Audience — one sentence on your primary buyer.
Example: 'Shop-Owner DACH, 3–20 Mitarbeiter, Shopify, 500k–5M Umsatz, Pain: 3 SEO-Agenturen gewechselt.'
(c) Optional: known buyer pain-points (comma-separated, forum language welcome)."
3. Parse the answer. Build:
business_type = one of the six canonical values
audience.primary = the sentence
audience.buyer_personas = extracted nouns from (b) — e.g. ["Shop-Owner Shopify", "DACH"]
audience.pain_points = list from (c), else []
4. Generate page_type_taxonomy from the business-type matrix
(see _shared/SETUP_STATE.md §"Business-type → page-type matrix"):
b2b-service → ["pillar", "landing_page", "blog_post", "case_study", "comparison", "faq", "pricing"]
b2c-ecommerce → ["pdp", "collection", "pillar", "blog_post", "guide", "category_page", "faq"]
b2b-saas → ["landing_page", "integration", "use_case", "blog_post", "comparison", "docs", "pricing"]
info-product → ["sales_page", "webinar_lp", "blog_post", "case_study", "faq", "lead_magnet"]
local-service → ["local_landing", "landing_page", "case_study", "blog_post", "faq"]
marketplace → ["collection", "pdp", "category_page", "pillar", "blog_post"]
5. Add "business_type" and "audience" to phases_completed.
Set setup_version = "1.2".
Persist immediately (atomic write).
6. Print one line:
"Business: · Audience: · Page types: "
Why this matters downstream:
/peec-content-intelpickspage_typeper brief — if the brief sayspdpbutbusiness_type=b2b-service, that's a rejected brief (caught by the taxonomy check)./peec-clusternames apage_typeper zone's one-move. If zone competitors are allCATEGORY_PAGEbut your taxonomy can't producecollection, the zone's one-move switches to outreach instead of content creation — automatically./peec-agentreadsaudience.pain_pointswhen generating Awareness-stage content recommendations./peec-reportattributes bypage_typeto learn which types actually moved visibility.
Never guess business_type. A .de domain selling shoes is not b2b-service even if it looks like a typical German agency URL. Always ASK once; persist once.
Phase 1 — Initial audit
Run in parallel:
mcp__peec-ai__list_projects
mcp__peec-ai__list_brands(project_id) # current competitors
mcp__peec-ai__list_prompts(project_id, limit=200)
mcp__peec-ai__list_topics(project_id)
mcp__peec-ai__list_tags(project_id)
Red flags to call out:
- Competitors list contains SaaS tool brands (SEMrush, Ahrefs, Sistrix, Moz, Ryte, Yoast, Screaming Frog, SurferSEO, Frase). For a freelancer / consultant project these distort SoV — they are not buyers' alternatives.
- Prompts clustered in one funnel stage only (e.g. all MOFU "empfiehl" — no Awareness / Decision / Retention coverage).
- Topics represent themes only (e.g. "AI" / "SEO") — can't track funnel performance.
- Tags are only Peec's default 4 (branded / non-branded / informational / transactional) — no offer-specific slicing possible.
Phase 2 — Competitor discovery (ground truth)
2a. Extract from AI chats (authoritative)
For each losing prompt (own brand 0% visibility, competitors present):
mcp__peec-ai__list_chats(project_id, start_date, end_date, prompt_id=)
→ pick 1 chat per engine (chatgpt-scraper, perplexity-scraper, google-ai-overview-scraper)
mcp__peec-ai__get_chat(project_id, chat_id)
→ inspect messages[] for freelancer / consultant names
→ inspect sources[] for their domains
Extract: human names, domain names, sources the AI pulled. These are the real competitors LLMs recommend against you.
2b. Supplement with web research
WebSearch("SEO Freelancer Deutschland 2026")
WebSearch(" Freelancer Experte KI ChatGPT empfehlen")
Cross-check against the domain report — any domain retrieving (get_domain_report) but not tracked as a brand is an invisible competitor:
mcp__peec-ai__get_domain_report(project_id, start_date, end_date, limit=25)
→ find domains with retrieved_percentage > 5% not yet in list_brands
Phase 3 — Competitor curation (mutation)
3a. Add real competitors
Batch-call in parallel:
mcp__peec-ai__create_brand(
project_id,
name="",
domains=["their-domain.de"],
aliases=["Alternate Spelling"] # Umlaut ↔ ASCII variants, abbreviations
)
Categories to include:
- Direct positioning overlap (e.g. KI-SEO, GEO, Neuro-SEO freelancers)
- Niche-specific freelancers (E-commerce / Shopify SEO)
- Local competitors (same city / region)
- Micro-agencies (5–20 person KI / GEO specialists)
- Invisible competitors already appearing in the domain report
3b. Remove irrelevant competitors
For solo freelancer / service-business projects, remove SaaS tool brands:
mcp__peec-ai__delete_brand(project_id, brand_id)
Tool brands to remove: SEMrush, Ahrefs, Sistrix, Moz, Ryte, Yoast, Screaming Frog, SurferSEO, Frase, SE Ranking.
Deletion is soft. Also save a feedback memory noting "track humans only" so future sessions don't re-suggest these.
Phase 4 — Keyword & intent analysis (Visibly AI + GSC)
4a. Verify GSC connection
mcp__visiblyai__get_google_connections()
→ confirm domain has a gsc_property and (ideally) a GA4 pairing
4b. Pull GSC keywords
mcp__visiblyai__get_keywords(domain="example.com", limit=200, location="Germany")
# or for finer control:
mcp__visiblyai__query_search_console(dimension="query", days=28, country="deu", limit=500)
4c. Classify intent
Cluster keywords into:
- Informational (TOFU) — "was ist", "wie funktioniert", " ohne anmeldung", ratgeber queries
- Brand — client brand name + variations
- Commercial (MOFU) — "beste", "vergleich", "Agentur vs Freelancer"
- Transactional (BOFU) — "Kosten", "Preis", "buchen", "kontaktieren", " + "
Frequent pattern: domain ranks well for TOFU informational (blog traffic) but is invisible for commercial / transactional — those are exactly the queries Peec prompts should test.
4d. Map GSC keywords → Peec prompts
For each top GSC keyword: does a Peec prompt exist that tests AI visibility for the same intent? If not, flag as "prompt gap".
Phase 5 — Forum pain-point mining
Mine verbatim buyer pain from public forums → convert into Peec prompts that match real customer language (not sanitized marketing phrasing). These prompts also reveal what LLMs pull from UGC, and whether the brand surfaces in those answers.
5a. Sources
German (priority for DACH):
- Reddit DE —
r/de,r/Finanzen,r/kmu,r/selbststaendig,r/Unternehmer; niche:r/shopify,r/ecommerce,r/SEO - Gutefrage.net — broadest DE consumer Q&A; strong for commercial / transactional pain
- t3n forum (
t3n.de/forum) — DACH digital / business pros - OMR forum (
omr.com/de/forum) — marketing / SEO operator pain - gründerszene comments / deutsche-startups — B2B startup pain
Global / EN fallback:
- Reddit:
r/SEO,r/localseo,r/ecommerce,r/shopify,r/smallbusiness,r/entrepreneur - Quora
- Stack Exchange (Webmasters, Freelancing) for technical pain
Video / social UGC (via WebFetch):
- YouTube comment sections under competitor videos surfaced in the domain report
- LinkedIn post comments on competitor pulse articles (from
get_actions)
5b. Query patterns
Run in parallel — different pain angles:
WebSearch("site:reddit.com ")
# problem-words: "funktioniert nicht", "erfahrungen", "lohnt sich", "hilfe", "enttäuscht"
WebSearch("site:gutefrage.net ")
WebSearch("site:t3n.de/forum ")
WebSearch("site:omr.com frage")
WebSearch(" erfahrungen forum")
WebSearch(" review reddit")
Example for a DACH SEO-retainer project:
site:reddit.com SEO Freelancer erfahrungensite:gutefrage.net SEO Berater lohnt sich"Shopify SEO" "funktioniert nicht" forum"KI SEO" reddit erfahrung
5c. Extract threads
WebFetch(url, "Extract the original question verbat
…
## Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [AntonioBlago](https://github.com/AntonioBlago)
- **Source:** [AntonioBlago/peec-ai-skills](https://github.com/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.