@growthub/cli 0.3.50 → 0.3.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/worker-kits/growthub-geo-seo-v1/.env.example +12 -0
- package/assets/worker-kits/growthub-geo-seo-v1/QUICKSTART.md +138 -0
- package/assets/worker-kits/growthub-geo-seo-v1/brands/NEW-CLIENT.md +104 -0
- package/assets/worker-kits/growthub-geo-seo-v1/brands/_template/brand-kit.md +116 -0
- package/assets/worker-kits/growthub-geo-seo-v1/brands/growthub/brand-kit.md +117 -0
- package/assets/worker-kits/growthub-geo-seo-v1/bundles/growthub-geo-seo-v1.json +54 -0
- package/assets/worker-kits/growthub-geo-seo-v1/docs/geo-seo-fork-integration.md +244 -0
- package/assets/worker-kits/growthub-geo-seo-v1/docs/pdf-report-layer.md +139 -0
- package/assets/worker-kits/growthub-geo-seo-v1/docs/scoring-methodology.md +230 -0
- package/assets/worker-kits/growthub-geo-seo-v1/docs/subagent-dispatch.md +273 -0
- package/assets/worker-kits/growthub-geo-seo-v1/examples/citability-sample.md +155 -0
- package/assets/worker-kits/growthub-geo-seo-v1/examples/geo-audit-sample.md +126 -0
- package/assets/worker-kits/growthub-geo-seo-v1/examples/pdf-report-sample.md +207 -0
- package/assets/worker-kits/growthub-geo-seo-v1/examples/prospect-proposal-sample.md +184 -0
- package/assets/worker-kits/growthub-geo-seo-v1/growthub-meta/README.md +124 -0
- package/assets/worker-kits/growthub-geo-seo-v1/growthub-meta/kit-standard.md +116 -0
- package/assets/worker-kits/growthub-geo-seo-v1/kit.json +102 -0
- package/assets/worker-kits/growthub-geo-seo-v1/output/README.md +114 -0
- package/assets/worker-kits/growthub-geo-seo-v1/output-standards.md +143 -0
- package/assets/worker-kits/growthub-geo-seo-v1/runtime-assumptions.md +175 -0
- package/assets/worker-kits/growthub-geo-seo-v1/setup/check-deps.sh +80 -0
- package/assets/worker-kits/growthub-geo-seo-v1/setup/clone-fork.sh +56 -0
- package/assets/worker-kits/growthub-geo-seo-v1/setup/verify-env.mjs +152 -0
- package/assets/worker-kits/growthub-geo-seo-v1/skills.md +359 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/brand-visibility-report.md +101 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/citability-analysis.md +131 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/client-proposal.md +172 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/content-analysis.md +136 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/crawler-access-report.md +115 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/geo-audit-brief.md +114 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/geo-score-summary.md +113 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/llmstxt-plan.md +173 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/remediation-roadmap.md +150 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/schema-validation.md +177 -0
- package/assets/worker-kits/growthub-geo-seo-v1/templates/technical-foundations.md +108 -0
- package/assets/worker-kits/growthub-geo-seo-v1/validation-checklist.md +139 -0
- package/assets/worker-kits/growthub-geo-seo-v1/workers/geo-seo-operator/CLAUDE.md +320 -0
- package/package.json +1 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// verify-env.mjs — Verify the geo-seo-claude environment is ready
|
|
3
|
+
// Usage: node setup/verify-env.mjs
|
|
4
|
+
// No network calls are made. All checks are local filesystem only.
|
|
5
|
+
|
|
6
|
+
import { existsSync, readFileSync } from "fs";
|
|
7
|
+
import { homedir } from "os";
|
|
8
|
+
import { resolve, join } from "path";
|
|
9
|
+
|
|
10
|
+
// ─── Helpers ───────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
function parseEnvFile(filePath) {
|
|
13
|
+
if (!existsSync(filePath)) return {};
|
|
14
|
+
const lines = readFileSync(filePath, "utf8").split("\n");
|
|
15
|
+
const env = {};
|
|
16
|
+
for (const line of lines) {
|
|
17
|
+
const trimmed = line.trim();
|
|
18
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
19
|
+
const eqIdx = trimmed.indexOf("=");
|
|
20
|
+
if (eqIdx === -1) continue;
|
|
21
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
22
|
+
const val = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, "");
|
|
23
|
+
env[key] = val;
|
|
24
|
+
}
|
|
25
|
+
return env;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function pass(label, note = "") {
|
|
29
|
+
console.log(` PASS ${label}${note ? " — " + note : ""}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function fail(label, message) {
|
|
33
|
+
console.log(` FAIL ${label} — ${message}`);
|
|
34
|
+
failures.push(label);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function warn(label, message) {
|
|
38
|
+
console.log(` WARN ${label} — ${message}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ─── State ─────────────────────────────────────────────────────────────────
|
|
42
|
+
|
|
43
|
+
const failures = [];
|
|
44
|
+
|
|
45
|
+
// ─── Load .env ─────────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
const envPath = resolve(process.cwd(), ".env");
|
|
48
|
+
const envExamplePath = resolve(process.cwd(), ".env.example");
|
|
49
|
+
|
|
50
|
+
console.log("=== Growthub GEO SEO Studio — Environment Verification ===");
|
|
51
|
+
console.log("");
|
|
52
|
+
|
|
53
|
+
let env = {};
|
|
54
|
+
if (existsSync(envPath)) {
|
|
55
|
+
env = parseEnvFile(envPath);
|
|
56
|
+
pass(".env file", `found at ${envPath}`);
|
|
57
|
+
} else if (existsSync(envExamplePath)) {
|
|
58
|
+
warn(".env file", ".env not found — using .env.example for reference only. Run: cp .env.example .env");
|
|
59
|
+
} else {
|
|
60
|
+
warn(".env file", ".env and .env.example both missing — proceeding with process.env only");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Merge with process.env (process.env takes priority over .env file)
|
|
64
|
+
const config = { ...env, ...process.env };
|
|
65
|
+
|
|
66
|
+
console.log("");
|
|
67
|
+
console.log("--- Fork Path Check ---");
|
|
68
|
+
|
|
69
|
+
// ─── Fork Path ─────────────────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
const forkPathRaw = config["GEO_SEO_FORK_PATH"] || join(homedir(), "geo-seo-claude");
|
|
72
|
+
const forkPath = resolve(forkPathRaw);
|
|
73
|
+
|
|
74
|
+
if (existsSync(forkPath)) {
|
|
75
|
+
pass("GEO_SEO_FORK_PATH", `fork found at ${forkPath}`);
|
|
76
|
+
|
|
77
|
+
// Check key scripts exist in the fork
|
|
78
|
+
const requiredScripts = [
|
|
79
|
+
"scripts/fetch_page.py",
|
|
80
|
+
"scripts/citability_scorer.py",
|
|
81
|
+
"scripts/brand_scanner.py",
|
|
82
|
+
"scripts/generate_pdf_report.py",
|
|
83
|
+
"scripts/llmstxt_generator.py",
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
for (const scriptPath of requiredScripts) {
|
|
87
|
+
const fullPath = join(forkPath, scriptPath);
|
|
88
|
+
if (existsSync(fullPath)) {
|
|
89
|
+
pass(scriptPath);
|
|
90
|
+
} else {
|
|
91
|
+
warn(scriptPath, `not found in fork at ${fullPath} — may be in a different path in this fork version`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
warn(
|
|
96
|
+
"GEO_SEO_FORK_PATH",
|
|
97
|
+
`fork not found at ${forkPath}. Run: bash setup/clone-fork.sh\n Agent-only mode is available without the fork.`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
console.log("");
|
|
102
|
+
console.log("--- API Key Check ---");
|
|
103
|
+
|
|
104
|
+
// ─── Anthropic API Key (optional) ─────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
const anthropicKey = config["ANTHROPIC_API_KEY"];
|
|
107
|
+
if (!anthropicKey) {
|
|
108
|
+
warn("ANTHROPIC_API_KEY", "not set — agent-enhanced analysis requires this key. Core Python analysis works without it.");
|
|
109
|
+
} else if (!anthropicKey.startsWith("sk-ant-")) {
|
|
110
|
+
fail("ANTHROPIC_API_KEY", `key does not start with 'sk-ant-' — this may be an invalid key. Check https://console.anthropic.com`);
|
|
111
|
+
} else if (anthropicKey.length < 40) {
|
|
112
|
+
fail("ANTHROPIC_API_KEY", "key appears too short — verify you copied the full key from https://console.anthropic.com");
|
|
113
|
+
} else {
|
|
114
|
+
pass("ANTHROPIC_API_KEY", "key format looks valid (starts with sk-ant-, adequate length)");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// ─── Optional Config ───────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
console.log("");
|
|
120
|
+
console.log("--- Optional Config ---");
|
|
121
|
+
|
|
122
|
+
const flaskPort = config["FLASK_PORT"] || "5000 (default)";
|
|
123
|
+
pass("FLASK_PORT", `${flaskPort} — Flask CRM dashboard will use this port`);
|
|
124
|
+
|
|
125
|
+
const outputRoot = config["GEO_OUTPUT_ROOT"] || "./output (default)";
|
|
126
|
+
pass("GEO_OUTPUT_ROOT", outputRoot);
|
|
127
|
+
|
|
128
|
+
const playwrightBrowser = config["PLAYWRIGHT_BROWSER"] || "chromium (default)";
|
|
129
|
+
pass("PLAYWRIGHT_BROWSER", playwrightBrowser);
|
|
130
|
+
|
|
131
|
+
// ─── Summary ───────────────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
console.log("");
|
|
134
|
+
console.log("=== Summary ===");
|
|
135
|
+
|
|
136
|
+
if (failures.length === 0) {
|
|
137
|
+
const forkReady = existsSync(forkPath);
|
|
138
|
+
if (forkReady) {
|
|
139
|
+
console.log("Environment is ready. Fork found. Run your first audit with /geo audit.");
|
|
140
|
+
} else {
|
|
141
|
+
console.log("Environment OK. Fork not found — agent-only mode available.");
|
|
142
|
+
console.log("To enable local-fork mode: bash setup/clone-fork.sh");
|
|
143
|
+
}
|
|
144
|
+
process.exit(0);
|
|
145
|
+
} else {
|
|
146
|
+
console.log(`${failures.length} check(s) failed:`);
|
|
147
|
+
for (const f of failures) {
|
|
148
|
+
console.log(` - ${f}`);
|
|
149
|
+
}
|
|
150
|
+
console.log("Resolve these before running local-fork mode workflows.");
|
|
151
|
+
process.exit(1);
|
|
152
|
+
}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# GEO SEO Operator — Master Skill Doc
|
|
2
|
+
|
|
3
|
+
**Source of truth for methodology. Read this file completely before beginning any task.**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## QUICK REFERENCE TABLE
|
|
8
|
+
|
|
9
|
+
| Resource | Path |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Agent operating law | `workers/geo-seo-operator/CLAUDE.md` |
|
|
12
|
+
| Brand kit template | `brands/_template/brand-kit.md` |
|
|
13
|
+
| Growthub example brand kit | `brands/growthub/brand-kit.md` |
|
|
14
|
+
| Output contract | `output-standards.md` |
|
|
15
|
+
| Runtime assumptions | `runtime-assumptions.md` |
|
|
16
|
+
| Fork integration notes | `docs/geo-seo-fork-integration.md` |
|
|
17
|
+
| Subagent dispatch | `docs/subagent-dispatch.md` |
|
|
18
|
+
| Scoring methodology | `docs/scoring-methodology.md` |
|
|
19
|
+
| PDF report layer | `docs/pdf-report-layer.md` |
|
|
20
|
+
| GEO audit brief | `templates/geo-audit-brief.md` |
|
|
21
|
+
| Citability analysis | `templates/citability-analysis.md` |
|
|
22
|
+
| Crawler access report | `templates/crawler-access-report.md` |
|
|
23
|
+
| Brand visibility report | `templates/brand-visibility-report.md` |
|
|
24
|
+
| GEO score summary | `templates/geo-score-summary.md` |
|
|
25
|
+
| Content analysis | `templates/content-analysis.md` |
|
|
26
|
+
| Schema validation | `templates/schema-validation.md` |
|
|
27
|
+
| Technical foundations | `templates/technical-foundations.md` |
|
|
28
|
+
| llms.txt plan | `templates/llmstxt-plan.md` |
|
|
29
|
+
| Remediation roadmap | `templates/remediation-roadmap.md` |
|
|
30
|
+
| Client proposal | `templates/client-proposal.md` |
|
|
31
|
+
| Sample audit brief | `examples/geo-audit-sample.md` |
|
|
32
|
+
| Sample citability | `examples/citability-sample.md` |
|
|
33
|
+
| Sample PDF data | `examples/pdf-report-sample.md` |
|
|
34
|
+
| Sample proposal | `examples/prospect-proposal-sample.md` |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## STEP 0 — BEFORE ANY TASK, ANSWER THESE QUESTIONS
|
|
39
|
+
|
|
40
|
+
Before producing anything, confirm:
|
|
41
|
+
|
|
42
|
+
1. Which client or brand is this for?
|
|
43
|
+
2. What is the target URL or domain?
|
|
44
|
+
3. What is the audit scope: quick / citability-only / full / specific command?
|
|
45
|
+
4. What delivery format is required: Markdown only / PDF / both?
|
|
46
|
+
5. Is the geo-seo-claude fork available locally?
|
|
47
|
+
6. What execution mode: local-fork / agent-only / hybrid?
|
|
48
|
+
|
|
49
|
+
If any of these are unknown after the 3-question gate in CLAUDE.md, stop and ask.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## STEP 1 — LOAD THE BRAND KIT
|
|
54
|
+
|
|
55
|
+
Read `brands/<client-slug>/brand-kit.md` if it exists. Otherwise start from `brands/_template/brand-kit.md`.
|
|
56
|
+
|
|
57
|
+
Extract:
|
|
58
|
+
- client identity (name, slug, industry)
|
|
59
|
+
- target URL and competitor URLs
|
|
60
|
+
- audit scope and delivery format preference
|
|
61
|
+
- messaging tone and guardrails
|
|
62
|
+
- agency context (prospect stage, retainer range)
|
|
63
|
+
- existing deliverables log
|
|
64
|
+
|
|
65
|
+
The brand kit drives all output naming, tone calibration, and proposal pricing context.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## STEP 2 — CHECK THE WORKING SUBSTRATE
|
|
70
|
+
|
|
71
|
+
If the user has a local geo-seo-claude fork, inspect it before planning anything.
|
|
72
|
+
|
|
73
|
+
### Source-of-truth file order in the fork
|
|
74
|
+
|
|
75
|
+
1. `README.md`
|
|
76
|
+
2. `geo/` — main skill entry point and command routing
|
|
77
|
+
3. `skills/` — 14 sub-skill definition files
|
|
78
|
+
4. `agents/` — 5 subagent definition files
|
|
79
|
+
5. `scripts/fetch_page.py` — fetches and parses pages via Playwright
|
|
80
|
+
6. `scripts/citability_scorer.py` — runs the 5-metric citability algorithm
|
|
81
|
+
7. `scripts/brand_scanner.py` — scans platforms for brand mentions
|
|
82
|
+
8. `scripts/generate_pdf_report.py` — produces branded PDF via ReportLab
|
|
83
|
+
9. `scripts/llmstxt_generator.py` — generates llms.txt and llms-full.txt
|
|
84
|
+
10. `scripts/crm_dashboard.py` — Flask-based CRM dashboard
|
|
85
|
+
11. `schema/` — 6 JSON-LD templates for structured data recommendations
|
|
86
|
+
|
|
87
|
+
### What to verify in the fork
|
|
88
|
+
|
|
89
|
+
- Which of the 14 commands are implemented and callable
|
|
90
|
+
- Whether Playwright is installed and chromium browser is available
|
|
91
|
+
- Whether `requirements.txt` dependencies are installed
|
|
92
|
+
- What the Python version is (`python3 --version`)
|
|
93
|
+
- Whether `schema/` contains JSON-LD templates for all common types
|
|
94
|
+
- Whether `agents/` has definitions for all 5 subagents
|
|
95
|
+
|
|
96
|
+
If the fork cannot be inspected, use the frozen assumptions in `runtime-assumptions.md` and label outputs `assumption-based`.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## STEP 3 — COMMAND SELECTION LOGIC
|
|
101
|
+
|
|
102
|
+
Select the narrowest command that satisfies the real job.
|
|
103
|
+
|
|
104
|
+
| Command | Primary Use | Phase 2 Subagents? | PDF Output? |
|
|
105
|
+
|---|---|---|---|
|
|
106
|
+
| `/geo audit` | Full GEO + SEO audit, all components | Yes | Optional |
|
|
107
|
+
| `/geo citability` | Citability score only, fast | No | No |
|
|
108
|
+
| `/geo crawlers` | AI crawler permission check | No | No |
|
|
109
|
+
| `/geo brands` | Brand mention and authority scan | No | No |
|
|
110
|
+
| `/geo report` | Structured Markdown report from existing data | No | No |
|
|
111
|
+
| `/geo report-pdf` | Branded PDF report via ReportLab | No | Yes |
|
|
112
|
+
| `/geo content` | E-E-A-T and content quality | Partial | No |
|
|
113
|
+
| `/geo schema` | Structured data validation | No | No |
|
|
114
|
+
| `/geo technical` | Server headers and technical health | No | No |
|
|
115
|
+
| `/geo llmstxt` | Generate llms.txt plan or file | No | No |
|
|
116
|
+
| `/geo quick` | 60-second AI visibility snapshot | No | No |
|
|
117
|
+
| `/geo proposal` | Client proposal with pricing | No | No |
|
|
118
|
+
| `/geo prospect` | Prospect qualification scan | Partial | No |
|
|
119
|
+
| `/geo compare` | Side-by-side GEO comparison of 2+ URLs | Yes | Optional |
|
|
120
|
+
|
|
121
|
+
Default selection rules:
|
|
122
|
+
- "Full audit" → `/geo audit`
|
|
123
|
+
- "Quick look" or "first pass" → `/geo quick`
|
|
124
|
+
- "Check if crawlers can access" → `/geo crawlers`
|
|
125
|
+
- "Can AI cite this page?" → `/geo citability`
|
|
126
|
+
- "Build a proposal for this prospect" → `/geo proposal`
|
|
127
|
+
- "Compare to competitors" → `/geo compare`
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## STEP 4 — PHASE 1: FETCH AND PARSE LOGIC
|
|
132
|
+
|
|
133
|
+
`fetch_page.py` uses Playwright (chromium) to load the target URL dynamically and extract all signals needed for Phase 2.
|
|
134
|
+
|
|
135
|
+
### What to extract
|
|
136
|
+
|
|
137
|
+
| Signal | Source | Notes |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `robots.txt` | `https://domain.com/robots.txt` | Parse Disallow/Allow rules for each of the 14 AI crawler user-agents |
|
|
140
|
+
| `llms.txt` | `https://domain.com/llms.txt` | Exists / missing / malformed — record file contents if present |
|
|
141
|
+
| `llms-full.txt` | `https://domain.com/llms-full.txt` | Exists / missing |
|
|
142
|
+
| `sitemap.xml` | `https://domain.com/sitemap.xml` | URL count, lastmod dates, priority values |
|
|
143
|
+
| HTML `<title>` | Page source | Record exact value |
|
|
144
|
+
| `<meta description>` | Page source | Record exact value |
|
|
145
|
+
| `<link rel="canonical">` | Page source | Record exact value |
|
|
146
|
+
| Open Graph tags | Page source | og:title, og:description, og:type, og:image |
|
|
147
|
+
| HTTP response headers | Server response | Server, Cache-Control, Content-Type, X-Robots-Tag, Strict-Transport-Security |
|
|
148
|
+
| Page word count | Rendered HTML | After JS execution — Playwright renders dynamic content |
|
|
149
|
+
| Heading hierarchy | Rendered HTML | H1 count, H2 count, nesting order |
|
|
150
|
+
| Structured data | Page source | JSON-LD blocks, Microdata, RDFa |
|
|
151
|
+
| HTTPS status | URL scheme + redirect | Confirm HTTPS redirect from HTTP |
|
|
152
|
+
|
|
153
|
+
In agent-only mode, perform this extraction manually by reading the page via fetch/curl equivalent and parsing visible content.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## STEP 5 — PHASE 2: SUBAGENT DISPATCH LOGIC
|
|
158
|
+
|
|
159
|
+
After Phase 1 completes, dispatch all 5 subagents in parallel. Each subagent receives the Phase 1 data as input.
|
|
160
|
+
|
|
161
|
+
### geo-ai-visibility (25% of GEO Score)
|
|
162
|
+
|
|
163
|
+
**Scope:** AI crawler access and citation format quality
|
|
164
|
+
|
|
165
|
+
**Inputs:** robots.txt parsed rules, llms.txt contents (if any), page HTML structure
|
|
166
|
+
|
|
167
|
+
**What it checks:**
|
|
168
|
+
- Permission status for each of the 14 AI crawlers (GPTBot, ClaudeBot, PerplexityBot, Google-Extended, Bingbot, Applebot-Extended, Anthropic-AI, cohere-ai, Meta-ExternalFetcher, YouBot, DuckAssistBot, Scrapy, CCBot, ia_archiver)
|
|
169
|
+
- Whether llms.txt exists and follows the correct format
|
|
170
|
+
- Whether llms-full.txt exists
|
|
171
|
+
- Citation format quality — does the page structure support clean citation by AI systems?
|
|
172
|
+
- Presence of clean canonical URLs, no JavaScript-only content walls
|
|
173
|
+
|
|
174
|
+
**Outputs:** Crawler permission matrix (14 rows), llms.txt status, citation format score (0–100)
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
### geo-content (20% of GEO Score)
|
|
179
|
+
|
|
180
|
+
**Scope:** E-E-A-T signals, answer block quality, content self-containment
|
|
181
|
+
|
|
182
|
+
**Inputs:** Rendered page HTML, word count, heading structure, author markup
|
|
183
|
+
|
|
184
|
+
**What it checks:**
|
|
185
|
+
- Experience signals: case studies, original data, first-person examples
|
|
186
|
+
- Expertise signals: author credentials, bylines, About page depth
|
|
187
|
+
- Authoritativeness signals: external citations, backlink signals (if available), Wikipedia mentions
|
|
188
|
+
- Trustworthiness signals: HTTPS, contact info, privacy policy, review count
|
|
189
|
+
- Answer block quality: does the page contain self-contained answer paragraphs that AI systems can quote directly?
|
|
190
|
+
- Self-containment check: word count vs. pronoun density — pages with high pronoun density relative to noun density score lower
|
|
191
|
+
- Statistical density: presence of percentages, numbered lists, data references
|
|
192
|
+
- Uniqueness signals: original research, proprietary data, non-generic claims
|
|
193
|
+
|
|
194
|
+
**Outputs:** E-E-A-T score (0–100), content quality score (0–100), top 3 content gaps
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
### geo-platform-analysis (10% of GEO Score)
|
|
199
|
+
|
|
200
|
+
**Scope:** Readiness for specific AI search platforms
|
|
201
|
+
|
|
202
|
+
**Inputs:** Page structure, schema markup, llms.txt status, content signals
|
|
203
|
+
|
|
204
|
+
**What it checks:**
|
|
205
|
+
- ChatGPT readiness: Browse with Bing access, clean URL structure, answer-block format
|
|
206
|
+
- Perplexity readiness: Direct URL crawlability, citation format, structured answers
|
|
207
|
+
- Google AI Overviews readiness: E-E-A-T signals, structured data, FAQ schema, featured snippet optimization
|
|
208
|
+
- Gemini readiness: Google entity graph signals, Knowledge Panel readiness, schema breadth
|
|
209
|
+
|
|
210
|
+
**Outputs:** Platform readiness table (4 platforms × 5 signals × score), composite platform score (0–100)
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
### geo-schema (10% of GEO Score)
|
|
215
|
+
|
|
216
|
+
**Scope:** Structured data coverage and validation
|
|
217
|
+
|
|
218
|
+
**Inputs:** Page source JSON-LD blocks, Microdata, RDFa markup
|
|
219
|
+
|
|
220
|
+
**What it checks:**
|
|
221
|
+
- Which schema types are present (Organization, WebSite, Article, BreadcrumbList, FAQPage, HowTo, Product, LocalBusiness, etc.)
|
|
222
|
+
- Validation errors (missing required properties, incorrect value types)
|
|
223
|
+
- Missing recommended schema types for the page type
|
|
224
|
+
- Schema richness score — number of types × completeness per type
|
|
225
|
+
|
|
226
|
+
**Outputs:** Schema type coverage table, validation error list, missing types list, schema score (0–100)
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
### geo-technical (15% of GEO Score)
|
|
231
|
+
|
|
232
|
+
**Scope:** Technical SEO and server health
|
|
233
|
+
|
|
234
|
+
**Inputs:** HTTP response headers, HTTPS status, page load signals, robots.txt
|
|
235
|
+
|
|
236
|
+
**What it checks:**
|
|
237
|
+
- HTTPS enforcement (redirect from HTTP, HSTS header)
|
|
238
|
+
- Mobile friendliness signals (viewport meta tag, responsive CSS indicators)
|
|
239
|
+
- robots.txt validity (valid syntax, no wildcard blocks on critical paths)
|
|
240
|
+
- Sitemap accessibility (sitemap.xml found, linked from robots.txt)
|
|
241
|
+
- Core Web Vitals signals (from Lighthouse or page source — LCP hints, CLS hints, FID/INP hints)
|
|
242
|
+
- Server headers (Cache-Control, Content-Encoding, CDN indicators)
|
|
243
|
+
- Page speed indicators (image optimization signals, script loading strategy)
|
|
244
|
+
|
|
245
|
+
**Outputs:** Server headers table, Core Web Vitals signal table, technical score (0–100), critical fixes list
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## STEP 6 — GEO SCORE SYNTHESIS
|
|
250
|
+
|
|
251
|
+
Apply the weighted formula after all subagent results are collected.
|
|
252
|
+
|
|
253
|
+
### GEO Score Formula
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
GEO Score = (AI Citability × 0.25) + (Brand Authority × 0.20) + (Content Quality × 0.20) +
|
|
257
|
+
(Technical Foundations × 0.15) + (Structured Data × 0.10) + (Platform Optimization × 0.10)
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Component Score Normalization
|
|
261
|
+
|
|
262
|
+
Each component subagent returns a raw score 0–100. If a component cannot be scored (data gap), use 50 as the neutral default and flag the component as `data-gap`.
|
|
263
|
+
|
|
264
|
+
### Letter Grade Thresholds
|
|
265
|
+
|
|
266
|
+
| Grade | Score Range | Meaning |
|
|
267
|
+
|---|---|---|
|
|
268
|
+
| A | 85–100 | Highly optimized for AI search — strong citability, clean access, rich schema |
|
|
269
|
+
| B | 70–84 | Good AI visibility — some gaps, addressable in one sprint cycle |
|
|
270
|
+
| C | 55–69 | Moderate visibility — missing key citability signals, schema gaps, crawler issues |
|
|
271
|
+
| D | 40–54 | Poor AI visibility — likely blocked or thin content, major remediation needed |
|
|
272
|
+
| F | Below 40 | Not AI-search-ready — crawlers blocked, no schema, low citability |
|
|
273
|
+
|
|
274
|
+
### Score Interpretation for Client Communication
|
|
275
|
+
|
|
276
|
+
- **A (85+):** "Your site is well-positioned for AI-driven search. We recommend ongoing monitoring and targeted improvements to maintain this position."
|
|
277
|
+
- **B (70–84):** "Good foundation. Targeted improvements in [lowest component] can push you into the A tier within 30–60 days."
|
|
278
|
+
- **C (55–69):** "Moderate visibility. You are not capturing significant AI-referred traffic yet. A full remediation roadmap is recommended."
|
|
279
|
+
- **D (40–54):** "Your site has significant AI search blindspots. AI systems may not be citing or recommending your content at all."
|
|
280
|
+
- **F (below 40):** "Critical issues detected. AI crawlers may be blocked outright. Immediate technical and content remediation required."
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## STEP 7 — CITABILITY ALGORITHM
|
|
285
|
+
|
|
286
|
+
The citability score measures how well a page can be cleanly quoted and cited by AI systems.
|
|
287
|
+
|
|
288
|
+
### 5-Metric Algorithm
|
|
289
|
+
|
|
290
|
+
| Metric | Weight | What It Measures |
|
|
291
|
+
|---|---|---|
|
|
292
|
+
| Answer Block Quality | 30% | Do paragraphs contain complete, self-sufficient answers AI can quote verbatim? |
|
|
293
|
+
| Self-Containment | 25% | Can a paragraph be understood without reading surrounding context? Low pronoun-to-noun ratio = better. |
|
|
294
|
+
| Structural Readability | 20% | Does the page use headings, short paragraphs, and numbered lists to enable AI parsing? |
|
|
295
|
+
| Statistical Density | 15% | Does the page contain specific numbers, percentages, and data references AI prefers to cite? |
|
|
296
|
+
| Uniqueness Signals | 10% | Does the content contain proprietary claims, original research, or data not found elsewhere? |
|
|
297
|
+
|
|
298
|
+
### Computing Each Metric
|
|
299
|
+
|
|
300
|
+
- **Answer Block Quality:** Score each paragraph 0–10 on: clear subject, predicate, supporting evidence, no unresolved pronouns. Average across all paragraphs.
|
|
301
|
+
- **Self-Containment:** Count pronoun references (it, they, this, that) as a fraction of total noun references. Lower ratio = higher score.
|
|
302
|
+
- **Structural Readability:** Check presence of: H1 (required), H2s (≥2), numbered/bulleted lists (≥1), paragraph length ≤150 words, no wall-of-text sections.
|
|
303
|
+
- **Statistical Density:** Count numerical data references (% signs, numbered lists, dates with years, dollar figures) per 1000 words. Optimal: 8–15 data points per 1000 words.
|
|
304
|
+
- **Uniqueness Signals:** Check for: "first-party study," "based on our data," "internal research," proprietary methodology references, or unique terminology.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## STEP 8 — REMEDIATION ROADMAP LOGIC
|
|
309
|
+
|
|
310
|
+
Build the roadmap by ranking all findings by impact × urgency.
|
|
311
|
+
|
|
312
|
+
### Priority Matrix
|
|
313
|
+
|
|
314
|
+
| Priority | Impact | Urgency | Action |
|
|
315
|
+
|---|---|---|---|
|
|
316
|
+
| P0 — Critical | High | Immediate | Fix this week — crawlers blocked, HTTPS broken, major schema errors |
|
|
317
|
+
| P1 — High | High | This sprint | Add llms.txt, fix citability blockers, add missing schema types |
|
|
318
|
+
| P2 — Medium | Medium | Week 2–3 | E-E-A-T improvements, statistical density, answer block rewrites |
|
|
319
|
+
| P3 — Low | Low | Week 4+ | Brand authority campaigns, platform optimization, monitoring setup |
|
|
320
|
+
|
|
321
|
+
### 4-Week Sprint Structure
|
|
322
|
+
|
|
323
|
+
- **Week 1:** P0 and P1 items — all technical and crawler-access blockers
|
|
324
|
+
- **Week 2:** P2 items — content quality improvements, schema additions
|
|
325
|
+
- **Week 3:** P2 continuation — E-E-A-T depth, self-containment rewrites
|
|
326
|
+
- **Week 4:** P3 items — brand platform seeding, monitoring, reporting loop setup
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## STEP 9 — OUTPUT ORDER
|
|
331
|
+
|
|
332
|
+
Produce artifacts in this strict order:
|
|
333
|
+
|
|
334
|
+
1. GEO Audit Brief (`templates/geo-audit-brief.md`)
|
|
335
|
+
2. Citability Analysis (`templates/citability-analysis.md`)
|
|
336
|
+
3. Crawler Access Report (`templates/crawler-access-report.md`)
|
|
337
|
+
4. Brand Visibility Report (`templates/brand-visibility-report.md`)
|
|
338
|
+
5. GEO Score Summary (`templates/geo-score-summary.md`)
|
|
339
|
+
6. Content Analysis (`templates/content-analysis.md`)
|
|
340
|
+
7. Schema Validation (`templates/schema-validation.md`)
|
|
341
|
+
8. Technical Foundations (`templates/technical-foundations.md`)
|
|
342
|
+
9. llms.txt Plan (`templates/llmstxt-plan.md`)
|
|
343
|
+
10. Remediation Roadmap (`templates/remediation-roadmap.md`)
|
|
344
|
+
11. Client Proposal (`templates/client-proposal.md`) — only if requested
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## STEP 10 — QUALITY BAR
|
|
349
|
+
|
|
350
|
+
Good output looks like this:
|
|
351
|
+
|
|
352
|
+
- All scores derived from actual page data — no invented numbers
|
|
353
|
+
- GEO Score uses the exact formula defined in Step 6 — no rounding before final aggregate
|
|
354
|
+
- Citability analysis applies all 5 metrics, not just the top 2
|
|
355
|
+
- Crawler access report covers all 14 AI crawlers by exact user-agent string
|
|
356
|
+
- Remediation roadmap is sequenced by impact × urgency, not alphabetically
|
|
357
|
+
- Client proposal grounds ROI projections in AI search traffic trend data
|
|
358
|
+
- Every output file can be handed to a client or developer and acted on immediately
|
|
359
|
+
- No filler paragraphs — every sentence either presents data, explains a finding, or specifies an action
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Brand Visibility Report
|
|
2
|
+
|
|
3
|
+
> Template: `templates/brand-visibility-report.md`
|
|
4
|
+
> Save output to: `output/<client-slug>/<project-slug>/BrandVisibilityReport_v<N>_<YYYYMMDD>.md`
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Brand Audited
|
|
9
|
+
|
|
10
|
+
| Field | Value |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Brand Name | <!-- client_name --> |
|
|
13
|
+
| Primary Domain | <!-- https://domain.com --> |
|
|
14
|
+
| Brand Slug | <!-- brand-slug --> |
|
|
15
|
+
| Scan Date | <!-- YYYY-MM-DD --> |
|
|
16
|
+
| Execution Mode | <!-- local-fork (brand_scanner.py) / agent-only --> |
|
|
17
|
+
| Script Used | <!-- scripts/brand_scanner.py / manual --> |
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Platform Scan Results
|
|
22
|
+
|
|
23
|
+
| Platform | Brand Present | Mention Count | Sentiment | Primary URL Found | Notes |
|
|
24
|
+
|---|---|---|---|---|---|
|
|
25
|
+
| YouTube | <!-- yes / no / partial --> | <!-- N --> | <!-- positive / neutral / negative / mixed --> | <!-- https://... --> | <!-- channel / mentions in videos --> |
|
|
26
|
+
| Reddit | <!-- yes / no / partial --> | <!-- N --> | <!-- positive / neutral / negative / mixed --> | <!-- subreddit or post URL --> | <!-- notable threads --> |
|
|
27
|
+
| Wikipedia | <!-- yes / no / partial --> | <!-- N --> | <!-- neutral --> | <!-- https://... --> | <!-- article or mention in related article --> |
|
|
28
|
+
| LinkedIn | <!-- yes / no / partial --> | <!-- N --> | <!-- positive / neutral / mixed --> | <!-- https://... --> | <!-- company page / employee mentions --> |
|
|
29
|
+
| Twitter / X | <!-- yes / no / partial --> | <!-- N --> | <!-- positive / neutral / negative / mixed --> | <!-- https://x.com/... --> | <!-- handle / mentions --> |
|
|
30
|
+
| GitHub | <!-- yes / no / partial --> | <!-- N --> | <!-- positive / neutral --> | <!-- https://github.com/... --> | <!-- repos / mentions --> |
|
|
31
|
+
| Quora | <!-- yes / no / partial --> | <!-- N --> | <!-- positive / neutral / negative --> | <!-- https://... --> | <!-- answers mentioning brand --> |
|
|
32
|
+
| Hacker News | <!-- yes / no / partial --> | <!-- N --> | <!-- positive / neutral / negative --> | <!-- https://news.ycombinator.com/... --> | <!-- posts / comments --> |
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Platform Detail Notes
|
|
37
|
+
|
|
38
|
+
### YouTube
|
|
39
|
+
<!-- Describe what was found: official channel exists / brand mentioned in competitor content / no presence found -->
|
|
40
|
+
|
|
41
|
+
### Reddit
|
|
42
|
+
<!-- Describe key threads, subreddits where brand appears, sentiment breakdown -->
|
|
43
|
+
|
|
44
|
+
### Wikipedia
|
|
45
|
+
<!-- Note: own Wikipedia article / mentioned in industry article / no presence -->
|
|
46
|
+
|
|
47
|
+
### LinkedIn
|
|
48
|
+
<!-- Official company page status, follower count if visible, employee mention density -->
|
|
49
|
+
|
|
50
|
+
### Twitter / X
|
|
51
|
+
<!-- Official handle / mention volume / notable brand advocates or critics -->
|
|
52
|
+
|
|
53
|
+
### GitHub
|
|
54
|
+
<!-- Open source repos / developer tools / mentions in issues or discussions -->
|
|
55
|
+
|
|
56
|
+
### Quora
|
|
57
|
+
<!-- Questions answered by brand representatives / brand mentioned in answers -->
|
|
58
|
+
|
|
59
|
+
### Hacker News
|
|
60
|
+
<!-- Any "Show HN" posts / brand mentioned in discussions / competitor comparisons -->
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Brand Authority Score
|
|
65
|
+
|
|
66
|
+
| Component | Score (0–100) | Weight | Weighted Score | Notes |
|
|
67
|
+
|---|---|---|---|---|
|
|
68
|
+
| Platform presence breadth | <!-- N --> | 30% | <!-- N × 0.30 --> | <!-- # platforms with meaningful presence / 8 --> |
|
|
69
|
+
| Sentiment quality | <!-- N --> | 25% | <!-- N × 0.25 --> | <!-- ratio of positive to negative mentions --> |
|
|
70
|
+
| Mention volume | <!-- N --> | 20% | <!-- N × 0.20 --> | <!-- total mentions normalized vs. category benchmark --> |
|
|
71
|
+
| Wikipedia or authority link | <!-- N --> | 15% | <!-- N × 0.15 --> | <!-- Wikipedia presence = 100, none = 0 --> |
|
|
72
|
+
| Developer / technical community | <!-- N --> | 10% | <!-- N × 0.10 --> | <!-- GitHub + HN combined signal --> |
|
|
73
|
+
| **TOTAL Brand Authority Score** | | **100%** | <!-- sum --> | |
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Gap Analysis
|
|
78
|
+
|
|
79
|
+
**Platforms with no meaningful presence:**
|
|
80
|
+
- <!-- Platform: why it matters and what to build there -->
|
|
81
|
+
- <!-- Platform: why it matters and what to build there -->
|
|
82
|
+
|
|
83
|
+
**Sentiment risks:**
|
|
84
|
+
- <!-- Any platform with negative-dominant sentiment: what is being said -->
|
|
85
|
+
|
|
86
|
+
**Brand authority gaps vs. competitors:**
|
|
87
|
+
| Gap | Competitor Advantage | Recommended Response |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| <!-- gap --> | <!-- competitor URL or example --> | <!-- recommended action --> |
|
|
90
|
+
| <!-- gap --> | <!-- competitor URL or example --> | <!-- recommended action --> |
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Recommended Actions
|
|
95
|
+
|
|
96
|
+
| Priority | Platform | Action | Timeline | Expected Impact |
|
|
97
|
+
|---|---|---|---|---|
|
|
98
|
+
| P1 | <!-- platform --> | <!-- specific action --> | <!-- Week 1-2 --> | <!-- High / Medium --> |
|
|
99
|
+
| P1 | <!-- platform --> | <!-- specific action --> | <!-- Week 1-2 --> | <!-- High / Medium --> |
|
|
100
|
+
| P2 | <!-- platform --> | <!-- specific action --> | <!-- Week 2-4 --> | <!-- Medium --> |
|
|
101
|
+
| P3 | <!-- platform --> | <!-- specific action --> | <!-- Week 4+ --> | <!-- Low / Long-term --> |
|