{"id":"652d0724-7b79-409a-8615-4138ceff8fd5","entityType":"agent","slug":"clawhub-psyb0t-rankrat","name":"rankrat","canonicalUrl":"https://www.xpersona.co/agent/clawhub-psyb0t-rankrat","canonicalPath":"/agent/clawhub-psyb0t-rankrat","generatedAt":"2026-10-10T21:51:04.346Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-10T16:26:43.961Z","emptyReason":null},"description":"Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control. Skill: rankrat Owner: psyb0t Summary: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server.","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.3K downloads reported by the source. Last updated 10/10/2026.","installCommand":"clawhub skill install s17fq93tmpky791n7516jcn08n83sfn2:rankrat","sourceUrl":"https://clawhub.ai/psyb0t/rankrat","homepage":"https://clawhub.ai/psyb0t/skills/rankrat","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/psyb0t/rankrat","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/psyb0t/skills/rankrat","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":63,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intellig"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:26:43.961Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:26:43.961Z","emptyReason":null},"stars":null,"forks":null,"downloads":1339,"packageName":null,"latestVersion":"0.20.1","tractionLabel":"1.3K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-10T16:26:43.961Z","emptyReason":null},"lastUpdatedAt":"2026-10-10T16:26:43.961Z","lastCrawledAt":"2026-10-10T16:26:43.961Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-11T16:26:43.961Z","lastVerifiedAt":null,"highlights":[{"version":"0.20.1","createdAt":"2026-10-10T14:53:48.619Z","changelog":"- Removed the skill-card.md file. - No other user-facing changes.","fileCount":4,"zipByteSize":18307},{"version":"0.20.0","createdAt":"2026-08-17T07:06:38.759Z","changelog":"- Removed the file skill-card.md. - No other functional or documentation changes.","fileCount":4,"zipByteSize":18655},{"version":"0.19.1","createdAt":"2026-08-17T06:10:34.666Z","changelog":"- Removed skill-card.md. - Updated SKILL.md; content changes appear to be negligible or only formatting.","fileCount":4,"zipByteSize":18851},{"version":"0.19.0","createdAt":"2026-08-17T02:50:38.154Z","changelog":"- Removed the skill-card.md file for a leaner codebase. - No changes to user-facing features or functionality.","fileCount":4,"zipByteSize":18284},{"version":"0.18.0","createdAt":"2026-08-17T01:49:46.724Z","changelog":"- Removed the skill-card.md file. - No changes to user-facing functionality. - Documentation and core description remain unchanged.","fileCount":4,"zipByteSize":18359},{"version":"0.17.1","createdAt":"2026-08-17T00:56:33.023Z","changelog":"- Removed the file skill-card.md. - No functional or user-facing changes; documentation file cleanup only.","fileCount":4,"zipByteSize":18224},{"version":"0.16.0","createdAt":"2026-08-16T15:05:35.361Z","changelog":"- Removed the redundant skill-card.md file. - Small fix or update to usage documentation in SKILL.md, clarifying write-tool discovery and default modes. - Minor edits to references/setup.md.","fileCount":4,"zipByteSize":18370},{"version":"0.15.0","createdAt":"2026-08-16T05:42:54.756Z","changelog":"- Removed the skill-card.md file. - No functional or UX changes in this release.","fileCount":4,"zipByteSize":18249}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17fq93tmpky791n7516jcn08n83sfn2:rankrat","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T21:51:04.342Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-psyb0t-rankrat/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-10T16:26:43.961Z","emptyReason":null},"readme":"Skill: rankrat\n\nOwner: psyb0t\n\nSummary: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control.\n\nTags: latest:0.20.1\n\nVersion history:\n\nv0.20.1 | 2026-10-10T14:53:48.619Z | auto\n\n- Removed the skill-card.md file.\n- No other user-facing changes.\n\nv0.20.0 | 2026-08-17T07:06:38.759Z | auto\n\n- Removed the file skill-card.md.\n- No other functional or documentation changes.\n\nv0.19.1 | 2026-08-17T06:10:34.666Z | auto\n\n- Removed skill-card.md.\n- Updated SKILL.md; content changes appear to be negligible or only formatting.\n\nv0.19.0 | 2026-08-17T02:50:38.154Z | auto\n\n- Removed the skill-card.md file for a leaner codebase.\n- No changes to user-facing features or functionality.\n\nv0.18.0 | 2026-08-17T01:49:46.724Z | auto\n\n- Removed the skill-card.md file.\n- No changes to user-facing functionality.\n- Documentation and core description remain unchanged.\n\nv0.17.1 | 2026-08-17T00:56:33.023Z | auto\n\n- Removed the file skill-card.md.\n- No functional or user-facing changes; documentation file cleanup only.\n\nv0.16.0 | 2026-08-16T15:05:35.361Z | auto\n\n- Removed the redundant skill-card.md file.\n- Small fix or update to usage documentation in SKILL.md, clarifying write-tool discovery and default modes.\n- Minor edits to references/setup.md.\n\nv0.15.0 | 2026-08-16T05:42:54.756Z | auto\n\n- Removed the skill-card.md file.\n- No functional or UX changes in this release.\n\nv0.14.2 | 2026-08-16T01:54:29.526Z | auto\n\n- Removed the file: skill-card.md.\n- No functional changes introduced; this update only deletes documentation.\n\nv0.14.1 | 2026-08-15T18:48:58.183Z | auto\n\n- Removed the skill-card.md file.\n- No other functional or documentation changes in this release.\n\nv0.14.0 | 2026-08-14T22:59:39.505Z | auto\n\n- Updated documentation in references/setup.md for clarity or accuracy.\n- Removed obsolete or redundant skill-card.md file.\n- No changes to core functionality; this release is documentation-focused.\n\nv0.13.1 | 2026-08-13T21:48:07.963Z | auto\n\n- Adds Google Tag Manager and Microsoft Clarity support, including GTM resource management and Clarity insights.\n- Introduces typed tag management and safe edge redirects via Cloudflare.\n- Removes bundled bash launcher in favor of a public rankrat launcher.\n- Drops backlink aggregators beyond Bing, simplifying backlink intelligence.\n- Updates documentation to reflect new and removed providers, new features, and a streamlined launch process.\n\nv0.10.0 | 2026-08-10T18:18:37.987Z | auto\n\n- Default mode is now writable; set `RANKRAT_READ_ONLY=true` to fully remove write tools and routes.\n- Provider resource arrays in config now represent discovered inventory, not act as a secondary permission layer.\n- Updated security documentation for simpler, just-one-switch access control.\n- Launcher script and Docker Compose improvements: easier use of persistent profiles, clarified project directory and file ownership.\n- Removed the skill-card.md file.\n\nv0.9.1 | 2026-08-10T01:46:49.537Z | auto\n\n- Added support for `google_account_discovery`: allows read-only targeting of all OAuth-visible Search Console sites and GA4 properties on a configured Google account, extending resource discovery (writes remain restricted).\n- Documentation now links to a public operator manual for comprehensive, topic-organized guidance.\n- SKILL.md security section improved for clarity about Google account/resource scope and the effect of discovery and onboarding flags.\n- Obsolete or redundant file `skill-card.md` removed.\n\nv0.9.0 | 2026-08-08T17:19:07.678Z | auto\n\nrankrat 0.9.0\n\n- Added support for more analytics and backlink providers: Cloudflare analytics, CrUX, Ahrefs, Majestic, Moz, Semrush, and DataForSEO.\n- Introduced persistent site-audit monitors and issue history using a local SQLite database.\n- Expanded reporting and audit tools: supports internal-link analysis, content opportunities, and Cloudflare cache operations.\n- Updated documentation for new provider integrations and persistent state.\n- Removed deprecated skill-card.md documentation file.\n\nv0.8.0 | 2026-08-07T19:30:11.683Z | auto\n\nrankrat 0.8.0 introduces DNS-based ownership automation, whole-site audits, and backlink aggregation.\n\n- Adds support for automating Google/Bing DNS ownership via a configured DNS provider adapter (Cloudflare supported)\n- Introduces bounded whole-site audits with remediation reporting for metadata, canonical, robots, sitemap, links, and structured data issues\n- Aggregates and reports Bing backlink evidence, now including referring-domain and anchor-text metrics\n- Updates permissions and documentation to reflect new network targets (e.g., DNS provider endpoints, public DNS)\n- Removes skill-card.md to streamline documentation\n\nv0.6.0 | 2026-08-06T10:25:44.611Z | auto\n\n- Updated Docker run examples in documentation to specify user IDs and add resource limits for improved security (memory, CPU, pids).\n- Clarified configuration for writable OAuth storage while keeping provider secrets read-only.\n- Revised onboarding instructions and permission descriptions for agent and unbounded onboarding modes.\n- Removed obsolete skill-card.md file.\n- Minor documentation cleanups in usage and metadata fields.\n\nv0.5.0 | 2026-08-06T02:38:41.265Z | auto\n\n- Adds optional support for local Lighthouse browser audits alongside Google Search Console, Bing Webmaster Tools, GA4, and PageSpeed Insights integration.\n- Introduces and ships a bundled rankrat.sh wrapper script for user convenience.\n- Updates the environment variable to RANKRAT_CONFIG_DIR and refines permissions description for optional Lighthouse traffic.\n- Removes the outdated skill-card.md file.\n- Reference docs updated, including setup instructions for multi-container usage with the Lighthouse worker.\n\nv0.4.1 | 2026-08-05T15:13:00.624Z | auto\n\n- Removed the file skill-card.md.\n- No other user-visible changes.\n\nv0.4.0 | 2026-08-05T12:31:21.286Z | auto\n\n- Updated permissions: clarified network permission wording and included IndexNow as a provider.\n- Removed the outdated \"skill-card.md\" file.\n- Expanded SKILL.md documentation with more detail on Google Analytics account inventory, property structure, and measurement IDs.\n- Provided clearer onboarding and usage instructions, including new tools related to GA4 properties.\n- Overall, this release improves provider support clarity and onboarding guidance.\n\nv0.2.0 | 2026-08-03T16:53:58.607Z | auto\n\nrankrat 0.2.0\n\n- Added onboarding guidance: instructions on onboarding sites are now included, detailing both provider resource creation and site verification steps.\n- Provided onboarding tools: introduced the onboarding_guide tool and clarified use of site_onboarding_submit, present only if agent-initiated onboarding is enabled.\n- Updated documentation for clarity: revised usage notes and onboarding procedures to help users distinguish when agent onboarding is possible or when user action is required.\n- Removed outdated skill-card.md file.\n\nv0.1.2 | 2026-08-03T16:12:58.960Z | auto\n\n- Updated documentation to clarify that the repo now includes a rankrat.sh wrapper script for local invocations.\n- Minor improvements to usage instructions in SKILL.md for better clarity.\n- Removed skill-card.md from the repository.\n\nv0.1.1 | 2026-08-03T15:37:33.727Z | auto\n\n- Removed redundant file: skill-card.md.\n- Updated internal references and maintained documentation in setup.md.\n\nv0.1.0 | 2026-08-03T14:57:44.532Z | auto\n\nInitial release of rankrat — a unified, self-hosted server for querying your own search-analytics and SEO APIs.\n\n- Supports Google Search Console, Bing Webmaster Tools, Google Analytics 4 (GA4), and PageSpeed Insights through one MCP API.\n- Provides search analytics, trends, anomaly detection, drop attribution, indexing diagnostics, ranking reports, URL/page performance, and GA4 reporting (including ecommerce and user behavior).\n- Robust security: read-only by default, strict provider and property boundaries, credentials never leave the host.\n- Offers stdio and HTTP MCP endpoints, plus a FastAPI-based JSON API.\n- Usable for analyzing your own sites (not for competitive research or tracking arbitrary domains).\n\nArchive index:\n\nArchive v0.20.1: 4 files, 18307 bytes\n\nFiles: references/setup.md (27008b), skill-card.md (2117b), SKILL.md (16108b), _meta.json (127b)\n\nFile v0.20.1:SKILL.md\n\n---\nname: rankrat\ndescription: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control.\nhomepage: https://github.com/psyb0t/rankrat\nuser-invocable: true\nmetadata:\n  openclaw:\n    emoji: \"🐀\"\n    requires:\n      bins: [docker]\npermissions:\n  network: \"outbound HTTPS to configured Google Search Console, Google Analytics, Google Tag Manager, Bing Webmaster Tools, Microsoft Clarity, PageSpeed/CrUX, Cloudflare, public DNS, public pages beneath configured sites, and IndexNow endpoints; optional Lighthouse browser traffic to explicitly requested bounded pages; inbound only on the port you bind.\"\n  shell: \"docker run invocations for the published image or the installed rankrat launcher; no other host access is required.\"\n  filesystem: \"reads provider-account config and credentials; writes the configured OAuth token store, persistent SQLite monitor state, locally initialized IndexNow key, and discovered resource inventory in the config file when writable.\"\n---\n\n# rankrat\n\nA self-hosted MCP server over the SEO and search-analytics APIs you already have\naccounts on — Google Search Console, Google Tag Manager, Bing Webmaster Tools,\nGA4, Microsoft Clarity, and PageSpeed Insights — so an agent can read and,\nwhen trusted, manage your own provider resources without you handing it a\nbrowser session or a service-account key.\n\nInstall, credentials and the full environment reference:\n[`references/setup.md`](references/setup.md).\nFor a human-readable operator manual organized by topic, use the public\n[Rankrat documentation](https://github.com/psyb0t/rankrat/tree/main/docs).\n\n## Contents\n\n- [Security and safety](#security-and-safety)\n- [When to use](#when-to-use)\n- [When NOT to use](#when-not-to-use)\n- [Usage](#usage)\n\n## Security and safety\n\nConfigured provider credentials are Rankrat's authority. A Google OAuth account,\nBing key, Cloudflare token, or Clarity project token can reach every supported\nresource that provider exposes to it. Resource arrays in the config are\ndiscovered inventory and URL-containment data, not a second permission system.\nFixed provider origins, typed requests, public-URL validation, and child-URL\ncontainment still apply.\n\nRankrat is **writable by default**. `RANKRAT_READ_ONLY=true` removes every write\ntool from `tools/list` and every write route from runtime OpenAPI, including\nsite onboarding. This is the only capability switch. The human decides whether\nthe caller is a careful human-directed agent or a fully autonomous one; if that\ncaller should not mutate the account, run a read-only process.\n\nYour provider credentials stay on the host running rankrat. Requests go to the\nprovider APIs over HTTPS. The optional Lighthouse companion opens only an\nexplicitly requested page beneath a configured PageSpeed site and receives no\nprovider credentials. Credentials, OAuth records and raw provider bodies are\nnever returned or logged. Bind Rankrat to loopback or a private network, and use\nthe bearer token if anything else can reach it.\n\n## When to use\n\n- Reading Search Console performance: queries, pages, countries, devices, dates\n  — as raw rows, summaries, trends, period comparisons, or anomaly and\n  traffic-drop attribution.\n- Diagnosing indexing: URL inspection (single or batch), sitemap listings,\n  crawl issues, crawl stats.\n- Bing Webmaster Tools equivalents, plus keyword statistics, related keywords,\n  ranking buckets, query/page opportunity reports and cannibalization analysis.\n- GA4 reporting: realtime, content and landing-page performance, organic search\n  landing pages, traffic sources, ecommerce, audience segments, user behavior,\n  conversion funnels.\n- Google Tag Manager account discovery plus typed containers, workspaces, tags,\n  triggers, variables, versions, and publication in writable mode.\n- Microsoft Clarity Data Export project insights in read-only mode.\n- PageSpeed Insights, CrUX history, and fetching a page's structured-data schema.\n- Whole-site crawling for deterministic metadata, canonical, robots, sitemap,\n  duplicate-title, link, and structured-data findings with remediation text.\n- Google/Bing ownership checks and narrowly scoped verification through the\n  configured DNS adapter; Cloudflare is currently supported.\n- IndexNow change notifications for bounded URLs. This is a writable push\n  protocol, not a reporting dashboard or an indexing guarantee.\n- Backlink intelligence from configured Bing Webmaster sites.\n- Internal-link graphs, same-site orphan-page joins, lexical link suggestions\n  limited to pages sharing normalized title/path tokens, and ranked content\n  opportunities joined across search, analytics, and crawl data.\n- Cloudflare hourly traffic/cache analytics, plus exact purges and two finite\n  cache templates in writable mode. Template mutations are serialized per zone\n  within the running Rankrat process.\n- Provider-neutral managed edge redirects. Cloudflare is the current adapter;\n  Rankrat never replaces unrelated provider rulesets.\n- Safe Bing content submission: Rankrat fetches the bounded public HTML page\n  itself rather than accepting caller-provided content or headers.\n- Persistent site-audit monitors, immutable snapshots, issue lifecycle events,\n  and explicit acknowledge/resolve operations. The background scheduler runs\n  only in the long-lived HTTP process; stdio supports explicit monitor runs and\n  history. Poll these tools because Rankrat does not send external notifications.\n- Local Lighthouse performance, accessibility, best-practices, and SEO scores\n  or category-specific failed findings when the companion worker is configured.\n- Checking which providers are actually wired up (`provider_readiness`,\n  `diagnostics`) before trusting a report.\n\n## When NOT to use\n\n- **Sites you don't control.** Everything is scoped to configured provider\n  accounts and site boundaries. It is not a competitor crawler or arbitrary\n  backlink scraper.\n- **A caller that should not have account-wide write access.** Start that caller\n  with `RANKRAT_READ_ONLY=true`; the write schemas will not be discoverable.\n- **Realtime dashboards.** Provider APIs lag (Search Console notably so), and\n  rankrat reports what they return.\n- **Editing an arbitrary CMS or repository.** Audits return deterministic fixes;\n  provider remediation resubmits sitemaps and URLs but does not rewrite pages.\n\n## Usage\n\nBoth MCP transports run from the published image. Read tools have a stable\ndiscovery surface even when their provider is not configured; ask\n`provider_readiness` before interpreting an empty or unavailable result. Only\nwrite-tool discovery changes, and only with `RANKRAT_READ_ONLY`.\n\nThe public `rankrat` launcher keeps stdio as a hardened direct `docker run`\nchild and uses Docker Compose for HTTP so Rankrat and Lighthouse share one\nlifecycle:\n\n```bash\nrankrat --data-dir /absolute/path/to/rankrat-profile stdio\nrankrat --data-dir /absolute/path/to/rankrat-profile http -d\n```\n\nHTTP uses the profile as its Compose project directory. The launcher creates\nthe reviewed `docker-compose.yml` there when missing, preserves an existing\nsafe regular file, and mounts only the fixed profile children—not the root\nitself. The project directory and Compose file must be owned by the current UID\nand not group/world writable.\nOmit `-d` to attach to logs; detached services restart unless stopped.\n\n**stdio** is the default mode, so a client that spawns its own server just runs\nthe image and talks to it — no port, no bridge:\n\n```bash\nexport RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run -i --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat stdio\n```\n\n**Manual single-container Streamable HTTP** is available when local Lighthouse\nis not needed. MCP is at `/mcp`, and the REST API is on the same port:\n\n```bash\nexport RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  -p 127.0.0.1:8080:8080 \\\n  -e RANKRAT_HTTP_HOST=0.0.0.0 \\\n  -e RANKRAT_HTTP_BEARER_SECRET_FILE=/run/secrets/rankrat/http-bearer-token \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat http\n```\n\n`RANKRAT_HTTP_HOST=0.0.0.0` binds inside the container; the `-p` publishes it on\nloopback only. Send `Authorization: Bearer <token>` when a bearer secret is\nconfigured.\n\nThese examples use the writable default, so config inventory can be updated.\nGoogle OAuth storage is writable because token refresh may rotate and persist a\nrefresh token; provider secrets stay read-only. For a read-only agent, set\n`RANKRAT_READ_ONLY=true` and make the config mount read-only as described in the\nsetup reference.\n\nThe repository ships one public launcher named `rankrat`; install it before\nasking an agent to use a human-managed profile. It uses direct Docker for\nstdio/operator commands and Compose for HTTP; agents can still invoke either\nimage directly. Omit `--data-dir` for the default `$HOME/.config/rankrat`\nprofile. A chosen profile's fixed `config/`, `secrets/`, `oauth/`, and `state/`\nchildren preserve provider sessions and inventory when launched from different\nsite repositories.\n\nThe one-container manual examples return `UNAVAILABLE` for Lighthouse because\nChromium is deliberately isolated in `psyb0t/rankrat-lighthouse`. Use the\nwrapper's Compose-backed HTTP mode or the published two-image commands in\n`references/setup.md` when local browser audits are required. The worker shares\nonly a Unix socket and receives no provider credential mounts.\n\nUse the browser worker only for operator-controlled sites. Its documented\nnon-root, capability-free container needs Chromium's `--no-sandbox`; a hostile\npage therefore requires a stronger outer sandbox such as gVisor or Kata. The\nworker blocks private/special-address egress, while public cross-origin\nsubresources—and a public redirect before Rankrat rejects its final URL—remain\npossible.\n\nThe browser surface is exactly `lighthouse_audit`,\n`lighthouse_seo_findings`, `lighthouse_accessibility_findings`,\n`lighthouse_performance_findings`, and\n`lighthouse_best_practices_findings`. Every call takes `account_id`, a\nconfigured `site_url`, a child `page_url`, and an optional timeout from 5 to 300\nseconds. The REST equivalents live under `/v1/lighthouse/`.\n\n### Finding where a site lives, and matching its tag\n\nGA4 nests every property under an *account*, and properties routinely sit under\nan unrelated one because that is whatever the dropdown defaulted to when they\nwere created. `google_analytics_account_inventory` lists every account the\ncredential can see with its properties — that is the tool for \"which account is\nthis site under\", and the answer is often surprising.\n\n`google_analytics_data_streams` returns a configured property's streams and their\n`G-` measurement IDs. Use it before telling anyone their tag is installed\ncorrectly: a tag whose measurement ID belongs to a different property looks\nperfectly installed and reports into a property nobody is reading.\n\n`google_analytics_account_rename` and `google_analytics_property_rename` exist in\nwritable mode. Account names are cosmetic — the numeric ID is what boundaries,\nmeasurement IDs and reports bind to — so renaming is safe and is the usual fix\nfor a misfiled property. There is no GA4 account-creation or Analytics deletion\ntool. Property creation is available through writable site onboarding.\n\n### Onboarding a site\n\nRead the `rankrat://onboarding` resource before saying anything about onboarding,\nor call the `onboarding_guide` tool if the client does not support resources —\npass `site_url` to get the methods that site's property form actually accepts.\nBoth are read-only and present on every server, including read-only ones, and\n`POST /v1/onboarding-guides` serves the same document over REST.\n\nCheck what already exists before creating anything. `accounts_list` shows how\nmany resources each account carries; `google_sites_list` lists the Search Console\nproperties the credential sees upstream, broader than the cached boundary; and\n`site_ownership_check` reports whether Google and Bing already treat the site as\nverified. A site that is already a verified Search Console and Bing property does\nnot need onboarding — onboarding always resolves or creates a GA4 property. When\nyou only need Rankrat to operate on existing properties, register them in the\naccount's `search_console_sites`, `pagespeed_sites`, and Bing `sites` inventory\nin `boundaries.json`, plus the site's zone in the Cloudflare `dns_zones` if you\nwill DNS-verify Bing, then restart so the boundary reloads. A Bing site stays\nunverified until `site_ownership_verify` or a manual method redeems its proof,\nand Bing rejects sitemap writes until then.\n\nIf the user has no GA4 account yet, do not attempt to create one and do not\nguess the steps. No tool can create a GA4 account — the Admin API has no\n`accounts.create`, and the flow ends at a Terms of Service page. The guide's\n`manual_provisioning` block carries the start URL and the exact ordered clicks;\nrelay those, then ask the user for the numeric account ID, which\n`google_analytics_account_inventory` can also read back once it exists.\n\nCreating provider resources and proving ownership are separate. When a DNS\nprovider account is configured, call `site_ownership_verify` after onboarding,\nthen poll `site_ownership_check` until `complete` is true. Cloudflare is the\ncurrently shipped DNS adapter; without a supported adapter, the guide lists the\nmanual methods accepted by the property form. Site onboarding does not deploy a\nGA4 tag, but writable typed Tag Manager tools can do so when the caller supplies\nan explicit container, workspace, tag definition, version, and publication\nrequest. Rankrat still cannot create a GA4 account. `site_onboarding_submit`\nexists in writable mode; when the process is read-only, guide the user through a\nseparate writable Rankrat process or the `rankrat onboard-site` terminal command.\n\nTypical flow for \"why did traffic drop\":\n\n1. `google_search_analytics_summary` — establish the baseline.\n2. `google_search_analytics_comparison` — the affected period against the prior one.\n3. `google_search_analytics_drop_attribution` — which queries and pages account for it.\n4. `google_url_inspection` on the worst pages — whether it is an indexing problem.\n\nTool names are prefixed by provider (`google_*`, `bing_*`), with a handful of\nserver-level ones (`server_info`, `accounts_list`, `sites_list`, `diagnostics`,\n`provider_readiness`). The complete grouped tool catalog, environment, and\ncredential setup live in [`references/setup.md`](references/setup.md).\n\nFile v0.20.1:_meta.json\n\n{\n  \"ownerId\": \"kn79dhvmpjng4rp2jjk8k0v5xx80ccbk\",\n  \"slug\": \"rankrat\",\n  \"version\": \"0.20.1\",\n  \"publishedAt\": 1791644028619\n}\n\nFile v0.20.1:references/setup.md\n\n# rankrat — setup reference\n\nEverything the [skill](../SKILL.md) needs but does not need loaded up front:\nconfiguration, credentials, and how to run it.\n\nThis file is the self-contained agent reference shipped with the skill. Human\noperators can use the topic-based\n[public manual](https://github.com/psyb0t/rankrat/tree/main/docs), especially\n[Getting started](https://github.com/psyb0t/rankrat/blob/main/docs/getting-started.md),\n[Providers and credentials](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md),\nand [Troubleshooting](https://github.com/psyb0t/rankrat/blob/main/docs/troubleshooting.md).\n\n## Contents\n\n- [Configuration](#configuration)\n- [The boundary file](#the-boundary-file)\n- [Write access](#write-access)\n- [Guided setup](#guided-setup)\n- [Provider credentials](#provider-credentials)\n- [Running it](#running-it)\n- [Onboarding](#onboarding)\n- [Complete MCP tool catalog](#complete-mcp-tool-catalog)\n- [Checking it works](#checking-it-works)\n\n## Configuration\n\nAll settings are read from the environment with the `RANKRAT_` prefix, so a\nfield named `http_port` is set by `RANKRAT_HTTP_PORT`. The defaults below are\nthe ones in the settings model, not example values.\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `RANKRAT_HTTP_HOST` | `127.0.0.1` | Listen address in `http` mode. Loopback by default — bind wider only deliberately. |\n| `RANKRAT_HTTP_PORT` | `8080` | Listen port in `http` mode. |\n| `RANKRAT_BOUNDARY_FILE` | `/run/config/boundaries.json` | Provider accounts plus discovered resource inventory and URL-containment roots. |\n| `RANKRAT_SECRET_ROOT` | `/run/secrets` | Directory holding provider credentials. |\n| `RANKRAT_OAUTH_TOKEN_ROOT` | `/run/oauth` | Directory holding stored Google OAuth tokens. |\n| `RANKRAT_LOG_FILE` | `/tmp/rankrat/rankrat.log` | Log destination. |\n| `RANKRAT_LOG_LEVEL` | `INFO` | Standard Python log levels. |\n| `RANKRAT_LIGHTHOUSE_WORKER_SOCKET` | `/run/lighthouse/lighthouse.sock` | Optional Unix socket for the isolated local Lighthouse worker. Empty disables it. |\n| `RANKRAT_STATE_DATABASE` | unset | Absolute SQLite path for monitors, snapshots, and issue events. Empty/unset disables persistence. The wrapper sets `/run/state/rankrat.sqlite3`. |\n| `RANKRAT_SCHEDULER_INTERVAL_SECONDS` | `60` | How often the HTTP process claims due monitors; accepted range 10–3600 seconds. |\n| `RANKRAT_STATE_RETENTION_DAYS` | `180` | Snapshot/event retention after a monitor run; accepted range 1–3650 days. |\n| `RANKRAT_ENABLE_OPENAPI` | `false` | Serve the OpenAPI document. |\n| `RANKRAT_READ_ONLY` | `false` | See \"Write access\" below. |\n| `RANKRAT_HTTP_BEARER_SECRET_FILE` | unset | File holding the bearer token required on HTTP requests. Unset means no auth, so only do that on loopback. |\n\nThe supported names and safe defaults are in `.env.example`. Invalid values for\nsupported settings fail startup instead of being silently accepted.\n`make run-http` always supplies a bearer-secret file, including for loopback\nuse; a custom loopback launch may deliberately omit it.\n\n`RANKRAT_DATA_DIR` is an optional compatibility environment override consumed\nby host launchers, not by the Python process. Prefer the explicit\n`rankrat --data-dir /absolute/profile ...` form when choosing a non-default\nprofile. The profile contains `config/boundaries.json`, `secrets/`, `oauth/`,\n`state/`, and, for HTTP, an operator-owned `docker-compose.yml`. `rankrat setup`\ncreates every required path and secret safely; do not create a profile tree or\ncopy an example file by hand. With no override, launchers use\n`$HOME/.config/rankrat` and never mount the root wholesale.\n\n## The boundary file\n\n`boundaries.json` fixes credential accounts and records resource inventory.\nEach credential authorizes every supported operation and resource that its\nprovider account can reach. Resource arrays cache discovered sites, properties,\nzones, and targets; they are not per-resource permission lists. Fixed provider\norigins, public-URL validation, and child-URL containment remain enforced.\nWritable discovery and onboarding persist inventory only after the config mount\npasses ownership and mode checks.\n\n## Write access\n\n`RANKRAT_READ_ONLY` defaults to `false`. The trusted caller gets direct access\nto every supported operation permitted by each configured provider account.\nThis is the only capability switch. HTTP uses its normal bearer for transport\nauthentication; stdio access is controlled by who can start the process and\nread its mounts.\n\nSet it to `true` and the effect is stronger than a refusal at call time: write\ntools are absent from `tools/list` and REST write routes are not mounted. An\nagent cannot discover them, let alone call them.\nWrites cover IndexNow submission, Bing URL/sitemap/property changes, Google\nIndexing notifications, Search Console site/sitemap changes, DNS-provider-backed\nownership verification, discovery remediation, and new-site onboarding, and\nmonitor lifecycle operations plus typed Google Tag Manager changes, safe Bing\ncontent submission, provider-neutral managed edge redirects, and finite\nCloudflare cache purges/templates, and are marked as writes in MCP. The human\nmay operate Rankrat interactively or delegate fully autonomous work; use\nread-only mode when that caller must not mutate provider or local state.\n\n## Guided setup\n\nFrom a checkout, the human runs one command:\n\n```bash\nmake setup\n```\n\nThe command initializes owner-only `config/`, `secrets/`, `oauth/`, and\n`state/` paths without replacing existing values. It asks for a comma-separated\nprovider set, prints each provider's credential console and account-wide\npermissions, then accepts secrets through non-echoing prompts. Standard paths\nare used automatically:\n\nReruns are additive. Selected providers are added or refreshed in place;\nunselected provider accounts and their inventory are preserved. When a\nselected provider has multiple account entries, setup rejects the ambiguous\nrefresh before asking for a secret; edit `config/boundaries.json` to identify\nthe intended account first.\n\n| Provider | Host credential path |\n|---|---|\n| Google | `secrets/google/oauth-client.json` |\n| Bing | `secrets/bing/api-key` |\n| Cloudflare | `secrets/cloudflare/api-token` |\n| Microsoft Clarity | `secrets/clarity/api-token` |\n\nGoogle accepts only an installed/Desktop OAuth client JSON. The same setup\ncommand prints the consent URL, waits for the loopback callback, and stores the\nfull Rankrat grant under `oauth/`. PageSpeed's separate API key is prompted at\nthe same time because that API does not use OAuth.\n\nAfter storage, setup runs account readiness. It does not create site properties,\nsubmit sitemaps/URLs, or send IndexNow notifications. Secret values are never\nprinted or written into `.env`.\n\n## Provider credentials\n\nEach provider is optional. Read tools stay discoverable regardless of local\ncredential state and return a finite unavailable/configuration error when their\nprovider cannot run. Ask `provider_readiness` which providers are live rather\nthan inferring it from discovery or an empty result. Write tools are the\nexception: they are absent unless writable mode enables them.\n\n- **Google Search Console / Google Analytics 4 / Google Tag Manager / Google\n  Indexing** — create a Google project and Desktop OAuth client JSON using the\n  exact [Google OAuth guide](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md#google-oauth).\n  Run setup and paste the client JSON's single line at the hidden prompt:\n\n  ```sh\n  rankrat setup\n  ```\n\n  The CLI validates the pasted JSON, writes it into `RANKRAT_SECRET_ROOT`, runs\n  one authorization flow, and stores the resulting token under\n  `RANKRAT_OAUTH_TOKEN_ROOT`. It\n  requests Search Console management, Google Indexing, GA4 read/edit, and Tag\n  Manager container edit, delete, version-edit, and publish scopes; provider-side\n  ownership still controls what the account can do.\n- **Bing Webmaster Tools** — open\n  [Bing Webmaster Tools](https://www.bing.com/webmasters/home), add and verify\n  one site, then **Settings → API Access → API Key → Generate API Key**. The\n  resulting key is account-wide, not site-specific; setup stores it under\n  `RANKRAT_SECRET_ROOT`.\n- **Cloudflare** — create one dedicated **User API Token**, not an Account API\n  Token: [open User API Tokens](https://dash.cloudflare.com/profile/api-tokens)\n  → **Create Token → Create Custom Token** → name it `rankrat`. Add **Zone →\n  Zone → Read**, **Zone → DNS → Edit**, **Zone → Analytics → Read**, **Zone →\n  Cache Purge → Purge**, **Zone → Cache Rules → Edit**, **Zone → Single\n  Redirect → Edit**, **Account → Account Rulesets → Edit**, and **Account →\n  Account Filter Lists → Edit**. Set **Zone Resources → Include → All zones**\n  and **Account Resources → Include → All accounts**, then **Continue to\n  summary → Create Token**. Copy the one-time value into Rankrat's hidden\n  prompt. This covers all current Cloudflare features. Rankrat discovers zone\n  IDs; it exposes no arbitrary DNS record, whole-zone purge, arbitrary\n  cache-rule body, or arbitrary ruleset replacement. Ownership records are\n  DNS-only and untagged, so no Cloudflare DNS-tag quota is needed. Readiness\n  confirms account reachability but deliberately does not create a throwaway\n  record to test DNS write access.\n- **Microsoft Clarity** — open [Microsoft Clarity](https://clarity.microsoft.com/),\n  choose a project, then **Settings → Data Export → Generate new API token**.\n  The token belongs to that project; setup stores it at the configured account\n  credential path. One Clarity account represents one project and is read-only\n  in Rankrat. The upstream API allows at most ten requests per project/day; see\n  [Microsoft's documentation](https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-data-export-api).\n- **PageSpeed Insights and CrUX** — setup separately asks for one optional API\n  key. Create it through [Google API Credentials](https://console.cloud.google.com/apis/credentials)\n  and restrict it to **PageSpeed Insights API** and **Chrome UX Report API**.\n  OAuth does not grant it. Without the key, PageSpeed runs under a tighter\n  anonymous quota and `crux_history` is unavailable.\n- **Local Lighthouse** — no credential. The optional companion image receives\n  only a shared Unix socket and outbound browser network access. Rankrat accepts\n  only requested URLs beneath the account's `pagespeed_sites` and rejects a\n  report whose final URL escapes that boundary. A public cross-origin redirect\n  can be fetched before this post-navigation check, while private and special\n  destinations are blocked by the worker's enforced proxy.\n\nCredentials stay on the host running rankrat. They are used to call the provider\nAPIs over HTTPS and are not sent anywhere else.\n\n## Running it\n\nAn agent runs the published image directly. A human creates the profile,\ncredentials, and Google authorization with `rankrat setup` beforehand — after\ninstalling the launcher. Download the installer, read it, then run it, per-user\n(no root) or system-wide:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/psyb0t/rankrat/main/install.sh -o rankrat-install.sh\nless rankrat-install.sh\nbash rankrat-install.sh                # per-user   -> ~/.local/bin/rankrat\nsudo bash rankrat-install.sh --system  # system-wide -> /usr/local/bin/rankrat\n```\n\nThe single public launcher is named `rankrat`; it is not duplicated into agent\nskills, so the shipped code cannot drift from what operators install:\n\n```bash\nrankrat --data-dir /absolute/path/to/rankrat-profile stdio\nrankrat --data-dir /absolute/path/to/rankrat-profile http       # attached Rankrat + Lighthouse\nrankrat --data-dir /absolute/path/to/rankrat-profile http -d    # detached, restart unless stopped\n```\n\nHTTP treats the profile as its Compose project directory. It atomically creates\nthe embedded reviewed `docker-compose.yml` when absent, preserves an existing\nsafe regular file, rejects symlinked/non-regular paths, and exports the chosen\nimage, port, UID/GID, and read-only values from its environment. The project\ndirectory and Compose file must be owned by the current UID and not group/world\nwritable. Only the four fixed children below are mounted into containers.\n\nBoth transports take the same four mounts. Container-side paths are the\nserver's defaults, so only the host side changes:\n\n| Host | Container | Access | Holds |\n|---|---|---|---|\n| `$RANKRAT_DATA_DIR/config` | `/run/config` | writable normally; read-only with `RANKRAT_READ_ONLY=true` | account registry and inventory |\n| `$RANKRAT_DATA_DIR/secrets` | `/run/secrets` | read-only | provider credentials, HTTP bearer secret |\n| `$RANKRAT_DATA_DIR/oauth` | `/run/oauth` | writable | stored Google OAuth token; refresh may rotate it |\n| `$RANKRAT_DATA_DIR/state` | `/run/state` | writable, owner-only | SQLite monitor definitions, snapshots, issues, and events |\n\n**stdio** — the default mode, for a client that owns the process:\n\n```bash\ndocker run -i --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat stdio\n```\n\n**Manual single-container Streamable HTTP** — for a shared server that does not\nneed local Lighthouse. MCP lands at `/mcp` and the REST API shares the port:\n\n```bash\ndocker run --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  -p 127.0.0.1:8080:8080 \\\n  -e RANKRAT_HTTP_HOST=0.0.0.0 \\\n  -e RANKRAT_HTTP_BEARER_SECRET_FILE=/run/secrets/rankrat/http-bearer-token \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat http\n```\n\n`RANKRAT_HTTP_HOST=0.0.0.0` binds inside the container while `-p` keeps it on\nloopback. MCP is then at `http://127.0.0.1:8080/mcp`; send\n`Authorization: Bearer <token>` whenever a bearer secret is configured.\n\nThe commands above use the writable default. Before mounting config writable,\nverify that the resolved directory is owner-only, `boundaries.json` is not a\nsymlink, both are owned by the current UID, and the file is not group- or\nworld-writable. The public `rankrat` launcher performs those checks. The OpenClaw\nlauncher additionally rejects symlinked path components. For a read-only\ncaller, set `RANKRAT_READ_ONLY=true` and make only `/run/config` read-only.\nNever make the provider-secret mount writable during normal service operation.\n\nLocal Lighthouse audits require the separate published browser image. Start it\nonce against a private named volume:\n\n```bash\ndocker volume create rankrat-lighthouse-runtime\ndocker run --rm --network none --user 0:0 --read-only \\\n  --cap-drop=ALL --cap-add=CHOWN --cap-add=FOWNER \\\n  --security-opt no-new-privileges:true \\\n  --pids-limit 16 --memory 64m --cpus 0.25 \\\n  --mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse \\\n  --entrypoint /bin/sh psyb0t/rankrat-lighthouse \\\n  -c 'chmod 1777 /run/lighthouse && touch /run/lighthouse/.initialized && chown -R 10001:10001 /run/lighthouse && chmod 0750 /run/lighthouse'\ndocker run --rm -d --name rankrat-lighthouse-worker --init --read-only \\\n  --user 10001:10001 --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 256 --memory 2g --cpus 2 --shm-size 1g \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=1g,mode=1777 \\\n  --mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse \\\n  psyb0t/rankrat-lighthouse\n```\n\nThe self-removing initializer assigns the private volume root to the non-root\nUID shared by Rankrat and the worker. When using a different UID/GID, change the\ninitializer's `chown` pair and the worker's `--user` pair to the same values.\nRun Rankrat under that pair as well if the primary image's built-in `10001:10001`\nuser is overridden. The provided Compose file applies `RANKRAT_UID` and\n`RANKRAT_GID` consistently to both long-lived services after running this\nhardened initializer.\n\nAdd this read-only volume mount to either published Rankrat invocation above:\n\n```bash\n--mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse,readonly\n```\n\nThe normal `psyb0t/rankrat stdio` command then exposes the five Lighthouse tools\nover stdio. The normal `psyb0t/rankrat http` command exposes the same tools over\nStreamable HTTP at `/mcp` and REST under `/v1/lighthouse/`. Leave\n`RANKRAT_LIGHTHOUSE_WORKER_SOCKET` empty to disable the worker explicitly. Stop\nand remove only the worker and volume you created when they are no longer\nneeded.\n\nThe worker is for pages you control and trust. Chromium runs with\n`--no-sandbox` because its built-in namespace/setuid sandbox cannot coexist with\nthe documented non-root, capability-free, `no-new-privileges` container. The\ncredential-free, read-only worker and public-address-only proxy reduce blast\nradius but do not replace the renderer sandbox after a browser exploit. Use an\nouter sandbox such as gVisor or Kata Containers before auditing hostile content.\n\n| MCP tool | REST route |\n|---|---|\n| `lighthouse_audit` | `POST /v1/lighthouse/audits` |\n| `lighthouse_seo_findings` | `POST /v1/lighthouse/seo-findings` |\n| `lighthouse_accessibility_findings` | `POST /v1/lighthouse/accessibility-findings` |\n| `lighthouse_performance_findings` | `POST /v1/lighthouse/performance-findings` |\n| `lighthouse_best_practices_findings` | `POST /v1/lighthouse/best-practices-findings` |\n\nEvery operation accepts the same strict body: `account_id`, a configured\n`site_url`, a child `page_url`, and optional `timeout_seconds` in the inclusive\n5–300 second range. The aggregate audit returns all four category scores and\nfailed findings; the other four operations return only that category's failed\nfindings.\n\n## Onboarding\n\n`site_onboarding_submit` is part of normal writable mode. It creates or reuses\nGA4, Search Console, and Bing resources, then records discovered IDs in the\nconfig file. It is absent from `tools/list` and REST when\n`RANKRAT_READ_ONLY=true`. The config directory must be safely writable; the\nbundled wrapper validates its ownership/mode.\n\nThe guidance is available either way, read-only, on every server:\n\n| Surface | What it gives |\n|---|---|\n| `rankrat://onboarding` resource | The whole procedure and this server's onboarding posture |\n| `rankrat://onboarding/{site_url}` template | Same, narrowed to one percent-encoded site |\n| `onboarding_guide` tool | The identical document, for clients without resource support |\n\nWith a configured DNS provider account, `site_ownership_verify` requests the\nreal Google TXT and Bing CNAME proofs, publishes only those records through the\nadapter selected by the account's `provider`, checks public DNS, and redeems\neach provider. Poll `site_ownership_check` until it reports `complete`; DNS\npropagation is asynchronous. Cloudflare is the currently shipped DNS adapter.\nWithout a supported adapter, a `sc-domain:` property accepts only DNS TXT,\nwhile a `https://` URL-prefix property also accepts the GA4 tag, an HTML file,\nor a meta tag.\n\nThe SEO expansion has the same names over stdio and Streamable HTTP MCP:\n\n| MCP tool | REST route |\n|---|---|\n| `site_ownership_check` | `POST /v1/site-ownership-checks` |\n| `site_ownership_verify` | `POST /v1/site-ownership-verifications` |\n| `site_audit` | `POST /v1/site-audits` |\n| `site_remediation_apply` | `POST /v1/site-remediations` |\n| `bing_backlink_intelligence` | `POST /v1/bing/backlink-intelligence` |\n| `internal_link_graph` | `POST /v1/internal-link-graphs` |\n| `orphan_page_report` | `POST /v1/orphan-page-reports` |\n| `internal_link_opportunities` | `POST /v1/internal-link-opportunity-reports` |\n| `crux_history` | `POST /v1/crux/history-reports` |\n| `cloudflare_analytics` | `POST /v1/cloudflare/analytics-reports` |\n| `content_opportunities` | `POST /v1/content-opportunity-reports` |\n\n## Complete MCP tool catalog\n\n`tools/list` is authoritative for a running server because startup settings\ndecide which tools exist. The grouped inventory below mirrors the tool catalog\nin the source. The exact REST paths and schemas live in the committed\n[merged OpenAPI document](https://github.com/psyb0t/rankrat/blob/main/openapi.json),\ncomposed from the\n[base](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/openapi.yaml)\nand\n[SEO intelligence](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/seo-openapi.yaml)\nand\n[free provider SEO](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/free-seo-openapi.yaml)\nYAML sources. When enabled, the runtime `/openapi.json` removes write routes\nfrom a read-only server.\n\n### Read-only tools\n\n- **Server, boundaries, and guidance:** `server_info`, `accounts_list`,\n  `sites_list`, `diagnostics`, `provider_readiness`, `onboarding_guide`.\n- **Site, ownership, schema, links, and opportunities:** `site_audit`,\n  `site_ownership_check`, `schema_validate_url`, `schema_validate_html`,\n  `schema_validate_json_ld`, `bing_backlink_intelligence`,\n  `internal_link_graph`, `orphan_page_report`,\n  `internal_link_opportunities`, `content_opportunities`.\n- **Persistent monitoring:** `monitors_list`, `monitor_snapshots_list`,\n  `monitor_issues_list`, `issue_events_list`.\n- **Google Search Console and Indexing metadata:**\n  `google_search_analytics_summary`, `google_search_analytics_comparison`,\n  `google_search_analytics_dimension_report`,\n  `google_search_analytics_drop_attribution`, `google_search_analytics_trend`,\n  `google_search_analytics_anomalies`,\n  `google_search_analytics_page_performance`,\n  `google_search_analytics_query`, `google_sites_list`, `google_site_get`,\n  `google_sitemaps_list`, `google_sitemap_get`, `google_url_inspection`,\n  `google_url_inspection_batch`, `google_indexing_metadata`.\n- **Google Analytics 4:** `google_analytics_account_inventory`,\n  `google_analytics_data_streams`, `google_analytics_report`,\n  `google_analytics_realtime_report`, `google_analytics_content_performance`,\n  `google_analytics_landing_page_performance`,\n  `google_analytics_organic_search_landing_pages`,\n  `google_analytics_traffic_source_performance`,\n  `google_analytics_ecommerce_performance`,\n  `google_analytics_audience_segments`, `google_analytics_user_behavior`,\n  `google_analytics_conversion_funnel`.\n- **Google Tag Manager, Microsoft Clarity, and managed redirects:**\n  `google_tag_manager_accounts_list`, `google_tag_manager_containers_list`,\n  `google_tag_manager_workspaces_list`, `google_tag_manager_entities_list`,\n  `clarity_insights`, `edge_redirects_list`.\n- **PageSpeed, CrUX, Cloudflare, and local Lighthouse:** `pagespeed_analyze`,\n  `pagespeed_core_web_vitals`, `lighthouse_audit`,\n  `lighthouse_seo_findings`, `lighthouse_accessibility_findings`,\n  `lighthouse_performance_findings`,\n  `lighthouse_best_practices_findings`, `crux_history`,\n  `cloudflare_analytics`.\n- **Cross-provider analysis:** `ga4_pagespeed_correlation`,\n  `ga4_search_console_comparison`, `search_engine_comparison`,\n  `search_engine_traffic_health`.\n- **Bing Webmaster Tools:** `bing_keyword_statistics`,\n  `bing_related_keywords`, `bing_traffic_trend`, `bing_traffic_anomalies`,\n  `bing_traffic_comparison`, `bing_query_performance`,\n  `bing_page_performance`, `bing_brand_analysis`, `bing_ranking_buckets`,\n  `bing_query_opportunities`, `bing_page_opportunities`,\n  `bing_opportunity_matrix`, `bing_query_page_performance`,\n  `bing_query_cannibalization`, `bing_page_query_performance`,\n  `bing_url_submission_quota`, `bing_crawl_issues`, `bing_crawl_stats`,\n  `bing_feeds`, `bing_link_counts`, `bing_url_information`.\n\n### Writable tools\n\nThese appear only when `RANKRAT_READ_ONLY=false`:\n\n- **IndexNow:** `indexnow_submit`. IndexNow is an open change-notification\n  protocol, not a dashboard: one participating endpoint shares an accepted\n  notification with the other participating engines, while each engine makes\n  its own crawl and indexing decisions.\n- **Bing:** `bing_url_submit`, `bing_sitemap_submit`, `bing_site_submit`.\n- **Bing content:** `bing_content_submission_create` fetches an allowed public\n  page itself, then submits that fresh HTML to Bing.\n- **Google Search Console and Indexing:** `google_indexing_submit`,\n  `google_indexing_batch_submit`, `google_site_submit`,\n  `google_sitemap_submit`.\n- **Google Analytics 4:** `google_analytics_account_rename`,\n  `google_analytics_property_rename`.\n- **Google Tag Manager:** `google_tag_manager_container_create`,\n  `google_tag_manager_container_delete`, `google_tag_manager_workspace_create`,\n  `google_tag_manager_workspace_delete`, `google_tag_manager_entity_create`,\n  `google_tag_manager_entity_update`, `google_tag_manager_entity_delete`,\n  `google_tag_manager_workspace_version_create`,\n  `google_tag_manager_version_publish`.\n- **Ownership and discovery remediation:** `site_ownership_verify`,\n  `site_remediation_apply`.\n- **Persistent monitoring:** `monitor_create`, `monitor_update`,\n  `monitor_delete`, `monitor_run`, `issue_status_update`.\n- **Cloudflare performance:** `cloudflare_cache_purge`,\n  `cloudflare_cache_template_apply`.\n- **Provider-neutral managed redirects:** `edge_redirect_upsert`,\n  `edge_redirect_delete`. Cloudflare is the currently shipped adapter.\n- **Site onboarding:** `site_onboarding_submit`.\n\n## Checking it works\n\n- `server_info` — the server is up and which mode it is in.\n- `provider_readiness` — which providers are actually configured.\n- `accounts_list` / `sites_list` — the boundary as the server sees it.\n- `diagnostics` — deeper detail when one of the above is not what you expected.\n- `monitors_list` and `monitor_issues_list` — whether scheduled audit history\n  is accumulating and which lifecycle issues remain open.\n\nIf a provider-specific tool returns nothing, check `provider_readiness` before\nassuming the data is missing upstream.\n\nAutomatic due-monitor execution belongs to the long-running HTTP process.\nStdio exposes the same monitor CRUD, manual-run, snapshot, issue, and event\ntools, but its process lifetime is controlled by the MCP client and it does not\nleave a background scheduler behind. Persist `/run/state` for either transport.\nFor backups, use SQLite's online-backup mechanism or stop Rankrat first; copying\nonly a live database file can omit WAL state.\n\nFile v0.20.1:skill-card.md\n\n## Description:\n\nRankrat helps agents inspect SEO, search traffic, indexing, site performance, and managed website settings through a self-hosted server for sites their operators control.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[psyb0t](https://clawhub.ai/user/psyb0t)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nSite owners, SEO practitioners, and developers use this skill to analyze their own search and analytics data, audit website health, and, when authorized, manage tags, redirects, indexing submissions, and monitoring.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Provider credentials grant broad access, and account-changing tools are enabled by default.\n\nMitigation: Grant only needed provider permissions and use RANKRAT_READ_ONLY=true for agents that should not make changes.\n\nRisk: An exposed HTTP endpoint could allow unauthorized access to connected accounts.\n\nMitigation: Bind HTTP to loopback or a private network and require a bearer token when others can reach it.\n\nRisk: Installer and container image references may change between reviews.\n\nMitigation: Review the installer and pin and verify the exact release or image digest before use.\n\n## Reference(s):\n\n- [ClawHub rankrat release](https://clawhub.ai/psyb0t/skills/rankrat)\n- [Setup and credentials](references/setup.md)\n- [Rankrat documentation](https://github.com/psyb0t/rankrat/tree/main/docs)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration guidance]\n\n**Output Format:** [Markdown with reports, recommendations, and command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Reports depend on configured provider accounts; account changes require write access.]\n\n## Skill Version(s):\n\n0.20.1 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.20.0: 4 files, 18655 bytes\n\nFiles: references/setup.md (27008b), skill-card.md (3080b), SKILL.md (16108b), _meta.json (127b)\n\nFile v0.20.0:SKILL.md\n\n---\nname: rankrat\ndescription: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control.\nhomepage: https://github.com/psyb0t/rankrat\nuser-invocable: true\nmetadata:\n  openclaw:\n    emoji: \"🐀\"\n    requires:\n      bins: [docker]\npermissions:\n  network: \"outbound HTTPS to configured Google Search Console, Google Analytics, Google Tag Manager, Bing Webmaster Tools, Microsoft Clarity, PageSpeed/CrUX, Cloudflare, public DNS, public pages beneath configured sites, and IndexNow endpoints; optional Lighthouse browser traffic to explicitly requested bounded pages; inbound only on the port you bind.\"\n  shell: \"docker run invocations for the published image or the installed rankrat launcher; no other host access is required.\"\n  filesystem: \"reads provider-account config and credentials; writes the configured OAuth token store, persistent SQLite monitor state, locally initialized IndexNow key, and discovered resource inventory in the config file when writable.\"\n---\n\n# rankrat\n\nA self-hosted MCP server over the SEO and search-analytics APIs you already have\naccounts on — Google Search Console, Google Tag Manager, Bing Webmaster Tools,\nGA4, Microsoft Clarity, and PageSpeed Insights — so an agent can read and,\nwhen trusted, manage your own provider resources without you handing it a\nbrowser session or a service-account key.\n\nInstall, credentials and the full environment reference:\n[`references/setup.md`](references/setup.md).\nFor a human-readable operator manual organized by topic, use the public\n[Rankrat documentation](https://github.com/psyb0t/rankrat/tree/main/docs).\n\n## Contents\n\n- [Security and safety](#security-and-safety)\n- [When to use](#when-to-use)\n- [When NOT to use](#when-not-to-use)\n- [Usage](#usage)\n\n## Security and safety\n\nConfigured provider credentials are Rankrat's authority. A Google OAuth account,\nBing key, Cloudflare token, or Clarity project token can reach every supported\nresource that provider exposes to it. Resource arrays in the config are\ndiscovered inventory and URL-containment data, not a second permission system.\nFixed provider origins, typed requests, public-URL validation, and child-URL\ncontainment still apply.\n\nRankrat is **writable by default**. `RANKRAT_READ_ONLY=true` removes every write\ntool from `tools/list` and every write route from runtime OpenAPI, including\nsite onboarding. This is the only capability switch. The human decides whether\nthe caller is a careful human-directed agent or a fully autonomous one; if that\ncaller should not mutate the account, run a read-only process.\n\nYour provider credentials stay on the host running rankrat. Requests go to the\nprovider APIs over HTTPS. The optional Lighthouse companion opens only an\nexplicitly requested page beneath a configured PageSpeed site and receives no\nprovider credentials. Credentials, OAuth records and raw provider bodies are\nnever returned or logged. Bind Rankrat to loopback or a private network, and use\nthe bearer token if anything else can reach it.\n\n## When to use\n\n- Reading Search Console performance: queries, pages, countries, devices, dates\n  — as raw rows, summaries, trends, period comparisons, or anomaly and\n  traffic-drop attribution.\n- Diagnosing indexing: URL inspection (single or batch), sitemap listings,\n  crawl issues, crawl stats.\n- Bing Webmaster Tools equivalents, plus keyword statistics, related keywords,\n  ranking buckets, query/page opportunity reports and cannibalization analysis.\n- GA4 reporting: realtime, content and landing-page performance, organic search\n  landing pages, traffic sources, ecommerce, audience segments, user behavior,\n  conversion funnels.\n- Google Tag Manager account discovery plus typed containers, workspaces, tags,\n  triggers, variables, versions, and publication in writable mode.\n- Microsoft Clarity Data Export project insights in read-only mode.\n- PageSpeed Insights, CrUX history, and fetching a page's structured-data schema.\n- Whole-site crawling for deterministic metadata, canonical, robots, sitemap,\n  duplicate-title, link, and structured-data findings with remediation text.\n- Google/Bing ownership checks and narrowly scoped verification through the\n  configured DNS adapter; Cloudflare is currently supported.\n- IndexNow change notifications for bounded URLs. This is a writable push\n  protocol, not a reporting dashboard or an indexing guarantee.\n- Backlink intelligence from configured Bing Webmaster sites.\n- Internal-link graphs, same-site orphan-page joins, lexical link suggestions\n  limited to pages sharing normalized title/path tokens, and ranked content\n  opportunities joined across search, analytics, and crawl data.\n- Cloudflare hourly traffic/cache analytics, plus exact purges and two finite\n  cache templates in writable mode. Template mutations are serialized per zone\n  within the running Rankrat process.\n- Provider-neutral managed edge redirects. Cloudflare is the current adapter;\n  Rankrat never replaces unrelated provider rulesets.\n- Safe Bing content submission: Rankrat fetches the bounded public HTML page\n  itself rather than accepting caller-provided content or headers.\n- Persistent site-audit monitors, immutable snapshots, issue lifecycle events,\n  and explicit acknowledge/resolve operations. The background scheduler runs\n  only in the long-lived HTTP process; stdio supports explicit monitor runs and\n  history. Poll these tools because Rankrat does not send external notifications.\n- Local Lighthouse performance, accessibility, best-practices, and SEO scores\n  or category-specific failed findings when the companion worker is configured.\n- Checking which providers are actually wired up (`provider_readiness`,\n  `diagnostics`) before trusting a report.\n\n## When NOT to use\n\n- **Sites you don't control.** Everything is scoped to configured provider\n  accounts and site boundaries. It is not a competitor crawler or arbitrary\n  backlink scraper.\n- **A caller that should not have account-wide write access.** Start that caller\n  with `RANKRAT_READ_ONLY=true`; the write schemas will not be discoverable.\n- **Realtime dashboards.** Provider APIs lag (Search Console notably so), and\n  rankrat reports what they return.\n- **Editing an arbitrary CMS or repository.** Audits return deterministic fixes;\n  provider remediation resubmits sitemaps and URLs but does not rewrite pages.\n\n## Usage\n\nBoth MCP transports run from the published image. Read tools have a stable\ndiscovery surface even when their provider is not configured; ask\n`provider_readiness` before interpreting an empty or unavailable result. Only\nwrite-tool discovery changes, and only with `RANKRAT_READ_ONLY`.\n\nThe public `rankrat` launcher keeps stdio as a hardened direct `docker run`\nchild and uses Docker Compose for HTTP so Rankrat and Lighthouse share one\nlifecycle:\n\n```bash\nrankrat --data-dir /absolute/path/to/rankrat-profile stdio\nrankrat --data-dir /absolute/path/to/rankrat-profile http -d\n```\n\nHTTP uses the profile as its Compose project directory. The launcher creates\nthe reviewed `docker-compose.yml` there when missing, preserves an existing\nsafe regular file, and mounts only the fixed profile children—not the root\nitself. The project directory and Compose file must be owned by the current UID\nand not group/world writable.\nOmit `-d` to attach to logs; detached services restart unless stopped.\n\n**stdio** is the default mode, so a client that spawns its own server just runs\nthe image and talks to it — no port, no bridge:\n\n```bash\nexport RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run -i --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat stdio\n```\n\n**Manual single-container Streamable HTTP** is available when local Lighthouse\nis not needed. MCP is at `/mcp`, and the REST API is on the same port:\n\n```bash\nexport RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  -p 127.0.0.1:8080:8080 \\\n  -e RANKRAT_HTTP_HOST=0.0.0.0 \\\n  -e RANKRAT_HTTP_BEARER_SECRET_FILE=/run/secrets/rankrat/http-bearer-token \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat http\n```\n\n`RANKRAT_HTTP_HOST=0.0.0.0` binds inside the container; the `-p` publishes it on\nloopback only. Send `Authorization: Bearer <token>` when a bearer secret is\nconfigured.\n\nThese examples use the writable default, so config inventory can be updated.\nGoogle OAuth storage is writable because token refresh may rotate and persist a\nrefresh token; provider secrets stay read-only. For a read-only agent, set\n`RANKRAT_READ_ONLY=true` and make the config mount read-only as described in the\nsetup reference.\n\nThe repository ships one public launcher named `rankrat`; install it before\nasking an agent to use a human-managed profile. It uses direct Docker for\nstdio/operator commands and Compose for HTTP; agents can still invoke either\nimage directly. Omit `--data-dir` for the default `$HOME/.config/rankrat`\nprofile. A chosen profile's fixed `config/`, `secrets/`, `oauth/`, and `state/`\nchildren preserve provider sessions and inventory when launched from different\nsite repositories.\n\nThe one-container manual examples return `UNAVAILABLE` for Lighthouse because\nChromium is deliberately isolated in `psyb0t/rankrat-lighthouse`. Use the\nwrapper's Compose-backed HTTP mode or the published two-image commands in\n`references/setup.md` when local browser audits are required. The worker shares\nonly a Unix socket and receives no provider credential mounts.\n\nUse the browser worker only for operator-controlled sites. Its documented\nnon-root, capability-free container needs Chromium's `--no-sandbox`; a hostile\npage therefore requires a stronger outer sandbox such as gVisor or Kata. The\nworker blocks private/special-address egress, while public cross-origin\nsubresources—and a public redirect before Rankrat rejects its final URL—remain\npossible.\n\nThe browser surface is exactly `lighthouse_audit`,\n`lighthouse_seo_findings`, `lighthouse_accessibility_findings`,\n`lighthouse_performance_findings`, and\n`lighthouse_best_practices_findings`. Every call takes `account_id`, a\nconfigured `site_url`, a child `page_url`, and an optional timeout from 5 to 300\nseconds. The REST equivalents live under `/v1/lighthouse/`.\n\n### Finding where a site lives, and matching its tag\n\nGA4 nests every property under an *account*, and properties routinely sit under\nan unrelated one because that is whatever the dropdown defaulted to when they\nwere created. `google_analytics_account_inventory` lists every account the\ncredential can see with its properties — that is the tool for \"which account is\nthis site under\", and the answer is often surprising.\n\n`google_analytics_data_streams` returns a configured property's streams and their\n`G-` measurement IDs. Use it before telling anyone their tag is installed\ncorrectly: a tag whose measurement ID belongs to a different property looks\nperfectly installed and reports into a property nobody is reading.\n\n`google_analytics_account_rename` and `google_analytics_property_rename` exist in\nwritable mode. Account names are cosmetic — the numeric ID is what boundaries,\nmeasurement IDs and reports bind to — so renaming is safe and is the usual fix\nfor a misfiled property. There is no GA4 account-creation or Analytics deletion\ntool. Property creation is available through writable site onboarding.\n\n### Onboarding a site\n\nRead the `rankrat://onboarding` resource before saying anything about onboarding,\nor call the `onboarding_guide` tool if the client does not support resources —\npass `site_url` to get the methods that site's property form actually accepts.\nBoth are read-only and present on every server, including read-only ones, and\n`POST /v1/onboarding-guides` serves the same document over REST.\n\nCheck what already exists before creating anything. `accounts_list` shows how\nmany resources each account carries; `google_sites_list` lists the Search Console\nproperties the credential sees upstream, broader than the cached boundary; and\n`site_ownership_check` reports whether Google and Bing already treat the site as\nverified. A site that is already a verified Search Console and Bing property does\nnot need onboarding — onboarding always resolves or creates a GA4 property. When\nyou only need Rankrat to operate on existing properties, register them in the\naccount's `search_console_sites`, `pagespeed_sites`, and Bing `sites` inventory\nin `boundaries.json`, plus the site's zone in the Cloudflare `dns_zones` if you\nwill DNS-verify Bing, then restart so the boundary reloads. A Bing site stays\nunverified until `site_ownership_verify` or a manual method redeems its proof,\nand Bing rejects sitemap writes until then.\n\nIf the user has no GA4 account yet, do not attempt to create one and do not\nguess the steps. No tool can create a GA4 account — the Admin API has no\n`accounts.create`, and the flow ends at a Terms of Service page. The guide's\n`manual_provisioning` block carries the start URL and the exact ordered clicks;\nrelay those, then ask the user for the numeric account ID, which\n`google_analytics_account_inventory` can also read back once it exists.\n\nCreating provider resources and proving ownership are separate. When a DNS\nprovider account is configured, call `site_ownership_verify` after onboarding,\nthen poll `site_ownership_check` until `complete` is true. Cloudflare is the\ncurrently shipped DNS adapter; without a supported adapter, the guide lists the\nmanual methods accepted by the property form. Site onboarding does not deploy a\nGA4 tag, but writable typed Tag Manager tools can do so when the caller supplies\nan explicit container, workspace, tag definition, version, and publication\nrequest. Rankrat still cannot create a GA4 account. `site_onboarding_submit`\nexists in writable mode; when the process is read-only, guide the user through a\nseparate writable Rankrat process or the `rankrat onboard-site` terminal command.\n\nTypical flow for \"why did traffic drop\":\n\n1. `google_search_analytics_summary` — establish the baseline.\n2. `google_search_analytics_comparison` — the affected period against the prior one.\n3. `google_search_analytics_drop_attribution` — which queries and pages account for it.\n4. `google_url_inspection` on the worst pages — whether it is an indexing problem.\n\nTool names are prefixed by provider (`google_*`, `bing_*`), with a handful of\nserver-level ones (`server_info`, `accounts_list`, `sites_list`, `diagnostics`,\n`provider_readiness`). The complete grouped tool catalog, environment, and\ncredential setup live in [`references/setup.md`](references/setup.md).\n\nFile v0.20.0:_meta.json\n\n{\n  \"ownerId\": \"kn79dhvmpjng4rp2jjk8k0v5xx80ccbk\",\n  \"slug\": \"rankrat\",\n  \"version\": \"0.20.0\",\n  \"publishedAt\": 1786950398759\n}\n\nFile v0.20.0:references/setup.md\n\n# rankrat — setup reference\n\nEverything the [skill](../SKILL.md) needs but does not need loaded up front:\nconfiguration, credentials, and how to run it.\n\nThis file is the self-contained agent reference shipped with the skill. Human\noperators can use the topic-based\n[public manual](https://github.com/psyb0t/rankrat/tree/main/docs), especially\n[Getting started](https://github.com/psyb0t/rankrat/blob/main/docs/getting-started.md),\n[Providers and credentials](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md),\nand [Troubleshooting](https://github.com/psyb0t/rankrat/blob/main/docs/troubleshooting.md).\n\n## Contents\n\n- [Configuration](#configuration)\n- [The boundary file](#the-boundary-file)\n- [Write access](#write-access)\n- [Guided setup](#guided-setup)\n- [Provider credentials](#provider-credentials)\n- [Running it](#running-it)\n- [Onboarding](#onboarding)\n- [Complete MCP tool catalog](#complete-mcp-tool-catalog)\n- [Checking it works](#checking-it-works)\n\n## Configuration\n\nAll settings are read from the environment with the `RANKRAT_` prefix, so a\nfield named `http_port` is set by `RANKRAT_HTTP_PORT`. The defaults below are\nthe ones in the settings model, not example values.\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `RANKRAT_HTTP_HOST` | `127.0.0.1` | Listen address in `http` mode. Loopback by default — bind wider only deliberately. |\n| `RANKRAT_HTTP_PORT` | `8080` | Listen port in `http` mode. |\n| `RANKRAT_BOUNDARY_FILE` | `/run/config/boundaries.json` | Provider accounts plus discovered resource inventory and URL-containment roots. |\n| `RANKRAT_SECRET_ROOT` | `/run/secrets` | Directory holding provider credentials. |\n| `RANKRAT_OAUTH_TOKEN_ROOT` | `/run/oauth` | Directory holding stored Google OAuth tokens. |\n| `RANKRAT_LOG_FILE` | `/tmp/rankrat/rankrat.log` | Log destination. |\n| `RANKRAT_LOG_LEVEL` | `INFO` | Standard Python log levels. |\n| `RANKRAT_LIGHTHOUSE_WORKER_SOCKET` | `/run/lighthouse/lighthouse.sock` | Optional Unix socket for the isolated local Lighthouse worker. Empty disables it. |\n| `RANKRAT_STATE_DATABASE` | unset | Absolute SQLite path for monitors, snapshots, and issue events. Empty/unset disables persistence. The wrapper sets `/run/state/rankrat.sqlite3`. |\n| `RANKRAT_SCHEDULER_INTERVAL_SECONDS` | `60` | How often the HTTP process claims due monitors; accepted range 10–3600 seconds. |\n| `RANKRAT_STATE_RETENTION_DAYS` | `180` | Snapshot/event retention after a monitor run; accepted range 1–3650 days. |\n| `RANKRAT_ENABLE_OPENAPI` | `false` | Serve the OpenAPI document. |\n| `RANKRAT_READ_ONLY` | `false` | See \"Write access\" below. |\n| `RANKRAT_HTTP_BEARER_SECRET_FILE` | unset | File holding the bearer token required on HTTP requests. Unset means no auth, so only do that on loopback. |\n\nThe supported names and safe defaults are in `.env.example`. Invalid values for\nsupported settings fail startup instead of being silently accepted.\n`make run-http` always supplies a bearer-secret file, including for loopback\nuse; a custom loopback launch may deliberately omit it.\n\n`RANKRAT_DATA_DIR` is an optional compatibility environment override consumed\nby host launchers, not by the Python process. Prefer the explicit\n`rankrat --data-dir /absolute/profile ...` form when choosing a non-default\nprofile. The profile contains `config/boundaries.json`, `secrets/`, `oauth/`,\n`state/`, and, for HTTP, an operator-owned `docker-compose.yml`. `rankrat setup`\ncreates every required path and secret safely; do not create a profile tree or\ncopy an example file by hand. With no override, launchers use\n`$HOME/.config/rankrat` and never mount the root wholesale.\n\n## The boundary file\n\n`boundaries.json` fixes credential accounts and records resource inventory.\nEach credential authorizes every supported operation and resource that its\nprovider account can reach. Resource arrays cache discovered sites, properties,\nzones, and targets; they are not per-resource permission lists. Fixed provider\norigins, public-URL validation, and child-URL containment remain enforced.\nWritable discovery and onboarding persist inventory only after the config mount\npasses ownership and mode checks.\n\n## Write access\n\n`RANKRAT_READ_ONLY` defaults to `false`. The trusted caller gets direct access\nto every supported operation permitted by each configured provider account.\nThis is the only capability switch. HTTP uses its normal bearer for transport\nauthentication; stdio access is controlled by who can start the process and\nread its mounts.\n\nSet it to `true` and the effect is stronger than a refusal at call time: write\ntools are absent from `tools/list` and REST write routes are not mounted. An\nagent cannot discover them, let alone call them.\nWrites cover IndexNow submission, Bing URL/sitemap/property changes, Google\nIndexing notifications, Search Console site/sitemap changes, DNS-provider-backed\nownership verification, discovery remediation, and new-site onboarding, and\nmonitor lifecycle operations plus typed Google Tag Manager changes, safe Bing\ncontent submission, provider-neutral managed edge redirects, and finite\nCloudflare cache purges/templates, and are marked as writes in MCP. The human\nmay operate Rankrat interactively or delegate fully autonomous work; use\nread-only mode when that caller must not mutate provider or local state.\n\n## Guided setup\n\nFrom a checkout, the human runs one command:\n\n```bash\nmake setup\n```\n\nThe command initializes owner-only `config/`, `secrets/`, `oauth/`, and\n`state/` paths without replacing existing values. It asks for a comma-separated\nprovider set, prints each provider's credential console and account-wide\npermissions, then accepts secrets through non-echoing prompts. Standard paths\nare used automatically:\n\nReruns are additive. Selected providers are added or refreshed in place;\nunselected provider accounts and their inventory are preserved. When a\nselected provider has multiple account entries, setup rejects the ambiguous\nrefresh before asking for a secret; edit `config/boundaries.json` to identify\nthe intended account first.\n\n| Provider | Host credential path |\n|---|---|\n| Google | `secrets/google/oauth-client.json` |\n| Bing | `secrets/bing/api-key` |\n| Cloudflare | `secrets/cloudflare/api-token` |\n| Microsoft Clarity | `secrets/clarity/api-token` |\n\nGoogle accepts only an installed/Desktop OAuth client JSON. The same setup\ncommand prints the consent URL, waits for the loopback callback, and stores the\nfull Rankrat grant under `oauth/`. PageSpeed's separate API key is prompted at\nthe same time because that API does not use OAuth.\n\nAfter storage, setup runs account readiness. It does not create site properties,\nsubmit sitemaps/URLs, or send IndexNow notifications. Secret values are never\nprinted or written into `.env`.\n\n## Provider credentials\n\nEach provider is optional. Read tools stay discoverable regardless of local\ncredential state and return a finite unavailable/configuration error when their\nprovider cannot run. Ask `provider_readiness` which providers are live rather\nthan inferring it from discovery or an empty result. Write tools are the\nexception: they are absent unless writable mode enables them.\n\n- **Google Search Console / Google Analytics 4 / Google Tag Manager / Google\n  Indexing** — create a Google project and Desktop OAuth client JSON using the\n  exact [Google OAuth guide](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md#google-oauth).\n  Run setup and paste the client JSON's single line at the hidden prompt:\n\n  ```sh\n  rankrat setup\n  ```\n\n  The CLI validates the pasted JSON, writes it into `RANKRAT_SECRET_ROOT`, runs\n  one authorization flow, and stores the resulting token under\n  `RANKRAT_OAUTH_TOKEN_ROOT`. It\n  requests Search Console management, Google Indexing, GA4 read/edit, and Tag\n  Manager container edit, delete, version-edit, and publish scopes; provider-side\n  ownership still controls what the account can do.\n- **Bing Webmaster Tools** — open\n  [Bing Webmaster Tools](https://www.bing.com/webmasters/home), add and verify\n  one site, then **Settings → API Access → API Key → Generate API Key**. The\n  resulting key is account-wide, not site-specific; setup stores it under\n  `RANKRAT_SECRET_ROOT`.\n- **Cloudflare** — create one dedicated **User API Token**, not an Account API\n  Token: [open User API Tokens](https://dash.cloudflare.com/profile/api-tokens)\n  → **Create Token → Create Custom Token** → name it `rankrat`. Add **Zone →\n  Zone → Read**, **Zone → DNS → Edit**, **Zone → Analytics → Read**, **Zone →\n  Cache Purge → Purge**, **Zone → Cache Rules → Edit**, **Zone → Single\n  Redirect → Edit**, **Account → Account Rulesets → Edit**, and **Account →\n  Account Filter Lists → Edit**. Set **Zone Resources → Include → All zones**\n  and **Account Resources → Include → All accounts**, then **Continue to\n  summary → Create Token**. Copy the one-time value into Rankrat's hidden\n  prompt. This covers all current Cloudflare features. Rankrat discovers zone\n  IDs; it exposes no arbitrary DNS record, whole-zone purge, arbitrary\n  cache-rule body, or arbitrary ruleset replacement. Ownership records are\n  DNS-only and untagged, so no Cloudflare DNS-tag quota is needed. Readiness\n  confirms account reachability but deliberately does not create a throwaway\n  record to test DNS write access.\n- **Microsoft Clarity** — open [Microsoft Clarity](https://clarity.microsoft.com/),\n  choose a project, then **Settings → Data Export → Generate new API token**.\n  The token belongs to that project; setup stores it at the configured account\n  credential path. One Clarity account represents one project and is read-only\n  in Rankrat. The upstream API allows at most ten requests per project/day; see\n  [Microsoft's documentation](https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-data-export-api).\n- **PageSpeed Insights and CrUX** — setup separately asks for one optional API\n  key. Create it through [Google API Credentials](https://console.cloud.google.com/apis/credentials)\n  and restrict it to **PageSpeed Insights API** and **Chrome UX Report API**.\n  OAuth does not grant it. Without the key, PageSpeed runs under a tighter\n  anonymous quota and `crux_history` is unavailable.\n- **Local Lighthouse** — no credential. The optional companion image receives\n  only a shared Unix socket and outbound browser network access. Rankrat accepts\n  only requested URLs beneath the account's `pagespeed_sites` and rejects a\n  report whose final URL escapes that boundary. A public cross-origin redirect\n  can be fetched before this post-navigation check, while private and special\n  destinations are blocked by the worker's enforced proxy.\n\nCredentials stay on the host running rankrat. They are used to call the provider\nAPIs over HTTPS and are not sent anywhere else.\n\n## Running it\n\nAn agent runs the published image directly. A human creates the profile,\ncredentials, and Google authorization with `rankrat setup` beforehand — after\ninstalling the launcher. Download the installer, read it, then run it, per-user\n(no root) or system-wide:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/psyb0t/rankrat/main/install.sh -o rankrat-install.sh\nless rankrat-install.sh\nbash rankrat-install.sh                # per-user   -> ~/.local/bin/rankrat\nsudo bash rankrat-install.sh --system  # system-wide -> /usr/local/bin/rankrat\n```\n\nThe single public launcher is named `rankrat`; it is not duplicated into agent\nskills, so the shipped code cannot drift from what operators install:\n\n```bash\nrankrat --data-dir /absolute/path/to/rankrat-profile stdio\nrankrat --data-dir /absolute/path/to/rankrat-profile http       # attached Rankrat + Lighthouse\nrankrat --data-dir /absolute/path/to/rankrat-profile http -d    # detached, restart unless stopped\n```\n\nHTTP treats the profile as its Compose project directory. It atomically creates\nthe embedded reviewed `docker-compose.yml` when absent, preserves an existing\nsafe regular file, rejects symlinked/non-regular paths, and exports the chosen\nimage, port, UID/GID, and read-only values from its environment. The project\ndirectory and Compose file must be owned by the current UID and not group/world\nwritable. Only the four fixed children below are mounted into containers.\n\nBoth transports take the same four mounts. Container-side paths are the\nserver's defaults, so only the host side changes:\n\n| Host | Container | Access | Holds |\n|---|---|---|---|\n| `$RANKRAT_DATA_DIR/config` | `/run/config` | writable normally; read-only with `RANKRAT_READ_ONLY=true` | account registry and inventory |\n| `$RANKRAT_DATA_DIR/secrets` | `/run/secrets` | read-only | provider credentials, HTTP bearer secret |\n| `$RANKRAT_DATA_DIR/oauth` | `/run/oauth` | writable | stored Google OAuth token; refresh may rotate it |\n| `$RANKRAT_DATA_DIR/state` | `/run/state` | writable, owner-only | SQLite monitor definitions, snapshots, issues, and events |\n\n**stdio** — the default mode, for a client that owns the process:\n\n```bash\ndocker run -i --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat stdio\n```\n\n**Manual single-container Streamable HTTP** — for a shared server that does not\nneed local Lighthouse. MCP lands at `/mcp` and the REST API shares the port:\n\n```bash\ndocker run --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  -p 127.0.0.1:8080:8080 \\\n  -e RANKRAT_HTTP_HOST=0.0.0.0 \\\n  -e RANKRAT_HTTP_BEARER_SECRET_FILE=/run/secrets/rankrat/http-bearer-token \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat http\n```\n\n`RANKRAT_HTTP_HOST=0.0.0.0` binds inside the container while `-p` keeps it on\nloopback. MCP is then at `http://127.0.0.1:8080/mcp`; send\n`Authorization: Bearer <token>` whenever a bearer secret is configured.\n\nThe commands above use the writable default. Before mounting config writable,\nverify that the resolved directory is owner-only, `boundaries.json` is not a\nsymlink, both are owned by the current UID, and the file is not group- or\nworld-writable. The public `rankrat` launcher performs those checks. The OpenClaw\nlauncher additionally rejects symlinked path components. For a read-only\ncaller, set `RANKRAT_READ_ONLY=true` and make only `/run/config` read-only.\nNever make the provider-secret mount writable during normal service operation.\n\nLocal Lighthouse audits require the separate published browser image. Start it\nonce against a private named volume:\n\n```bash\ndocker volume create rankrat-lighthouse-runtime\ndocker run --rm --network none --user 0:0 --read-only \\\n  --cap-drop=ALL --cap-add=CHOWN --cap-add=FOWNER \\\n  --security-opt no-new-privileges:true \\\n  --pids-limit 16 --memory 64m --cpus 0.25 \\\n  --mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse \\\n  --entrypoint /bin/sh psyb0t/rankrat-lighthouse \\\n  -c 'chmod 1777 /run/lighthouse && touch /run/lighthouse/.initialized && chown -R 10001:10001 /run/lighthouse && chmod 0750 /run/lighthouse'\ndocker run --rm -d --name rankrat-lighthouse-worker --init --read-only \\\n  --user 10001:10001 --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 256 --memory 2g --cpus 2 --shm-size 1g \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=1g,mode=1777 \\\n  --mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse \\\n  psyb0t/rankrat-lighthouse\n```\n\nThe self-removing initializer assigns the private volume root to the non-root\nUID shared by Rankrat and the worker. When using a different UID/GID, change the\ninitializer's `chown` pair and the worker's `--user` pair to the same values.\nRun Rankrat under that pair as well if the primary image's built-in `10001:10001`\nuser is overridden. The provided Compose file applies `RANKRAT_UID` and\n`RANKRAT_GID` consistently to both long-lived services after running this\nhardened initializer.\n\nAdd this read-only volume mount to either published Rankrat invocation above:\n\n```bash\n--mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse,readonly\n```\n\nThe normal `psyb0t/rankrat stdio` command then exposes the five Lighthouse tools\nover stdio. The normal `psyb0t/rankrat http` command exposes the same tools over\nStreamable HTTP at `/mcp` and REST under `/v1/lighthouse/`. Leave\n`RANKRAT_LIGHTHOUSE_WORKER_SOCKET` empty to disable the worker explicitly. Stop\nand remove only the worker and volume you created when they are no longer\nneeded.\n\nThe worker is for pages you control and trust. Chromium runs with\n`--no-sandbox` because its built-in namespace/setuid sandbox cannot coexist with\nthe documented non-root, capability-free, `no-new-privileges` container. The\ncredential-free, read-only worker and public-address-only proxy reduce blast\nradius but do not replace the renderer sandbox after a browser exploit. Use an\nouter sandbox such as gVisor or Kata Containers before auditing hostile content.\n\n| MCP tool | REST route |\n|---|---|\n| `lighthouse_audit` | `POST /v1/lighthouse/audits` |\n| `lighthouse_seo_findings` | `POST /v1/lighthouse/seo-findings` |\n| `lighthouse_accessibility_findings` | `POST /v1/lighthouse/accessibility-findings` |\n| `lighthouse_performance_findings` | `POST /v1/lighthouse/performance-findings` |\n| `lighthouse_best_practices_findings` | `POST /v1/lighthouse/best-practices-findings` |\n\nEvery operation accepts the same strict body: `account_id`, a configured\n`site_url`, a child `page_url`, and optional `timeout_seconds` in the inclusive\n5–300 second range. The aggregate audit returns all four category scores and\nfailed findings; the other four operations return only that category's failed\nfindings.\n\n## Onboarding\n\n`site_onboarding_submit` is part of normal writable mode. It creates or reuses\nGA4, Search Console, and Bing resources, then records discovered IDs in the\nconfig file. It is absent from `tools/list` and REST when\n`RANKRAT_READ_ONLY=true`. The config directory must be safely writable; the\nbundled wrapper validates its ownership/mode.\n\nThe guidance is available either way, read-only, on every server:\n\n| Surface | What it gives |\n|---|---|\n| `rankrat://onboarding` resource | The whole procedure and this server's onboarding posture |\n| `rankrat://onboarding/{site_url}` template | Same, narrowed to one percent-encoded site |\n| `onboarding_guide` tool | The identical document, for clients without resource support |\n\nWith a configured DNS provider account, `site_ownership_verify` requests the\nreal Google TXT and Bing CNAME proofs, publishes only those records through the\nadapter selected by the account's `provider`, checks public DNS, and redeems\neach provider. Poll `site_ownership_check` until it reports `complete`; DNS\npropagation is asynchronous. Cloudflare is the currently shipped DNS adapter.\nWithout a supported adapter, a `sc-domain:` property accepts only DNS TXT,\nwhile a `https://` URL-prefix property also accepts the GA4 tag, an HTML file,\nor a meta tag.\n\nThe SEO expansion has the same names over stdio and Streamable HTTP MCP:\n\n| MCP tool | REST route |\n|---|---|\n| `site_ownership_check` | `POST /v1/site-ownership-checks` |\n| `site_ownership_verify` | `POST /v1/site-ownership-verifications` |\n| `site_audit` | `POST /v1/site-audits` |\n| `site_remediation_apply` | `POST /v1/site-remediations` |\n| `bing_backlink_intelligence` | `POST /v1/bing/backlink-intelligence` |\n| `internal_link_graph` | `POST /v1/internal-link-graphs` |\n| `orphan_page_report` | `POST /v1/orphan-page-reports` |\n| `internal_link_opportunities` | `POST /v1/internal-link-opportunity-reports` |\n| `crux_history` | `POST /v1/crux/history-reports` |\n| `cloudflare_analytics` | `POST /v1/cloudflare/analytics-reports` |\n| `content_opportunities` | `POST /v1/content-opportunity-reports` |\n\n## Complete MCP tool catalog\n\n`tools/list` is authoritative for a running server because startup settings\ndecide which tools exist. The grouped inventory below mirrors the tool catalog\nin the source. The exact REST paths and schemas live in the committed\n[merged OpenAPI document](https://github.com/psyb0t/rankrat/blob/main/openapi.json),\ncomposed from the\n[base](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/openapi.yaml)\nand\n[SEO intelligence](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/seo-openapi.yaml)\nand\n[free provider SEO](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/free-seo-openapi.yaml)\nYAML sources. When enabled, the runtime `/openapi.json` removes write routes\nfrom a read-only server.\n\n### Read-only tools\n\n- **Server, boundaries, and guidance:** `server_info`, `accounts_list`,\n  `sites_list`, `diagnostics`, `provider_readiness`, `onboarding_guide`.\n- **Site, ownership, schema, links, and opportunities:** `site_audit`,\n  `site_ownership_check`, `schema_validate_url`, `schema_validate_html`,\n  `schema_validate_json_ld`, `bing_backlink_intelligence`,\n  `internal_link_graph`, `orphan_page_report`,\n  `internal_link_opportunities`, `content_opportunities`.\n- **Persistent monitoring:** `monitors_list`, `monitor_snapshots_list`,\n  `monitor_issues_list`, `issue_events_list`.\n- **Google Search Console and Indexing metadata:**\n  `google_search_analytics_summary`, `google_search_analytics_comparison`,\n  `google_search_analytics_dimension_report`,\n  `google_search_analytics_drop_attribution`, `google_search_analytics_trend`,\n  `google_search_analytics_anomalies`,\n  `google_search_analytics_page_performance`,\n  `google_search_analytics_query`, `google_sites_list`, `google_site_get`,\n  `google_sitemaps_list`, `google_sitemap_get`, `google_url_inspection`,\n  `google_url_inspection_batch`, `google_indexing_metadata`.\n- **Google Analytics 4:** `google_analytics_account_inventory`,\n  `google_analytics_data_streams`, `google_analytics_report`,\n  `google_analytics_realtime_report`, `google_analytics_content_performance`,\n  `google_analytics_landing_page_performance`,\n  `google_analytics_organic_search_landing_pages`,\n  `google_analytics_traffic_source_performance`,\n  `google_analytics_ecommerce_performance`,\n  `google_analytics_audience_segments`, `google_analytics_user_behavior`,\n  `google_analytics_conversion_funnel`.\n- **Google Tag Manager, Microsoft Clarity, and managed redirects:**\n  `google_tag_manager_accounts_list`, `google_tag_manager_containers_list`,\n  `google_tag_manager_workspaces_list`, `google_tag_manager_entities_list`,\n  `clarity_insights`, `edge_redirects_list`.\n- **PageSpeed, CrUX, Cloudflare, and local Lighthouse:** `pagespeed_analyze`,\n  `pagespeed_core_web_vitals`, `lighthouse_audit`,\n  `lighthouse_seo_findings`, `lighthouse_accessibility_findings`,\n  `lighthouse_performance_findings`,\n  `lighthouse_best_practices_findings`, `crux_history`,\n  `cloudflare_analytics`.\n- **Cross-provider analysis:** `ga4_pagespeed_correlation`,\n  `ga4_search_console_comparison`, `search_engine_comparison`,\n  `search_engine_traffic_health`.\n- **Bing Webmaster Tools:** `bing_keyword_statistics`,\n  `bing_related_keywords`, `bing_traffic_trend`, `bing_traffic_anomalies`,\n  `bing_traffic_comparison`, `bing_query_performance`,\n  `bing_page_performance`, `bing_brand_analysis`, `bing_ranking_buckets`,\n  `bing_query_opportunities`, `bing_page_opportunities`,\n  `bing_opportunity_matrix`, `bing_query_page_performance`,\n  `bing_query_cannibalization`, `bing_page_query_performance`,\n  `bing_url_submission_quota`, `bing_crawl_issues`, `bing_crawl_stats`,\n  `bing_feeds`, `bing_link_counts`, `bing_url_information`.\n\n### Writable tools\n\nThese appear only when `RANKRAT_READ_ONLY=false`:\n\n- **IndexNow:** `indexnow_submit`. IndexNow is an open change-notification\n  protocol, not a dashboard: one participating endpoint shares an accepted\n  notification with the other participating engines, while each engine makes\n  its own crawl and indexing decisions.\n- **Bing:** `bing_url_submit`, `bing_sitemap_submit`, `bing_site_submit`.\n- **Bing content:** `bing_content_submission_create` fetches an allowed public\n  page itself, then submits that fresh HTML to Bing.\n- **Google Search Console and Indexing:** `google_indexing_submit`,\n  `google_indexing_batch_submit`, `google_site_submit`,\n  `google_sitemap_submit`.\n- **Google Analytics 4:** `google_analytics_account_rename`,\n  `google_analytics_property_rename`.\n- **Google Tag Manager:** `google_tag_manager_container_create`,\n  `google_tag_manager_container_delete`, `google_tag_manager_workspace_create`,\n  `google_tag_manager_workspace_delete`, `google_tag_manager_entity_create`,\n  `google_tag_manager_entity_update`, `google_tag_manager_entity_delete`,\n  `google_tag_manager_workspace_version_create`,\n  `google_tag_manager_version_publish`.\n- **Ownership and discovery remediation:** `site_ownership_verify`,\n  `site_remediation_apply`.\n- **Persistent monitoring:** `monitor_create`, `monitor_update`,\n  `monitor_delete`, `monitor_run`, `issue_status_update`.\n- **Cloudflare performance:** `cloudflare_cache_purge`,\n  `cloudflare_cache_template_apply`.\n- **Provider-neutral managed redirects:** `edge_redirect_upsert`,\n  `edge_redirect_delete`. Cloudflare is the currently shipped adapter.\n- **Site onboarding:** `site_onboarding_submit`.\n\n## Checking it works\n\n- `server_info` — the server is up and which mode it is in.\n- `provider_readiness` — which providers are actually configured.\n- `accounts_list` / `sites_list` — the boundary as the server sees it.\n- `diagnostics` — deeper detail when one of the above is not what you expected.\n- `monitors_list` and `monitor_issues_list` — whether scheduled audit history\n  is accumulating and which lifecycle issues remain open.\n\nIf a provider-specific tool returns nothing, check `provider_readiness` before\nassuming the data is missing upstream.\n\nAutomatic due-monitor execution belongs to the long-running HTTP process.\nStdio exposes the same monitor CRUD, manual-run, snapshot, issue, and event\ntools, but its process lifetime is controlled by the MCP client and it does not\nleave a background scheduler behind. Persist `/run/state` for either transport.\nFor backups, use SQLite's online-backup mechanism or stop Rankrat first; copying\nonly a live database file can omit WAL state.\n\nFile v0.20.0:skill-card.md\n\n## Description:\n\nrankrat lets agents query SEO and search analytics providers, run bounded site audits, manage typed tags and safe redirects, and automate site ownership or remediation for sites the operator controls through a self-hosted MCP and HTTP server.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[psyb0t](https://clawhub.ai/user/psyb0t)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, site operators, and SEO teams use rankrat to inspect and improve search visibility, indexing, analytics, site health, internal links, tags, redirects, and performance for websites they control.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Writable mode can mutate provider and local state using powerful configured credentials.\n\nMitigation: Run with RANKRAT_READ_ONLY=true unless the agent is explicitly trusted to make changes, and use least-privilege provider credentials.\n\nRisk: Installation and container examples can rely on mutable remote code or unpinned images while mounting secrets and OAuth state.\n\nMitigation: Review the installer before execution, avoid the sudo installer path where possible, and use pinned or verified container images or a vetted local image.\n\nRisk: Local Lighthouse audits browse operator-selected pages with a Chromium worker that documents a no-sandbox browser configuration.\n\nMitigation: Use the browser worker only for sites the operator controls, and add an outer sandbox such as gVisor or Kata before auditing hostile content.\n\nRisk: Provider API lag or unavailable credentials can make reports incomplete or stale.\n\nMitigation: Check provider_readiness and diagnostics before interpreting empty results, and avoid treating Rankrat as a realtime dashboard.\n\n## Reference(s):\n\n- [rankrat setup reference](references/setup.md)\n- [ClawHub rankrat skill page](https://clawhub.ai/psyb0t/skills/rankrat)\n- [Rankrat public documentation](https://github.com/psyb0t/rankrat/tree/main/docs)\n- [Getting started](https://github.com/psyb0t/rankrat/blob/main/docs/getting-started.md)\n- [Providers and credentials](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md)\n- [Troubleshooting](https://github.com/psyb0t/rankrat/blob/main/docs/troubleshooting.md)\n- [Merged OpenAPI document](https://github.com/psyb0t/rankrat/blob/main/openapi.json)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown guidance, shell command examples, MCP tool calls, and structured API responses]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Outputs depend on configured provider accounts, read-only mode, transport, and optional Lighthouse worker availability.]\n\n## Skill Version(s):\n\n0.20.0 (source: server release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.19.1: 4 files, 18851 bytes\n\nFiles: references/setup.md (27008b), skill-card.md (3487b), SKILL.md (16108b), _meta.json (127b)\n\nFile v0.19.1:SKILL.md\n\n---\nname: rankrat\ndescription: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control.\nhomepage: https://github.com/psyb0t/rankrat\nuser-invocable: true\nmetadata:\n  openclaw:\n    emoji: \"🐀\"\n    requires:\n      bins: [docker]\npermissions:\n  network: \"outbound HTTPS to configured Google Search Console, Google Analytics, Google Tag Manager, Bing Webmaster Tools, Microsoft Clarity, PageSpeed/CrUX, Cloudflare, public DNS, public pages beneath configured sites, and IndexNow endpoints; optional Lighthouse browser traffic to explicitly requested bounded pages; inbound only on the port you bind.\"\n  shell: \"docker run invocations for the published image or the installed rankrat launcher; no other host access is required.\"\n  filesystem: \"reads provider-account config and credentials; writes the configured OAuth token store, persistent SQLite monitor state, locally initialized IndexNow key, and discovered resource inventory in the config file when writable.\"\n---\n\n# rankrat\n\nA self-hosted MCP server over the SEO and search-analytics APIs you already have\naccounts on — Google Search Console, Google Tag Manager, Bing Webmaster Tools,\nGA4, Microsoft Clarity, and PageSpeed Insights — so an agent can read and,\nwhen trusted, manage your own provider resources without you handing it a\nbrowser session or a service-account key.\n\nInstall, credentials and the full environment reference:\n[`references/setup.md`](references/setup.md).\nFor a human-readable operator manual organized by topic, use the public\n[Rankrat documentation](https://github.com/psyb0t/rankrat/tree/main/docs).\n\n## Contents\n\n- [Security and safety](#security-and-safety)\n- [When to use](#when-to-use)\n- [When NOT to use](#when-not-to-use)\n- [Usage](#usage)\n\n## Security and safety\n\nConfigured provider credentials are Rankrat's authority. A Google OAuth account,\nBing key, Cloudflare token, or Clarity project token can reach every supported\nresource that provider exposes to it. Resource arrays in the config are\ndiscovered inventory and URL-containment data, not a second permission system.\nFixed provider origins, typed requests, public-URL validation, and child-URL\ncontainment still apply.\n\nRankrat is **writable by default**. `RANKRAT_READ_ONLY=true` removes every write\ntool from `tools/list` and every write route from runtime OpenAPI, including\nsite onboarding. This is the only capability switch. The human decides whether\nthe caller is a careful human-directed agent or a fully autonomous one; if that\ncaller should not mutate the account, run a read-only process.\n\nYour provider credentials stay on the host running rankrat. Requests go to the\nprovider APIs over HTTPS. The optional Lighthouse companion opens only an\nexplicitly requested page beneath a configured PageSpeed site and receives no\nprovider credentials. Credentials, OAuth records and raw provider bodies are\nnever returned or logged. Bind Rankrat to loopback or a private network, and use\nthe bearer token if anything else can reach it.\n\n## When to use\n\n- Reading Search Console performance: queries, pages, countries, devices, dates\n  — as raw rows, summaries, trends, period comparisons, or anomaly and\n  traffic-drop attribution.\n- Diagnosing indexing: URL inspection (single or batch), sitemap listings,\n  crawl issues, crawl stats.\n- Bing Webmaster Tools equivalents, plus keyword statistics, related keywords,\n  ranking buckets, query/page opportunity reports and cannibalization analysis.\n- GA4 reporting: realtime, content and landing-page performance, organic search\n  landing pages, traffic sources, ecommerce, audience segments, user behavior,\n  conversion funnels.\n- Google Tag Manager account discovery plus typed containers, workspaces, tags,\n  triggers, variables, versions, and publication in writable mode.\n- Microsoft Clarity Data Export project insights in read-only mode.\n- PageSpeed Insights, CrUX history, and fetching a page's structured-data schema.\n- Whole-site crawling for deterministic metadata, canonical, robots, sitemap,\n  duplicate-title, link, and structured-data findings with remediation text.\n- Google/Bing ownership checks and narrowly scoped verification through the\n  configured DNS adapter; Cloudflare is currently supported.\n- IndexNow change notifications for bounded URLs. This is a writable push\n  protocol, not a reporting dashboard or an indexing guarantee.\n- Backlink intelligence from configured Bing Webmaster sites.\n- Internal-link graphs, same-site orphan-page joins, lexical link suggestions\n  limited to pages sharing normalized title/path tokens, and ranked content\n  opportunities joined across search, analytics, and crawl data.\n- Cloudflare hourly traffic/cache analytics, plus exact purges and two finite\n  cache templates in writable mode. Template mutations are serialized per zone\n  within the running Rankrat process.\n- Provider-neutral managed edge redirects. Cloudflare is the current adapter;\n  Rankrat never replaces unrelated provider rulesets.\n- Safe Bing content submission: Rankrat fetches the bounded public HTML page\n  itself rather than accepting caller-provided content or headers.\n- Persistent site-audit monitors, immutable snapshots, issue lifecycle events,\n  and explicit acknowledge/resolve operations. The background scheduler runs\n  only in the long-lived HTTP process; stdio supports explicit monitor runs and\n  history. Poll these tools because Rankrat does not send external notifications.\n- Local Lighthouse performance, accessibility, best-practices, and SEO scores\n  or category-specific failed findings when the companion worker is configured.\n- Checking which providers are actually wired up (`provider_readiness`,\n  `diagnostics`) before trusting a report.\n\n## When NOT to use\n\n- **Sites you don't control.** Everything is scoped to configured provider\n  accounts and site boundaries. It is not a competitor crawler or arbitrary\n  backlink scraper.\n- **A caller that should not have account-wide write access.** Start that caller\n  with `RANKRAT_READ_ONLY=true`; the write schemas will not be discoverable.\n- **Realtime dashboards.** Provider APIs lag (Search Console notably so), and\n  rankrat reports what they return.\n- **Editing an arbitrary CMS or repository.** Audits return deterministic fixes;\n  provider remediation resubmits sitemaps and URLs but does not rewrite pages.\n\n## Usage\n\nBoth MCP transports run from the published image. Read tools have a stable\ndiscovery surface even when their provider is not configured; ask\n`provider_readiness` before interpreting an empty or unavailable result. Only\nwrite-tool discovery changes, and only with `RANKRAT_READ_ONLY`.\n\nThe public `rankrat` launcher keeps stdio as a hardened direct `docker run`\nchild and uses Docker Compose for HTTP so Rankrat and Lighthouse share one\nlifecycle:\n\n```bash\nrankrat --data-dir /absolute/path/to/rankrat-profile stdio\nrankrat --data-dir /absolute/path/to/rankrat-profile http -d\n```\n\nHTTP uses the profile as its Compose project directory. The launcher creates\nthe reviewed `docker-compose.yml` there when missing, preserves an existing\nsafe regular file, and mounts only the fixed profile children—not the root\nitself. The project directory and Compose file must be owned by the current UID\nand not group/world writable.\nOmit `-d` to attach to logs; detached services restart unless stopped.\n\n**stdio** is the default mode, so a client that spawns its own server just runs\nthe image and talks to it — no port, no bridge:\n\n```bash\nexport RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run -i --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat stdio\n```\n\n**Manual single-container Streamable HTTP** is available when local Lighthouse\nis not needed. MCP is at `/mcp`, and the REST API is on the same port:\n\n```bash\nexport RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  -p 127.0.0.1:8080:8080 \\\n  -e RANKRAT_HTTP_HOST=0.0.0.0 \\\n  -e RANKRAT_HTTP_BEARER_SECRET_FILE=/run/secrets/rankrat/http-bearer-token \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat http\n```\n\n`RANKRAT_HTTP_HOST=0.0.0.0` binds inside the container; the `-p` publishes it on\nloopback only. Send `Authorization: Bearer <token>` when a bearer secret is\nconfigured.\n\nThese examples use the writable default, so config inventory can be updated.\nGoogle OAuth storage is writable because token refresh may rotate and persist a\nrefresh token; provider secrets stay read-only. For a read-only agent, set\n`RANKRAT_READ_ONLY=true` and make the config mount read-only as described in the\nsetup reference.\n\nThe repository ships one public launcher named `rankrat`; install it before\nasking an agent to use a human-managed profile. It uses direct Docker for\nstdio/operator commands and Compose for HTTP; agents can still invoke either\nimage directly. Omit `--data-dir` for the default `$HOME/.config/rankrat`\nprofile. A chosen profile's fixed `config/`, `secrets/`, `oauth/`, and `state/`\nchildren preserve provider sessions and inventory when launched from different\nsite repositories.\n\nThe one-container manual examples return `UNAVAILABLE` for Lighthouse because\nChromium is deliberately isolated in `psyb0t/rankrat-lighthouse`. Use the\nwrapper's Compose-backed HTTP mode or the published two-image commands in\n`references/setup.md` when local browser audits are required. The worker shares\nonly a Unix socket and receives no provider credential mounts.\n\nUse the browser worker only for operator-controlled sites. Its documented\nnon-root, capability-free container needs Chromium's `--no-sandbox`; a hostile\npage therefore requires a stronger outer sandbox such as gVisor or Kata. The\nworker blocks private/special-address egress, while public cross-origin\nsubresources—and a public redirect before Rankrat rejects its final URL—remain\npossible.\n\nThe browser surface is exactly `lighthouse_audit`,\n`lighthouse_seo_findings`, `lighthouse_accessibility_findings`,\n`lighthouse_performance_findings`, and\n`lighthouse_best_practices_findings`. Every call takes `account_id`, a\nconfigured `site_url`, a child `page_url`, and an optional timeout from 5 to 300\nseconds. The REST equivalents live under `/v1/lighthouse/`.\n\n### Finding where a site lives, and matching its tag\n\nGA4 nests every property under an *account*, and properties routinely sit under\nan unrelated one because that is whatever the dropdown defaulted to when they\nwere created. `google_analytics_account_inventory` lists every account the\ncredential can see with its properties — that is the tool for \"which account is\nthis site under\", and the answer is often surprising.\n\n`google_analytics_data_streams` returns a configured property's streams and their\n`G-` measurement IDs. Use it before telling anyone their tag is installed\ncorrectly: a tag whose measurement ID belongs to a different property looks\nperfectly installed and reports into a property nobody is reading.\n\n`google_analytics_account_rename` and `google_analytics_property_rename` exist in\nwritable mode. Account names are cosmetic — the numeric ID is what boundaries,\nmeasurement IDs and reports bind to — so renaming is safe and is the usual fix\nfor a misfiled property. There is no GA4 account-creation or Analytics deletion\ntool. Property creation is available through writable site onboarding.\n\n### Onboarding a site\n\nRead the `rankrat://onboarding` resource before saying anything about onboarding,\nor call the `onboarding_guide` tool if the client does not support resources —\npass `site_url` to get the methods that site's property form actually accepts.\nBoth are read-only and present on every server, including read-only ones, and\n`POST /v1/onboarding-guides` serves the same document over REST.\n\nCheck what already exists before creating anything. `accounts_list` shows how\nmany resources each account carries; `google_sites_list` lists the Search Console\nproperties the credential sees upstream, broader than the cached boundary; and\n`site_ownership_check` reports whether Google and Bing already treat the site as\nverified. A site that is already a verified Search Console and Bing property does\nnot need onboarding — onboarding always resolves or creates a GA4 property. When\nyou only need Rankrat to operate on existing properties, register them in the\naccount's `search_console_sites`, `pagespeed_sites`, and Bing `sites` inventory\nin `boundaries.json`, plus the site's zone in the Cloudflare `dns_zones` if you\nwill DNS-verify Bing, then restart so the boundary reloads. A Bing site stays\nunverified until `site_ownership_verify` or a manual method redeems its proof,\nand Bing rejects sitemap writes until then.\n\nIf the user has no GA4 account yet, do not attempt to create one and do not\nguess the steps. No tool can create a GA4 account — the Admin API has no\n`accounts.create`, and the flow ends at a Terms of Service page. The guide's\n`manual_provisioning` block carries the start URL and the exact ordered clicks;\nrelay those, then ask the user for the numeric account ID, which\n`google_analytics_account_inventory` can also read back once it exists.\n\nCreating provider resources and proving ownership are separate. When a DNS\nprovider account is configured, call `site_ownership_verify` after onboarding,\nthen poll `site_ownership_check` until `complete` is true. Cloudflare is the\ncurrently shipped DNS adapter; without a supported adapter, the guide lists the\nmanual methods accepted by the property form. Site onboarding does not deploy a\nGA4 tag, but writable typed Tag Manager tools can do so when the caller supplies\nan explicit container, workspace, tag definition, version, and publication\nrequest. Rankrat still cannot create a GA4 account. `site_onboarding_submit`\nexists in writable mode; when the process is read-only, guide the user through a\nseparate writable Rankrat process or the `rankrat onboard-site` terminal command.\n\nTypical flow for \"why did traffic drop\":\n\n1. `google_search_analytics_summary` — establish the baseline.\n2. `google_search_analytics_comparison` — the affected period against the prior one.\n3. `google_search_analytics_drop_attribution` — which queries and pages account for it.\n4. `google_url_inspection` on the worst pages — whether it is an indexing problem.\n\nTool names are prefixed by provider (`google_*`, `bing_*`), with a handful of\nserver-level ones (`server_info`, `accounts_list`, `sites_list`, `diagnostics`,\n`provider_readiness`). The complete grouped tool catalog, environment, and\ncredential setup live in [`references/setup.md`](references/setup.md).\n\nFile v0.19.1:_meta.json\n\n{\n  \"ownerId\": \"kn79dhvmpjng4rp2jjk8k0v5xx80ccbk\",\n  \"slug\": \"rankrat\",\n  \"version\": \"0.19.1\",\n  \"publishedAt\": 1786947034666\n}\n\nFile v0.19.1:references/setup.md\n\n# rankrat — setup reference\n\nEverything the [skill](../SKILL.md) needs but does not need loaded up front:\nconfiguration, credentials, and how to run it.\n\nThis file is the self-contained agent reference shipped with the skill. Human\noperators can use the topic-based\n[public manual](https://github.com/psyb0t/rankrat/tree/main/docs), especially\n[Getting started](https://github.com/psyb0t/rankrat/blob/main/docs/getting-started.md),\n[Providers and credentials](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md),\nand [Troubleshooting](https://github.com/psyb0t/rankrat/blob/main/docs/troubleshooting.md).\n\n## Contents\n\n- [Configuration](#configuration)\n- [The boundary file](#the-boundary-file)\n- [Write access](#write-access)\n- [Guided setup](#guided-setup)\n- [Provider credentials](#provider-credentials)\n- [Running it](#running-it)\n- [Onboarding](#onboarding)\n- [Complete MCP tool catalog](#complete-mcp-tool-catalog)\n- [Checking it works](#checking-it-works)\n\n## Configuration\n\nAll settings are read from the environment with the `RANKRAT_` prefix, so a\nfield named `http_port` is set by `RANKRAT_HTTP_PORT`. The defaults below are\nthe ones in the settings model, not example values.\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `RANKRAT_HTTP_HOST` | `127.0.0.1` | Listen address in `http` mode. Loopback by default — bind wider only deliberately. |\n| `RANKRAT_HTTP_PORT` | `8080` | Listen port in `http` mode. |\n| `RANKRAT_BOUNDARY_FILE` | `/run/config/boundaries.json` | Provider accounts plus discovered resource inventory and URL-containment roots. |\n| `RANKRAT_SECRET_ROOT` | `/run/secrets` | Directory holding provider credentials. |\n| `RANKRAT_OAUTH_TOKEN_ROOT` | `/run/oauth` | Directory holding stored Google OAuth tokens. |\n| `RANKRAT_LOG_FILE` | `/tmp/rankrat/rankrat.log` | Log destination. |\n| `RANKRAT_LOG_LEVEL` | `INFO` | Standard Python log levels. |\n| `RANKRAT_LIGHTHOUSE_WORKER_SOCKET` | `/run/lighthouse/lighthouse.sock` | Optional Unix socket for the isolated local Lighthouse worker. Empty disables it. |\n| `RANKRAT_STATE_DATABASE` | unset | Absolute SQLite path for monitors, snapshots, and issue events. Empty/unset disables persistence. The wrapper sets `/run/state/rankrat.sqlite3`. |\n| `RANKRAT_SCHEDULER_INTERVAL_SECONDS` | `60` | How often the HTTP process claims due monitors; accepted range 10–3600 seconds. |\n| `RANKRAT_STATE_RETENTION_DAYS` | `180` | Snapshot/event retention after a monitor run; accepted range 1–3650 days. |\n| `RANKRAT_ENABLE_OPENAPI` | `false` | Serve the OpenAPI document. |\n| `RANKRAT_READ_ONLY` | `false` | See \"Write access\" below. |\n| `RANKRAT_HTTP_BEARER_SECRET_FILE` | unset | File holding the bearer token required on HTTP requests. Unset means no auth, so only do that on loopback. |\n\nThe supported names and safe defaults are in `.env.example`. Invalid values for\nsupported settings fail startup instead of being silently accepted.\n`make run-http` always supplies a bearer-secret file, including for loopback\nuse; a custom loopback launch may deliberately omit it.\n\n`RANKRAT_DATA_DIR` is an optional compatibility environment override consumed\nby host launchers, not by the Python process. Prefer the explicit\n`rankrat --data-dir /absolute/profile ...` form when choosing a non-default\nprofile. The profile contains `config/boundaries.json`, `secrets/`, `oauth/`,\n`state/`, and, for HTTP, an operator-owned `docker-compose.yml`. `rankrat setup`\ncreates every required path and secret safely; do not create a profile tree or\ncopy an example file by hand. With no override, launchers use\n`$HOME/.config/rankrat` and never mount the root wholesale.\n\n## The boundary file\n\n`boundaries.json` fixes credential accounts and records resource inventory.\nEach credential authorizes every supported operation and resource that its\nprovider account can reach. Resource arrays cache discovered sites, properties,\nzones, and targets; they are not per-resource permission lists. Fixed provider\norigins, public-URL validation, and child-URL containment remain enforced.\nWritable discovery and onboarding persist inventory only after the config mount\npasses ownership and mode checks.\n\n## Write access\n\n`RANKRAT_READ_ONLY` defaults to `false`. The trusted caller gets direct access\nto every supported operation permitted by each configured provider account.\nThis is the only capability switch. HTTP uses its normal bearer for transport\nauthentication; stdio access is controlled by who can start the process and\nread its mounts.\n\nSet it to `true` and the effect is stronger than a refusal at call time: write\ntools are absent from `tools/list` and REST write routes are not mounted. An\nagent cannot discover them, let alone call them.\nWrites cover IndexNow submission, Bing URL/sitemap/property changes, Google\nIndexing notifications, Search Console site/sitemap changes, DNS-provider-backed\nownership verification, discovery remediation, and new-site onboarding, and\nmonitor lifecycle operations plus typed Google Tag Manager changes, safe Bing\ncontent submission, provider-neutral managed edge redirects, and finite\nCloudflare cache purges/templates, and are marked as writes in MCP. The human\nmay operate Rankrat interactively or delegate fully autonomous work; use\nread-only mode when that caller must not mutate provider or local state.\n\n## Guided setup\n\nFrom a checkout, the human runs one command:\n\n```bash\nmake setup\n```\n\nThe command initializes owner-only `config/`, `secrets/`, `oauth/`, and\n`state/` paths without replacing existing values. It asks for a comma-separated\nprovider set, prints each provider's credential console and account-wide\npermissions, then accepts secrets through non-echoing prompts. Standard paths\nare used automatically:\n\nReruns are additive. Selected providers are added or refreshed in place;\nunselected provider accounts and their inventory are preserved. When a\nselected provider has multiple account entries, setup rejects the ambiguous\nrefresh before asking for a secret; edit `config/boundaries.json` to identify\nthe intended account first.\n\n| Provider | Host credential path |\n|---|---|\n| Google | `secrets/google/oauth-client.json` |\n| Bing | `secrets/bing/api-key` |\n| Cloudflare | `secrets/cloudflare/api-token` |\n| Microsoft Clarity | `secrets/clarity/api-token` |\n\nGoogle accepts only an installed/Desktop OAuth client JSON. The same setup\ncommand prints the consent URL, waits for the loopback callback, and stores the\nfull Rankrat grant under `oauth/`. PageSpeed's separate API key is prompted at\nthe same time because that API does not use OAuth.\n\nAfter storage, setup runs account readiness. It does not create site properties,\nsubmit sitemaps/URLs, or send IndexNow notifications. Secret values are never\nprinted or written into `.env`.\n\n## Provider credentials\n\nEach provider is optional. Read tools stay discoverable regardless of local\ncredential state and return a finite unavailable/configuration error when their\nprovider cannot run. Ask `provider_readiness` which providers are live rather\nthan inferring it from discovery or an empty result. Write tools are the\nexception: they are absent unless writable mode enables them.\n\n- **Google Search Console / Google Analytics 4 / Google Tag Manager / Google\n  Indexing** — create a Google project and Desktop OAuth client JSON using the\n  exact [Google OAuth guide](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md#google-oauth).\n  Run setup and paste the client JSON's single line at the hidden prompt:\n\n  ```sh\n  rankrat setup\n  ```\n\n  The CLI validates the pasted JSON, writes it into `RANKRAT_SECRET_ROOT`, runs\n  one authorization flow, and stores the resulting token under\n  `RANKRAT_OAUTH_TOKEN_ROOT`. It\n  requests Search Console management, Google Indexing, GA4 read/edit, and Tag\n  Manager container edit, delete, version-edit, and publish scopes; provider-side\n  ownership still controls what the account can do.\n- **Bing Webmaster Tools** — open\n  [Bing Webmaster Tools](https://www.bing.com/webmasters/home), add and verify\n  one site, then **Settings → API Access → API Key → Generate API Key**. The\n  resulting key is account-wide, not site-specific; setup stores it under\n  `RANKRAT_SECRET_ROOT`.\n- **Cloudflare** — create one dedicated **User API Token**, not an Account API\n  Token: [open User API Tokens](https://dash.cloudflare.com/profile/api-tokens)\n  → **Create Token → Create Custom Token** → name it `rankrat`. Add **Zone →\n  Zone → Read**, **Zone → DNS → Edit**, **Zone → Analytics → Read**, **Zone →\n  Cache Purge → Purge**, **Zone → Cache Rules → Edit**, **Zone → Single\n  Redirect → Edit**, **Account → Account Rulesets → Edit**, and **Account →\n  Account Filter Lists → Edit**. Set **Zone Resources → Include → All zones**\n  and **Account Resources → Include → All accounts**, then **Continue to\n  summary → Create Token**. Copy the one-time value into Rankrat's hidden\n  prompt. This covers all current Cloudflare features. Rankrat discovers zone\n  IDs; it exposes no arbitrary DNS record, whole-zone purge, arbitrary\n  cache-rule body, or arbitrary ruleset replacement. Ownership records are\n  DNS-only and untagged, so no Cloudflare DNS-tag quota is needed. Readiness\n  confirms account reachability but deliberately does not create a throwaway\n  record to test DNS write access.\n- **Microsoft Clarity** — open [Microsoft Clarity](https://clarity.microsoft.com/),\n  choose a project, then **Settings → Data Export → Generate new API token**.\n  The token belongs to that project; setup stores it at the configured account\n  credential path. One Clarity account represents one project and is read-only\n  in Rankrat. The upstream API allows at most ten requests per project/day; see\n  [Microsoft's documentation](https://learn.microsoft.com/en-us/clarity/setup-and-installation/clarity-data-export-api).\n- **PageSpeed Insights and CrUX** — setup separately asks for one optional API\n  key. Create it through [Google API Credentials](https://console.cloud.google.com/apis/credentials)\n  and restrict it to **PageSpeed Insights API** and **Chrome UX Report API**.\n  OAuth does not grant it. Without the key, PageSpeed runs under a tighter\n  anonymous quota and `crux_history` is unavailable.\n- **Local Lighthouse** — no credential. The optional companion image receives\n  only a shared Unix socket and outbound browser network access. Rankrat accepts\n  only requested URLs beneath the account's `pagespeed_sites` and rejects a\n  report whose final URL escapes that boundary. A public cross-origin redirect\n  can be fetched before this post-navigation check, while private and special\n  destinations are blocked by the worker's enforced proxy.\n\nCredentials stay on the host running rankrat. They are used to call the provider\nAPIs over HTTPS and are not sent anywhere else.\n\n## Running it\n\nAn agent runs the published image directly. A human creates the profile,\ncredentials, and Google authorization with `rankrat setup` beforehand — after\ninstalling the launcher. Download the installer, read it, then run it, per-user\n(no root) or system-wide:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/psyb0t/rankrat/main/install.sh -o rankrat-install.sh\nless rankrat-install.sh\nbash rankrat-install.sh                # per-user   -> ~/.local/bin/rankrat\nsudo bash rankrat-install.sh --system  # system-wide -> /usr/local/bin/rankrat\n```\n\nThe single public launcher is named `rankrat`; it is not duplicated into agent\nskills, so the shipped code cannot drift from what operators install:\n\n```bash\nrankrat --data-dir /absolute/path/to/rankrat-profile stdio\nrankrat --data-dir /absolute/path/to/rankrat-profile http       # attached Rankrat + Lighthouse\nrankrat --data-dir /absolute/path/to/rankrat-profile http -d    # detached, restart unless stopped\n```\n\nHTTP treats the profile as its Compose project directory. It atomically creates\nthe embedded reviewed `docker-compose.yml` when absent, preserves an existing\nsafe regular file, rejects symlinked/non-regular paths, and exports the chosen\nimage, port, UID/GID, and read-only values from its environment. The project\ndirectory and Compose file must be owned by the current UID and not group/world\nwritable. Only the four fixed children below are mounted into containers.\n\nBoth transports take the same four mounts. Container-side paths are the\nserver's defaults, so only the host side changes:\n\n| Host | Container | Access | Holds |\n|---|---|---|---|\n| `$RANKRAT_DATA_DIR/config` | `/run/config` | writable normally; read-only with `RANKRAT_READ_ONLY=true` | account registry and inventory |\n| `$RANKRAT_DATA_DIR/secrets` | `/run/secrets` | read-only | provider credentials, HTTP bearer secret |\n| `$RANKRAT_DATA_DIR/oauth` | `/run/oauth` | writable | stored Google OAuth token; refresh may rotate it |\n| `$RANKRAT_DATA_DIR/state` | `/run/state` | writable, owner-only | SQLite monitor definitions, snapshots, issues, and events |\n\n**stdio** — the default mode, for a client that owns the process:\n\n```bash\ndocker run -i --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat stdio\n```\n\n**Manual single-container Streamable HTTP** — for a shared server that does not\nneed local Lighthouse. MCP lands at `/mcp` and the REST API shares the port:\n\n```bash\ndocker run --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  -p 127.0.0.1:8080:8080 \\\n  -e RANKRAT_HTTP_HOST=0.0.0.0 \\\n  -e RANKRAT_HTTP_BEARER_SECRET_FILE=/run/secrets/rankrat/http-bearer-token \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat http\n```\n\n`RANKRAT_HTTP_HOST=0.0.0.0` binds inside the container while `-p` keeps it on\nloopback. MCP is then at `http://127.0.0.1:8080/mcp`; send\n`Authorization: Bearer <token>` whenever a bearer secret is configured.\n\nThe commands above use the writable default. Before mounting config writable,\nverify that the resolved directory is owner-only, `boundaries.json` is not a\nsymlink, both are owned by the current UID, and the file is not group- or\nworld-writable. The public `rankrat` launcher performs those checks. The OpenClaw\nlauncher additionally rejects symlinked path components. For a read-only\ncaller, set `RANKRAT_READ_ONLY=true` and make only `/run/config` read-only.\nNever make the provider-secret mount writable during normal service operation.\n\nLocal Lighthouse audits require the separate published browser image. Start it\nonce against a private named volume:\n\n```bash\ndocker volume create rankrat-lighthouse-runtime\ndocker run --rm --network none --user 0:0 --read-only \\\n  --cap-drop=ALL --cap-add=CHOWN --cap-add=FOWNER \\\n  --security-opt no-new-privileges:true \\\n  --pids-limit 16 --memory 64m --cpus 0.25 \\\n  --mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse \\\n  --entrypoint /bin/sh psyb0t/rankrat-lighthouse \\\n  -c 'chmod 1777 /run/lighthouse && touch /run/lighthouse/.initialized && chown -R 10001:10001 /run/lighthouse && chmod 0750 /run/lighthouse'\ndocker run --rm -d --name rankrat-lighthouse-worker --init --read-only \\\n  --user 10001:10001 --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 256 --memory 2g --cpus 2 --shm-size 1g \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=1g,mode=1777 \\\n  --mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse \\\n  psyb0t/rankrat-lighthouse\n```\n\nThe self-removing initializer assigns the private volume root to the non-root\nUID shared by Rankrat and the worker. When using a different UID/GID, change the\ninitializer's `chown` pair and the worker's `--user` pair to the same values.\nRun Rankrat under that pair as well if the primary image's built-in `10001:10001`\nuser is overridden. The provided Compose file applies `RANKRAT_UID` and\n`RANKRAT_GID` consistently to both long-lived services after running this\nhardened initializer.\n\nAdd this read-only volume mount to either published Rankrat invocation above:\n\n```bash\n--mount type=volume,src=rankrat-lighthouse-runtime,dst=/run/lighthouse,readonly\n```\n\nThe normal `psyb0t/rankrat stdio` command then exposes the five Lighthouse tools\nover stdio. The normal `psyb0t/rankrat http` command exposes the same tools over\nStreamable HTTP at `/mcp` and REST under `/v1/lighthouse/`. Leave\n`RANKRAT_LIGHTHOUSE_WORKER_SOCKET` empty to disable the worker explicitly. Stop\nand remove only the worker and volume you created when they are no longer\nneeded.\n\nThe worker is for pages you control and trust. Chromium runs with\n`--no-sandbox` because its built-in namespace/setuid sandbox cannot coexist with\nthe documented non-root, capability-free, `no-new-privileges` container. The\ncredential-free, read-only worker and public-address-only proxy reduce blast\nradius but do not replace the renderer sandbox after a browser exploit. Use an\nouter sandbox such as gVisor or Kata Containers before auditing hostile content.\n\n| MCP tool | REST route |\n|---|---|\n| `lighthouse_audit` | `POST /v1/lighthouse/audits` |\n| `lighthouse_seo_findings` | `POST /v1/lighthouse/seo-findings` |\n| `lighthouse_accessibility_findings` | `POST /v1/lighthouse/accessibility-findings` |\n| `lighthouse_performance_findings` | `POST /v1/lighthouse/performance-findings` |\n| `lighthouse_best_practices_findings` | `POST /v1/lighthouse/best-practices-findings` |\n\nEvery operation accepts the same strict body: `account_id`, a configured\n`site_url`, a child `page_url`, and optional `timeout_seconds` in the inclusive\n5–300 second range. The aggregate audit returns all four category scores and\nfailed findings; the other four operations return only that category's failed\nfindings.\n\n## Onboarding\n\n`site_onboarding_submit` is part of normal writable mode. It creates or reuses\nGA4, Search Console, and Bing resources, then records discovered IDs in the\nconfig file. It is absent from `tools/list` and REST when\n`RANKRAT_READ_ONLY=true`. The config directory must be safely writable; the\nbundled wrapper validates its ownership/mode.\n\nThe guidance is available either way, read-only, on every server:\n\n| Surface | What it gives |\n|---|---|\n| `rankrat://onboarding` resource | The whole procedure and this server's onboarding posture |\n| `rankrat://onboarding/{site_url}` template | Same, narrowed to one percent-encoded site |\n| `onboarding_guide` tool | The identical document, for clients without resource support |\n\nWith a configured DNS provider account, `site_ownership_verify` requests the\nreal Google TXT and Bing CNAME proofs, publishes only those records through the\nadapter selected by the account's `provider`, checks public DNS, and redeems\neach provider. Poll `site_ownership_check` until it reports `complete`; DNS\npropagation is asynchronous. Cloudflare is the currently shipped DNS adapter.\nWithout a supported adapter, a `sc-domain:` property accepts only DNS TXT,\nwhile a `https://` URL-prefix property also accepts the GA4 tag, an HTML file,\nor a meta tag.\n\nThe SEO expansion has the same names over stdio and Streamable HTTP MCP:\n\n| MCP tool | REST route |\n|---|---|\n| `site_ownership_check` | `POST /v1/site-ownership-checks` |\n| `site_ownership_verify` | `POST /v1/site-ownership-verifications` |\n| `site_audit` | `POST /v1/site-audits` |\n| `site_remediation_apply` | `POST /v1/site-remediations` |\n| `bing_backlink_intelligence` | `POST /v1/bing/backlink-intelligence` |\n| `internal_link_graph` | `POST /v1/internal-link-graphs` |\n| `orphan_page_report` | `POST /v1/orphan-page-reports` |\n| `internal_link_opportunities` | `POST /v1/internal-link-opportunity-reports` |\n| `crux_history` | `POST /v1/crux/history-reports` |\n| `cloudflare_analytics` | `POST /v1/cloudflare/analytics-reports` |\n| `content_opportunities` | `POST /v1/content-opportunity-reports` |\n\n## Complete MCP tool catalog\n\n`tools/list` is authoritative for a running server because startup settings\ndecide which tools exist. The grouped inventory below mirrors the tool catalog\nin the source. The exact REST paths and schemas live in the committed\n[merged OpenAPI document](https://github.com/psyb0t/rankrat/blob/main/openapi.json),\ncomposed from the\n[base](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/openapi.yaml)\nand\n[SEO intelligence](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/seo-openapi.yaml)\nand\n[free provider SEO](https://github.com/psyb0t/rankrat/blob/main/src/rankrat/api/free-seo-openapi.yaml)\nYAML sources. When enabled, the runtime `/openapi.json` removes write routes\nfrom a read-only server.\n\n### Read-only tools\n\n- **Server, boundaries, and guidance:** `server_info`, `accounts_list`,\n  `sites_list`, `diagnostics`, `provider_readiness`, `onboarding_guide`.\n- **Site, ownership, schema, links, and opportunities:** `site_audit`,\n  `site_ownership_check`, `schema_validate_url`, `schema_validate_html`,\n  `schema_validate_json_ld`, `bing_backlink_intelligence`,\n  `internal_link_graph`, `orphan_page_report`,\n  `internal_link_opportunities`, `content_opportunities`.\n- **Persistent monitoring:** `monitors_list`, `monitor_snapshots_list`,\n  `monitor_issues_list`, `issue_events_list`.\n- **Google Search Console and Indexing metadata:**\n  `google_search_analytics_summary`, `google_search_analytics_comparison`,\n  `google_search_analytics_dimension_report`,\n  `google_search_analytics_drop_attribution`, `google_search_analytics_trend`,\n  `google_search_analytics_anomalies`,\n  `google_search_analytics_page_performance`,\n  `google_search_analytics_query`, `google_sites_list`, `google_site_get`,\n  `google_sitemaps_list`, `google_sitemap_get`, `google_url_inspection`,\n  `google_url_inspection_batch`, `google_indexing_metadata`.\n- **Google Analytics 4:** `google_analytics_account_inventory`,\n  `google_analytics_data_streams`, `google_analytics_report`,\n  `google_analytics_realtime_report`, `google_analytics_content_performance`,\n  `google_analytics_landing_page_performance`,\n  `google_analytics_organic_search_landing_pages`,\n  `google_analytics_traffic_source_performance`,\n  `google_analytics_ecommerce_performance`,\n  `google_analytics_audience_segments`, `google_analytics_user_behavior`,\n  `google_analytics_conversion_funnel`.\n- **Google Tag Manager, Microsoft Clarity, and managed redirects:**\n  `google_tag_manager_accounts_list`, `google_tag_manager_containers_list`,\n  `google_tag_manager_workspaces_list`, `google_tag_manager_entities_list`,\n  `clarity_insights`, `edge_redirects_list`.\n- **PageSpeed, CrUX, Cloudflare, and local Lighthouse:** `pagespeed_analyze`,\n  `pagespeed_core_web_vitals`, `lighthouse_audit`,\n  `lighthouse_seo_findings`, `lighthouse_accessibility_findings`,\n  `lighthouse_performance_findings`,\n  `lighthouse_best_practices_findings`, `crux_history`,\n  `cloudflare_analytics`.\n- **Cross-provider analysis:** `ga4_pagespeed_correlation`,\n  `ga4_search_console_comparison`, `search_engine_comparison`,\n  `search_engine_traffic_health`.\n- **Bing Webmaster Tools:** `bing_keyword_statistics`,\n  `bing_related_keywords`, `bing_traffic_trend`, `bing_traffic_anomalies`,\n  `bing_traffic_comparison`, `bing_query_performance`,\n  `bing_page_performance`, `bing_brand_analysis`, `bing_ranking_buckets`,\n  `bing_query_opportunities`, `bing_page_opportunities`,\n  `bing_opportunity_matrix`, `bing_query_page_performance`,\n  `bing_query_cannibalization`, `bing_page_query_performance`,\n  `bing_url_submission_quota`, `bing_crawl_issues`, `bing_crawl_stats`,\n  `bing_feeds`, `bing_link_counts`, `bing_url_information`.\n\n### Writable tools\n\nThese appear only when `RANKRAT_READ_ONLY=false`:\n\n- **IndexNow:** `indexnow_submit`. IndexNow is an open change-notification\n  protocol, not a dashboard: one participating endpoint shares an accepted\n  notification with the other participating engines, while each engine makes\n  its own crawl and indexing decisions.\n- **Bing:** `bing_url_submit`, `bing_sitemap_submit`, `bing_site_submit`.\n- **Bing content:** `bing_content_submission_create` fetches an allowed public\n  page itself, then submits that fresh HTML to Bing.\n- **Google Search Console and Indexing:** `google_indexing_submit`,\n  `google_indexing_batch_submit`, `google_site_submit`,\n  `google_sitemap_submit`.\n- **Google Analytics 4:** `google_analytics_account_rename`,\n  `google_analytics_property_rename`.\n- **Google Tag Manager:** `google_tag_manager_container_create`,\n  `google_tag_manager_container_delete`, `google_tag_manager_workspace_create`,\n  `google_tag_manager_workspace_delete`, `google_tag_manager_entity_create`,\n  `google_tag_manager_entity_update`, `google_tag_manager_entity_delete`,\n  `google_tag_manager_workspace_version_create`,\n  `google_tag_manager_version_publish`.\n- **Ownership and discovery remediation:** `site_ownership_verify`,\n  `site_remediation_apply`.\n- **Persistent monitoring:** `monitor_create`, `monitor_update`,\n  `monitor_delete`, `monitor_run`, `issue_status_update`.\n- **Cloudflare performance:** `cloudflare_cache_purge`,\n  `cloudflare_cache_template_apply`.\n- **Provider-neutral managed redirects:** `edge_redirect_upsert`,\n  `edge_redirect_delete`. Cloudflare is the currently shipped adapter.\n- **Site onboarding:** `site_onboarding_submit`.\n\n## Checking it works\n\n- `server_info` — the server is up and which mode it is in.\n- `provider_readiness` — which providers are actually configured.\n- `accounts_list` / `sites_list` — the boundary as the server sees it.\n- `diagnostics` — deeper detail when one of the above is not what you expected.\n- `monitors_list` and `monitor_issues_list` — whether scheduled audit history\n  is accumulating and which lifecycle issues remain open.\n\nIf a provider-specific tool returns nothing, check `provider_readiness` before\nassuming the data is missing upstream.\n\nAutomatic due-monitor execution belongs to the long-running HTTP process.\nStdio exposes the same monitor CRUD, manual-run, snapshot, issue, and event\ntools, but its process lifetime is controlled by the MCP client and it does not\nleave a background scheduler behind. Persist `/run/state` for either transport.\nFor backups, use SQLite's online-backup mechanism or stop Rankrat first; copying\nonly a live database file can omit WAL state.\n\nFile v0.19.1:skill-card.md\n\n## Description:\n\nQuery Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[psyb0t](https://clawhub.ai/user/psyb0t)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, site operators, and SEO practitioners use rankrat to inspect and improve search visibility, indexing, analytics, site health, tags, redirects, backlinks, and performance for sites they control. It is intended for self-hosted use with configured provider accounts and can operate in read-only or writable modes.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Configured provider credentials can authorize broad read or write access across connected SEO, analytics, DNS, tag-management, and cache resources.\n\nMitigation: Install only for provider accounts and sites under the operator's control, protect profile directories and backups, and run with RANKRAT_READ_ONLY=true when the agent should not make account changes.\n\nRisk: Writable mode can mutate provider or local state, including onboarding, URL submissions, tag-manager changes, redirects, cache actions, and monitor lifecycle data.\n\nMitigation: Use read-only mode for autonomous or lower-trust callers, and reserve writable mode for human-directed operations with reviewed credentials and bounded site configuration.\n\nRisk: The optional Lighthouse worker opens requested public pages and uses Chromium without its internal sandbox in the documented container posture.\n\nMitigation: Use the worker only for operator-controlled sites, keep it credential-free, and add an outer sandbox such as gVisor or Kata before auditing hostile content.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/psyb0t/skills/rankrat)\n- [rankrat setup reference](references/setup.md)\n- [Rankrat documentation](https://github.com/psyb0t/rankrat/tree/main/docs)\n- [Getting started](https://github.com/psyb0t/rankrat/blob/main/docs/getting-started.md)\n- [Providers and credentials](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md)\n- [Troubleshooting](https://github.com/psyb0t/rankrat/blob/main/docs/troubleshooting.md)\n\n## Skill Output:\n\n**Output Type(s):** [text, markdown, shell commands, configuration, guidance]\n\n**Output Format:** [Markdown text with command blocks, configuration guidance, and provider/API result summaries]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [May include MCP tool calls, REST API requests, and bounded SEO or analytics reports based on configured provider accounts.]\n\n## Skill Version(s):\n\n0.19.1 (source: server release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v0.19.0: 4 files, 18284 bytes\n\nFiles: references/setup.md (27008b), skill-card.md (2867b), SKILL.md (15183b), _meta.json (127b)\n\nFile v0.19.0:SKILL.md\n\n---\nname: rankrat\ndescription: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control.\nhomepage: https://github.com/psyb0t/rankrat\nuser-invocable: true\nmetadata:\n  openclaw:\n    emoji: \"🐀\"\n    requires:\n      bins: [docker]\npermissions:\n  network: \"outbound HTTPS to configured Google Search Console, Google Analytics, Google Tag Manager, Bing Webmaster Tools, Microsoft Clarity, PageSpeed/CrUX, Cloudflare, public DNS, public pages beneath configured sites, and IndexNow endpoints; optional Lighthouse browser traffic to explicitly requested bounded pages; inbound only on the port you bind.\"\n  shell: \"docker run invocations for the published image or the installed rankrat launcher; no other host access is required.\"\n  filesystem: \"reads provider-account config and credentials; writes the configured OAuth token store, persistent SQLite monitor state, locally initialized IndexNow key, and discovered resource inventory in the config file when writable.\"\n---\n\n# rankrat\n\nA self-hosted MCP server over the SEO and search-analytics APIs you already have\naccounts on — Google Search Console, Google Tag Manager, Bing Webmaster Tools,\nGA4, Microsoft Clarity, and PageSpeed Insights — so an agent can read and,\nwhen trusted, manage your own provider resources without you handing it a\nbrowser session or a service-account key.\n\nInstall, credentials and the full environment reference:\n[`references/set\n\nArchive v0.18.0: 4 files, 18359 bytes\n\nFiles: references/setup.md (27008b), skill-card.md (3181b), SKILL.md (15183b), _meta.json (127b)\n\nArchive v0.17.1: 4 files, 18224 bytes\n\nFiles: references/setup.md (27008b), skill-card.md (2862b), SKILL.md (15183b), _meta.json (127b)\n\nArchive v0.16.0: 4 files, 18370 bytes\n\nFiles: references/setup.md (27008b), skill-card.md (3155b), SKILL.md (15183b), _meta.json (127b)\n\nArchive v0.15.0: 4 files, 18249 bytes\n\nFiles: references/setup.md (26627b), skill-card.md (3435b), SKILL.md (15178b), _meta.json (127b)\n\nArchive v0.14.2: 4 files, 18052 bytes\n\nFiles: references/setup.md (26627b), skill-card.md (2833b), SKILL.md (15178b), _meta.json (127b)\n\nArchive v0.14.1: 4 files, 18178 bytes\n\nFiles: references/setup.md (26627b), skill-card.md (3127b), SKILL.md (15178b), _meta.json (127b)","readmeExcerpt":"Skill: rankrat Owner: psyb0t Summary: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server.","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"rankrat --data-dir /absolute/path/to/rankrat-profile stdio\nrankrat --data-dir /absolute/path/to/rankrat-profile http -d"},{"language":"bash","snippet":"export RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run -i --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat stdio"},{"language":"bash","snippet":"export RANKRAT_DATA_DIR=/absolute/path/to/rankrat-profile\ndocker run --rm --init --read-only \\\n  --user \"$(id -u):$(id -g)\" \\\n  --cap-drop=ALL --security-opt no-new-privileges:true \\\n  --pids-limit 128 --memory 512m --cpus 1 \\\n  --tmpfs /tmp:rw,noexec,nosuid,size=32m \\\n  -p 127.0.0.1:8080:8080 \\\n  -e RANKRAT_HTTP_HOST=0.0.0.0 \\\n  -e RANKRAT_HTTP_BEARER_SECRET_FILE=/run/secrets/rankrat/http-bearer-token \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/config\",dst=/run/config \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/secrets\",dst=/run/secrets,readonly \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/oauth\",dst=/run/oauth \\\n  --mount type=bind,src=\"$RANKRAT_DATA_DIR/state\",dst=/run/state \\\n  -e RANKRAT_STATE_DATABASE=/run/state/rankrat.sqlite3 \\\n  psyb0t/rankrat http"},{"language":"bash","snippet":"make setup"},{"language":"sh","snippet":"rankrat setup"},{"language":"bash","snippet":"curl -fsSL https://raw.githubusercontent.com/psyb0t/rankrat/main/install.sh -o rankrat-install.sh"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: rankrat\ndescription: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control.\nhomepage: https://github.com/psyb0t/rankrat\nuser-invocable: true\nmetadata:\n  openclaw:\n    emoji: \"🐀\"\n    requires:\n      bins: [docker]\npermissions:\n  network: \"outbound HTTPS to configured Google Search Console, Google Analytics, Google Tag Manager, Bing Webmaster Tools, Microsoft Clarity, PageSpeed/CrUX, Cloudflare, public DNS, public pages beneath configured sites, and IndexNow endpoints; optional Lighthouse browser traffic to explicitly requested bounded pages; inbound only on the port you bind.\"\n  shell: \"docker run invocations for the published image or the installed rankrat launcher; no other host access is required.\"\n  filesystem: \"reads provider-account config and credentials; writes the configured OAuth token store, persistent SQLite monitor state, locally initialized IndexNow key, and discovered resource inventory in the config file when writable.\"\n---\n\n# rankrat\n\nA self-hosted MCP server over the SEO and search-analytics APIs you already have\naccounts on — Google Search Console, Google Tag Manager, Bing Webmaster Tools,\nGA4, Microsoft Clarity, and PageSpeed Insights — so an agent can read and,\nwhen trusted, manage your own provider resources without you handing it a\nbrowser session or a service-account key.\n\nInstall, credentials and the full environment reference:\n[`references/setup.md`](references/setup.md).\nFor a human-readable operator manual organized by topic, use the public\n[Rankrat documentation](https://github.com/psyb0t/rankrat/tree/main/docs).\n\n## Contents\n\n- [Security and safety](#security-and-safety)\n- [When to use](#when-to-use)\n- [When NOT to use](#when-not-to-use)\n- [Usage](#usage)\n\n## Security and safety\n\nConfigured provider credentials are Rankrat's authority. A Google OAuth account,\nBing key, Cloudflare token, or Clarity project token can reach every supported\nresource that provider exposes to it. Resource arrays in the config are\ndiscovered inventory and URL-containment data, not a second permission system.\nFixed provider origins, typed requests, public-URL validation, and child-URL\ncontainment still apply.\n\nRankrat is **writable by default**. `RANKRAT_READ_ONLY=true` removes every write\ntool from `tools/list` and every write route from runtime OpenAPI, including\nsite onboarding. This is the only capability switch. The human decides whether\nthe calle"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn79dhvmpjng4rp2jjk8k0v5xx80ccbk\",\n  \"slug\": \"rankrat\",\n  \"version\": \"0.20.1\",\n  \"publishedAt\": 1791644028619\n}"},{"path":"references/setup.md","content":"# rankrat — setup reference\n\nEverything the [skill](../SKILL.md) needs but does not need loaded up front:\nconfiguration, credentials, and how to run it.\n\nThis file is the self-contained agent reference shipped with the skill. Human\noperators can use the topic-based\n[public manual](https://github.com/psyb0t/rankrat/tree/main/docs), especially\n[Getting started](https://github.com/psyb0t/rankrat/blob/main/docs/getting-started.md),\n[Providers and credentials](https://github.com/psyb0t/rankrat/blob/main/docs/providers.md),\nand [Troubleshooting](https://github.com/psyb0t/rankrat/blob/main/docs/troubleshooting.md).\n\n## Contents\n\n- [Configuration](#configuration)\n- [The boundary file](#the-boundary-file)\n- [Write access](#write-access)\n- [Guided setup](#guided-setup)\n- [Provider credentials](#provider-credentials)\n- [Running it](#running-it)\n- [Onboarding](#onboarding)\n- [Complete MCP tool catalog](#complete-mcp-tool-catalog)\n- [Checking it works](#checking-it-works)\n\n## Configuration\n\nAll settings are read from the environment with the `RANKRAT_` prefix, so a\nfield named `http_port` is set by `RANKRAT_HTTP_PORT`. The defaults below are\nthe ones in the settings model, not example values.\n\n| Variable | Default | Purpose |\n|---|---|---|\n| `RANKRAT_HTTP_HOST` | `127.0.0.1` | Listen address in `http` mode. Loopback by default — bind wider only deliberately. |\n| `RANKRAT_HTTP_PORT` | `8080` | Listen port in `http` mode. |\n| `RANKRAT_BOUNDARY_FILE` | `/run/config/boundaries.json` | Provider accounts plus discovered resource inventory and URL-containment roots. |\n| `RANKRAT_SECRET_ROOT` | `/run/secrets` | Directory holding provider credentials. |\n| `RANKRAT_OAUTH_TOKEN_ROOT` | `/run/oauth` | Directory holding stored Google OAuth tokens. |\n| `RANKRAT_LOG_FILE` | `/tmp/rankrat/rankrat.log` | Log destination. |\n| `RANKRAT_LOG_LEVEL` | `INFO` | Standard Python log levels. |\n| `RANKRAT_LIGHTHOUSE_WORKER_SOCKET` | `/run/lighthouse/lighthouse.sock` | Optional Unix socket for the isolated local Lighthouse worker. Empty disables it. |\n| `RANKRAT_STATE_DATABASE` | unset | Absolute SQLite path for monitors, snapshots, and issue events. Empty/unset disables persistence. The wrapper sets `/run/state/rankrat.sqlite3`. |\n| `RANKRAT_SCHEDULER_INTERVAL_SECONDS` | `60` | How often the HTTP process claims due monitors; accepted range 10–3600 seconds. |\n| `RANKRAT_STATE_RETENTION_DAYS` | `180` | Snapshot/event retention after a monitor run; accepted range 1–3650 days. |\n| `RANKRAT_ENABLE_OPENAPI` | `false` | Serve the OpenAPI document. |\n| `RANKRAT_READ_ONLY` | `false` | See \"Write access\" below. |\n| `RANKRAT_HTTP_BEARER_SECRET_FILE` | unset | File holding the bearer token required on HTTP requests. Unset means no auth, so only do that on loopback. |\n\nThe supported names and safe defaults are in `.env.example`. Invalid values for\nsupported settings fail startup instead of being silently accepted.\n`make run-http` always supplies a bearer-secret file, including for loopback\nuse; a c"},{"path":"skill-card.md","content":"## Description:\n\nRankrat helps agents inspect SEO, search traffic, indexing, site performance, and managed website settings through a self-hosted server for sites their operators control.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[psyb0t](https://clawhub.ai/user/psyb0t)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nSite owners, SEO practitioners, and developers use this skill to analyze their own search and analytics data, audit website health, and, when authorized, manage tags, redirects, indexing submissions, and monitoring.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Provider credentials grant broad access, and account-changing tools are enabled by default.\n\nMitigation: Grant only needed provider permissions and use RANKRAT_READ_ONLY=true for agents that should not make changes.\n\nRisk: An exposed HTTP endpoint could allow unauthorized access to connected accounts.\n\nMitigation: Bind HTTP to loopback or a private network and require a bearer token when others can reach it.\n\nRisk: Installer and container image references may change between reviews.\n\nMitigation: Review the installer and pin and verify the exact release or image digest before use.\n\n## Reference(s):\n\n- [ClawHub rankrat release](https://clawhub.ai/psyb0t/skills/rankrat)\n- [Setup and credentials](references/setup.md)\n- [Rankrat documentation](https://github.com/psyb0t/rankrat/tree/main/docs)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Shell commands, Configuration guidance]\n\n**Output Format:** [Markdown with reports, recommendations, and command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Reports depend on configured provider accounts; account changes require write access.]\n\n## Skill Version(s):\n\n0.20.1 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server. Speaks MCP over stdio and Streamable HTTP, plus a FastAPI JSON API. Use when the user wants to inspect or improve SEO, indexing, ownership, internal links, tags, redirects, backlinks, browser scores, performance history, or search traffic for sites they control. Skill: rankrat Owner: psyb0t Summary: Query Google Search Console, Google Tag Manager, Bing Webmaster Tools, GA4, Microsoft Clarity, PageSpeed, CrUX, Cloudflare analytics, and Bing backlink intelligence; manage typed tags and safe edge redirects; run Lighthouse and bounded whole-site/internal-link audits; persist monitors and issue history; automate ownership and finite remediation through one self-hosted MCP server.","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1596,"uniquenessScore":45,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-10T16:26:43.961Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-10T16:26:43.961Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T21:51:04.346Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}