nowork-studio/notfair
Operate ads and analytics, and run open-source SEO, GEO, and content workflows from compatible AI agents.
Changelog
All notable changes to the NotFair plugin (formerly toprank) will be documented here.
The format follows Keep a Changelog.
[Unreleased]
Added
-
Portable agent marketplace manifests (v0.27.1). Added Agent Plugins 1.0 manifests for Kiro Powers and compatible hosts, a Gemini CLI extension manifest for automatic gallery discovery, and universal NotFair Ads metadata for the official MCP Registry. Cursor and Codex now share the standards-based root MCP manifest.
-
X Ads, LinkedIn Ads, GA4, and Search Console MCP skills (v0.26.0). Added a live X Ads operator plus dedicated Google Analytics and Search Console workflows, and upgraded the existing LinkedIn skill from export-first planning to live read/write operation. Registered the four sibling-server endpoints in
.mcp.json, expanded cross-channel routing and approval guardrails, added reproducible live OAuth-discovery end-to-end coverage, and refreshed the public skill/integration catalog. -
Cross-channel paid-ads skills (v0.25.11). Added an evidence-first paid-media router plus guide, setup, integration, launch, review, optimization, creative, LinkedIn, TikTok, Amazon, and ChatGPT Ads workflows. Google and Meta requests route to the established NotFair operator skills; platforms without a declared NotFair MCP surface remain explicitly plan/review-only until a verified connector is available. Every workflow carries shared approval, measurement, and publication-status guardrails.
-
Evidence-based ads creative and assets (v0.25.10). Added
/google-ads-assetsfor reviewable extension, image-asset, and PMax production briefs, and/meta-ads-creativefor grounded Facebook/Instagram concept slates and refresh tests. Both distinguish an approved brief from a published asset and keep unsupported claims, rights, and MCP capability boundaries explicit.
Changed
- One-command universal MCP onboarding (v0.27.0). Replaced the six bundled platform server registrations with one
NotFairMCP connection athttps://notfair.co/api/mcp/notfair_ads. Codex and Claude now need one OAuth grant; workspaces enabled in the staged Google-first rollout connect Google Ads during that flow, and every supported platform remains isolated behind explicit tool prefixes such asgoogle_ads_,meta_ads_, andsearch_console_. - Repository renamed to
nowork-studio/notfair-plugin. Active clone, install, update-check, package metadata, and source links now use the new GitHub repository name. The plugin name and/notfair:*command namespace remain unchanged. /google-ads-copynow records concepts and claim sources, requires unsupported proof to be marked for substantiation, and makes test decisions from pre-set metrics and adequate exposure rather than early conversion-rate gaps.
[0.25.9] — 2026-07-21
Fixed
--no-openis honored on macOS and Windows in the content-calendar viewer. An operator-precedence bug in the auto-open guard meant the two platforms where auto-open actually fires never consulted the flag; the guard is now an explicit helper with unit tests. Contributed by @Osamaali313 (#92).
[0.25.8] — 2026-07-21
Added — ten new SEO skills (local, international, technical, commerce, off-page)
Major expansion of the SEO suite. All native skills built to repo conventions
(frontmatter triggers, seo/shared/preamble.md integration):
local-seo— Local pack / Google Business Profile audit: NAP consistency, GBP completeness, review health, local & service-area pages,LocalBusinessschema.hreflang-international— Hreflang correctness (return tags, x-default, codes, hreflang↔canonical conflicts) + international URL-structure strategy.sitemap-audit— XML sitemap discovery, structural limits, lastmod accuracy, and a URL reality cross-check (non-200 / noindex / canonicalized-away listed).image-seo— Alt text, WebP/AVIF, compression, srcset, CLS width/height, lazy-load (incl. lazy-loaded-LCP), image sitemaps,ImageObjectschema.ecommerce-seo— PLP/PDP, faceted-navigation crawl-budget traps, variant canonicals, out-of-stock handling,Product/Offer/Reviewschema.programmatic-seo— Templated pages at scale: demand validation, a uniqueness/value gate, internal-link hubs, indexation mgmt, doorway-page guardrails.competitor-pages— Coverage matrix + intent/depth/schema/E-E-A-T comparison vs. top-ranking URLs, producing a brief handable tocontent-writer.sxo— Search Experience Optimization: SERP click factors + post-click experience/conversion (above-the-fold intent match, CWV, CTAs, anti-pogo-sticking).seo-drift— Baseline + compare to catch regressions (lost rankings, deindexed pages, overwritten titles, flipped noindex/canonical).backlink-audit— Off-page audit from the free GSC Links report by default (or a paid Ahrefs/Semrush/DataForSEO export); explicit about data limits.
All registered in AGENTS.md, .claude-plugin/plugin.json,
.claude-plugin/marketplace.json, and README.md.
Skills that would duplicate existing skills were intentionally not added (to avoid
skill-routing collisions); the pure paid-data MCP wiring was skipped in favor of
backlink-audit consuming such data when present.
[0.25.7] — 2026-07-14
Changed
- Updated the public skill catalog to include the GSC-driven content planner and NotFair upgrade skill, and clarified that compatible coding agents can discover the host-agnostic skills through
AGENTS.md. - Brought the local NotFair app documentation in line with the shipped goal lifecycle, Codex account and model UI, platform selection, pull-request workflow, supported npm platform, and lowercase CLI commands.
- Documented the app's current trust boundaries accurately: Codex runs as trusted unsandboxed local automation, workflow and pull-request limits are behavioral guardrails, and OAuth credentials are not yet encrypted at the application layer.
[0.25.6] — 2026-06-04
Added
- Wired the NotFair Google Search Console MCP server (
https://notfair.co/api/mcp/google_search_console) into the plugin's.mcp.json, exposing it asNotFair-SearchConsole. The hosted endpoint and the SEO connector were already live, but the plugin never registered the server, so its tools (search analytics, URL inspection, sitemaps) were unavailable in Claude Code alongside the existing Google Ads and Meta Ads servers.
[0.25.5] — 2026-05-28
Added
- Added Google Ads operator references for daily briefs, search-term triage, safe MCP execution, intervention memory, client reporting, local lead-gen accounts, and SaaS/B2B product-led accounts.
- Added Google Ads management evals covering daily operator briefs, safe search-term cleanup, failed mutation handling, and NotFair-style SaaS activation optimization.
Changed
- Expanded Google Ads skills with repeatable optimization loops for search-term/n-gram triage, budget/rank diagnosis, broad match containment, RSA testing, landing-page message-chain testing, and conversion/network integrity checks.
- Updated
/google-adsrouting guidance to use the new daily operator, safe executor, intervention memory, and domain playbook references for recurring account-management workflows.
[0.25.4] — 2026-05-28
Changed
- Strengthened SEO content-quality guidance for compliance-sensitive claims, official-source citation requirements, internal links, and image asset validation.
[0.25.3] — 2026-05-28
Removed
- Removed the legacy OpenClaw adaptive layer, including repo-local orchestrator skills, cron/install scripts, schemas, examples, runtime helpers, and OpenClaw-specific tests.
- Removed the OpenClaw-backed
/notfair:cmolaunch skill from the Claude Code plugin manifest and public resolver.
Changed
- Updated public install and resolver docs to describe the remaining host-agnostic NotFair skill surface for Claude Code, Codex, and Hermes.
[0.25.2] — 2026-05-24
Fixed
/notfair:cmonow self-updates. The skill had no update-check preamble (unlike the google-ads / meta-ads / seo skills, which runnotfair-update-checkat Step 0). So a stale plugin ran stale instructions — e.g. probing the old port3000while the published CLI had moved to3327. Added a Step 0 that runsnotfair-update-checkand, onUPGRADE_AVAILABLE, follows the/notfair:upgradeflow, then re-reads the refreshed skill before launching. AddedAskUserQuestionto the skill'sallowed-toolsfor the upgrade handoff.
[0.25.1] — 2026-05-24
Fixed
notfair-cmostandalone build now boots. The published tarball crashed on launch withCannot find module 'bindings'—better-sqlite3's native loader was present in the pnpm store but not at a path Node could resolve.scripts/copy-standalone-assets.mjsnow hoistsbindingsandfile-uri-to-pathinto the standalone's top-levelnode_modules/.notfair-cmopackage.json— corrected thebinpath (./bin/cli.mjs→bin/cli.mjs, which npm 11 was stripping at publish), set first real release version0.1.0, and added anos/cpuguard (darwin/arm64) so unsupported platforms fail install cleanly instead of crashing at runtime.
Changed
- Portal default port moved
3000→3327(dev server stays on3326), avoiding the common3000collision and keeping dev/published ports adjacent./notfair:cmoand thenotfair-cmoCLI now use3327. next.config.ts— addedallowedDevOrigins: ["127.0.0.1"]so the dev server hydrates when opened on the loopback IP.
[0.25.0] — 2026-05-24
Added
notfair-cmo/— open-sourced the local CMO portal as a sibling project in this repo. Node app (Next.js) that runs onhttp://127.0.0.1:3000, orchestrates specialist marketing agents (CMO, Google Ads, SEO) per project, exposes chat + cron + activity log + MCP connections. Distributed via npm asnotfair-cmo. Each project gets its own OpenClaw workspace under~/.notfair-cmo/agents/. Source:notfair-cmo/README.md./notfair:cmo— new slash command. Probeshttp://127.0.0.1:3000; if not running, runsnotfair-cmo doctor, thennpx notfair-cmo@latest startdetached, then opens the browser. Supports a custom port (/notfair:cmo --port 4001). Source:notfair-cmo-skill/SKILL.md.
The plugin and the CMO portal share the same skills engine but ship through different channels (Claude Code marketplace vs npm) and on independent release cadences. The plugin's VERSION and notfair-cmo/package.json version are intentionally decoupled.
[0.24.0] — 2026-05-24
⚠️ Breaking — plugin renamed toprank → notfair
The Claude Code plugin name, slash-command prefix, and several internal
directories and binaries have been renamed from toprank to notfair to
align with the user-facing NotFair brand. This is a breaking change for
every installed user.
You must uninstall the old plugin and reinstall under the new name:
/plugin uninstall toprank@nowork-studio
/plugin marketplace add nowork-studio/notfair
/plugin install notfair@nowork-studio
After reinstall, every slash command moves from /toprank:foo →
/notfair:foo (e.g. /notfair:google-ads-audit, /notfair:seo-analysis).
The upgrade skill is now /notfair:upgrade (previously
/toprank:toprank-upgrade).
Renamed
- Plugin —
namein.claude-plugin/plugin.jsonand.claude-plugin/marketplace.jsonis nownotfair(previouslytoprank). - Skill directories —
toprank-upgrade-skill/→notfair-upgrade-skill/;openclaw/skills/toprank-{site-onboard, portfolio-review,weekly-review,improve-page,investigate-drop}/→openclaw/skills/notfair-{...}/. - Bin scripts —
bin/toprank-{config,update-check,change-watch, content-calendar}→bin/notfair-{...}. SessionStart hooks that ran the old path will need to be re-pointed. - Cron / launchd example —
openclaw/install/toprank-openclaw.cron.example→notfair-openclaw.cron.example. - Upgrade skill name — frontmatter
name: toprank-upgrade→name: upgrade; slash command consequently/notfair:upgrade. - Managed-block fence — installers now write
<!-- notfair:managed -->fences (previously<!-- toprank:managed -->). Re-running an installer against a file that has the old fence will create a second fence; users who want a fully clean state can delete the old block manually. - GitHub repository —
nowork-studio/toprank→nowork-studio/notfair(GitHub auto-redirects the old URL).
Intentionally preserved (carve-outs)
The following paths and identifiers were not renamed in this release so existing installs keep working without a migration step. A future release may migrate them with proper backup logic.
~/.toprank/runtime state directory — holds OpenClaw portfolio artifacts (~/.toprank/openclaw/), Google Ads change logs (~/.toprank/ads/<account>/change-log.json), SEO audit history (~/.toprank/audit-log/<domain>.json), business-context cache (~/.toprank/business-context/<domain>.json), and upgrade markers. Renaming this would orphan every existing user's accumulated data.TOPRANK_*environment variables —TOPRANK_DIR,TOPRANK_STATE_DIR,TOPRANK_REMOTE_URL,TOPRANK_OPENCLAW_HOME,TOPRANK_VERCEL_PROTECTION_BYPASS. These are internal testing / configuration overrides; renaming would silently break any user, cron job, or CI pipeline that sets them.com.noworkstudio.toprank.openclaw.schedulerlaunchd label — renaming would orphan the existing launchd job; the user would have to manuallylaunchctl unloadthe old one.~/.toprank-evals/test result store — used only by the test suite.
CHANGELOG history preserved verbatim
Past releases shipped under the toprank name and the historical record
reflects that. CHANGELOG entries below this one are unchanged.
Out of scope (pre-existing)
meta-ads/manage/andmeta-ads/audit/do not shipevals/evals.jsonfiles. This gap predates 0.24.0 (introduced in 0.17.0). The renamedtest/install.test.shnow enumerates all 18 skills correctly and surfaces the missing eval files as 2 failures; the prior test masked them by enumerating only 16 skills. A follow-up release should add the missing evals; this release does not change skill behavior.
Migration footnotes
- OpenClaw users who ran
./openclaw/install/install-openclaw-cron.shon a prior release will have cron jobs namedToprank OpenClaw SchedulerandToprank Weekly Review — <site>. After upgrading, re-running the install script will register new jobs namedNotFair ...alongside the oldToprank ...ones. To clean up, runopenclaw cron remove "Toprank OpenClaw Scheduler"and equivalent for each per-site weekly review job before re-installing. - Hooks pointing at
bin/toprank-change-watchin~/.claude/settings.jsonmust be updated tobin/notfair-change-watchafter reinstall.
[0.23.0] — 2026-05-16
Changed — full removal of legacy AdsAgent branding from active code
- The legacy AdsAgent brand is now fully removed from all active skill text, docs, MCP detection logic, install tests, and project guidance. CHANGELOG history is intentionally preserved verbatim — past releases shipped under that name and the historical record reflects that.
google-ads/shared/preamble.md— dropped the one-time.adsagent→.notfairfilesystem migration step entirely. Renumbered the remaining steps (Resolve config → Step 1, MCP detection → Step 2, Onboarding → Step 3, Calling tools → Step 4). MCP prefix detection now only looks for NotFair / NotFair-GoogleAds variants; the legacymcp__adsagent__*/mcp__claude_ai_AdsAgent__*prefixes have been removed from the detection table, the legacy-prefix nudge, and the tool-call prefix reference list.gemini/SKILL.md— Step 2a (Google Ads change detection) no longer scans for the legacy MCP prefix or the legacy.adsagent/data-dir path.google-ads/shared/preamble.md,google-ads/shared/analysis-principles.md,google-ads/audit/SKILL.md,google-ads/manage/SKILL.md— the four active references to MCP playbook resources usenotfair://playbooks/*rather than the prioradsagent://scheme.CLAUDE.md— "Branding: NotFair going forward" rewritten to "Branding: NotFair." The load-bearing-compat carve-out is gone (there is nothing left to carve out). The "Related repos" mention of the siblingadsagent-plugin/directory has been removed.README.md— Connectors table no longer mentionsmcp__adsagent__*as a detected variant.test/install.test.sh— dropped the assertion that skills don't inline the legacy MCP prefix. The current assertion (no inlinemcp__notfair__listConnectedAccounts) still guards against bypassing the shared preamble's prefix-detection logic.
Coordination (shipped server-side in notfair 56d9106)
- The
NotFair-GoogleAdsMCP server now dual-publishes the three playbook resources (audit-account,explain-regression,run-experiment) under both the canonicalnotfair://scheme and the legacyadsagent://scheme. New toprank (v0.23.0+) skills fetch vianotfair://; pre-v0.23.0 toprank skills keep working via the legacy URI. The legacy server-side registration can be removed in a later release once telemetry confirms zeroresources/readtraffic underadsagent://.
Breaking — pre-0.19 users without migrated config
- The auto-migration shipped in 0.15.0 (legacy
.adsagentpaths →.notfairpaths) is gone. Users who first installed the plugin before 0.15.0 AND never invoked any google-ads skill on a 0.15.x–0.22.x version will, on upgrade to 0.23.0, find their savedaccountIdand data files invisible to the plugin. Resolution: rename the legacy global directory (~/.adsagent→~/.notfair), the legacy project config file (.adsagent.json→.notfair.json), and the legacy project data dir if any (.adsagent/→.notfair/) manually, or simply re-run the/google-adsonboarding to save a freshaccountId. One-time-per-machine fix.
[0.22.0] — 2026-05-15
Added — opt-in OpenClaw cron publisher
openclaw/bin/publish_pending.py— stdlib Python publisher. Readscontent-calendar.json, finds entries withstatus: "ready_to_publish"and abodyPath, POSTs each to$NOTFAIR_PUBLISH_URL(default:https://notfair.co/api/blog/publish) withAuthorization: Bearer $NOTFAIR_PUBLISH_TOKEN. Dry-run by default — needs--commit(orOPENCLAW_PUBLISH_COMMIT=1) to actually fire. Response handling: 2xx →publishedwith stored URL; 4xx →failed(non-retryable); 5xx / network error → entry staysready_to_publish, exits non-zero so the next cron pass retries.openclaw/install/install-openclaw-cron.sh --enable-publisher— new opt-in flag that registers a recurringToprank NotFair Publishercron job viaopenclaw cron add. Default interval: 15m (override with--publisher-every). Existing installs are unaffected — without the flag, the publisher is not registered.openclaw/install/notfair-publisher.md— webhook contract for the Next.js side: endpoint, auth, request payload shape, expected responses, idempotency, status-code semantics, versioning. Single source of truth — keeppublish_pending.pyand the Next.js handler in lockstep via this doc.seo/content-planner/SKILL.md— schema now documentsready_to_publish/published/failedstatuses andbodyPath,featuredImage,inlineImages,structuredData,metaDescriptionfields. Includes a status-lifecycle table. The planner never auto-promotes — the hand-flip toready_to_publishis the user's explicit go-ahead.- 15 unit tests (
openclaw/tests/test_publish_pending.py) covering missing calendar, no ready entries, missing token, dry-run, 2xx / 4xx / 5xx / network, missing body file, multiple entries, site filter, payload shape, and CLI/env-var precedence.
Changed — opt-in carve-out, not policy flip
openclaw/README.md"What it is not" — narrowed from "not a production auto-publisher" (absolute) to "not an auto-publisher by default" (opt-in carve-out). Existing installs stay read-only / advisory; users explicitly opt in with--enable-publisher.
Notes — what's intentionally NOT here
- No dependency on
gbrain(Garry Tan's open-source memory/scheduler runtime). It's a real and capable project, but for a stateless POST-on-a-timer the marginal value overopenclaw cronis zero and the dependency surface is large. The publisher is runtime-agnostic stdlib Python — if someone later wants to drive it from gbrain or plain crontab, they wire up a one-line shell job pointing atpublish_pending.py. - No HMAC signing in v1. Add
X-NotFair-Signatureand bumpschemaVersionif needed.
[0.21.0] — 2026-05-15
Added — /content-planner skill + local calendar viewer
- New skill:
seo/content-planner. A GSC-driven content calendar. Pulls 90 days of Search Console query × page data, classifies every (query, page) row into one of five buckets (striking-distance positions 5–20, unanswered-intent gaps, CTR underperformers, related-keyword expansions, and cannibalization warnings), computes a click-potential score per topic (projectedImpressions × (targetCtrAtPosition3 − currentCtr)), and writes a dated, prioritized calendar to{data_dir}/content-calendar.json. Refuses to ship the calendar when GSC isn't connected, when there's < 50 rows of data to reason about, or when two scheduled topics share a primary keyword. Hands off to/content-writer,/meta-tags-optimizer, and/seo-analysisbased on bucket. - New binary:
bin/toprank-content-calendar. Stdlib-only Python HTTP server that readscontent-calendar.jsonand renders a read-only calendar view onlocalhost:8323(configurable). Auto-discovers the calendar at./.notfair/content-calendar.jsonthen~/.notfair/content-calendar.json, falls forward through the next 9 ports if the default is in use, exits cleanly on Ctrl+C. No pip install, no framework, no auth — loopback-only. - Methodology reference:
seo/content-planner/references/planning-methodology.md. Codifies the CTR-by-position curve, the five-bucket classification rubric, the click-potential formula with seasonality factors, scheduling rules (one post per week by default, P0s first, refreshes parallel to new posts), and explicit failure modes (calendar padding, intent mismatch, treating GSC impressions as third-party volume).
Changed — boundary cleanup against /keyword-research
/keyword-researchdescription now scopes it explicitly to seed-driven keyword discovery and points users at/content-plannerfor editorial calendars built from their own GSC data. AGENTS.md row updated to match.
Notes
- The calendar viewer is read-only by design — editing happens in the JSON file, the viewer re-reads on every request. Loop: edit JSON → reload page.
- The viewer auto-opens the browser on macOS/Windows and on Linux with
$DISPLAYset; pass--no-opento disable.
[0.20.0] — 2026-05-15
Changed — /content-writer blog-post bar raised
- Hook-driven titles are now required. The reference now ships four working title-hook patterns (number + specificity, audience-named guide, contrarian myth-break, outcome promise + proof) with examples and an explicit disqualifier list. Bare-keyword titles ("Facebook SEO Optimization") no longer pass the quality gate.
- Images are now a hard requirement, not a "should-have". Every blog post
ships with a featured/thumbnail image plus ≥ 3 inline images placed at
meaningful points (diagram, screenshot, comparison, data viz — decorative stock
fails the gate). The skill instructs the agent to generate images in the same
pass: use host-native image gen (Codex
gpt-image, Gemini Imagen) when available, fall back to NotFair MCPgenerate_image, otherwise emit detailed prompts so the user can run them in their own tool. Image SEO rules (file naming, alt text, format, lazy-loading) are now codified. - Table of contents is required at the top of every blog post. Anchor links to every H2, regardless of length — the prior > 1500-word threshold is gone.
- Minimum length: 1000 words of substantive body content. Anything shorter reads like AI filler and doesn't earn the click.
- Editorial bar referenced explicitly.
SKILL.mdnow points at NotFair's ownfacebook-seo-optimizationpost as the quality benchmark for tone, depth, and structure.
Changed — /google-ads* MCP-not-detected prompt now leads with a clear NotFair connect CTA
- The "no MCP server detected" branch in
google-ads/shared/preamble.mdused to open with a troubleshooting sentence. It now opens with "Connect to NotFair to manage Google Ads" and presents a three-step connect flow (/mcp→ sign in → re-run request) before the OAuth-refresh and Google- official-MCP fallback notes. New users now see a clear action, not a diagnostic.
Notes
- No file moves, no skill renames, no breaking changes —
toprankremains the plugin / package name, NotFair remains the user-facing brand perCLAUDE.md. - Existing posts written under the 0.19.x bar still work; the new requirements apply to fresh content.
[0.19.0] — 2026-05-14
Added — multi-host support
AGENTS.mdat the repo root — universal skill resolver. Maps user intents (SEO audit, ad copy, traffic drop, landing page audit, etc.) to the rightSKILL.mdfor every supported agent host. Read natively by Codex; read by OpenClaw, Hermes, Cursor, and any agent followingINSTALL_FOR_AGENTS.md. Claude Code continues to use.claude-plugin/plugin.jsonas before —AGENTS.mdis additive, not a replacement.INSTALL_FOR_AGENTS.mdat the repo root — single paste-URL install entry point. The user pastes one line into their agent; the agent detects the host (Claude Code / OpenClaw / Codex / Hermes / generic) and follows the matching install branch.install/README.md— convention for adding future per-host install adapters without duplicating skills. Documents the managed-block fence rule (<!-- toprank:managed -->) so installers that write to user-edited config files stay idempotent and preserve hand-edits.
Changed
CLAUDE.mdreframed from "Claude Code plugin" to "host-agnostic plugin." Adding a new skill now requires registering it in bothAGENTS.mdand.claude-plugin/plugin.json.CLAUDE.mdbranding rule — added an explicit "NotFair going forward" section. New user-facing text and docs must use NotFair. Existing legacyadsagentreferences are kept only where they are load-bearing (filesystem migration, prefix detection during the rename window) or historical (CHANGELOG).
Removed
- Stale "server source" link from
README.md. The link previously pointed tonowork-studio/ads-agent(404) and the actual server source is not public. Removed the pointer entirely — the surrounding paragraph already covers what Toprank users need (endpoint URL, registry name, OAuth flow).
Notes
- No skill behavior changes. All canonical SEO, Google Ads, Meta Ads, and Gemini skills work identically to 0.18.0.
- OpenClaw multi-site orchestrators under
openclaw/skills/are unchanged; they're now explicitly tagged as OpenClaw-only inAGENTS.md.
[0.18.0] — 2026-05-09
Changed
- Google Ads skills are now less prescriptive and more evidence-driven. All four
/google-ads*skills (manage,audit,copy,landing) have been rewritten to lean on the agent's diagnostic judgment instead of step-by-step decision trees. The skills now require every recommendation to cite specific data from the user's account — entity name, dollar amount, time window — and refuse to fall back on generic "industry typical" claims. - New shared analysis principles. Added
google-ads/shared/analysis-principles.mdcovering the universal evidence requirement, the high-level approach, and the non-negotiable guardrails (STOP on broken conversion tracking, never pause Tier 1 keywords on short windows, statistical significance gate, server-side limits, undo window, bulk-write confirmation). Every Google Ads skill now reads this on entry alongsidepreamble.md. - Audit no longer emits a 0–5 rubric score.
/google-ads-auditnow produces three pulse metrics — Waste ($/mo), Demand captured (%), CPA ($) — each annotated with its top contributor and a pointer to the fix. The metric IS the verdict; no letter grades, no opaque numerical scores. The seven diagnostic areas remain as the surface area you look across to back the pulse metrics; the rigid scoring math is gone. - Trimmed the most prescriptive references.
manage/references/analysis-heuristics.md,manage/references/quality-score-framework.md, andaudit/references/account-health-scoring.mdall drop the prescriptive "if condition X → action Y" threshold tables and keep the genuinely load-bearing material: signal-quality red flags, keyword tier classification (Tier 1 guardrail), statistical-significance gate, brand-leakage / weighted-QS / counting-type / Display+Search domain facts, the impression-share interpretive matrix, the wasted-spend formula with de-duplication, brand vs. non-brand framing, the pulse-metrics output spec, and industry CPA calibration anchors.
Added — tool-surface guidance for newer MCP capabilities
- Experiments framework —
/google-ads-copynow points A/B work atcreateAdVariationExperiment(and the broadercreateExperiment/addExperimentArms/scheduleExperiment/graduateExperiment/promoteExperimentflow) instead of the old "deploy two paused ads side by side" pattern. - Change observability and interventions —
/google-adssurfaceslistChangeInterventions,getChangeIntervention,evaluateChangeIntervention,getChanges, andreviewChangeImpactas first-class tools alongsideundoChange. - Shared negative keyword lists, portfolio bidding strategies, asset management (callout / sitelink / structured snippet / image — create + link + unlink), all campaign-creation types (PMax / Shopping / Video / Demand Gen / Display / App), PMax asset-group controls, offline conversion uploads (
uploadClickConversions), tracking templates, server-side guardrails (getGuardrails/setGuardrails), andsummarizeAccountSetupare now categorically named inmanage/SKILL.md's tool-surface section so the agent knows the capabilities exist without enumerating every individual tool.
[0.17.0]
Added
- New skills:
/meta-adsand/meta-ads-audit— Meta Ads (Facebook + Instagram) operate / diagnose / audit skills./meta-adsis the analytical brain layered on top of the NotFair-MetaAds MCP server: it covers performance and ROAS analysis, creative fatigue diagnosis, Learning Phase / Learning Limited triage, audience overlap and lookalike strategy, CBO/ABO/Advantage+ Shopping campaign structure, and the dedicated mutations the Meta MCP exposes (pauseCampaign/pauseAdSet/pauseAd,enable*,updateCampaignBudget,updateAdSetBudget,renameCampaign)./meta-ads-auditis the read-only health check — 7 dimensions scored 0–5 (Pixel + CAPI Health, Attribution & Measurement, Campaign Structure, Creative Health, Audience Strategy, Spend Efficiency, Scaling Readiness) — and persistsmeta/business-context.json+meta/personas/{accountId}.jsonfor downstream skills. Skills follow the existinggoogle-ads/template (manage/,audit/,shared/) and reuse the same.notfair.jsonconfig file via a newmetaAccountIdfield. Intentionally scoped:/meta-ads-copyand/meta-ads-landingare not shipped in this release — Meta's creative-led, no-Quality-Score reality means those skills warrant Meta-native designs rather than literal mirrors of the Google Ads versions. - MCP server:
NotFair-MetaAds— added to.mcp.json(https://notfair.co/api/mcp/meta_ads). Same OAuth 2.1 / native HTTP transport asNotFair-GoogleAds. Existing OAuth tokens for NotFair apply; restart Claude Code after upgrading to pick up the new server. meta-ads/shared/— preamble (MCP detection + onboarding formetaAccountId),policy-registry.json(Meta-specific assumptions: CBO/ABO, Learning Phase 50-in-7, attribution defaults, frequency thresholds, ASC, AEM/CAPI), andmeta-math.md(CPM, link CTR, hook rate, frequency, Break-Even ROAS, MER, budget-forecasting respecting the 20% rule that resets Meta Learning Phase).- OpenClaw adaptive layer (working MVP). Added a new
openclaw/repo surface that wraps the existing Toprank SEO skills for OpenClaw without duplicating them. The MVP includes multi-site portfolio docs, per-site work-folder conventions, wrapper skills (toprank-site-onboard,toprank-portfolio-review,toprank-weekly-review,toprank-improve-page,toprank-investigate-drop), JSON artifact schemas, helper scripts to bootstrap a portfolio and per-site workspace, onboarding persistence, weekly-review run persistence, portfolio review ranking, page-improvement persistence, drop-investigation persistence, follow-up discovery, a simple scheduler runner that processes duefeedback_checkitems and surfaces manual-attention work, automatic baseline snapshot inheritance for feedback queue items, a first-pass feedback scorer that classifies follow-ups aswin,neutral,loss, orinconclusivefrom before/after metric snapshots, learned-prior updates inlearned-patterns.json, and a helper to hydrate observed metrics from real Google Search Console data.
[0.16.0] — 2026-04-30
Changed (breaking)
- Google Ads slash commands renamed.
/ads→/google-ads,/ads-audit→/google-ads-audit,/ads-copy→/google-ads-copy,/ads-landing→/google-ads-landing. Disambiguates the namespace ahead of future Meta Ads / LinkedIn Ads skills. Update saved prompts, Coworker tasks, and any scripts that invoke the old names. - Skill folder layout reorganized. Inside
google-ads/, sub-folders are now platform-agnostic short names (manage/,audit/,copy/,landing/) — the platform context lives in the parent dir, not duplicated in every child. Skillname:frontmatter carries the fully-qualified slash command (e.g.name: google-ads-audit). New ad platforms will follow the same template (meta-ads/{manage,audit,copy,...}). - MCP server renamed to NotFair-GoogleAds.
server.jsontitleis nowNotFair-GoogleAdsand the streamable-HTTP endpoint moved fromhttps://notfair.co/api/mcptohttps://notfair.co/api/mcp/google_ads, namespacing the route ahead of future per-platform MCP endpoints. The plugin's.mcp.jsonis updated automatically on upgrade; existing OAuth tokens still apply.
[0.15.2] — 2026-04-29
Changed
- Branding cleanup across the public plugin surface. Updated Toprank's README, marketplace metadata, plugin metadata, eval prompts, and Google Ads skill copy to present the product as NotFair /
notfair.coinstead of the old AdsAgent branding where the references were still user-facing. Kept intentional legacy migration notes and technical compatibility references (.adsagent,mcp__adsagent__*,adsagent://playbooks/...) intact where they still describe real compatibility behavior.
[0.15.1] — 2026-04-28
Changed
google-ads/shared/preamble.md— Step 4 zero-account guidance. Updated the onboarding instructions for users whose Google identity has no accessible Google Ads customer (listConnectedAccountsreturns an empty list /noAccount: true). The previous copy directed them to a static "connect at notfair.co" link; the new flow is a self-contained recovery loop driven from inside Claude — Claude tells the user to create a Google Ads account at https://ads.google.com (Smart Mode is the fastest path; payment method optional), then calls the newrefreshAccountsMCP tool to detect the account without re-authentication. Includes propagation guidance for the 1-2 minute delay between Google account creation and the customer record becoming queryable. Pairs with the NotFair server-side change that ships an MCP bearer token even for no-account sessions, so the Claude Desktop OAuth handshake completes instead of dead-ending in a hung browser tab.
[0.15.0] — 2026-04-28
Changed
- MCP server moved from AdsAgent to NotFair — endpoint migrated from
https://adsagent.org/api/mcptohttps://notfair.co/api/mcp. The plugin's.mcp.jsonis updated automatically when you upgrade; restart Claude Code to pick up the new server. - Auth scheme switched from API key to native OAuth 2.1 —
ADSAGENT_API_KEYis no longer required, and themcp-remote(npx) bridge has been removed..mcp.jsonnow uses Claude Code's native HTTP transport ("type": "http"); on first connection Claude Code opens a browser tab for OAuth sign-in to NotFair and stores the token in your OS keychain. You can removeADSAGENT_API_KEYfrom~/.claude/settings.jsononce the new server is connected. - Local namespace renamed
.adsagent→.notfair— affects the global config dir (~/.adsagent/→~/.notfair/), the project config file (.adsagent.json→.notfair.json), and the project data dir (.adsagent/→.notfair/). The shared preamble runs a one-time atomicmvmigration on first invocation; if both old and new paths exist (partial state from a manual move), it stops and asks you to reconcile rather than risk losing writes. Update your.gitignoreif you were ignoring.adsagent.json/.adsagent/. - Tool prefix renamed
mcp__adsagent__*→mcp__notfair__*— driven by the.mcp.jsonserver-name change. The shared preamble's MCP detection prefers the new prefix but still detects the legacy one (and the legacymcp__claude_ai_AdsAgent__*connector) so skills keep working through the rename window. If you're on a session that hasn't restarted yet, the preamble nudges you to restart Claude Code once. - MCP registry identifier renamed
io.github.nowork-studio/adsagent→io.github.nowork-studio/notfair— for users who consume the standalone MCP server directly (Claude Desktop, Cursor, Inspector, custom agents). Bumped the published server version to 0.3.0 to reflect the rename.
Migration notes
- The shared preamble handles
.adsagent→.notfairfilesystem migration automatically — no manual steps for global users. - Users who ran "save this account for this project only" will have their project-level config (
.adsagent.jsonand the.adsagent/data dir) renamed in place on next skill invocation. - OAuth tokens are stored in the OS keychain (Keychain on macOS, Credential Manager on Windows, Secret Service on Linux). On first connection to the new endpoint you'll see a browser tab for sign-in; tokens refresh automatically afterwards.
[0.14.0] — 2026-04-27
Added
- New Skill:
geo-optimizer— Generative Engine Optimization for AI search engines (ChatGPT, Claude, Perplexity, Gemini, Google AI Overviews). Three modes: audit (score content on the GEO Signal Stack with a 0–100 GEO Score across Evidence Density / Structure & Position / Authority Signals / AI Crawlability), optimize (rewrite content applying real-evidence patterns derived from the Princeton GEO paper, KDD 2024, and CMU AutoGEO, ICLR 2026), and strategy (30/60/90-day per-engine playbook). Distinct from the existingcontent-writerskill — content-writer optimizes for Google's blue-link rankings, geo-optimizer optimizes for AI citation. Includes a comprehensivereferences/geo-techniques.mdcovering PAWC front-loading, evidence density targets, per-engine playbooks (each engine has a different citation profile — ChatGPT cites Wikipedia ~48%, Perplexity weights freshness, Gemini leans Reddit, Claude weights primary sources), AI crawler robots.txt configuration, and measurement patterns aligned withgegoandllmoptopen-source trackers. Hard rule: no fabricated stats, quotes, or citations — ships an Evidence Hunt workflow that requires real, verifiable sources before any rewrite.
[0.13.2] — 2026-04-26
Added
- New SEO Skill:
broken-link-checker— Scans websites to find broken internal and external links (404s, 5xx errors). Provides a detailed report with source pages and status codes. CONTRIBUTING.md— A guide for community contributors on how to add new skills, fix bugs, and follow the project's quality standards.
[0.13.1] — 2026-04-25
Fixed
- Windows portability — replaced POSIX-only
os.getuid()with a portable_uid.portable_uid()helper across the seo-analysis scripts (pagespeed.py,analyze_gsc.py,list_gsc_sites.py,url_inspection.py,show_gsc.py,show_pagespeed.py, all fourfetch_*_content.pyCMS connectors) and theSKILL.mdCMS heredoc. Native CPython on Windows has noos.getuid(), which crashed the entire SEO analysis flow withAttributeError. Reported in #44 — thanks @seo4pymesjesus-ux. The new helper returns the same numeric uid on POSIX (preserving existing tmp filenames) and falls back to a sanitized username on Windows.
Security
- Hardened tmp-file writes against symlink attacks.
pagespeed.py,analyze_gsc.py,list_gsc_sites.py, andurl_inspection.pypreviously wrote results to predictable paths in the system tempdir using directopen(path, "w")— exploitable on shared/tmpby pre-creating the destination as a symlink. They now use_uid.secure_write_json(), which writes viatempfile.mkstemp()+chmod 0600+ atomicos.replace()(the same pattern the CMS fetchers already used). Files are also now created with mode 0600 instead of the umask default, preventing other users on shared hosts from reading cached GSC analytics or CMS content. - Sanitize Windows username before interpolating into a tmp path, defending against env-var-driven path traversal in privilege-separation contexts.
Internal
- Repaired the unit test suite.
test/unit/test_analyze_gsc.py,test_cms_scripts.py,test_strapi_scripts.py, andtest_url_inspection.pyreferenced askills/seo-analysis/scripts/path that no longer exists (the directory was renamed toseo/seo-analysis/scripts/). The tests had been failing to even collect. Paths corrected and the loaders now insert the scripts directory intosys.pathsofrom _uid import …resolves underimportlib.util.spec_from_file_location. 255 unit tests pass.
[0.13.0] — 2026-04-24
Changed
- Realigned google-ads skills with the new MCP server surface. The AdsAgent MCP server consolidated read-only tools behind
runScript(a JS sandbox exposingads.gaql()andads.gaqlParallel()), retired the per-surface helpers (listCampaigns,getKeywords,getSearchTermReport,getCampaignPerformance,getImpressionShare,runGaqlQuery,getAccountInfo,getCampaignSettings,listAds,listAdGroups, etc.), and removed the bespokeaudit()tool. Skills referenced those tools by name in workflow tables, reference docs, and SKILL bodies — guidance that no longer applied. - Relaxed the prescriptive style. Skills now provide frameworks, scoring rubrics, benchmarks, business-context schemas, and operational discipline — not step-by-step "call X then Y" choreography. Tool routing is delegated to the server's own MCP instructions, which already tell the agent to fan out reads through
runScript+gaqlParalleland route mutations through dedicated write tools. The agent does the heavy lifting; the skill supplies the judgment. ads/SKILL.md— dropped the "Available Tools" enumeration and the prescriptive "Performance Summary / Waste Audit / …" workflow playbooks. Kept operating principles, the reference-routing table, the account-baseline contract, change-tracking discipline, and conditional handoffs.ads-audit/SKILL.md— replaced the now-removedaudit(accountId, days=30)payload contract with a description of the GAQL surfaces a complete audit needs (customer, campaign, ad_group, keyword_view, search_term_view, conversion_action, ad_group_ad, campaign_criterion for geo, change_event). The agent assembles the dataset via onerunScript+gaqlParallelcall, optionally seeded by the server'sadsagent://playbooks/audit-accountMCP resource. Kept the 7-dimension scoring rubric, business-context and persona schemas + filesystem contract, encoded heuristics, and the impression-share interpretation matrix.ads-copy/SKILL.mdandads-landing/SKILL.md— replaced helper-tool sequences ("calllistAds, thengetKeywords, then …") with GAQL surface descriptions the agent can fan out in onerunScriptcall.shared/preamble.md— Step 5 now describes the read/write split (runScript for reads, dedicated tools for mutations) and points at the server's playbook resources, instead of pushingrunGaqlQueryagainst a 50-row limit.ads/references/session-checks.md,ads-audit/references/persona-discovery.md,ads-audit/references/business-context.md,ads-audit/references/account-health-scoring.md— scrubbed dead tool names; persona discovery and the audit website-resolution step now reference GAQL surfaces directly.
Removed
ads/references/workflow-playbooks.md— the server now shipsadsagent://playbooks/audit-accountandadsagent://playbooks/explain-regressionas MCP resources covering the same ground; maintaining a parallel skill-side copy guarantees drift.shared/gaql-cookbook.md— built aroundrunGaqlQuery's 50-row limit, which no longer applies. The server's own MCP instructions already teach thegaqlParallelfan-out pattern with worked examples.
[0.12.1] — 2026-04-22
Changed
- Added explicit AdsAgent attribution in README and plugin metadata (no functional changes; plugin name and skill IDs unchanged).
[0.12.0] — 2026-04-19
Changed
- ads-audit SKILL.md slimmed from ~600 to ~140 lines — Stripped phase-by-phase narrative, report markdown templates, output-discipline rules, per-dimension prose, and the conditional-handoff table. Modern models handle structure and formatting on their own; the skill no longer needs to spell that out.
- Kept the durable encoded judgment — Audit response shape, field→dimension scoring map, 0–5 score rubric, Impression Share Interpretation Matrix, the agency-earned heuristics (weighted QS by spend, brand leakage 5–10× CPA premium, waste formula, Display+Search mixing, STOP condition on conversion tracking), policy freshness check, and the filesystem contract (
business-context.json+personas/{accountId}.jsonschemas). - Tightened guardrails — Explicit "read-only skill, mutations go through
/ads" rule at top and bottom; STOP condition for broken conversion tracking; mandate to always persist business-context and personas even on short reports.
[0.11.4] — 2026-04-15
Fixed
- Google Ads MCP detection on Claude Desktop plugin — When connected through the claude.ai plugin connector, the AdsAgent MCP server is exposed as
mcp__claude_ai_AdsAgent__*instead ofmcp__adsagent__*. The shared preamble only recognized the Claude Code CLI prefix, so ads-audit and other google-ads skills incorrectly reported "MCP not connected" and refused to run. Detection now scans the available tool list for any*listConnectedAccountstool, extracts the prefix, and uses that prefix for all subsequent tool calls. Supports Claude Code CLI, Claude Desktop, and any future host using an AdsAgent variant.
Changed
- Consistent tool references across google-ads skills —
ads-copy/SKILL.mdhad hardcodedmcp__adsagent__prefixes on tool references (createAd,updateAdAssets,enableAd,undoChange,listAds,pauseAd,listCampaigns,listAdGroups). Stripped to bare tool names to matchads,ads-audit, andads-landing, which already used bare names. Skills now uniformly defer to the preamble for prefix resolution.
[0.11.3] — 2026-04-12
Added
- Change impact review mode — Users can now say "check my changes" or "did my changes work" to review the impact of recent Google Ads changes. The ads skill routes these requests through session-checks with proper before/after metric comparison
- Maturation guidance — When changes haven't had enough time to accumulate data (7 days for bid/keyword changes, 14 days for structural changes), the skill explains why and tells the user when to check back instead of showing misleading early metrics
Changed
- Deduped headline/description formulas — Removed 50-line inline formula table from ads-copy SKILL.md; now references
rsa-best-practices.mdas single source of truth - Deduped business context intake — Removed 75-line duplicate intake procedure from ads-copy SKILL.md; now references
ads-audit/references/business-context.mdas canonical source - Fixed session-checks query logic — Changed from filtering only matured entries to finding all unreviewed entries, then branching on maturation status. Previously the "still maturing" message could never fire
- Removed overly generic triggers — Dropped "did it improve" and "what happened after" which could false-positive on non-ads queries
[0.11.2] — 2026-04-11
Changed
- Ads skill SKILL.md slimmed down — Extracted analysis heuristics, change tracking, session checks, and workflow playbooks into dedicated reference files under
google-ads/ads/references/. Main SKILL.md went from ~770 lines to ~160 lines, loading references on demand instead of carrying everything inline - New reference routing table — SKILL.md now has a quick-lookup table mapping situations (performance analysis, QS diagnostics, bid strategy, etc.) to the right reference file
- Added new MCP tools — Listed
getKeywordIdeas,getPmaxAssetGroups,getPmaxAssets,searchGeoTargets,updateCampaignBidding,updateCampaignGoals,removeAd,pausePmaxAssetGroup,enablePmaxAssetGroupin the tool catalog - Two interaction modes — SKILL.md now distinguishes direct actions (fast path, no session checks) from analysis requests (full checks and reporting)
- Dev symlink detection —
bin/toprank-update-checkand the upgrade skill now detect dev symlinks and skip update checks, preventing upgrade attempts on developer-managed installs
[0.11.1] — 2026-04-11
Changed
- Ads audit restructured around 5 analysis layers and 3 actionable passes — Replaced the 7-dimension scoring model (0-5 per dimension, 0-100 composite) with a layered analysis approach: Signals → Relevance → Efficiency → Scale → Growth. Findings now map to 3 action-oriented passes: Stop Wasting, Capture More, Fix Fundamentals. Tracks 3 objective pulse metrics (waste rate, demand captured, CPA) with trend comparison on re-audits
- Added PMax campaign support — Asset group completeness checks, PMax cannibalization detection for brand Search traffic, and PMax-specific bid strategy guidance
- Added audience signals check — Flags Search campaigns missing audience segments and PMax asset groups without audience signals, both of which limit Smart Bidding performance
- Smarter waste calculation — Keyword waste threshold changed from "clicks > 10" to "spend > 2x account average CPA", which respects Smart Bidding's learning curve. Added de-duplication rules to prevent double-counting between keyword and search term waste
- On-demand reference loading — Quality score, search term analysis, industry benchmarks, and campaign structure references now load only when relevant issues are detected, saving ~1,000 lines of context per audit
- Extracted reference docs — Persona discovery template and business context crawl procedure moved to dedicated reference files for reuse across skills
[0.11.0] — 2026-04-09
Added
- Gemini cross-model review skill — New
/toprank:geminiskill that launches Google's Gemini CLI as an independent reviewer. Three modes: review (pass/fail gate), challenge (adversarial stress test), and consult (open Q&A). Unlike code-only review tools, handles Google Ads changes (campaign structure, bid strategies, keywords) and SEO metadata changes (title tags, meta descriptions, schema markup) alongside code diffs. Produces cross-model analysis when Claude has already reviewed the same changes, highlighting overlapping findings, unique catches, and disagreements.
[0.10.0.1] — 2026-04-08
Changed
- Consolidated root files — Merged
CONNECTORS.mdandCONTRIBUTING.mdintoREADME.mdto reduce file count without losing content. Connectors section now lives under "## Connectors" and contributing guide under "## Contributing" in the main README. - Updated install test — Test suite now checks for connector content in
README.mdinstead of the removedCONNECTORS.mdfile. - Added
seo-pageto directory tree in README to reflect the new single-page analysis skill.
Removed
CONNECTORS.md— Content moved to README.md.CONTRIBUTING.md— Content moved to README.md.requirements-test.lock— Stale lock file that didn't matchrequirements-test.txt.
[0.10.0] — 2026-04-08
Added
- PageSpeed Insights API integration — New
pagespeed.pyscript calls the Google PageSpeed Insights API for multiple URLs with concurrent execution. Collects Lighthouse performance scores, Core Web Vitals (LCP, INP, CLS, FCP, TTFB), CrUX field data, optimization opportunities, and diagnostics. Supports both mobile and desktop strategies. - PageSpeed display script — New
show_pagespeed.pyrenders PageSpeed results in a terminal-friendly format with scores, metrics, opportunities, and diagnostics. - Phase 5.5 in SEO analysis — PageSpeed analysis runs in parallel alongside URL Inspection and CMS detection during audits. Results feed into the report with a dedicated "PageSpeed & Core Web Vitals" section and are logged in the audit history for tracking performance over time.
- Preflight PageSpeed checks —
preflight.pynow auto-enables the PageSpeed Insights API and checks for aPAGESPEED_API_KEYin the environment or~/.toprank/.env.
[0.9.9] — 2026-04-08
Changed
- API key check moved to shared preamble — Moved the
ADSAGENT_API_KEYverification from the/adsskill into the shared preamble so all google-ads skills (/ads,/ads-audit,/ads-copy) verify the key automatically. The key is saved to~/.claude/settings.jsonunderenv(not config files) since the MCP server reads it from the environment. - Preamble rewrite — Clean step numbering (0–5), fixed MCP detection to always run (was skipped for returning users with saved accountId), eliminated duplicate
listConnectedAccountscalls, explicit deep-merge instructions for settings.json to avoid clobbering existing env vars. - Removed
apiKeyfrom config schema — Config files (.adsagent.json,config.json) now only storeaccountId. API key storage is exclusively in~/.claude/settings.json.
[0.9.8.0] — 2026-04-08
Added
- API key verification gate — The
/adsskill now checks forADSAGENT_API_KEYin~/.claude/settings.jsonbefore executing any other step. If the key is missing, it prompts the user to obtain one from adsagent.org, collects the key interactively, and saves it automatically.
[0.9.7] — 2026-04-08
Changed
- Plugin-aware auto-upgrade — Rewrote the upgrade system from the old
~/.claude/skills/paths to the new~/.claude/plugins/cache/plugin model. The upgrade flow now updates the marketplace repo, copies to a versioned cache directory, and updatesinstalled_plugins.jsondirectly. - Preamble script discovery — Both
bin/preamble.mdandgoogle-ads/shared/preamble.mdnow findtoprank-update-checkvia glob in the plugin cache instead of hardcoded skill paths.
Removed
- Legacy skill paths — Dropped all references to
~/.claude/skills/toprank/,~/.claude/skills/stockholm/, and the./setupscript that no longer exists in the plugin model.
[0.9.6] — 2026-04-08
Added
- Business relevance gate for keyword evaluation — The
/adsskill now classifies keywords into Tier 1 (Core), Tier 2 (Adjacent), and Tier 3 (Irrelevant) before applying performance heuristics. Core keywords that directly describe the business are never paused — they get a diagnostic workflow instead. - Statistical significance gate — Conversion-based decisions now require expected conversions >= 3 before acting. Prevents false negatives from small sample sizes.
- Core Keyword Diagnostic workflow — 6-step diagnostic for underperforming Tier 1 keywords: statistical significance, sibling comparison, match type analysis, QS subcomponents, position/impression share, and optimization recommendations.
Changed
- Wasted spend calculation excludes Tier 1 (Core) keywords. A core keyword with 0 conversions is an optimization opportunity, not waste.
- Bid optimization and waste audit workflows updated to classify keywords by business relevance before applying performance actions.
[0.9.5] — 2026-04-07
Changed
- MCP server URL updated —
adsagentMCP now points tohttps://adsagent.org/api/mcp(removedwww.prefix to match the canonical domain).
[0.9.4] — 2026-04-07
Changed
seo-analysisreport restructured for clarity — Phase 6 now leads with "Top Priority Actions" (3–5 items, ordered by expected click impact) instead of 12+ equal-weight sections. Each action requires a specific URL, specific metric as evidence, and a copy-paste-ready fix with estimated click impact. Supporting data (indexing issues, cannibalization, gaps, schema, technical) is condensed into reference tables shown only when findings exist.seo-analysisaudit history tracking — new Step 0.5 reads~/.toprank/audit-log/<domain>.jsonat startup to surface previously flagged issues and their current resolution status. New Phase 6.5 writes a concise log entry after each audit (date, traffic snapshot, top issues with metrics and expected impact). Future audits show which prior issues are resolved, improved, or still open.
Fixed
seo-analysisPhase 3.7 — removed duplicate$DOMAINextraction; now reuses the variable set in Step 0.5 instead of re-deriving it.
[0.9.3] — 2026-04-07
Added
- SEO business context (
seo/shared/business-context.md) — persistent per-domain business profile for SEO skills. Caches business name, summary, industry, primary goal, target audience, locations, brand terms, competitors, and key topics at~/.toprank/business-context/<domain>.json. Fresh for 90 days; auto-refreshes when stale. seo-analysisPhase 3.8 — business context generation after GSC data is collected. First run asks 3 targeted questions and infers the rest from GSC + homepage. Subsequent runs are silent (cache load only).seo-analysisPhase 2 fast-path — brand terms are loaded from business context cache when available, skipping the manual question entirely.- Phase 6 report Business Profile section — report now opens with a business context block (name, goal, audience, competitors) so all recommendations read as contextual rather than generic.
[0.9.2] — 2026-04-06
Changed
- Config resolution — replaced single global config (
~/.adsagent/config.json) with 3-tier chain: project-level (.adsagent.json), Claude project-level (~/.claude/projects/{path}/adsagent.json), and global fallback. Fields merge up the chain so a project file with onlyaccountIdinheritsapiKeyfrom global. - Project-scoped data storage — when a project-level config exists, data files (business-context, personas, change-log, account-baseline) are stored in
.adsagent/relative to the project root instead of globally - Account switching — now asks whether to save the selection for the current project or globally
- Security — preamble instructs LLM to add
.adsagent.jsonand.adsagent/to.gitignorewhen using project-local storage
[0.9.1] — 2026-04-04
Added
- Google Ads Setup section in README — two-path install guide: Option A (free hosted server via adsagent.org) and Option B (self-hosted MCP server for users with their own Google Ads API access)
- Collapsible manual MCP config block for users who skip the setup script
Changed
/adsskill — MCP is now the only tool-calling method. Removed mcporter CLI fallback andmcporter.jsonconfig file. The "Calling tools" section now documents themcp__adsagent__<toolName>pattern directly.setup— MCP server config is built inline instead of reading frommcporter.json. Ads skill detection uses directory prefix instead of file existence check. Fixed Windows path compatibility for ads skill detection.- README hook questions — rewritten to target real pain points: wasted ad spend, traffic drops, and conversion growth without budget increases
Removed
google-ads/ads/mcporter.json— no longer needed; MCP server config is generated directly by the setup script._replace_key()helper in setup — was only used for mcporter placeholder substitution.
[0.8.0] — 2026-03-31
Added
/setup-cmsskill — interactive wizard to connect WordPress, Strapi, Contentful, or Ghost. Detects existing config, collects credentials, tests the connection, and writes to.env.local.- WordPress CMS integration (Phase 3.6) —
preflight_wordpress.py+fetch_wordpress_content.py. REST API with Application Password auth. Extracts SEO fields from Yoast SEO (yoast_head_json) or RankMath (meta.rank_math_title). - Contentful CMS integration (Phase 3.6) —
preflight_contentful.py+fetch_contentful_content.py. Delivery API with Bearer token auth. Resolves linked SEO component entries (include=1), supports pagination up to 1000 entries/page. - Ghost CMS integration (Phase 3.6) —
preflight_ghost.py+fetch_ghost_content.py. Content API with auto-detection between v4+ (/ghost/api/content/) and v3 (/ghost/api/v3/content/). Uses nativemeta_title/meta_descriptionfields. cms_detect.py— lightweight CMS routing script. Checks env vars in priority order (WP_URL → Contentful → Ghost → Strapi), exits 0 with CMS name if found, exits 2 if none configured.- 56 unit tests (
test/unit/test_cms_scripts.py) covering SEO field extraction, entry normalisation, SEO audit aggregation, SSRF protection, and WordPress auth header encoding across all 4 CMSes.
Changed
seo-analysisPhase 3.6 — rewritten from Strapi-specific to CMS-agnostic. Now routes throughcms_detect.pyand runs the appropriate preflight + fetch script viacasestatement. All CMSes produce the same normalized JSON format.- Report template: "Strapi SEO Field Audit" → "CMS SEO Field Audit" (supports WordPress, Strapi, Contentful, Ghost).
Fixed
- Ghost/WordPress/Contentful false negatives — SEO extraction no longer falls back to the content title when no explicit meta title is set. Entries with no SEO plugin / no meta title override are now correctly flagged as
missing_meta_title=True. - Ghost
detect_api_pathsys.exit trap — replacedghost_get()probe (which callssys.exit(1)on errors) with inlineurllibprobe, allowing the v3 API path fallback to actually run. - Ghost
PAGE_SIZE— changed from 15 (display default) to 100 (actual API max).
[0.7.1] — 2026-04-01
Fixed
seo-analysis— GSC display crash — addedshow_gsc.pydisplay utility to replace fragile inline Python scripts. FixesTypeError: string indices must be integers, not 'str'that occurred when iteratingcomparisondict fields (which mixes string metadata and list data at the same level). Also fixes CTR being displayed as 474% instead of 4.74% (was being multiplied by 100 twice).
[0.7.0] — 2026-04-01
Added
seo-analysis— URL-first flow — Step 0 now asks for the target website URL before running any preflight or API calls. The URL is stored and used throughout the entire audit for URL Inspection, technical crawl, and metadata fetching.seo-analysis— URL Inspection API (Phase 3.5) — newurl_inspection.pyscript callsPOST https://searchconsole.googleapis.com/v1/urlInspection/index:inspectfor the top pages. Returns per-page indexing status (INDEXED,NOT_INDEXED,DUPLICATE_WITHOUT_CANONICAL, etc.), mobile usability verdict, rich result status, last crawl time, and referring sitemaps. Results surface immediately as critical flags in the report.seo-analysis— Keyword Gap Analysis (Phase 4.5) — finds keyword orphans (queries ranking 4-20 with no dedicated page), builds topic clusters from GSC data with pillar page recommendations, and identifies business-relevant keywords the site should rank for but has no impressions for.seo-analysis— Deep Metadata Audit — for each audited page, fetches the live<title>and<meta description>, cross-references against top GSC queries for title/query alignment, checks character counts, detects duplicate titles, and audits Open Graph tags. Outputs a structured per-page table.seo-analysis— Deep Schema Markup Audit — detects site type (E-commerce, SaaS, Local Business, etc.), defines expected schema types per site type, audits each page's<script type="application/ld+json">blocks, and flags missing high-impact schema and errors in existing schema. Cross-references with URL Inspection rich result findings.seo-analysis— Skill Handoffs (Phase 7) — after delivering the report, surfaces targeted follow-up actions:/meta-tags-optimizerfor pages with metadata issues,/schema-markup-generatorfor schema gaps,/keyword-researchwith seed terms from the gap analysis.- Branded vs non-branded segmentation (
branded_split) — pass--brand-terms "Acme,AcmeCorp"to split all GSC traffic into branded and non-branded segments. Each segment gets its own clicks, impressions, CTR, average position, query count, and top-20 queries. Non-branded metrics become the true baseline for Quick Wins and content recommendations. Returnsnullif no brand terms provided. - Page group clustering (
page_groups) — automatically buckets top pages by URL path pattern (/blog/, /products/, /locations/, /services/, /pricing/, /docs/, /about/, /faq/, /lp/, /case-studies/) with per-section aggregate stats. Exposes template-level problems: "all /products/ pages have 0.8% CTR" can be fixed once, not 50 times. - Winner/loser scoring for cannibalization — each
cannibalizationentry now includeswinner_page,winner_reason,loser_pages, andrecommended_action("consolidate: 301 redirect..." or "monitor: possible SERP domination"). test/unit/test_url_inspection.py— 25 unit tests coveringnormalize_site_url_for_inspection,parse_inspection_result, andsummarize_findings.- 35 new unit tests covering
classify_branded,derive_branded_split,cluster_page_groups, and all new cannibalization fields. - Strapi CMS integration (Phase 3.6) — the
/seo-analysisskill now cross-references your published Strapi content against GSC data. Three new scripts:preflight_strapi.py— validates config, tests connectivity, detects Strapi v4 vs v5. Exit code 2 = not configured (non-fatal skip).fetch_strapi_content.py— paginates all published entries, extracts SEO fields from the officialstrapi-community/plugin-seocomponent and root-level fallbacks, writes a structured JSON audit.push_strapi_seo.py— batch write-back with before/after diff preview, stale-write guard, and locale support for v5 localized content.
- 59 new unit tests for the Strapi scripts — version detection, entry normalisation, SEO audit counting, payload building, stale-write guard logic, and SSRF IP classification.
Changed
seo-analysis—analyze_gsc.pyparallelized — all 9 GSC API calls now run concurrently viaThreadPoolExecutor, cutting wall-clock data collection time by ~70%. Each worker has an exception guard so a single failed call logs an error and continues rather than crashing the script.url_inspection.py— parallel URL inspection — inspections run with--concurrency 3(default).--max-urlsdefault reduced from 20 to 5 to stay well within the 2000/day API quota. Worker failures are caught and logged without aborting the run.seo-analysis— technical crawl capped at 5 pages — Phase 5 now has a hard cap of 5 pages (homepage first, then top by clicks, then flagged pages) to keep the audit fast without losing insight.seo-analysis— broader OAuth scope — re-auth instructions throughout the skill now include bothwebmastersandwebmasters.readonlyscopes, required for the URL Inspection API.seo-analysisPhase 2 now asks for brand terms before pulling data.seo-analysisPhase 4 adds "Branded vs Non-Branded Split" and "Page Group Performance" sections.seo-analysis/evals/evals.json— 3-scenario test suite covering URL-first behavior, no-GSC technical fallback, and comprehensive GSC+inspection audit.- Cannibalization
competing_pagesnow sorted by position ascending (best first) instead of clicks descending. - Strapi integration is opt-in and non-blocking — if
STRAPI_URLis not configured, Phase 3.6 skips silently.
[0.6.1] — 2026-03-31
Added
test/install.test.sh— mock-HOME install test suite for./setup. 61 assertions across 6 scenarios: Claude Code global install (symlinks, targets, preamble injection), auto-detect via path, idempotency, real-directory protection, Codex install (openai.yaml + SKILL.md symlinks), and invalid--hostflag handling. Includes a count-guard that fails fast if a new skill is added to the repo without updating the test's SKILLS array.
Changed
seo-analysis— deeper Google Search Console data in every audit. The script now pulls four additional data sets from a single API session:- Cannibalization (
cannibalization) — queries where multiple pages compete, with per-page click/impression breakdown. Previously the skill inferred this from single-dimension data; now it uses the real[query, page]dimension so every recommendation names specific URLs. - CTR gaps by page (
ctr_gaps_by_page) — high-impression, low-CTR pairs at the query+page level. Replaces query-only CTR opportunities so every title/meta rewrite suggestion includes the exact page to fix. - Country split (
country_split) — top 20 countries by clicks with CTR and position. Surfaces geo opportunities and region-specific ranking problems. - Search type breakdown (
search_type_split) — web, image, video, news, Discover, and Google News traffic shown separately. Many sites have Discover or image traffic they don't know about.
- Cannibalization (
device_splitnow includes CTR and position alongside clicks and impressions.- Phase 4 analysis guidance updated to use the new data fields directly.
- New "Segment Analysis" subsection added to Phase 4 for device, country, and search type interpretation.
- Unit tests: 49 → 79 (+30 tests covering all new functions with boundary and edge case coverage).
[0.6.0] — 2026-03-30
Added
keyword-research— new skill for keyword discovery, intent classification, difficulty assessment, opportunity scoring, and topic clustering. Includes reference materials for intent taxonomy, prioritization framework, cluster templates, and example reports.meta-tags-optimizer— new skill for creating and optimizing title tags, meta descriptions, Open Graph, and Twitter Card tags with A/B test variations and CTR analysis. Includes reference materials for tag formulas, CTR benchmarks, and code templates.schema-markup-generator— new skill for generating JSON-LD structured data (FAQ, HowTo, Article, Product, LocalBusiness, etc.) with validation guidance and rich result eligibility checks. Includes reference materials for schema templates, decision tree, and validation guide.geo-content-optimizer— new skill for optimizing content to appear in AI-generated responses (ChatGPT, Perplexity, Google AI Overviews, Claude). Scores GEO readiness and applies citation, authority, and structure optimization techniques. Includes reference materials for AI citation patterns, GEO techniques, and quotable content examples.
Changed
- README.md — updated with documentation for all 4 new skills, expanded install instructions and directory tree
[0.5.1] — 2026-03-27
Security
- Predictable /tmp paths —
analyze_gsc.pyandlist_gsc_sites.pynow usegsc_analysis_{uid}.json/gsc_sites_{uid}.jsonviatempfile.gettempdir()+os.getuid(), preventing cross-user data exposure on multi-user systems .gstack/gitignored — local security audit reports excluded from git history- Test dependency lockfile — added
requirements-test.lock(pip-compiled) to pin test dependencies and prevent supply-chain drift
[0.5.0] — 2026-03-27
Added
preflight.py— pre-flight check that runs before any GSC operations; detects gcloud with OS-specific install instructions (Homebrew / apt / dnf / curl / winget), auto-triggersgcloud authbrowser flow if no ADC credentials foundsetup.py— cross-platform Python equivalent of./setupfor Windows users who can't run bash; falls back to directory junctions (no admin rights required) when symlinks are unavailable- Phase 0 in SKILL.md — preflight step added before GSC access check; also restores the "skip GSC → Phase 5" escape hatch for technical-only audits
Changed
seo-analysis/SKILL.md— Phase 1 simplified (error cases now handled by preflight); Phase 1 bash block is self-contained (no shell variable leak from Phase 0)
[0.4.2] — 2026-03-27
Added
- README demo section — "See It Work" example conversation showing end-to-end
/seo-analysisflow for clearer onboarding
Changed
- Auto-upgrade on every skill use — removed the 4-option prompt (Yes / Always / Not now / Never); updates now apply automatically whenever
UPGRADE_AVAILABLEis detected - Update check frequency — reduced UP_TO_DATE cache TTL from 60 min to 5 min so checks run on nearly every skill invocation
- Zero-dependency GSC auth — removed
google-authPython package requirement; reverts 0.4.1 approach; scripts now callgcloud auth application-default print-access-tokendirectly via subprocess and use stdliburllibfor HTTP, eliminating thepip installsetup step gsc_auth.pyremoved — auth logic inlined inlist_gsc_sites.pyandanalyze_gsc.py; simpler, no shared module- SKILL.md Phase 1 — GSC setup instructions updated to reflect the simpler auth flow
Security
- Predictable /tmp paths — GSC output files now use
gsc_analysis_{uid}.jsonandgsc_sites_{uid}.jsoninstead of shared paths, preventing cross-user data exposure on multi-user systems .gstack/gitignored — security audit reports are now excluded from git commits- Test dependency lockfile — added
requirements-test.lock(pip-compiled) to pin exact versions and prevent supply-chain drift
[0.4.1] — 2026-03-27
Fixed
- GSC quota project header — replaced raw
urllibHTTP calls withgoogle-authlibrary (AuthorizedSession), which automatically sends thex-goog-user-projectheader required for ADC user credentials; this was the root cause of 403 errors during onboarding - Auto-detect quota project — scripts now read
quota_project_idfrom ADC credentials and fall back togcloud config get-value projectif missing, eliminating the manualset-quota-projectstep
Changed
- Shared auth module — extracted
gsc_auth.pywithget_credentials(),get_session(), and_ensure_quota_project()to eliminate duplicated auth logic betweenlist_gsc_sites.pyandanalyze_gsc.py - SKILL.md Phase 1 — streamlined GSC setup instructions from ~50 lines to ~25 lines for faster onboarding and lower token usage
- gsc_setup.md — updated setup guide to reflect 2-step process (
pip install google-auth+gcloud auth application-default login) and documented new troubleshooting entries
Added
google-authdependency — new pip requirement for proper Google API authentication- 4 new unit tests for
_ensure_quota_project()covering: already-set, auto-detect from gcloud, gcloud not found, gcloud returns empty
[0.4.0] — 2026-03-27
Added
content-writerskill — standalone SEO content creation, directly invocable without running a full SEO audit- Handles three jobs: new blog posts, new landing pages, and improving existing pages
- 6-step workflow: determine job → gather context → read guidelines → research & plan → write → quality gate
- Follows Google's E-E-A-T and Helpful Content guidelines via shared reference doc
- Outputs publication-ready content with SEO metadata, JSON-LD structured data, internal linking plan, and publishing checklist
- Smart content type detection from user intent (informational → blog, transactional → landing page)
content-writing.mdreference doc — single source of truth for Google content best practices (E-E-A-T framework, helpful content signals, blog/landing page templates, search intent matching, on-page SEO checklist, anti-patterns including AI content pitfalls)seo-analysisPhase 7 — optional content generation after audit; spawns up to 5 content agents in parallel when content gaps are identified, each reading the sharedcontent-writing.mdguidelines
Changed
- CONTRIBUTING.md — expanded with detailed SKILL.md structure, script requirements, reference file guidelines, and skill ideas table
- README.md — added
content-writerto skills table and updated project description
[0.3.0] — 2026-03-27
Added
- Python test suite — full pytest infrastructure under
test/replacing the prior TypeScript/Bun approach; no build step requiredtest/unit/— 42 fast unit tests (stdlib only, no API calls); covers date math, GSC data processing, report structure, and skill SKILL.md content validationtest/test_skill_e2e.py— E2E skill tests gated behindEVALS=1; uses mockgcloud+ mockanalyze_gsc.pyfixture to run the full skill workflow without real credentialstest/test_skill_llm_eval.py— LLM-as-judge quality evals gated behindEVALS=1; scores report clarity, actionability, and phase coverage on a 1–5 scaletest/test_skill_routing_e2e.py— routing evals verify the skill triggers on SEO prompts and stays silent on unrelated requeststest/helpers/— session runner (spawnsclaude -p --output-format stream-json), LLM judge, eval store, and diff-based test selectiontest/fixtures/— mock gcloud binary, mock analyze_gsc.py, and sample GSC JSON fixture dataconftest.py— root-level pytest config for import path setuprequirements-test.txt— minimal test dependencies
Fixed
- Routing tests — added harness failure guard;
should-not-triggertests no longer silently pass when the subprocess times out or crashes - Env isolation — test subprocess now strips
ANTHROPIC_*vars (in addition toCLAUDE_*) to preventANTHROPIC_BASE_URLorANTHROPIC_MODELfrom redirecting evals to an unintended endpoint - LLM judge retry — exponential backoff (3 attempts: 1s, 2s, 4s) replaces single-retry on rate limit
- Mock gcloud — removed fall-through to real
gcloudbinary that caused infinite recursion when mock was first in PATH .gitignore— restored credential patterns (credentials.json,token.json,.env, etc.) accidentally dropped in initial commit
[0.2.3] — 2026-03-27
Changed
- Simplified CONTRIBUTING.md — removed skill ideas table and verbose guidelines, kept essentials for getting started
[0.2.2] — 2026-03-27
Changed
- Rewrote README intro for clarity and power — headline now communicates that Toprank analyzes, recommends, and fixes SEO issues directly in your repo
[0.2.0] — 2026-03-27
Added
- Autoupdate system — skills now check GitHub for new versions on every invocation
bin/toprank-update-check— fetchesVERSIONfrom GitHub with 60-min cache; outputsUPGRADE_AVAILABLE <old> <new>or nothingbin/toprank-config— read/write~/.toprank/config.yaml; supportsupdate_check,auto_upgradekeystoprank-upgrade/SKILL.md— upgrade skill with inline and standalone flows, snooze (24h/48h/7d backoff), auto-upgrade mode, changelog diff- Preamble in
seo-analysisand auto-inject viasetupfor all future skills bin/preamble.md— single source of truth for the preamble template
VERSIONfile — tracks current release for update checks
Fixed
toprank-update-check: validate local VERSION format before writing cache; exit afterJUST_UPGRADEDto prevent dual stdout output; movemkdir -pto top of scriptsetup: atomic SKILL.md writes via temp file +os.replace(); addpipefailto catch silent Python errorstoprank-upgrade: clear stale.bakbefore vendored upgrade to prevent collision
[0.2.1] — 2026-03-27
Changed
seo-analysisPhase 1 — replaced two-step auth check (token print + separate site list) with singlelist_gsc_sites.pycall that tests auth, scopes, and GSC access in one shot; added distinct handling for each failure mode (wrong account, wrong scopes, API not enabled, gcloud not installed)seo-analysisscript paths — replaced hardcoded~/.claude/skills/seo-analysis/scripts/with afind-basedSKILL_SCRIPTSlookup that works for Claude Code, Codex, and custom install paths; added guard for empty result so missing installs fail with a clear error instead of a confusing path errorseo-analysisproperty selection — added explicit rule to prefer domain property (sc-domain:example.com) over URL-prefix when both exist for the same sitegsc_setup.md— moved "Which Google Account" guidance to top (most common failure cause); replaced brokenoauth_setup.pyOption B with Linux (Debian/Ubuntu, RPM) and Windows install instructions; fixed deprecatedapt-keywithgpg --dearmorfor Debian 12+/Ubuntu 24.04+; expanded troubleshooting to coverinsufficient_scope403s
Fixed
list_gsc_sites.py— unhandledFileNotFoundErrorwhen gcloud is not installed now shows a clean error message; addedURLErrorhandling for network failures (DNS, TLS, proxy)analyze_gsc.py— sameFileNotFoundErrorandURLErrorfixesgsc_setup.md— removed reference tooauth_setup.pywhich did not existseo-analysisSKILL.md — corrected error-branch description from "Python traceback" to "ERROR: gcloud not found" to match the actual script output
[0.1.1] — 2026-03-27
Changed
- README intro — rewritten to lead with user outcome ("Finally know what to do about your SEO") and emphasize zero-risk install; blockquote examples now show real questions users would type
[0.1.0] — 2026-03-26
Added
seo-analysisskill — comprehensive SEO audit powered by Google Search Console- Phase 1: GSC API setup detection and guided auth via
gcloudApplication Default Credentials - Phase 2: Auto-detect site URL from website repo (
package.json,next.config.js,astro.config.*, etc.) or prompt for URL - Phase 3: Data collection — top queries, top pages, position buckets (1–3, 4–10, 11–20, 21+), CTR opportunities, 28-day period comparison, device split
- Phase 4a: Search Console analysis — quick wins, content gaps, traffic drops
- Phase 4b: Technical SEO audit — indexability, meta tags, heading structure, structured data, performance signals
- Phase 5: Structured report with executive summary, traffic snapshot, and 30-day action plan
- Phase 1: GSC API setup detection and guided auth via
scripts/list_gsc_sites.py— list all GSC properties for the authenticated accountscripts/analyze_gsc.py— pull and process GSC data, output structured JSONreferences/gsc_setup.md— complete setup guide for gcloud ADC and OAuth fallback