/02-audit
Run a Claude-native visibility audit. For each query in brand_context.target_queries, ask Claude to answer the query as a real user would (using WebSearch + WebFetch), then record whether the client brand is mentioned, at what position, and which URLs were cited. Outputs
> /plugin marketplace add ViryaZheng/recomby-geo > /plugin install recomby-geo@recomby-geo
How it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/02-audit
Context preview
What this command does when you run it.
Run a Claude-native visibility audit. For each query in brand_context.target_queries, ask Claude to answer the query as a real user would (using WebSearch + WebFetch), then record whether the client brand is mentioned, at what position, and which URLs were cited. Outputs
Command definition
02-audit.mddescription: Run a Claude-native visibility audit. For each query in brand_context.target_queries, ask Claude to answer the query as a real user would (using WebSearch + WebFetch), then record whether the client brand is mentioned, at what position, and which URLs were cited. Outputs visibility_baseline.json validated against schema. This is the BASELINE — the reference point for 07-reaudit. Use after 01-intake; rerun for re-audit rounds.
argument-hint: "<client-folder, e.g. clients/acme>"
02 · Audit — Claude Visibility Baseline
This command measures **what Claude tells real users** when they ask the brand's target queries — without telling Claude who the client is.
We deliberately scope the baseline to Claude only. Multi-LLM coverage (ChatGPT / Perplexity / Gemini / AI Overviews) sounds appealing but requires per-engine API keys and per-engine output normalization, which turns the plugin into a heavy ops project. Single-engine + reproducible beats multi-engine + flaky.
If you later need cross-engine coverage, the vendored `seo-geo-optimizer` (199-bio) skill has multi-engine analysis paths (see its `scripts/platform_optimizer.py`).
---
Inputs
- `clients/<slug>/brand_context.json` — required. Reads `target_queries`,
`layer_1_business_identity.company.name`, `competitors`.
Output
- `clients/<slug>/visibility_baseline.json` (round 1) — validates against
`schemas/visibility_baseline.schema.json`.
- `clients/<slug>/baselines/round-N.json` (round 2+) — preserved snapshots
for 07-reaudit diff.
- `clients/<slug>/baseline-report.md` — human-readable summary.
---
Procedure
Step 1 — Prepare query list
jq '.target_queries | map({query, query_id: (.query | gsub(" "; "-") | ascii_downcase), priority, intent})' \
clients/<slug>/brand_context.json > /tmp/queries.jsonStrip P2 if budget-tight. Default: run all P0 + P1 + P2.
Step 2 — Define the unbiased query runner
For each query, spawn a **fresh sub-agent context** that does NOT see the brand_context. The sub-agent answers the query like a normal user — it uses WebSearch + WebFetch as Claude does by default, no system prompt nudging it toward our client.
Procedure for each query (loop):
Sub-agent task prompt (template):
"You are answering a user's question. The user asked: <query>.
Search the web (WebSearch + WebFetch as needed), then write a
substantive answer (300-600 words) the way you would if asked
conversationally. List specific brands/companies/products by
name when relevant. Include the URLs you actually cited."
Use the `Agent` tool with a generic subagent (`general-purpose` or `Explore`). Capture:
- `raw_response` — full answer text.
- `cited_urls` — every URL the sub-agent fetched or referenced.
- `model_id` — `claude-opus-4-7` (or whichever model the runtime uses).
- `captured_at` — ISO timestamp.
**Failure definition** — a run FAILED (skip the query, do not retry into synthesis) when any of:
- the sub-agent errored or returned nothing (`subagent-error` / `empty-response`);
- the response contains no substantive answer — under ~100 words or a
refusal (`empty-response`);
- the sub-agent could not search the web and answered purely from memory
when the query needs current info (`no-web-access`);
- the answer does not address the query asked (`off-topic-response`).
A response that answers the query but doesn't mention the client is NOT a failure — that's a legitimate `mentioned: false` data point (the most important kind). Record each failed query in `meta.failed_queries[]` (query_id + reason enum + optional detail; see schema) and exclude it from every Step 5 denominator. If more than 20% of queries fail, stop and report to the user instead of shipping a thin baseline.
Step 3 — Brand & competitor extraction
For each query result, extract:
| Field | How | |-------|-----| | `mentioned` | regex: `\b(<company.name>|<aliases>)\b` (case-insensitive, word-boundary) | | `position` | If response is list-formatted (numbered, bulleted, ranked), find rank of first brand mention; else `null` | | `description_quoted` | Sentence containing the brand name (full sentence, not snippet) | | `competitors_mentioned` | List of competitor names (from `brand_context.competitors[*].name`) found in response | | `is_owned_by_client` (per citation) | Domain match: parse URL, check against `company.url` |
If brand has aliases or alternate names in `brand_context.layer_1_business_identity.company`, include them in the regex.
Step 4 — Verify cited URLs are live
For each unique URL across all `cited_urls[]`:
WebFetch <url> with prompt "summarize this page in one sentence; flag
if 404, redirect, or off-topic from query"
Set `verified_live: true` if the page resolves and is on-topic. `false` otherwise. Skip URLs already verified in this client's previous baseline (cache file: `clients/<slug>/.url-verify-cache.json`).
This step is non-negotiable. AI hallucinated citations are common, and they will silently corrupt 07-reaudit's attribution if not pruned.
Step 5 — Compute summary metrics
mention_rate = sum(1 for r in runs if r.mentioned) / len(runs)
positions = [r.position for r in runs if r.mentioned and r.position]
avg_position_when_mentioned = sum(positions)/len(positions) if positions else None
total_citations = sum(len(r.citations) for r in runs)
owned_citations = sum(1 for r in runs for c in r.citations if c.is_owned_by_client)
owned_citation_rate = owned_citations / total_citations if total_citations else 0
overall_visibility_score = round(
100 * (
0.5 * mention_rate +
0.3 * (1 / (avg_position_when_mentioned or 10)) +
0.2 * owned_citation_rate
),
1
)Per-query verdict:
- `winning` — `mention_rate >= 0.6` AND `avg_position <= 3` (across N≥2 runs of the same query, if you choose to run repeats; default is N=1 per query)
- `contested` — `0 < mention_rate < 0.6`
- `absent` — `mention_rate == 0`
- `regressing` — only set i
Read more
description: Run a Claude-native visibility audit. For each query in brand_context.target_queries, ask Claude to answer the query as a real user would (using WebSearch + WebFetch), then record whether the client brand is mentioned, at what position, and which URLs were cited. Outputs visibility_baseline.json validated against schema. This is the BASELINE — the reference point for 07-reaudit. Use after 01-intake; rerun for re-audit rounds. argument-hint: "<client-folder, e.g. clients/acme>"
02 · Audit — Claude Visibility Baseline
This command measures **what Claude tells real users** when they ask the brand's target queries — without telling Claude who the client is.
We deliberately scope the baseline to Claude only. Multi-LLM coverage (ChatGPT / Perplexity / Gemini / AI Overviews) sounds appealing but requires per-engine API keys and per-engine output normalization, which turns the plugin into a heavy ops project. Single-engine + reproducible beats multi-engine + flaky.
If you later need cross-engine coverage, the vendored `seo-geo-optimizer` (199-bio) skill has multi-engine analysis paths (see its `scripts/platform_optimizer.py`).
---
Inputs
- `clients/<slug>/brand_context.json` — required. Reads `target_queries`,
`layer_1_business_identity.company.name`, `competitors`.
Output
- `clients/<slug>/visibility_baseline.json` (round 1) — validates against
`schemas/visibility_baseline.schema.json`.
- `clients/<slug>/baselines/round-N.json` (round 2+) — preserved snapshots
for 07-reaudit diff.
- `clients/<slug>/baseline-report.md` — human-readable summary.
---
Procedure
Step 1 — Prepare query list
jq '.target_queries | map({query, query_id: (.query | gsub(" "; "-") | ascii_downcase), priority, intent})' \
clients/<slug>/brand_context.json > /tmp/queries.jsonStrip P2 if budget-tight. Default: run all P0 + P1 + P2.
Step 2 — Define the unbiased query runner
For each query, spawn a **fresh sub-agent context** that does NOT see the brand_context. The sub-agent answers the query like a normal user — it uses WebSearch + WebFetch as Claude does by default, no system prompt nudging it toward our client.
Procedure for each query (loop):
Sub-agent task prompt (template): "You are answering a user's question. The user asked: <query>. Search the web (WebSearch + WebFetch as needed), then write a substantive answer (300-600 words) the way you would if asked conversationally. List specific brands/companies/products by name when relevant. Include the URLs you actually cited."
Use the `Agent` tool with a generic subagent (`general-purpose` or `Explore`). Capture:
- `raw_response` — full answer text.
- `cited_urls` — every URL the sub-agent fetched or referenced.
- `model_id` — `claude-opus-4-7` (or whichever model the runtime uses).
- `captured_at` — ISO timestamp.
**Failure definition** — a run FAILED (skip the query, do not retry into synthesis) when any of:
- the sub-agent errored or returned nothing (`subagent-error` / `empty-response`);
- the response contains no substantive answer — under ~100 words or a
refusal (`empty-response`);
- the sub-agent could not search the web and answered purely from memory
when the query needs current info (`no-web-access`);
- the answer does not address the query asked (`off-topic-response`).
A response that answers the query but doesn't mention the client is NOT a failure — that's a legitimate `mentioned: false` data point (the most important kind). Record each failed query in `meta.failed_queries[]` (query_id + reason enum + optional detail; see schema) and exclude it from every Step 5 denominator. If more than 20% of queries fail, stop and report to the user instead of shipping a thin baseline.
Step 3 — Brand & competitor extraction
For each query result, extract:
| Field | How | |-------|-----| | `mentioned` | regex: `\b(<company.name>|<aliases>)\b` (case-insensitive, word-boundary) | | `position` | If response is list-formatted (numbered, bulleted, ranked), find rank of first brand mention; else `null` | | `description_quoted` | Sentence containing the brand name (full sentence, not snippet) | | `competitors_mentioned` | List of competitor names (from `brand_context.competitors[*].name`) found in response | | `is_owned_by_client` (per citation) | Domain match: parse URL, check against `company.url` |
If brand has aliases or alternate names in `brand_context.layer_1_business_identity.company`, include them in the regex.
Step 4 — Verify cited URLs are live
For each unique URL across all `cited_urls[]`:
WebFetch <url> with prompt "summarize this page in one sentence; flag if 404, redirect, or off-topic from query"
Set `verified_live: true` if the page resolves and is on-topic. `false` otherwise. Skip URLs already verified in this client's previous baseline (cache file: `clients/<slug>/.url-verify-cache.json`).
This step is non-negotiable. AI hallucinated citations are common, and they will silently corrupt 07-reaudit's attribution if not pruned.
Step 5 — Compute summary metrics
mention_rate = sum(1 for r in runs if r.mentioned) / len(runs)
positions = [r.position for r in runs if r.mentioned and r.position]
avg_position_when_mentioned = sum(positions)/len(positions) if positions else None
total_citations = sum(len(r.citations) for r in runs)
owned_citations = sum(1 for r in runs for c in r.citations if c.is_owned_by_client)
owned_citation_rate = owned_citations / total_citations if total_citations else 0
overall_visibility_score = round(
100 * (
0.5 * mention_rate +
0.3 * (1 / (avg_position_when_mentioned or 10)) +
0.2 * owned_citation_rate
),
1
)Per-query verdict:
- `winning` — `mention_rate >= 0.6` AND `avg_position <= 3` (across N≥2 runs of the same query, if you choose to run repeats; default is N=1 per query)
- `contested` — `0 < mention_rate < 0.6`
- `absent` — `mention_rate == 0`
- `regressing` — only set i
GEO 领域 AI 员工开源方案 · Open-source GEO AI-employee solution (MIT). GEO Skills package + curated lists of agents and office CLIs that make up the AI-employee stack.
Other commands on recomby-geo.
- /01-intake
Build the GEO brand context for a client by ingesting provided materials (PDF/DOCX/PPTX/XLSX, URLs, raw notes) and conducting structured AI-perception + competitor + community research. Writes brand_context.json validated against schemas/brand_context.schema.json. Use when
Open command - /03-gap
Translate the visibility baseline + brand context into a ranked list of content actions that should move the needle. Identifies absent queries, contested queries, and competitor-displacement opportunities. Outputs content_priorities.json validated against schema. Use after
Open command - /04-content-brief
For one priority from content_priorities.json, generate a content brief with explicit slots for the human expert (founder/domain specialist) to fill with real cases, real data, and real opinions. This is the human-in-loop checkpoint — the moat that prevents the entire workflow
Open command - /05-production
Convert an expert-filled brief into a publishable draft. Applies Princeton KDD 2024 GEO techniques (statistics, quotations, citations, authoritative language) to maximize AI citation likelihood. Refuses to run on briefs that haven't been filled by the expert. Outputs
Open command - /06-distribution
For a published-ready draft, generate JSON-LD schema markup, internal linking suggestions, third-party distribution targets, and llms.txt block. Outputs distribution/<id>.json and distribution/<id>.publish-bundle.md. Use after 05-production; consumed by 07-reaudit (records
Open command - /07-reaudit
Re-run 02-audit, diff against the previous baseline, attribute movement to specific content/distribution actions. Outputs reaudit/round-N.json validated against attribution_diff.schema.json. This is the closing-of- loop artifact that proves (or disproves) what's actually
Open command

