optbrew 0.0.0-stage → 0.1.2

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.
Files changed (179) hide show
  1. package/.claude-plugin/marketplace.json +6 -0
  2. package/.claude-plugin/plugin.json +6 -0
  3. package/.codex-plugin/plugin.json +13 -0
  4. package/CHANGELOG.md +50 -0
  5. package/LICENSE +21 -0
  6. package/README.ko.md +149 -0
  7. package/README.md +148 -2
  8. package/THIRD_PARTY_NOTICES.md +10 -0
  9. package/bin/optbrew.mjs +4 -0
  10. package/docs/platforms.md +107 -0
  11. package/docs/release.md +14 -0
  12. package/lib/cli.mjs +116 -0
  13. package/lib/doctor.mjs +45 -0
  14. package/lib/install.mjs +158 -0
  15. package/lib/paths.mjs +30 -0
  16. package/lib/records.mjs +44 -0
  17. package/lib/reinstall.mjs +92 -0
  18. package/lib/transaction.mjs +205 -0
  19. package/lib/update.mjs +189 -0
  20. package/package.json +39 -4
  21. package/plugin.json +13 -0
  22. package/skills/optbrew/LICENSE +21 -0
  23. package/skills/optbrew/SKILL.md +17 -0
  24. package/skills/optbrew/THIRD_PARTY_NOTICES.md +10 -0
  25. package/skills/optbrew/agents/openai.yaml +4 -0
  26. package/skills/optbrew/bundle-manifest.json +687 -0
  27. package/skills/optbrew/licenses/firecrawl-seo-audit.txt +15 -0
  28. package/skills/optbrew/licenses/magnus-seo.txt +21 -0
  29. package/skills/optbrew/licenses/marketing-search.txt +21 -0
  30. package/skills/optbrew/licenses/mblode-seo.txt +21 -0
  31. package/skills/optbrew/licenses/naver-searchadvisor.txt +29 -0
  32. package/skills/optbrew/licenses/seranking-seo.txt +21 -0
  33. package/skills/optbrew/modules/firecrawl-seo-audit/GUIDE.md +64 -0
  34. package/skills/optbrew/modules/magnus-seo/GUIDE.md +79 -0
  35. package/skills/optbrew/modules/magnus-seo/README.md +45 -0
  36. package/skills/optbrew/modules/magnus-seo/assets/audit-report-template.md +76 -0
  37. package/skills/optbrew/modules/magnus-seo/references/aeo-methodology.md +105 -0
  38. package/skills/optbrew/modules/magnus-seo/references/agent-readable-content.md +28 -0
  39. package/skills/optbrew/modules/magnus-seo/references/content-and-entity-architecture.md +100 -0
  40. package/skills/optbrew/modules/magnus-seo/references/content-strategy-seo.md +142 -0
  41. package/skills/optbrew/modules/magnus-seo/references/discovery-and-freshness.md +47 -0
  42. package/skills/optbrew/modules/magnus-seo/references/evidence-boundaries.md +75 -0
  43. package/skills/optbrew/modules/magnus-seo/references/ghost-metadata.md +204 -0
  44. package/skills/optbrew/modules/magnus-seo/references/implementation-playbook.md +114 -0
  45. package/skills/optbrew/modules/magnus-seo/references/measurement-and-experimentation.md +47 -0
  46. package/skills/optbrew/modules/magnus-seo/references/onpage-seo.md +154 -0
  47. package/skills/optbrew/modules/magnus-seo/references/platform-guidance.md +30 -0
  48. package/skills/optbrew/modules/magnus-seo/references/schema-markup.md +244 -0
  49. package/skills/optbrew/modules/magnus-seo/references/source-index.md +36 -0
  50. package/skills/optbrew/modules/magnus-seo/references/structured-data.md +56 -0
  51. package/skills/optbrew/modules/magnus-seo/references/technical-seo.md +99 -0
  52. package/skills/optbrew/modules/magnus-seo/scripts/aeo_audit.py +158 -0
  53. package/skills/optbrew/modules/magnus-seo/scripts/build_prompt_matrix.py +52 -0
  54. package/skills/optbrew/modules/magnus-seo/templates/aeo-implementation-plan.md +53 -0
  55. package/skills/optbrew/modules/magnus-seo/templates/citation-observation-log.md +16 -0
  56. package/skills/optbrew/modules/magnus-seo/templates/llms.txt.template +15 -0
  57. package/skills/optbrew/modules/magnus-seo/templates/question-cluster.md +27 -0
  58. package/skills/optbrew/modules/magnus-seo/templates/robots-ai-crawlers.txt +23 -0
  59. package/skills/optbrew/modules/marketing-search/skills/ai-seo/GUIDE.md +483 -0
  60. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/agent-readiness.md +57 -0
  61. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/citations-vs-recommendations.md +85 -0
  62. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-patterns.md +287 -0
  63. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/content-types.md +71 -0
  64. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/format-volatility.md +98 -0
  65. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/okf.md +104 -0
  66. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/platform-ranking-factors.md +154 -0
  67. package/skills/optbrew/modules/marketing-search/skills/ai-seo/references/youtube-ai-citations.md +60 -0
  68. package/skills/optbrew/modules/marketing-search/skills/analytics/GUIDE.md +303 -0
  69. package/skills/optbrew/modules/marketing-search/skills/analytics/references/event-library.md +260 -0
  70. package/skills/optbrew/modules/marketing-search/skills/analytics/references/ga4-implementation.md +300 -0
  71. package/skills/optbrew/modules/marketing-search/skills/analytics/references/gtm-implementation.md +390 -0
  72. package/skills/optbrew/modules/marketing-search/skills/content-strategy/GUIDE.md +432 -0
  73. package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/content-distribution.md +83 -0
  74. package/skills/optbrew/modules/marketing-search/skills/content-strategy/references/headless-cms.md +194 -0
  75. package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/GUIDE.md +231 -0
  76. package/skills/optbrew/modules/marketing-search/skills/programmatic-seo/references/playbooks.md +308 -0
  77. package/skills/optbrew/modules/marketing-search/skills/schema/GUIDE.md +172 -0
  78. package/skills/optbrew/modules/marketing-search/skills/schema/references/schema-examples.md +398 -0
  79. package/skills/optbrew/modules/marketing-search/skills/seo-audit/GUIDE.md +492 -0
  80. package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/ai-writing-detection.md +200 -0
  81. package/skills/optbrew/modules/marketing-search/skills/seo-audit/references/international-seo.md +230 -0
  82. package/skills/optbrew/modules/marketing-search/skills/site-architecture/GUIDE.md +350 -0
  83. package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/mermaid-templates.md +216 -0
  84. package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/navigation-patterns.md +305 -0
  85. package/skills/optbrew/modules/marketing-search/skills/site-architecture/references/site-type-templates.md +293 -0
  86. package/skills/optbrew/modules/mblode-seo/GUIDE.md +74 -0
  87. package/skills/optbrew/modules/mblode-seo/references/answer-engines.md +58 -0
  88. package/skills/optbrew/modules/mblode-seo/references/audit.md +78 -0
  89. package/skills/optbrew/modules/mblode-seo/references/brief-template.md +47 -0
  90. package/skills/optbrew/modules/mblode-seo/references/monitoring.md +56 -0
  91. package/skills/optbrew/modules/mblode-seo/references/nextjs-implementation.md +65 -0
  92. package/skills/optbrew/modules/mblode-seo/references/research-protocol.md +37 -0
  93. package/skills/optbrew/modules/mblode-seo/references/sources.md +47 -0
  94. package/skills/optbrew/modules/mblode-seo/references/validation-evidence.md +21 -0
  95. package/skills/optbrew/modules/naver-searchadvisor/GUIDE.md +75 -0
  96. package/skills/optbrew/modules/naver-searchadvisor/NOTICE.md +59 -0
  97. package/skills/optbrew/modules/naver-searchadvisor/references/INDEX.md +97 -0
  98. package/skills/optbrew/modules/naver-searchadvisor/scripts/audit.mjs +742 -0
  99. package/skills/optbrew/modules/naver-searchadvisor/scripts/robots.mjs +77 -0
  100. package/skills/optbrew/modules/seranking-seo/skills/seo-ai-search-share-of-voice/GUIDE.md +94 -0
  101. package/skills/optbrew/modules/seranking-seo/skills/seo-api/GUIDE.md +186 -0
  102. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/api-surface-map.md +207 -0
  103. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/auth-and-keys.md +182 -0
  104. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/integration-patterns.md +283 -0
  105. package/skills/optbrew/modules/seranking-seo/skills/seo-api/references/rate-limits-and-credits.md +235 -0
  106. package/skills/optbrew/modules/seranking-seo/skills/seo-competitor-gap-analysis/GUIDE.md +117 -0
  107. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/GUIDE.md +155 -0
  108. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/cite.md +84 -0
  109. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/references/core-eeat.md +147 -0
  110. package/skills/optbrew/modules/seranking-seo/skills/seo-content-audit/templates/verdict.md +63 -0
  111. package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/GUIDE.md +141 -0
  112. package/skills/optbrew/modules/seranking-seo/skills/seo-firecrawl/references/preflight.md +73 -0
  113. package/skills/optbrew/modules/seranking-seo/skills/seo-geo/GUIDE.md +159 -0
  114. package/skills/optbrew/modules/seranking-seo/skills/seo-google/GUIDE.md +393 -0
  115. package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/cwv-audit-report.md +48 -0
  116. package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/gsc-performance-report.md +44 -0
  117. package/skills/optbrew/modules/seranking-seo/skills/seo-google/assets/templates/indexation-status-report.md +43 -0
  118. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/auth-setup.md +160 -0
  119. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/cross-skill-integration.md +187 -0
  120. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/ga4-data-api.md +184 -0
  121. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/indexing-api.md +109 -0
  122. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/keyword-planner-api.md +66 -0
  123. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/nlp-api.md +55 -0
  124. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/pagespeed-crux-api.md +204 -0
  125. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/rate-limits-quotas.md +75 -0
  126. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/search-console-api.md +156 -0
  127. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/supplementary-apis.md +99 -0
  128. package/skills/optbrew/modules/seranking-seo/skills/seo-google/references/youtube-api.md +49 -0
  129. package/skills/optbrew/modules/seranking-seo/skills/seo-keyword-niche/GUIDE.md +174 -0
  130. package/skills/optbrew/modules/seranking-seo/skills/seo-page/GUIDE.md +174 -0
  131. package/skills/optbrew/modules/seranking-seo/skills/seo-plan/GUIDE.md +220 -0
  132. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/GUIDE.md +135 -0
  133. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/references/google-rich-results.md +89 -0
  134. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/article.json +23 -0
  135. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/breadcrumb-list.json +18 -0
  136. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/faq-page.json +22 -0
  137. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/local-business.json +32 -0
  138. package/skills/optbrew/modules/seranking-seo/skills/seo-schema/templates/product.json +25 -0
  139. package/skills/optbrew/modules/seranking-seo/skills/seo-sitemap/GUIDE.md +128 -0
  140. package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/GUIDE.md +235 -0
  141. package/skills/optbrew/modules/seranking-seo/skills/seo-technical-audit/references/severity-mapping.md +133 -0
  142. package/skills/optbrew/references/ai-crawlers.json +21 -0
  143. package/skills/optbrew/references/ai-crawlers.md +24 -0
  144. package/skills/optbrew/references/api.md +45 -0
  145. package/skills/optbrew/references/check-registry.json +28 -0
  146. package/skills/optbrew/references/evidence.md +9 -0
  147. package/skills/optbrew/references/intake.md +9 -0
  148. package/skills/optbrew/references/measurement.md +29 -0
  149. package/skills/optbrew/references/policies.md +7 -0
  150. package/skills/optbrew/references/profiles.json +13 -0
  151. package/skills/optbrew/references/remediations.json +12 -0
  152. package/skills/optbrew/references/report.md +29 -0
  153. package/skills/optbrew/references/routing.md +15 -0
  154. package/skills/optbrew/references/schemas/contract.schema.json +51 -0
  155. package/skills/optbrew/references/scoring.md +62 -0
  156. package/skills/optbrew/scripts/adapters/anthropic.mjs +116 -0
  157. package/skills/optbrew/scripts/adapters/imports.mjs +81 -0
  158. package/skills/optbrew/scripts/audit.mjs +124 -0
  159. package/skills/optbrew/scripts/cli.mjs +41 -0
  160. package/skills/optbrew/scripts/core/bootstrap.mjs +31 -0
  161. package/skills/optbrew/scripts/core/bundle.mjs +73 -0
  162. package/skills/optbrew/scripts/core/capabilities.mjs +19 -0
  163. package/skills/optbrew/scripts/core/collector.mjs +250 -0
  164. package/skills/optbrew/scripts/core/compare.mjs +47 -0
  165. package/skills/optbrew/scripts/core/contracts.mjs +144 -0
  166. package/skills/optbrew/scripts/core/cost-ledger.mjs +95 -0
  167. package/skills/optbrew/scripts/core/crawlers.mjs +11 -0
  168. package/skills/optbrew/scripts/core/derive.mjs +168 -0
  169. package/skills/optbrew/scripts/core/facts.mjs +189 -0
  170. package/skills/optbrew/scripts/core/findings.mjs +54 -0
  171. package/skills/optbrew/scripts/core/html.mjs +53 -0
  172. package/skills/optbrew/scripts/core/metrics.mjs +97 -0
  173. package/skills/optbrew/scripts/core/protocol.mjs +125 -0
  174. package/skills/optbrew/scripts/core/report.mjs +742 -0
  175. package/skills/optbrew/scripts/core/scope.mjs +52 -0
  176. package/skills/optbrew/scripts/core/score.mjs +71 -0
  177. package/skills/optbrew/scripts/core/weights.mjs +139 -0
  178. package/skills/optbrew/source-lock.json +2686 -0
  179. package/source-lock.json +2686 -0
@@ -0,0 +1,160 @@
1
+ # Google API Authentication Setup
2
+
3
+ ## Overview
4
+
5
+ Three credential types serve different APIs:
6
+
7
+ | Type | Used By | Cost |
8
+ |------|---------|------|
9
+ | **API Key** | PageSpeed Insights, CrUX, CrUX History, Knowledge Graph, YouTube, NLP, Web Risk | Free |
10
+ | **Service Account** | Search Console, Indexing API, GA4 | Free |
11
+ | **Google Ads developer token** | Keyword Planner (volumes / suggestions) | Free (token approval ~24h) |
12
+ | **Both** | Full seo-google skill | Free |
13
+
14
+ ## Step 1: Create a Google Cloud Project
15
+
16
+ 1. Go to [console.cloud.google.com](https://console.cloud.google.com)
17
+ 2. Click **Select a project** > **New Project**
18
+ 3. Name it (e.g., "Claude SEO") and note the project ID
19
+ 4. Select the project after creation
20
+
21
+ ## Step 2: Enable APIs
22
+
23
+ Navigate to **APIs & Services > Library** and enable:
24
+
25
+ | API | Required For |
26
+ |-----|-------------|
27
+ | Google Search Console API | GSC Search Analytics, URL Inspection, Sitemaps |
28
+ | PageSpeed Insights API | PSI Lighthouse lab data |
29
+ | Chrome UX Report API | CrUX field data + History |
30
+ | Web Search Indexing API | Indexing API v3 |
31
+ | Google Analytics Data API | GA4 organic traffic |
32
+ | Google Analytics Admin API | `ga4-properties` (account/property discovery) |
33
+ | Knowledge Graph Search API | Entity verification |
34
+ | YouTube Data API v3 | `youtube` / `youtube-video` commands |
35
+ | Cloud Natural Language API | `nlp` / `entities` commands |
36
+ | Web Risk API | `safety` command (malware / social-engineering check) |
37
+ | Google Ads API | `keywords` / `volume` commands (also requires a Google Ads developer token — see [`keyword-planner-api.md`](keyword-planner-api.md)) |
38
+
39
+ ## Step 3: Create an API Key
40
+
41
+ 1. **APIs & Services > Credentials > Create Credentials > API key**
42
+ 2. Click **Restrict key**:
43
+ - Under **API restrictions**, select: PageSpeed Insights API, Chrome UX Report API, Knowledge Graph Search API, YouTube Data API v3, Cloud Natural Language API, Web Risk API
44
+ 3. Copy the key (starts with `AIzaSy...`)
45
+
46
+ ## Step 4: Create a Service Account
47
+
48
+ 1. **IAM & Admin > Service Accounts > Create Service Account**
49
+ 2. Name: `seo-skills` (or similar)
50
+ 3. Skip optional permissions steps
51
+ 4. Click on the created service account > **Keys > Add Key > Create new key > JSON**
52
+ 5. Download the JSON file and store it securely (e.g., `~/.config/seo-skills/service_account.json`)
53
+
54
+ The JSON file looks like:
55
+ ```json
56
+ {
57
+ "type": "service_account",
58
+ "project_id": "your-project-id",
59
+ "private_key_id": "...",
60
+ "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
61
+ "client_email": "seo-skills@your-project.iam.gserviceaccount.com",
62
+ "client_id": "...",
63
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
64
+ "token_uri": "https://oauth2.googleapis.com/token"
65
+ }
66
+ ```
67
+
68
+ The `client_email` field is what you add to GSC and GA4.
69
+
70
+ ## Step 5: Grant Search Console Access
71
+
72
+ 1. Go to [Google Search Console](https://search.google.com/search-console)
73
+ 2. Select your property
74
+ 3. **Settings > Users and permissions > Add user**
75
+ 4. Paste the service account `client_email`
76
+ 5. Set permission level:
77
+ - **Full** for read-only (Search Analytics, URL Inspection, Sitemaps)
78
+ - **Owner** if you also need the Indexing API
79
+
80
+ ## Step 6: Grant GA4 Access
81
+
82
+ 1. Go to [Google Analytics](https://analytics.google.com)
83
+ 2. **Admin > Property Access Management > Add users** (the + icon)
84
+ 3. Paste the service account `client_email`
85
+ 4. Set role: **Viewer** (minimum for read-only reporting)
86
+ 5. Note the numeric property ID from **Admin > Property Details** (e.g., `123456789`)
87
+
88
+ ## Step 7: Create Config File
89
+
90
+ ```bash
91
+ mkdir -p ~/.config/seo-skills
92
+ ```
93
+
94
+ Save to `~/.config/seo-skills/google-api.json`:
95
+
96
+ ```json
97
+ {
98
+ "service_account_path": "~/.config/seo-skills/service_account.json",
99
+ "api_key": "AIzaSy...",
100
+ "default_property": "sc-domain:example.com",
101
+ "ga4_property_id": "properties/123456789"
102
+ }
103
+ ```
104
+
105
+ ### Property URL Formats
106
+
107
+ | Format | Example | When to Use |
108
+ |--------|---------|-------------|
109
+ | Domain property | `sc-domain:example.com` | Covers all URLs on the domain (recommended) |
110
+ | URL-prefix property | `https://example.com/` | Covers only that specific prefix |
111
+
112
+ ## Step 8: Verify Setup
113
+
114
+ ```bash
115
+ upstream script excluded; use optbrew capability routing
116
+ ```
117
+
118
+ Expected output at Tier 2 (full):
119
+ ```
120
+ Credential Tier: 2 -- Full (API key + Service Account + GA4)
121
+
122
+ [OK] PageSpeed Insights v5
123
+ [OK] Chrome UX Report (CrUX) API
124
+ [OK] CrUX History API
125
+ [OK] Google Search Console API
126
+ Service account: seo-skills@your-project.iam.gserviceaccount.com
127
+ [OK] Google Indexing API v3
128
+ [OK] GA4 Data API v1beta
129
+ ```
130
+
131
+ ## Environment Variable Alternatives
132
+
133
+ Instead of (or in addition to) the config file:
134
+
135
+ | Variable | Purpose |
136
+ |----------|---------|
137
+ | `GOOGLE_API_KEY` | API key for PSI/CrUX |
138
+ | `GOOGLE_APPLICATION_CREDENTIALS` | Path to service account JSON |
139
+ | `GA4_PROPERTY_ID` | GA4 property (e.g., `properties/123456789`) |
140
+ | `GSC_PROPERTY` | Default GSC property (e.g., `sc-domain:example.com`) |
141
+
142
+ ## OAuth Scopes Used
143
+
144
+ | Scope | APIs |
145
+ |-------|------|
146
+ | `https://www.googleapis.com/auth/webmasters.readonly` | GSC (read) |
147
+ | `https://www.googleapis.com/auth/webmasters` | GSC (read/write, needed for sitemap submission) |
148
+ | `https://www.googleapis.com/auth/indexing` | Indexing API |
149
+ | `https://www.googleapis.com/auth/analytics.readonly` | GA4 (read) |
150
+
151
+ ## Troubleshooting
152
+
153
+ | Error | Fix |
154
+ |-------|-----|
155
+ | `403 Forbidden` on GSC | Service account email not added to GSC property, or wrong permission level |
156
+ | `403 Forbidden` on GA4 | Service account email not added to GA4 property as Viewer |
157
+ | `404 Not Found` on GSC | Wrong property URL format. Use `sc-domain:` or include trailing slash for URL-prefix |
158
+ | `404 Not Found` on CrUX | Site has insufficient Chrome traffic. Not a credentials issue. |
159
+ | `429 Rate Limit` | Wait and retry. See rate-limits-quotas.md for per-API limits |
160
+ | `API not enabled` | Enable the specific API in GCP Console > APIs & Services > Library |
@@ -0,0 +1,187 @@
1
+ # Cross-skill integration: enriching other skills with real Google field data
2
+
3
+ This file is the contract other skills follow to enrich their deliverables with Google-API field data **without** spawning the full `seo-google` skill. Each enrichment is a single Python script call that returns JSON; the calling skill parses it and folds the data into its primary deliverable.
4
+
5
+ The pattern was adapted from `AgriciDaniel/claude-seo`'s wiring across `seo-audit`, `seo-technical`, and `seo-drift`. Config path is namespaced to `~/.config/seo-skills/` so the two plugins coexist cleanly.
6
+
7
+ ## Trigger pattern (every enrichment-aware skill)
8
+
9
+ Add this near the top of the skill's Process steps, immediately after the existing preflight (credit balance / Firecrawl detection):
10
+
11
+ ```
12
+ **Google data availability check.** Run `upstream script excluded; use optbrew capability routing`
13
+ and parse the result. If `tier >= 0` (any creds present), Google enrichment runs in step
14
+ N (see below). If `tier == -1` or the file is missing, the skill proceeds without
15
+ Google enrichment and notes "Google field data: not configured (run `optbrew capability setup (see top-level routing)`)" in the deliverable.
16
+ ```
17
+
18
+ The `google_auth.py --check --json` output shape:
19
+
20
+ ```json
21
+ {
22
+ "tier": 1,
23
+ "available": ["pagespeed", "crux", "crux-history", "gsc", "inspect", "sitemaps", "index"],
24
+ "missing": ["ga4", "ga4-pages", "keywords", "volume"],
25
+ "config_path": "/Users/.../.config/seo-skills/google-api.json"
26
+ }
27
+ ```
28
+
29
+ The skill should branch on `available`. Each enrichment lists its required entry below.
30
+
31
+ ## Per-skill enrichment recipes
32
+
33
+ ### `seo-technical-audit` — CrUX field data + per-URL Inspection (Tier 0 + Tier 1)
34
+
35
+ Replaces the audit's lab-only CWV with actual Chrome user metrics from CrUX, and adds per-URL indexation reality from GSC URL Inspection.
36
+
37
+ **Step 8b — CrUX (Tier 0):**
38
+
39
+ ```bash
40
+ # Domain-level CrUX (origin)
41
+ upstream script excluded; use optbrew capability routing "https://{domain}" --crux-only --json
42
+
43
+ # 25-week trend (catches degradation we'd otherwise miss until next month's audit)
44
+ upstream script excluded; use optbrew capability routing "https://{domain}" --origin --json
45
+ ```
46
+
47
+ Surface in `TECH-AUDIT.md` as "## Core Web Vitals (field data)" with p75 LCP / INP / CLS, source label "CrUX 28-day origin", and the 25-week trend direction.
48
+
49
+ If CrUX has no field data for the origin (low-traffic site), surface "CrUX: insufficient data for {domain}" and continue.
50
+
51
+ **Step 8c — Per-URL Inspection (Tier 1, mirrors theirs at `seo-technical/GUIDE.md:164`):**
52
+
53
+ For each of the top 5 traffic URLs from step 5 (or homepage + key landing pages):
54
+
55
+ ```bash
56
+ upstream script excluded; use optbrew capability routing "{url}" --site-url "{config.default_property}" --json
57
+ ```
58
+
59
+ Capture `indexStatusVerdict`, `coverageState`, `googleCanonical` vs `userCanonical`, and `lastCrawlTime`.
60
+
61
+ Cross-check against the audit's noindex / canonical findings:
62
+ - GSC says `INDEXED` but audit flagged `noindex` → audit is stale, flag for re-audit.
63
+ - GSC says `EXCLUDED` for a "healthy" page → hidden indexability issue invisible to SE Ranking's audit.
64
+ - `userCanonical ≠ googleCanonical` on a top-traffic page → elevated to Critical in the Top-10 fix list regardless of `severity-mapping.md` defaults.
65
+
66
+ Surface in `TECH-AUDIT.md` as "## Indexation reality check (GSC URL Inspection)" with one row per URL.
67
+
68
+ If property not verified in this account: "GSC: {domain} not verified — add it in Search Console" and skip 8c only (8b still runs).
69
+
70
+ ### `seo-page` — GSC URL performance + URL Inspection (Tier 1 — `gsc`, `inspect` available)
71
+
72
+ Replaces inferred-from-SE-Ranking traffic with first-party Google data for the target URL.
73
+
74
+ ```bash
75
+ # GSC search analytics for the URL (requires default_property in config to be set
76
+ # to a verified property that owns this URL — sc-domain:example.com)
77
+ upstream script excluded; use optbrew capability routing "{config.default_property}" --url "{target_url}" --days 28 --json
78
+
79
+ # URL Inspection (real indexation status, canonical Google sees, last crawl date)
80
+ upstream script excluded; use optbrew capability routing "{target_url}" --site-url "{config.default_property}" --json
81
+ ```
82
+
83
+ Surface in `PAGE.md` "## Snapshot" as new rows:
84
+ - GSC last 28d: `{clicks} clicks / {impressions} impressions / {ctr}% CTR / pos {position}`
85
+ - Google sees: `index status: {INDEXED|EXCLUDED|...}`, canonical: `{userCanonical} → {googleCanonical}`, last crawled: `{date}`
86
+
87
+ Feed into the verdict heuristic:
88
+ - `INDEXED` + impressions > 100 + position 4–10 → harden REFRESH (clear quick-win territory).
89
+ - `EXCLUDED` (any reason) → harden KILL or CONSOLIDATE.
90
+ - googleCanonical ≠ userCanonical → flag in PAGE.md as a critical issue regardless of verdict.
91
+
92
+ If the URL's domain isn't a verified GSC property, surface "GSC: {target_domain} not verified — add it in Search Console" and continue.
93
+
94
+ ### `seo-content-audit` — GA4 organic traffic on the audited URL (Tier 2 — `ga4-pages` available)
95
+
96
+ Replaces estimated traffic with measured organic traffic for the audited URL.
97
+
98
+ ```bash
99
+ upstream script excluded; use optbrew capability routing top-pages --days 28 --json
100
+ ```
101
+
102
+ Filter the result client-side for the audited URL's path. Surface in `VERDICT.md` "## Snapshot" alongside the existing AIO citation cross-check:
103
+ - GA4 organic last 28d: `{sessions} sessions / {users} users / avg engagement time {n}s`
104
+ - If the audited URL doesn't appear in the top-100 organic landing pages: "GA4: not in top-100 organic landing pages last 28d — low or zero traffic."
105
+
106
+ This is a *signal*, not a veto. Low GA4 traffic on a YMYL page with high E-E-A-T is informative ("we're not earning the visibility our content quality should support") but doesn't change the publish decision.
107
+
108
+ ### `seo-drift` — CrUX-history + indexation drift + SSRF protection (Tier 0+1)
109
+
110
+ Three additions versus the bare-MCP drift run.
111
+
112
+ **SSRF protection (always, mirrors theirs at `seo-drift/GUIDE.md:97`):**
113
+
114
+ Before any URL fetch (Firecrawl, WebFetch, Google APIs), validate via:
115
+
116
+ ```python
117
+ from scripts.google_auth import validate_url
118
+ if not validate_url(target_url):
119
+ abort("URL rejected: loopback, private IP, link-local, or metadata endpoint")
120
+ ```
121
+
122
+ Or invoke as a one-liner:
123
+
124
+ ```bash
125
+ python3 -c "from scripts.google_auth import validate_url; import sys; sys.exit(0 if validate_url('{url}') else 1)"
126
+ ```
127
+
128
+ `validate_url()` (defined at `upstream script excluded; use optbrew capability routing:366`) rejects: loopback (127.0.0.1, ::1, localhost), RFC1918 private ranges (10/8, 172.16/12, 192.168/16), link-local (169.254/16), and Google metadata endpoints. Refuses non-http(s) schemes.
129
+
130
+ **`--skip-cwv` flag** (mirrors theirs at `seo-drift/GUIDE.md:107, 131`): skips the entire Google field-data snapshot (step 4b) even when `google-api.json` is configured. Useful when you only care about content/structural drift, or when CrUX rate-limit concerns outweigh CWV coverage.
131
+
132
+ **Field-data drift** (the actual enrichment):
133
+
134
+ ```bash
135
+ # CWV drift over 25 weeks (origin or per-URL based on baseline scope)
136
+ upstream script excluded; use optbrew capability routing "{baseline_url_or_origin}" --json
137
+
138
+ # Indexation drift: re-run Inspection on each baselined URL and diff
139
+ upstream script excluded; use optbrew capability routing "{url}" --site-url "{config.default_property}" --json
140
+ ```
141
+
142
+ Compare against the previous baseline's stored CrUX + Inspection JSON. New drift triggers:
143
+ - LCP p75 increased ≥20% → red.
144
+ - INP p75 increased ≥20% → red.
145
+ - CLS p75 increased ≥0.05 absolute → yellow.
146
+ - FCP / TTFB p75 increased ≥30% → yellow.
147
+ - Inspection status changed from `INDEXED` to anything else → red.
148
+ - googleCanonical changed → yellow.
149
+ - last crawl date >60 days old → yellow.
150
+
151
+ Append to `DRIFT-REPORT.md` "## Field-data drift" section.
152
+
153
+ **Skip note when `--skip-cwv` was passed:** "Field-data drift: skipped — `--skip-cwv` flag passed at baseline (or this compare)."
154
+
155
+ ### `seo-plan` — Phase-0 auto-spawn (any tier)
156
+
157
+ Plan composes other skills' outputs. If creds are present and the user hasn't already run `seo-google` in this session, Phase-0 should print:
158
+
159
+ ```
160
+ > Google APIs detected (tier {n}). For real CWV / GSC / GA4 enrichment in
161
+ > downstream phases, run `seo-google {pagespeed,gsc,ga4-pages} <domain>`
162
+ > before re-running this plan. Continue without Google enrichment? (y/n)
163
+ ```
164
+
165
+ If user continues, plan proceeds with SE Ranking data only and notes the limitation in PLAN.md. If user opts to run `seo-google` first, plan exits and re-runs after.
166
+
167
+ This is the lightest possible auto-spawn — plan doesn't dispatch the skill itself (transferring friction is theirs' anti-pattern we critiqued in EVAL_RESULT_v2.md), it just tells the user there's a richer path available.
168
+
169
+ ## Failure modes (handle gracefully across all skills)
170
+
171
+ | Failure | Detection | Skill response |
172
+ |---|---|---|
173
+ | Config file missing | `google_auth.py --check` exits non-zero | Note "Google field data: not configured" and skip enrichment |
174
+ | API key invalid | Script returns `{"error": "API_KEY_INVALID"}` | Note "Google API key rejected — re-check `~/.config/seo-skills/google-api.json`" and skip |
175
+ | Property not verified (GSC) | `gsc_query.py` returns `{"error": "PROPERTY_NOT_VERIFIED"}` | Note "GSC property `{x}` not verified for this account" and skip GSC enrichment only |
176
+ | GA4 property not configured | `ga4_property_id` empty in config | Note "GA4: property ID not configured (Tier 2 setup required)" and skip GA4 only |
177
+ | Insufficient CrUX data | `pagespeed_check.py --crux-only` returns `{"crux": null}` | Note "CrUX: insufficient field data for `{url}` (low traffic)" and skip CrUX only |
178
+ | Rate-limit hit | Script returns HTTP 429 | Note "Google API rate-limit reached — try again in 1h" and skip the affected enrichment |
179
+
180
+ A skill **never** fails the run because Google enrichment failed. Enrichment is optional uplift; the SE Ranking-based deliverable always ships.
181
+
182
+ ## Why this pattern (vs spawning `seo-google` as a sub-skill)
183
+
184
+ - One Python call per enrichment, returns JSON, parsed in-line — no extra agent context, no extra latency.
185
+ - Each skill stays self-contained; no orchestration logic in the calling skill.
186
+ - Failure-isolated: a failed Google call doesn't pollute the SE Ranking-based primary deliverable.
187
+ - Mirrors the upstream wiring (`AgriciDaniel/claude-seo`'s `seo-technical/GUIDE.md:164` invokes the same scripts directly).
@@ -0,0 +1,184 @@
1
+ # GA4 Data API v1beta Reference
2
+
3
+ ## Overview
4
+
5
+ The Google Analytics Data API v1beta provides programmatic access to GA4 report data. For SEO, the primary use case is organic traffic analysis.
6
+
7
+ **Base URL:** `https://analyticsdata.googleapis.com/v1beta`
8
+
9
+ ## Key Methods
10
+
11
+ | Method | Description |
12
+ |--------|-------------|
13
+ | `properties.runReport` | Run a standard report |
14
+ | `properties.batchRunReports` | Up to 5 reports in one call |
15
+ | `properties.runRealtimeReport` | Last 30 minutes of data |
16
+ | `properties.getMetadata` | Available dimensions and metrics |
17
+ | `properties.checkCompatibility` | Verify dimension/metric combinations |
18
+
19
+ ## runReport Request
20
+
21
+ ```json
22
+ {
23
+ "property": "properties/123456789",
24
+ "dimensions": [
25
+ { "name": "date" },
26
+ { "name": "landingPage" }
27
+ ],
28
+ "metrics": [
29
+ { "name": "sessions" },
30
+ { "name": "totalUsers" }
31
+ ],
32
+ "dateRanges": [
33
+ { "startDate": "28daysAgo", "endDate": "yesterday" }
34
+ ],
35
+ "dimensionFilter": {
36
+ "filter": {
37
+ "fieldName": "sessionDefaultChannelGroup",
38
+ "stringFilter": {
39
+ "matchType": "EXACT",
40
+ "value": "Organic Search"
41
+ }
42
+ }
43
+ },
44
+ "orderBys": [
45
+ { "metric": { "metricName": "sessions" }, "desc": true }
46
+ ],
47
+ "limit": 100,
48
+ "returnPropertyQuota": true
49
+ }
50
+ ```
51
+
52
+ ## SEO-Relevant Dimensions
53
+
54
+ | Dimension | Description |
55
+ |-----------|-------------|
56
+ | `date` | Date in YYYYMMDD format |
57
+ | `pagePath` | Page path (e.g., `/blog/post`) |
58
+ | `landingPage` | Entry page path |
59
+ | `landingPagePlusQueryString` | Entry page with query params |
60
+ | `fullPageUrl` | Full page URL |
61
+ | `pageTitle` | Page title |
62
+ | `sessionSource` | Traffic source (e.g., `google`) |
63
+ | `sessionMedium` | Traffic medium (e.g., `organic`) |
64
+ | `sessionDefaultChannelGroup` | Channel grouping (e.g., `Organic Search`) |
65
+ | `country` | User country |
66
+ | `deviceCategory` | `desktop`, `mobile`, `tablet` |
67
+ | `hostName` | Domain name |
68
+ | `pageReferrer` | Referrer URL |
69
+
70
+ ## SEO-Relevant Metrics
71
+
72
+ | Metric | Description |
73
+ |--------|-------------|
74
+ | `sessions` | Number of sessions |
75
+ | `totalUsers` | Total unique users |
76
+ | `newUsers` | First-time users |
77
+ | `activeUsers` | Users with engagement |
78
+ | `screenPageViews` | Page views |
79
+ | `bounceRate` | Bounce rate (0-1, multiply by 100 for %) |
80
+ | `averageSessionDuration` | Avg duration in seconds |
81
+ | `engagementRate` | Engaged session rate (0-1) |
82
+ | `keyEvents` | Key events (replaced deprecated `conversions`) |
83
+ | `eventCount` | Total event count |
84
+
85
+ ## Filter Expressions
86
+
87
+ ### String Filter
88
+
89
+ ```json
90
+ {
91
+ "filter": {
92
+ "fieldName": "sessionDefaultChannelGroup",
93
+ "stringFilter": {
94
+ "matchType": "EXACT",
95
+ "value": "Organic Search"
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ Match types: `EXACT`, `BEGINS_WITH`, `ENDS_WITH`, `CONTAINS`, `FULL_REGEXP`, `PARTIAL_REGEXP`
102
+
103
+ ### Combining Filters
104
+
105
+ ```json
106
+ {
107
+ "andGroup": {
108
+ "expressions": [
109
+ { "filter": { "fieldName": "country", "stringFilter": { "matchType": "EXACT", "value": "US" }}},
110
+ { "filter": { "fieldName": "deviceCategory", "stringFilter": { "matchType": "EXACT", "value": "mobile" }}}
111
+ ]
112
+ }
113
+ }
114
+ ```
115
+
116
+ Also supports `orGroup` and `notExpression`.
117
+
118
+ ## Date Range Shortcuts
119
+
120
+ | Value | Meaning |
121
+ |-------|---------|
122
+ | `today` | Current day |
123
+ | `yesterday` | Previous day |
124
+ | `NdaysAgo` | N days ago (e.g., `28daysAgo`) |
125
+ | `YYYY-MM-DD` | Specific date |
126
+
127
+ Up to 4 date ranges per request (for period-over-period comparison).
128
+
129
+ ## Token-Based Quotas
130
+
131
+ | Quota | Limit | Scope |
132
+ |-------|-------|-------|
133
+ | Daily tokens | 25,000 | Per property per project |
134
+ | Hourly tokens | 5,000 | Per property per project |
135
+ | Concurrent requests | 10 | Per property per project |
136
+ | Hourly tokens (project-wide) | 1,250 | Per project per property per hour |
137
+
138
+ Set `returnPropertyQuota: true` to monitor consumption. Simple reports cost ~1-10 tokens; complex ones up to ~100.
139
+
140
+ ## Python Example
141
+
142
+ ```python
143
+ from google.analytics.data_v1beta import BetaAnalyticsDataClient
144
+ from google.analytics.data_v1beta.types import (
145
+ DateRange, Dimension, Filter, FilterExpression,
146
+ Metric, OrderBy, RunReportRequest,
147
+ )
148
+ from google.oauth2 import service_account
149
+
150
+ credentials = service_account.Credentials.from_service_account_file(
151
+ "service_account.json",
152
+ scopes=["https://www.googleapis.com/auth/analytics.readonly"],
153
+ )
154
+
155
+ client = BetaAnalyticsDataClient(credentials=credentials)
156
+
157
+ request = RunReportRequest(
158
+ property="properties/123456789",
159
+ dimensions=[Dimension(name="landingPage")],
160
+ metrics=[Metric(name="sessions"), Metric(name="totalUsers")],
161
+ date_ranges=[DateRange(start_date="28daysAgo", end_date="yesterday")],
162
+ dimension_filter=FilterExpression(
163
+ filter=Filter(
164
+ field_name="sessionDefaultChannelGroup",
165
+ string_filter=Filter.StringFilter(
166
+ match_type=Filter.StringFilter.MatchType.EXACT,
167
+ value="Organic Search",
168
+ ),
169
+ )
170
+ ),
171
+ order_bys=[OrderBy(metric=OrderBy.MetricOrderBy(metric_name="sessions"), desc=True)],
172
+ limit=50,
173
+ return_property_quota=True,
174
+ )
175
+
176
+ response = client.run_report(request)
177
+ for row in response.rows:
178
+ print(f"{row.dimension_values[0].value}: {row.metric_values[0].value} sessions")
179
+ ```
180
+
181
+ ## Authentication
182
+ - **Scope:** `https://www.googleapis.com/auth/analytics.readonly`
183
+ - Service account must have **Viewer** role in GA4 property
184
+ - Add via GA4 Admin > Property Access Management
@@ -0,0 +1,109 @@
1
+ > optbrew distribution notice: Submission disabled. The POST publish and batch examples below document upstream behavior; do not execute them from optbrew. A separate user authority decision and approved submission path are required.
2
+
3
+ # Google Indexing API v3 Reference
4
+
5
+ ## Overview
6
+
7
+ The Indexing API allows you to notify Google when pages are added or removed.
8
+
9
+ **IMPORTANT:** Officially restricted to pages with **JobPosting** or **BroadcastEvent/VideoObject** structured data. Google may process other page types, but provides no guarantees. Always inform users of this limitation.
10
+
11
+ ## Endpoints
12
+
13
+ ### Publish Notification
14
+
15
+ **`POST https://indexing.googleapis.com/v3/urlNotifications:publish`**
16
+
17
+ ```json
18
+ {
19
+ "url": "https://example.com/jobs/software-engineer",
20
+ "type": "URL_UPDATED"
21
+ }
22
+ ```
23
+
24
+ | Field | Values |
25
+ |-------|--------|
26
+ | `url` | The fully qualified URL |
27
+ | `type` | `URL_UPDATED` (page added/changed), `URL_DELETED` (page removed) |
28
+
29
+ **Response:**
30
+ ```json
31
+ {
32
+ "urlNotificationMetadata": {
33
+ "url": "https://example.com/jobs/software-engineer",
34
+ "latestUpdate": {
35
+ "url": "https://example.com/jobs/software-engineer",
36
+ "type": "URL_UPDATED",
37
+ "notifyTime": "2026-03-27T10:00:00Z"
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ### Get Notification Metadata
44
+
45
+ **`GET https://indexing.googleapis.com/v3/urlNotifications/metadata?url={ENCODED_URL}`**
46
+
47
+ Returns `latestUpdate` and `latestRemove` timestamps for the URL.
48
+
49
+ ### Batch Requests
50
+
51
+ **`POST https://indexing.googleapis.com/batch`**
52
+
53
+ Up to **100 URLs** per batch request using `multipart/mixed` format:
54
+
55
+ ```
56
+ POST /batch HTTP/1.1
57
+ Content-Type: multipart/mixed; boundary=batch_boundary
58
+
59
+ --batch_boundary
60
+ Content-Type: application/http
61
+ Content-ID: <item1>
62
+
63
+ POST /v3/urlNotifications:publish HTTP/1.1
64
+ Content-Type: application/json
65
+
66
+ {"url": "https://example.com/jobs/1", "type": "URL_UPDATED"}
67
+ --batch_boundary
68
+ Content-Type: application/http
69
+ Content-ID: <item2>
70
+
71
+ POST /v3/urlNotifications:publish HTTP/1.1
72
+ Content-Type: application/json
73
+
74
+ {"url": "https://example.com/jobs/2", "type": "URL_UPDATED"}
75
+ --batch_boundary--
76
+ ```
77
+
78
+ ## Authentication
79
+
80
+ - **Scope:** `https://www.googleapis.com/auth/indexing`
81
+ - **Auth type:** Service account (OAuth 2.0)
82
+ - The service account must be **Owner** in Google Search Console for the target domain
83
+
84
+ ## Quotas
85
+
86
+ | Limit | Value | Scope |
87
+ |-------|-------|-------|
88
+ | Publish requests | **200/day** (default) | Per project |
89
+ | Read-only requests | 180/min | Per project |
90
+ | Total requests | 380/min | Per project |
91
+
92
+ Request a quota increase: [Indexing API Quota Increase Form](https://developers.google.com/search/apis/indexing-api/v3/quota-increase)
93
+
94
+ ## Error Codes
95
+
96
+ | Code | Meaning | Action |
97
+ |------|---------|--------|
98
+ | 400 | Malformed URL or request body | Check URL format |
99
+ | 403 | Permission denied or quota exceeded | Add service account as Owner in GSC, or check quota |
100
+ | 429 | Rate limit exceeded | Back off and retry with exponential delay |
101
+ | 500/503 | Server error | Retry with exponential backoff |
102
+
103
+ ## Best Practices
104
+
105
+ 1. Submit only URLs with actual content changes (don't spam updates)
106
+ 2. Use `URL_DELETED` only when a page is permanently removed (returns 404/410)
107
+ 3. Track daily quota usage -- the 200/day limit resets at midnight Pacific Time
108
+ 4. For large-scale indexing, use XML sitemaps + Search Console instead
109
+ 5. Batch requests count individually against the daily quota (100 batch = 100 quota)