seo-platform-detect
Skill81 starsChanged 2 months agoMITView on GitHub
Build the SiteProfile for an audited site — platform, framework, CMS plugins, hosting, environment, capabilities and write targets — by running scripts/detect-platform.mjs over the persisted PageSnapshot, then pick the knowledge cards each subagent needs. Support skill for seo-orchestrator; it merges this output with seo-vertical-detect into <run_dir>/profile.json.
In this repository33 other files it gives its agents.
- auditSkill
- compareSkill
- fixSkill
- geoSkill
- scoreSkill
- seo-agent-readinessSkill
- seo-ai-crawlersSkill
- seo-ai-discoverySkill
- seo-core-web-vitalsSkill
- seo-crawlabilitySkill
- seo-crawl-renderSkill
- seo-ecommerceSkill
- seo-eeatSkill
- seo-entity-linkingSkill
- seo-fix-applySkill
- seo-freshnessSkill
- seo-geo-answerblocksSkill
- seo-geo-factdensitySkill
- seo-headings-structureSkill
- seo-images-mediaSkill
- seo-indexabilitySkill
- seo-internal-linkingSkill
- seo-internationalSkill
- seo-localSkill
- seo-meta-onpageSkill
- seo-mobileSkill
- seo-orchestratorSkill
- seo-renderingSkill
- seo-schema-jsonldSkill
- seo-scoreSkill
- seo-sitemapsSkill
- seo-social-cardsSkill
- seo-vertical-detectSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 2 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 22
Read that file first. Run the script directly only when you need a signal the headless pass could not use — --path <project> for …
- Distinctive: line 33
Add flags when they apply, and only then:
- Distinctive: line 90
emit the card's §10 check ids: when the rule matches;
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- Portions Copyright (c) 2026 Enrique Rocha (@soyenriquerocha) - see LICENSE for original authors · tododeia.com · id er-d03758e1 -->seo-platform-detect
The profile decides three things no module can decide on its own: which platform-conditional check
ids fire, which findings are not_applicable because the platform owns the thing, and which fix
adapter fix will reach for. Run it once per audit, right after the snapshot, before dispatch.
Detection is orthogonal to the vertical: seo-vertical-detect answers what kind of site is this,
this skill answers what is it built on. Both feed one profile.json.
When to run
In the normal /audit and /geo flow you do not run this yourself: audit.mjs already calls the
same detect() over the run's homepage snapshot and persists the result as <run_dir>/profile.json.
Read that file first. Run the script directly only when you need a signal the headless pass could not
use — --path <project> for repo/package signals, --probe for the WordPress plugin verdict — or when
you are working outside the runner. Either way it is one run per audit, before the dispatch envelopes
are built; every subagent reads the same profile.
How to run
node "${CLAUDE_PLUGIN_ROOT}/scripts/detect-platform.mjs" --snapshot "<run_dir>/pages/<home-slug>.json"Add flags when they apply, and only then:
--path <project>when the user gave a local project (--project). This is the only way repo and package signals are consulted; without it, Payload is undetectable and Next.js router detection falls back to DOM markers. It is also what turnscapabilities.local_fileson, which is what makes local file fixes possible at all.--probewhen the target is reachable and a WordPress plugin verdict matters. It requests/wp-json/,/.well-known/ucp,/products.jsonand/wp-sitemap.xml— four GETs, no more. The REST namespace list is the only reliable way to tell Yoast from Rank Math from AIOSEO; HTML comments name a plugin that printed a comment, not one that is active.--out "<run_dir>/profile.platform.json"to persist it instead of piping the stdout JSON.
Offline / fixture mode (used by the tests, and by you when there is no network):
--html <file> [--headers <json>] [--cookies <json>] [--probes <json>] [--url <u>].
Exit codes: 0 ok · 1 bad invocation or unreadable input · 2 fetch failure.
What comes back
{ version: "detect-platform/1", target, platform, framework, cms_plugins[], hosting, environment,
capabilities, write_targets[], candidates, vertical_hints[], cards[], sources, notes[] }.
Each of platform / framework / cms_plugins[] / hosting carries its own confidence
(high ≥ 8 with ≥ 2 signal kinds, medium ≥ 5, low ≥ 2) and the signals that produced it.
A layer with less evidence than that is null — an unresolved platform is a result, not a gap.
Report it as unresolved and let the run continue on instructions; never round a low up in prose.
Four layers are scored independently, so headless setups resolve correctly: a WordPress backend with
a Next.js front end yields platform: wordpress and framework: nextjs, and
capabilities.head_owner becomes framework. Follow head_owner whenever the cards disagree.
Merging into profile.json
<run_dir>/profile.json is the union of this output and seo-vertical-detect's. audit.mjs writes it: it
refreshes every key detect() owns and preserves the ones you added, so a vertical block already in the
file survives a re-run (a --vertical flag overrides it). Shape:
{ "version": "detect-platform/1", "platform": {…}, "framework": {…}, "cms_plugins": [],
"hosting": {…}, "environment": {…}, "capabilities": {…}, "write_targets": [],
"candidates": {…}, "vertical_hints": [], "cards": [], "sources": {…}, "notes": [],
"vertical": { "primary": "ecommerce", "also": [], "multilingual": false, "locales": [] } }Pass vertical_hints[] to seo-vertical-detect as signals, never as verdicts — it must still cite
its own evidence. Pass environment.kind to the scorer
(score.mjs --environment preview|staging|local), which suppresses noindex-type severity-5 caps on
a non-production host and reports them as expected instead.
Which card goes to which subagent
profile.cards[] already lists the paths (references/platforms/<id>.md). Put them in every
dispatch envelope as platform_cards, alongside the platform field (the absolute profile.json
path) and a one-line summary
("shopify (high) · theme head · staging theme available · environment production"), with these two
instructions verbatim:
- emit the card's §10 check ids when the rule matches;
- card §4 items ⇒
not_applicablenaming the owner inevidence.observed— never a silent pass, never afailfor something the platform will not let anyone change.
Hand out the platform card, the framework card and any plugin card together; a headless site legibly
needs all three. When capabilities.instructions_only is true, also tell the agents that every fix
they propose will be delivered as a click-path, so fix_preview must be human-readable prose rather
than a diff.
Honesty
needsinwrite_targetslists credential key names. Presence is checked forCLAUDE_PLUGIN_OPTION_<KEY>/<KEY>— values are never read, printed or logged.ready: falsemeans "not configured", never "wrong key".- Cookie names are evidence; cookie values are never recorded.
- Repo signals are absent without
--path, probe signals absent without--probe, and the profile'snotes[]says so. Repeat that in the report rather than presenting a partial profile as complete. - A signal marked
UNVERIFIEDin a card's §12 may support a detection verdict but must never support a write. When a fix depends on an unverified API detail, the answer isneeds_api.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

