peec-checkup — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited peec-checkup (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Single read-only pass over a Peec project that answers three questions:
No writes. No content production. No outreach. Pure diagnosis + recommendations.
project_id — Peec project (read from setup_state.json per pre-flight; fallback to mcp__peec-ai__list_projects if state missing)date_range — default last 28 days (falls back to whatever data exists if project is younger)top_n — number of improvements to surface, default 5, max 8One markdown report saved to <project>/checkups/YYYY-MM-DD_checkup.md (schema in §6). Mirrored to stdout for the user. Never modifies setup_state.json or any Peec data.
peec-report instead when history exists)Do not use when:
/peec-agent/peec-report/peec-setup (full mode)Per _shared/SETUP_STATE.md, this skill prefers a state file but does not hard-stop without one — checkup is itself the audit you'd run when state is missing. Logic:
Read <project>/growth_loop/setup_state.json
If present:
Use peec_project_id, target_country, prompt_language from state.
Note the setup age in the report.
If missing:
Resolve project via mcp__peec-ai__list_projects.
Note in the report: "no setup_state.json — run /peec-setup
(mode: import) after this checkup to persist findings."
Default target_country=DE, prompt_language=de UNLESS the user said otherwise.This is the only consumer skill allowed to run without a state file — because its whole job is to tell you whether you should run peec-setup next.
Parallel reads:
mcp__peec-ai__list_brands(project_id)
mcp__peec-ai__list_prompts(project_id, limit=200)
mcp__peec-ai__list_topics(project_id)
mcp__peec-ai__list_tags(project_id)Score against this checklist (each item = +/− points; record per-finding evidence):
| Check | Red flag |
|---|---|
| Competitors are real buyer alternatives | SaaS tool brands present (SEMrush, Ahrefs, Sistrix, Moz, Ryte, Yoast, Frase, Surfer, ScreamingFrog) — distort SoV |
| Competitors include AI-recommended ones | Compare list to brands appearing in list_chats sources but not tracked → "invisible competitors" |
| Funnel coverage balanced | Counts per stage (Awareness/Consideration/Decision/Retention) — flag any stage <20% or >50% of total |
| Prompts use buyer language | Quick scan: ≥3 prompts contain platform-vendor phrases ("empfiehl", "vergleich", "alternativ") |
| Prompts under 200 chars | Peec hard limit — list any over |
| Topics enable funnel slicing | Topics named after funnel stages OR by clear analytical axis (offer, audience). Flag topics that are pure themes ("AI", "SEO") with no slicing value |
| Tags are richer than the default 4 | If only branded/non-branded/informational/transactional exist → no offer/persona slicing possible |
| Brand aliases handle Umlauts | Any brand with Umlauts in name but no ASCII alias ("Stürkat" without "Stuerkat" alias) → matching fails on chats |
| Hero prompt identified | setup_state.hero_prompt_id set OR clearly inferrable from get_brand_report; flag if not |
Output: a Setup Health Score = % of checks passing, plus the bulleted findings (severity P0/P1/P2).
own_brand_id = first brand whose domain matches setup_state.domain
(or whose name == own_domain root); if ambiguous, ASK once
# Per-stage visibility
mcp__peec-ai__get_brand_report(
project_id, start_date, end_date,
dimensions=["topic_id"],
filters=[{field: "brand_id", operator: "in", values: [own_brand_id]}]
)
# Per-engine visibility
mcp__peec-ai__get_brand_report(
project_id, start_date, end_date,
dimensions=["model_id"],
filters=[{field: "brand_id", operator: "in", values: [own_brand_id]}]
)
# Per-prompt — find winners + losers
mcp__peec-ai__get_brand_report(
project_id, start_date, end_date,
dimensions=["prompt_id"],
filters=[{field: "brand_id", operator: "in", values: [own_brand_id]}]
)
# Source diversity (how many distinct sources is the brand cited from)
mcp__peec-ai__get_url_report(
project_id, start_date, end_date,
dimensions=["url"],
filters=[{field: "brand_id", operator: "in", values: [own_brand_id]}],
limit=50
)
# Competitor delta — strongest opposition per topic
mcp__peec-ai__get_brand_report(
project_id, start_date, end_date,
dimensions=["topic_id", "brand_id"]
)Compute:
If the project has < 7 days of data: explicitly say so and skip the per-prompt sections — only report counts. Do not invent insights from one day of data.
mcp__peec-ai__get_actions(project_id, scope="overview", start_date, end_date, limit=10)
mcp__peec-ai__get_actions(project_id, scope="editorial", start_date, end_date, limit=10)
mcp__peec-ai__get_actions(project_id, scope="ugc", start_date, end_date, limit=10)
mcp__peec-ai__get_actions(project_id, scope="owned", start_date, end_date, limit=10)
# Where competitors get cited but I don't
mcp__peec-ai__get_url_report(
project_id, start_date, end_date,
filters=[{field: "gap", operator: "gt", value: 0}],
limit=25
)This produces a raw candidate pool of ~50 items. Do not return all of them.
For each candidate, compute a leverage score:
leverage = impact × actionability × strategic_fit| Dimension | Scoring rule |
|---|---|
| impact (0–3) | Peec opportunity_score band (0=low, 1=mid, 2=high, 3=top quartile) |
| actionability (0–3) | 3 = direct edit (own URL, own prompt fix); 2 = one outreach pitch; 1 = content brief required; 0 = needs new SEO project (>4 weeks) |
| strategic_fit (0–3) | 3 = fixes funnel weakness from §2 OR aligns to user's prior setup_state.notes / SkillMind priors; 1 = generic |
Multiplicative — anything with a 0 in any dimension is dropped (those are noise).
Take top top_n (default 5). For each, output:
/peec-content-intel, /peec-outreach, /peec-setup partial:<phase>)Always include at least one structural improvement (from §1) if the Setup Health Score is < 80%. Don't drown setup issues under content opportunities — broken setup invalidates everything else.
Save to <project>/checkups/YYYY-MM-DD_checkup.md (create dir if missing) and stream to user. See §6 schema.
End with one decisive sentence: "Empfohlene nächste Aktion: <skill>" — the single most leveraged item from §4.
# Peec Checkup — <domain> · <YYYY-MM-DD>
## TL;DR
- Visibility now: **<X%>** (was <prev>% N days ago — only if prior checkup exists)
- Setup health: **<Y%>** (<P0 count> P0 issues, <P1 count> P1)
- Strongest funnel: <stage> (<X%>) · Weakest: <stage> (<Y%>)
- Top competitor on weak stage: <brand>
- Recommended next action: <one skill + scope>
## 0. Inventory (counts as of <date>)
| Bucket | Count | Notes |
|---|---|---|
| Brands tracked | <N> | own=1 · competitors=<N-1> · invisible candidates=<N> |
| Prompts total | <M> | active=<M_active> · paused=<M_paused> |
| · Awareness | <a> | <a/M %> |
| · Consideration | <b> | <b/M %> |
| · Decision | <c> | <c/M %> |
| · Retention | <d> | <d/M %> |
| · Unclassified | <e> | flag if >0 — funnel-stage missing |
| Topics | <T> | named: <list first 5> |
| Tags | <G> | non-default: <list non-default tags> |
| Chats analysed in window | <C> | per engine: chatgpt=<x> · perplexity=<y> · gao=<z> |
| Window | <date_range> | days_with_data=<N> |
If `days_with_data < 7` → mark sections 2 + 3 with **"insufficient data"** badge and skip per-prompt detail.
## 1. Setup health (<Y%>)
### P0 — must fix (block valid measurement)
- <finding> — evidence: <data point>
### P1 — should fix (skews insights)
- <finding> — evidence: <data point>
### P2 — nice to have
- <finding>
## 2. Brand performance now (window: <date_range>)
### Visibility per funnel stage
| Stage | Visibility | Top competitor (delta) |
|---|---|---|
| Awareness | X% | comp.de (-Y%) |
| Consideration | … | … |
| Decision | … | … |
| Retention | … | … |
### Visibility per engine
| Engine | Visibility |
|---|---|
| chatgpt-scraper | X% |
| perplexity-scraper | … |
| google-ai-overview-scraper | … |
### Hero prompts — winning (top 5)
1. **<prompt text>** — Y% visibility, mostly via <engine> · sources: <count distinct>
### Hero prompts — losing (top 5)
1. **<prompt text>** — 0% visibility · top competitor: <brand> at <Z%> · cited URL type: <LISTICLE/ARTICLE/COMPARISON/HOW_TO_GUIDE/DISCUSSION>
### Source diversity
<N> distinct source URLs · top sources: <list 5> · health: <weak / OK / healthy>
## 3. Top <N> improvements (priority-ranked)
### #1 — <short action title>
- **Why now:** <causal trace from §1 or §2>
- **Handoff:** <skill + parameters>
- **Effort:** <S / M / L>
- **4-week metric:** <specific delta>
### #2 …
## Recommended next action
**<one skill invocation>** — because <one sentence>.
---
*Read-only checkup. No Peec data was modified. State file: <found at path | missing>.* or delete_` or `update_`.** Pure read.peec-setup writes it. If state was missing, the report tells the user to run /peec-setup partial:import to persist findings./peec-checkup
│ (read-only diagnosis)
↓
reports → user decides
│
├── if structural P0 → /peec-setup (partial / audit)
├── if specific prompt to win → /peec-content-intel
├── if outreach gaps → /peec-outreach
├── if you want ONE decisive next move → /peec-agent
└── if you want time-series + attribution → /peec-report (needs 4+ weeks)/peec-start may route to /peec-checkup when the user's intent is observational ("how am I doing?") rather than action-driven ("what should I do?"). The two are complementary, not redundant: checkup is the lens, growth-agent is the trigger.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.