forgedock 1.0.0
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/LICENSE +244 -0
- package/README.md +251 -0
- package/bin/forgedock.mjs +232 -0
- package/commands/analytics.md +777 -0
- package/commands/audit-agents.md +410 -0
- package/commands/audit.md +410 -0
- package/commands/autopilot.md +432 -0
- package/commands/cleanup.md +264 -0
- package/commands/deploy-info.md +292 -0
- package/commands/failure-recon.md +375 -0
- package/commands/forge-stats.md +183 -0
- package/commands/geo-audit.md +343 -0
- package/commands/incident-response.md +384 -0
- package/commands/issue.md +506 -0
- package/commands/milestone.md +599 -0
- package/commands/orchestrate.md +1044 -0
- package/commands/pipeline-health.md +2343 -0
- package/commands/qa-sweep.md +237 -0
- package/commands/quality-gate.md +777 -0
- package/commands/review-pr-agents.md +1711 -0
- package/commands/review-pr-staging.md +325 -0
- package/commands/review-pr.md +888 -0
- package/commands/rollback.md +253 -0
- package/commands/security-audit.md +529 -0
- package/commands/sync-ecosystem.md +527 -0
- package/commands/validate.md +131 -0
- package/commands/work-on/build/architect.md +291 -0
- package/commands/work-on/build/context.md +349 -0
- package/commands/work-on/build/implement.md +280 -0
- package/commands/work-on/build/validate.md +292 -0
- package/commands/work-on/build.md +262 -0
- package/commands/work-on/close.md +350 -0
- package/commands/work-on/decompose.md +254 -0
- package/commands/work-on/investigate.md +437 -0
- package/commands/work-on/review.md +245 -0
- package/commands/work-on-monolithic.md +298 -0
- package/commands/work-on.md +1089 -0
- package/docs/CODEX.md +92 -0
- package/docs/WORKFLOW.md +104 -0
- package/package.json +45 -0
- package/scripts/verify-env-vars.sh +201 -0
- package/scripts/verify-host-headers.sh +117 -0
- package/scripts/verify-route-registration.sh +118 -0
- package/scripts/verify-sops-chain.sh +163 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Track command sizes, detect bloat, compare against baselines and thresholds
|
|
3
|
+
argument-hint: [diff | baseline | full]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /forge-stats — Prompt Bloat Tracker
|
|
7
|
+
|
|
8
|
+
**Input**: $ARGUMENTS (default: `diff`)
|
|
9
|
+
|
|
10
|
+
Tracks the size of every Forge command file over time. Detects bloat by comparing current sizes against the git-tracked baseline and per-command thresholds.
|
|
11
|
+
|
|
12
|
+
**FORGE_HOME**: `~/projects/forge`
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Thresholds
|
|
17
|
+
|
|
18
|
+
Commands are classified by role. Each role has a max line count — beyond this, the prompt is too large for Sonnet to reliably follow all instructions.
|
|
19
|
+
|
|
20
|
+
| Role | Max Lines | Rationale |
|
|
21
|
+
|------|-----------|-----------|
|
|
22
|
+
| Orchestrator (work-on, orchestrate, review-pr) | 800 | Delegates to sub-agents; needs full pipeline logic |
|
|
23
|
+
| Agent catalog (review-pr-agents, review-pr-staging) | 1000 | Reference file read on demand, not fed whole to one agent |
|
|
24
|
+
| Specialist (milestone, analytics, validate, etc.) | 400 | Single-purpose; Sonnet attention degrades past this |
|
|
25
|
+
| Utility (cleanup, sync-ecosystem, forge-stats) | 250 | Simple tasks; should stay lean |
|
|
26
|
+
| Sub-file (quality-gate, pipeline-health) | 350 | Invoked by parent; shares context budget |
|
|
27
|
+
|
|
28
|
+
**Current overages (v1.1.0 baseline):**
|
|
29
|
+
- `work-on.md`: 289 lines (threshold 800) — OK (compressed from 1,565)
|
|
30
|
+
- `review-pr-staging.md`: 218 lines (threshold 1,000) — OK (compressed from 1,201)
|
|
31
|
+
- `qa-sweep.md`: 196 lines (threshold 400) — OK (compressed from 1,058)
|
|
32
|
+
- `review-pr-agents.md`: 815 lines (threshold 1,000) — OK
|
|
33
|
+
- `review-pr.md`: 796 lines (threshold 800) — OK
|
|
34
|
+
- `validate.md`: 97 lines (threshold 400) — OK (compressed from 679)
|
|
35
|
+
- `orchestrate.md`: 654 lines (threshold 800) — OK
|
|
36
|
+
- `analytics.md`: 590 lines (threshold 400) — **48% over**
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Mode: `diff` (default)
|
|
41
|
+
|
|
42
|
+
Compare current line counts against the last git commit. Shows what grew and what shrank.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
cd ~/projects/forge
|
|
46
|
+
|
|
47
|
+
echo "=== Forge Command Sizes — $(date +%Y-%m-%d) ==="
|
|
48
|
+
echo ""
|
|
49
|
+
printf "%-35s %6s %6s %6s %s\n" "Command" "Now" "Prev" "Delta" "Status"
|
|
50
|
+
printf "%-35s %6s %6s %6s %s\n" "-------" "---" "----" "-----" "------"
|
|
51
|
+
|
|
52
|
+
for cmd in commands/*.md; do
|
|
53
|
+
name=$(basename "$cmd")
|
|
54
|
+
current=$(wc -l < "$cmd")
|
|
55
|
+
|
|
56
|
+
# Get line count from last commit
|
|
57
|
+
previous=$(git show HEAD:"$cmd" 2>/dev/null | wc -l || echo 0)
|
|
58
|
+
|
|
59
|
+
delta=$((current - previous))
|
|
60
|
+
|
|
61
|
+
# Determine threshold based on filename
|
|
62
|
+
case "$name" in
|
|
63
|
+
work-on.md|orchestrate.md|review-pr.md) threshold=800 ;;
|
|
64
|
+
review-pr-agents.md|review-pr-staging.md) threshold=1000 ;;
|
|
65
|
+
cleanup.md|sync-ecosystem.md|forge-stats.md) threshold=250 ;;
|
|
66
|
+
quality-gate.md|pipeline-health.md) threshold=350 ;;
|
|
67
|
+
*) threshold=400 ;;
|
|
68
|
+
esac
|
|
69
|
+
|
|
70
|
+
# Status
|
|
71
|
+
if [ "$current" -gt "$threshold" ]; then
|
|
72
|
+
overage=$(( (current - threshold) * 100 / threshold ))
|
|
73
|
+
status="⚠ ${overage}% over (max ${threshold})"
|
|
74
|
+
else
|
|
75
|
+
headroom=$(( (threshold - current) * 100 / threshold ))
|
|
76
|
+
status="OK (${headroom}% headroom)"
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Delta formatting
|
|
80
|
+
if [ "$delta" -gt 0 ]; then
|
|
81
|
+
delta_str="+${delta}"
|
|
82
|
+
elif [ "$delta" -eq 0 ]; then
|
|
83
|
+
delta_str="="
|
|
84
|
+
else
|
|
85
|
+
delta_str="${delta}"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
printf "%-35s %6d %6d %6s %s\n" "$name" "$current" "$previous" "$delta_str" "$status"
|
|
89
|
+
done
|
|
90
|
+
|
|
91
|
+
echo ""
|
|
92
|
+
echo "Total: $(wc -l commands/*.md | tail -1 | awk '{print $1}') lines across $(ls commands/*.md | wc -l) commands"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**After running, flag any command where:**
|
|
96
|
+
1. Delta > +50 lines in a single commit → "Significant growth — review if this is necessary"
|
|
97
|
+
2. Current > threshold → "Over limit — consider splitting into sub-files or rewriting"
|
|
98
|
+
3. Total across all commands > 10,000 lines → "Pipeline total is growing — review for consolidation"
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Mode: `baseline`
|
|
103
|
+
|
|
104
|
+
Record the current sizes as the new baseline. Run this after a deliberate refactor or rewrite.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
cd ~/projects/forge
|
|
108
|
+
|
|
109
|
+
echo "# Forge Command Baselines — $(date +%Y-%m-%d)" > .baselines
|
|
110
|
+
echo "# Auto-generated by /forge-stats baseline" >> .baselines
|
|
111
|
+
echo "" >> .baselines
|
|
112
|
+
|
|
113
|
+
for cmd in commands/*.md; do
|
|
114
|
+
name=$(basename "$cmd")
|
|
115
|
+
lines=$(wc -l < "$cmd")
|
|
116
|
+
echo "${name}:${lines}" >> .baselines
|
|
117
|
+
done
|
|
118
|
+
|
|
119
|
+
git add .baselines
|
|
120
|
+
git commit -m "stats: update command baselines — $(date +%Y-%m-%d)"
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Mode: `full`
|
|
126
|
+
|
|
127
|
+
Full analysis with git history trend. Shows how each command has grown over time.
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd ~/projects/forge
|
|
131
|
+
|
|
132
|
+
echo "=== Forge Command Growth History ==="
|
|
133
|
+
echo ""
|
|
134
|
+
|
|
135
|
+
for cmd in commands/*.md; do
|
|
136
|
+
name=$(basename "$cmd")
|
|
137
|
+
echo "--- $name ---"
|
|
138
|
+
|
|
139
|
+
# Get size at each commit that touched this file
|
|
140
|
+
git log --oneline --follow -- "$cmd" | while read sha msg; do
|
|
141
|
+
lines=$(git show "${sha}:${cmd}" 2>/dev/null | wc -l || echo "?")
|
|
142
|
+
echo " ${sha} | ${lines} lines | ${msg}"
|
|
143
|
+
done
|
|
144
|
+
echo ""
|
|
145
|
+
done
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Also compute:
|
|
149
|
+
- **Growth rate**: lines added per commit (average)
|
|
150
|
+
- **Bloat ratio**: current_lines / baseline_lines
|
|
151
|
+
- **Attention budget**: For commands that spawn sub-agents, estimate how much of Sonnet's context window the prompt consumes (rough: 1 line ≈ 15 tokens, Sonnet effective window ≈ 150K tokens, but attention quality degrades past ~30K tokens of instructions)
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
Attention budget estimate:
|
|
155
|
+
work-on.md: 1,565 lines × 15 ≈ 23,475 tokens — 78% of quality attention budget
|
|
156
|
+
orchestrate: 654 lines × 15 ≈ 9,810 tokens — 33% of quality attention budget
|
|
157
|
+
review-pr: 796 lines × 15 ≈ 11,940 tokens — 40% of quality attention budget
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Commands consuming >50% of the quality attention budget should be split into orchestrator + sub-files.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Bloat Reduction Patterns
|
|
165
|
+
|
|
166
|
+
When a command exceeds its threshold, use these patterns to reduce without losing functionality:
|
|
167
|
+
|
|
168
|
+
### 1. Extract sub-files (preferred)
|
|
169
|
+
Move reference material into a separate file loaded on demand:
|
|
170
|
+
```
|
|
171
|
+
review-pr.md (orchestrator, 400 lines)
|
|
172
|
+
→ reads review-pr-agents.md (agent catalog, on demand)
|
|
173
|
+
→ reads review-pr-staging.md (staging mode, on demand)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 2. Externalize templates
|
|
177
|
+
Move large output templates (report formats, comment templates) into `docs/templates/`.
|
|
178
|
+
|
|
179
|
+
### 3. Deduplicate cross-command content
|
|
180
|
+
If 3+ commands repeat the same instruction block (e.g., "how to create a worktree"), extract to `docs/WORKFLOW.md` and reference it.
|
|
181
|
+
|
|
182
|
+
### 4. Remove motivational padding
|
|
183
|
+
Emojis, ALL CAPS warnings, "YOU MUST", "CRITICAL", "NO EXCEPTIONS" — these are noise. Sonnet follows clear instructions, not emphasis. Replace 5 lines of warnings with 1 line of instruction.
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Run a GEO audit — check AI referral traffic, page compliance, and auto-create improvement issues"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /geo-audit — GEO Discoverability Audit & Issue Generator
|
|
6
|
+
|
|
7
|
+
You are the GEO (Generative Engine Optimization) auditor. Pull AI referral data from Umami and Clarity, check every public page for GEO compliance (structured data, OG tags, freshness, sitemap, llms.txt), and auto-create GitHub issues for gaps.
|
|
8
|
+
|
|
9
|
+
**You have access to ALL tools** — MCP tools for Clarity, Bash for Umami/curl checks, gh CLI for issues.
|
|
10
|
+
|
|
11
|
+
**NEVER use plan mode (EnterPlanMode)** — it breaks execution context.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Constants
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
DOMAIN = "alterlab.io"
|
|
19
|
+
SITE_URL = "https://alterlab.io"
|
|
20
|
+
UMAMI_WEBSITE_ID = "ccfb1cdd-5a05-4b41-8e61-48695b4ff6c0"
|
|
21
|
+
UMAMI_API = "https://umami.alterlab.io"
|
|
22
|
+
CLARITY_PROJECT = "v28wblv737"
|
|
23
|
+
TODAY = (current date in YYYY-MM-DD)
|
|
24
|
+
THIRTY_DAYS_AGO = (TODAY minus 30 days)
|
|
25
|
+
|
|
26
|
+
AI_REFERRERS = [
|
|
27
|
+
"chatgpt.com",
|
|
28
|
+
"claude.ai",
|
|
29
|
+
"gemini.google.com",
|
|
30
|
+
"perplexity.ai",
|
|
31
|
+
"copilot.microsoft.com",
|
|
32
|
+
"grok.com",
|
|
33
|
+
"phind.com",
|
|
34
|
+
"you.com"
|
|
35
|
+
]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Phase 1: Collect AI Referral Data
|
|
41
|
+
|
|
42
|
+
### 1A. Umami — AI Referrer Metrics
|
|
43
|
+
|
|
44
|
+
Authenticate with Umami (credentials from `credentials.yaml`):
|
|
45
|
+
```bash
|
|
46
|
+
UMAMI_USER=$(python3 -c "import yaml; print(yaml.safe_load(open('/home/mrdubey/projects/ScraperAPI/credentials.yaml'))['umami']['username'])")
|
|
47
|
+
UMAMI_PASS=$(python3 -c "import yaml; print(yaml.safe_load(open('/home/mrdubey/projects/ScraperAPI/credentials.yaml'))['umami']['password'])")
|
|
48
|
+
UMAMI_TOKEN=$(curl -s -X POST "https://umami.alterlab.io/api/auth/login" \
|
|
49
|
+
-H "Content-Type: application/json" \
|
|
50
|
+
-d "{\"username\":\"$UMAMI_USER\",\"password\":\"$UMAMI_PASS\"}" | jq -r '.token')
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Then pull referrer metrics for the last 30 days:
|
|
54
|
+
```bash
|
|
55
|
+
START_AT=$(date -d '30 days ago' +%s)000
|
|
56
|
+
END_AT=$(date +%s)000
|
|
57
|
+
curl -s "https://umami.alterlab.io/api/websites/ccfb1cdd-5a05-4b41-8e61-48695b4ff6c0/metrics?startAt=${START_AT}&endAt=${END_AT}&type=referrer" \
|
|
58
|
+
-H "Authorization: Bearer $UMAMI_TOKEN" | jq '.'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
From the results, filter for AI_REFERRERS. Record each AI referrer's session count. If a referrer appears that is NOT in our known list but looks AI-related (contains "ai", "chat", "copilot", "assistant"), flag it as a new AI referrer.
|
|
62
|
+
|
|
63
|
+
Also pull landing page metrics to see WHERE AI traffic lands:
|
|
64
|
+
```bash
|
|
65
|
+
curl -s "https://umami.alterlab.io/api/websites/ccfb1cdd-5a05-4b41-8e61-48695b4ff6c0/metrics?startAt=${START_AT}&endAt=${END_AT}&type=url" \
|
|
66
|
+
-H "Authorization: Bearer $UMAMI_TOKEN" | jq '.'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
For previous period comparison (30-60 days ago):
|
|
70
|
+
```bash
|
|
71
|
+
PREV_START=$(date -d '60 days ago' +%s)000
|
|
72
|
+
PREV_END=$(date -d '30 days ago' +%s)000
|
|
73
|
+
curl -s "https://umami.alterlab.io/api/websites/ccfb1cdd-5a05-4b41-8e61-48695b4ff6c0/metrics?startAt=${PREV_START}&endAt=${PREV_END}&type=referrer" \
|
|
74
|
+
-H "Authorization: Bearer $UMAMI_TOKEN" | jq '.'
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Calculate trend (current vs previous) for each AI referrer.
|
|
78
|
+
|
|
79
|
+
### 1B. Clarity — AI Channel Data
|
|
80
|
+
|
|
81
|
+
Use the MCP Clarity tool to get AI-related traffic:
|
|
82
|
+
- `mcp__clarity__query-analytics-dashboard`: "AITools channel sessions last 7 days"
|
|
83
|
+
- `mcp__clarity__query-analytics-dashboard`: "Top referrers last 7 days"
|
|
84
|
+
- `mcp__clarity__query-analytics-dashboard`: "Sessions from chatgpt.com last 7 days"
|
|
85
|
+
- `mcp__clarity__query-analytics-dashboard`: "Bot browser sessions last 7 days"
|
|
86
|
+
|
|
87
|
+
Cross-reference Clarity referrer data with Umami to validate numbers.
|
|
88
|
+
|
|
89
|
+
**If Umami or Clarity fails**: Report what you have. Partial data > no data.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Phase 2: Page GEO Compliance Audit
|
|
94
|
+
|
|
95
|
+
### 2A. Discover Public Pages
|
|
96
|
+
|
|
97
|
+
Get the sitemap to find all public pages:
|
|
98
|
+
```bash
|
|
99
|
+
curl -s "https://alterlab.io/sitemap.xml" | grep -oP '<loc>\K[^<]+' | sort
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Also check llms.txt for listed pages:
|
|
103
|
+
```bash
|
|
104
|
+
curl -s "https://alterlab.io/llms.txt"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
And the full version:
|
|
108
|
+
```bash
|
|
109
|
+
curl -s "https://alterlab.io/llms-full.txt"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Build the list of all unique public pages from both sources.
|
|
113
|
+
|
|
114
|
+
### 2B. Check Each Page
|
|
115
|
+
|
|
116
|
+
For EACH public page, run these checks (batch curl requests, don't hammer the server — add a small delay between pages):
|
|
117
|
+
|
|
118
|
+
**1. JSON-LD Structured Data**
|
|
119
|
+
```bash
|
|
120
|
+
curl -s "PAGE_URL" | grep -c 'application/ld\+json'
|
|
121
|
+
```
|
|
122
|
+
- PASS: count > 0
|
|
123
|
+
- FAIL: count == 0 → flag "Missing JSON-LD"
|
|
124
|
+
|
|
125
|
+
If JSON-LD exists, extract and check for `dateModified`:
|
|
126
|
+
```bash
|
|
127
|
+
curl -s "PAGE_URL" | grep -oP '<script type="application/ld\+json">\K[^<]+' | jq '.dateModified // empty' 2>/dev/null
|
|
128
|
+
```
|
|
129
|
+
- If `dateModified` exists, check if it's older than 90 days from TODAY
|
|
130
|
+
- STALE: dateModified > 90 days ago → flag "Stale dateModified"
|
|
131
|
+
|
|
132
|
+
**2. OG Tags**
|
|
133
|
+
```bash
|
|
134
|
+
curl -s "PAGE_URL" | grep -oP 'property="og:title" content="\K[^"]+'
|
|
135
|
+
```
|
|
136
|
+
- PASS: og:title exists and is NOT the generic site default (e.g., not just "AlterLab" or empty)
|
|
137
|
+
- FAIL: missing or generic → flag "Missing/generic OG tags"
|
|
138
|
+
|
|
139
|
+
Also check og:description:
|
|
140
|
+
```bash
|
|
141
|
+
curl -s "PAGE_URL" | grep -oP 'property="og:description" content="\K[^"]+'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**3. Sitemap Presence**
|
|
145
|
+
Check if page URL appears in the sitemap (from 2A).
|
|
146
|
+
- FAIL: page in llms.txt but NOT in sitemap → flag "Missing from sitemap"
|
|
147
|
+
|
|
148
|
+
**4. llms.txt Presence**
|
|
149
|
+
Check if page URL appears in llms.txt content.
|
|
150
|
+
- FAIL: page in sitemap but NOT referenced in llms.txt → flag "Missing from llms.txt"
|
|
151
|
+
|
|
152
|
+
### 2C. Check robots.txt for AI Bots
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
curl -s "https://alterlab.io/robots.txt"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Known AI crawler user-agents to check for:
|
|
159
|
+
- `GPTBot` (OpenAI/ChatGPT)
|
|
160
|
+
- `ChatGPT-User` (ChatGPT browsing)
|
|
161
|
+
- `Google-Extended` (Gemini)
|
|
162
|
+
- `anthropic-ai` (Claude)
|
|
163
|
+
- `ClaudeBot` (Claude)
|
|
164
|
+
- `PerplexityBot` (Perplexity)
|
|
165
|
+
- `Bytespider` (TikTok/Doubao)
|
|
166
|
+
- `CCBot` (Common Crawl, used by many AI)
|
|
167
|
+
- `cohere-ai` (Cohere)
|
|
168
|
+
|
|
169
|
+
For each: check if it appears in robots.txt. If an AI referrer is sending traffic but its bot is NOT mentioned in robots.txt (either Allow or User-agent), flag it.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Phase 3: Identify Issues
|
|
174
|
+
|
|
175
|
+
Compile all findings into issue candidates:
|
|
176
|
+
|
|
177
|
+
| Condition | Issue Title Template | Priority | Labels |
|
|
178
|
+
|-----------|---------------------|----------|--------|
|
|
179
|
+
| Page missing JSON-LD | `GEO: Add structured data to {path}` | P2 | `seo,geo` |
|
|
180
|
+
| dateModified > 90 days | `GEO: Refresh content on {path}` | P3 | `seo,geo` |
|
|
181
|
+
| Page missing from sitemap | `GEO: Add {path} to sitemap` | P2 | `seo,geo` |
|
|
182
|
+
| Page missing from llms.txt | `GEO: Add {path} to llms.txt` | P2 | `seo,geo` |
|
|
183
|
+
| OG tags missing/generic | `GEO: Fix OG tags on {path}` | P2 | `seo,geo` |
|
|
184
|
+
| AI bot not in robots.txt | `GEO: Add {bot} to robots.txt` | P1 | `seo,geo` |
|
|
185
|
+
| New unknown AI referrer | `GEO: Investigate new AI referrer {source}` | P2 | `seo,geo` |
|
|
186
|
+
| AI referral traffic down >30% MoM | `GEO: Investigate {source} traffic drop ({pct}%)` | P1 | `seo,geo` |
|
|
187
|
+
|
|
188
|
+
**Deduplication**: Before creating, search for existing open issues with the same title prefix:
|
|
189
|
+
```bash
|
|
190
|
+
gh issue list --state open --search "GEO:" --limit 100 --json number,title
|
|
191
|
+
```
|
|
192
|
+
Skip any issue that already exists.
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Phase 4: Present Report
|
|
197
|
+
|
|
198
|
+
Show the user a structured report BEFORE creating issues:
|
|
199
|
+
|
|
200
|
+
```markdown
|
|
201
|
+
## GEO Audit Report — {DATE}
|
|
202
|
+
|
|
203
|
+
**Period**: Last 30 days (Umami) | Last 7 days (Clarity)
|
|
204
|
+
**Sources**: Umami {ok/fail} | Clarity {ok/fail}
|
|
205
|
+
|
|
206
|
+
### AI Referral Traffic (Last 30 Days)
|
|
207
|
+
| Source | Sessions | Prev Period | Trend |
|
|
208
|
+
|--------|----------|-------------|-------|
|
|
209
|
+
| chatgpt.com | X | Y | +/-Z% |
|
|
210
|
+
| claude.ai | X | Y | +/-Z% |
|
|
211
|
+
| ... | | | |
|
|
212
|
+
| **Total AI** | **X** | **Y** | **+/-Z%** |
|
|
213
|
+
|
|
214
|
+
### Top AI Landing Pages
|
|
215
|
+
| Page | AI Sessions | % of Total |
|
|
216
|
+
|------|-------------|------------|
|
|
217
|
+
| /blog/... | X | Y% |
|
|
218
|
+
|
|
219
|
+
### Page GEO Compliance
|
|
220
|
+
| Page | JSON-LD | OG Tags | dateModified | Sitemap | llms.txt |
|
|
221
|
+
|------|---------|---------|--------------|---------|----------|
|
|
222
|
+
| / | ok/missing | ok/generic | fresh/stale/missing | ok/missing | ok/missing |
|
|
223
|
+
| /pricing | ... | ... | ... | ... | ... |
|
|
224
|
+
|
|
225
|
+
### robots.txt AI Bot Coverage
|
|
226
|
+
| Bot | Status |
|
|
227
|
+
|-----|--------|
|
|
228
|
+
| GPTBot | allowed/blocked/not mentioned |
|
|
229
|
+
| ClaudeBot | ... |
|
|
230
|
+
|
|
231
|
+
### Proposed Issues ({N} total, {M} new after dedup)
|
|
232
|
+
| # | Priority | Title | Reason |
|
|
233
|
+
|---|----------|-------|--------|
|
|
234
|
+
| 1 | P1 | GEO: Add GPTBot to robots.txt | Sending traffic but not in robots.txt |
|
|
235
|
+
| 2 | P2 | GEO: Add structured data to /pricing | No JSON-LD found |
|
|
236
|
+
|
|
237
|
+
**Create these as GitHub issues?** (yes / adjust / pick specific ones)
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Quality rules:**
|
|
241
|
+
- Interpret the data — "5 sessions from ChatGPT" is data. "ChatGPT is our fastest-growing AI channel, up 200% MoM, landing primarily on /blog/web-scraping-api — optimize that page first" is an insight.
|
|
242
|
+
- Quantify every finding with actual numbers from the data.
|
|
243
|
+
- Be honest about small sample sizes.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Phase 5: Create GitHub Issues
|
|
248
|
+
|
|
249
|
+
**Only after user confirms.** If "adjust" — modify. If specific ones — only create those.
|
|
250
|
+
|
|
251
|
+
For each approved issue:
|
|
252
|
+
```bash
|
|
253
|
+
gh issue create \
|
|
254
|
+
--title "{fix|feat}: {concise description}" \
|
|
255
|
+
--label "{priority},{labels}" \
|
|
256
|
+
--body "$(cat <<'BODY_EOF'
|
|
257
|
+
## Problem
|
|
258
|
+
|
|
259
|
+
{1-3 sentences: what the GEO audit found is wrong or missing. Current state with specific numbers.}
|
|
260
|
+
|
|
261
|
+
## Root Cause (if known)
|
|
262
|
+
|
|
263
|
+
{Why this AI discoverability gap exists — missing metadata, stale content, wrong file, etc. If unknown: "Root cause unknown — investigation needed."}
|
|
264
|
+
|
|
265
|
+
## Affected Files
|
|
266
|
+
|
|
267
|
+
Files that need changes:
|
|
268
|
+
1. `{filepath}` — {what needs to change}
|
|
269
|
+
2. `{filepath}` — {what needs to change}
|
|
270
|
+
|
|
271
|
+
## Acceptance Criteria
|
|
272
|
+
|
|
273
|
+
- [ ] {Measurable criterion}
|
|
274
|
+
- [ ] Verified in next GEO audit
|
|
275
|
+
|
|
276
|
+
## Context
|
|
277
|
+
|
|
278
|
+
Identified in GEO audit on {DATE}.
|
|
279
|
+
**Data Sources**: Umami, Clarity, page crawl
|
|
280
|
+
**Period**: Last 30 days
|
|
281
|
+
|
|
282
|
+
## Evidence
|
|
283
|
+
|
|
284
|
+
{Specific data points — referral counts, missing elements, stale dates}
|
|
285
|
+
|
|
286
|
+
## Recommended Fix
|
|
287
|
+
|
|
288
|
+
{Concrete technical steps}
|
|
289
|
+
BODY_EOF
|
|
290
|
+
)"
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
If a `geo-ai-discoverability` milestone exists, assign issues to it:
|
|
294
|
+
```bash
|
|
295
|
+
gh issue edit {NUMBER} --milestone "geo-ai-discoverability"
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Add GEO issues to Project board
|
|
299
|
+
|
|
300
|
+
For each created issue, add to the GitHub Project. Reference `~/projects/forge/docs/WORKFLOW.md` → "Project Board Integration" for field IDs.
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
ISSUE_URL="https://github.com/RapierCraft/AlterLab/issues/${ISSUE_NUM}"
|
|
304
|
+
ITEM_ID=$(gh project item-add 1 --owner RapierCraft --url "$ISSUE_URL" --format json --jq '.id' 2>/dev/null)
|
|
305
|
+
if [ -n "$ITEM_ID" ]; then
|
|
306
|
+
gh project item-edit --project-id PVT_kwHOCx3gR84BSK2L --id "$ITEM_ID" --field-id PVTSSF_lAHOCx3gR84BSK2Lzg_yF6E --single-select-option-id f75ad846 2>/dev/null || true # Status=Todo
|
|
307
|
+
gh project item-edit --project-id PVT_kwHOCx3gR84BSK2L --id "$ITEM_ID" --field-id PVTSSF_lAHOCx3gR84BSK2Lzg_yF98 --single-select-option-id 62864af4 2>/dev/null || true # Lane=Fast
|
|
308
|
+
gh project item-edit --project-id PVT_kwHOCx3gR84BSK2L --id "$ITEM_ID" --field-id PVTSSF_lAHOCx3gR84BSK2Lzg_yF-o --single-select-option-id 214c4d65 2>/dev/null || true # Component=Platform
|
|
309
|
+
gh project item-edit --project-id PVT_kwHOCx3gR84BSK2L --id "$ITEM_ID" --field-id PVTSSF_lAHOCx3gR84BSK2Lzg_yF8o --single-select-option-id {PRIORITY_OPTION_ID} 2>/dev/null || true # Priority
|
|
310
|
+
fi
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Phase 6: Summary
|
|
316
|
+
|
|
317
|
+
```markdown
|
|
318
|
+
## GEO Audit Complete
|
|
319
|
+
|
|
320
|
+
### Issues Created
|
|
321
|
+
| # | Issue | Priority |
|
|
322
|
+
|---|-------|----------|
|
|
323
|
+
|
|
324
|
+
### Key Findings
|
|
325
|
+
1. {Most important insight}
|
|
326
|
+
2. {Second insight}
|
|
327
|
+
3. {Third insight}
|
|
328
|
+
|
|
329
|
+
### Next Steps
|
|
330
|
+
- `/work-on #{first}` for highest priority issue
|
|
331
|
+
- Re-run `/geo-audit` in 2-4 weeks to track progress
|
|
332
|
+
- Check `/analytics` for broader traffic context
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Error Handling
|
|
338
|
+
|
|
339
|
+
- **Umami auth fails**: Try SOPS credentials. If still broken, skip Umami and note in report.
|
|
340
|
+
- **Clarity MCP fails**: Skip Clarity data, proceed with Umami only.
|
|
341
|
+
- **curl to alterlab.io fails**: Report "Site unreachable — cannot run compliance checks" and only show referral data.
|
|
342
|
+
- **No AI referral data at all**: Report "No AI referral traffic detected in the last 30 days" — this IS an insight (we need to improve discoverability).
|
|
343
|
+
- **Rate limits or timeouts**: Note which checks were incomplete. Partial audit > no audit.
|