About seo-orchestrator
seo-orchestrator coordinates a multi-stage SEO audit, from deterministic data collection through specialist review to report synthesis. It is intended for running and consolidating audits while keeping project files untouched and storing artifacts in the plugin data directory.
Key features
- 01Runs deterministic audit pipeline
- 02Profiles platform and environment
- 03Dispatches four specialist agents
- 04Merges and scores findings
- 05Produces JSON and Markdown reports
- 06Keeps audit artifacts outside project
Use cases
- 01Running a multi-page SEO audit
- 02Combining deterministic checks with specialist findings
- 03Generating scored reports for a site
- 04Reviewing crawl coverage and sampled pages
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ hainrixz/ claude-seo-ai --skill seo-orchestratorAfter installing, type/seo-orchestratorin Claude Code to confirm it loaded.
Details
From the project READMEseo-orchestrator (Layer 2)
Coordinates the whole audit in three phases: detect → dispatch → synthesize. The scripts are the acquisition layer; the model only judges. Read the compact stdout summaries and the JSON files they name — never paste HTML into the conversation. Nothing is written to the user's project; every artifact lives under ${CLAUDE_PLUGIN_DATA}/runs/<host>/<run-id>/.
1. Detect — one call
- Resolve the target and the flags forwarded by the command (
--pages,--max,--render,--ua,--vertical,--environment,--feed,--out; default--out "${CLAUDE_PLUGIN_DATA}/runs"). - Run the whole deterministic pipeline in one command.
audit.mjsacquires the target (it callscrawl.mjsfor a URL,snapshot.mjsfor--pages 1or a local path, and skips acquisition entirely when handed a run directory), writesprofile.json(platform / framework / cms plugins / hosting / environment / capabilities / write_targets /vertical_hints, plus a vertical guess), runs the checks registry, and callsreport.mjsfor a first deterministic-only report:
node "${CLAUDE_PLUGIN_ROOT}/scripts/audit.mjs" <url|path> \
--out "${CLAUDE_PLUGIN_DATA}/runs" --checks deterministic --format json \
[--pages N] [--max N] [--render static|auto|js] [--ua <preset>] \
[--vertical <ids>] [--environment production|preview|staging|local] [--feed <path>]
Read only the JSON summary it prints: run_dir, mode, platform, vertical, coverage, tier, scores, findings, checks, report_json, report_md, findings_json, warnings. --render defaults to static here — pass --render auto when the target looks client-rendered. Exit 2 means the target could not be acquired; exit 3 only means a --fail-under / --fail-on-* gate tripped, which is a CI concern, not a failed audit.
3. Read <run_dir>/crawl.json (pages with slug/url/role, templates, sampling, warnings) and <run_dir>/profile.json.
4. Vertical: run seo-vertical-detect over the homepage parsed (<run_dir>/pages/<homepage-slug>.json) plus profile.vertical_hints. The script only guesses — profile.vertical.source is "inferred" unless --vertical was passed. If your reading adds or changes a vertical, re-run the deterministic pass over the same run (no re-crawl) so the conditional checks actually fire:
node "${CLAUDE_PLUGIN_ROOT}/scripts/audit.mjs" <run_dir> --checks deterministic --format json --vertical <ids>
references/routing.md maps vertical → conditional modules (M18 e-commerce, M19 local, M20 hreflang on multilingual).
5. The run now holds <run_dir>/findings.deterministic.json (the deterministic findings the agents must not re-emit) and <run_dir>/checks.json (checks run, errors, needs_api, manual_review, dropped).
2. Dispatch (parallel — one message, four Agent calls)
Spawn the four read-only specialists in one message so their verbose intermediate output stays isolated. Each prompt = the envelope block + that agent's module list. Agents never rely on ${…} substitution: pass absolute paths.
ENVELOPE
plugin_root: <absolute ${CLAUDE_PLUGIN_ROOT}>
run_dir: <absolute run dir>
pages: [{slug, url, role}, …] # <run_dir>/pages/<slug>.json (+ <slug>.html, + <slug>.rendered.html when rendered)
site: robots=<run_dir>/site/robots.json sitemaps=<run_dir>/site/sitemaps.json discovery=<run_dir>/site/discovery.json
vertical: {primary: <v>, also: [<v>…], multilingual: <bool>}
platform: <run_dir>/profile.json # one line: <platform>/<framework>, env=<kind>, head_owner=<…>
platform_cards: [<plugin_root>/references/platforms/<id>.md, …] # omit when the platform is unknown
modules: [<M-ids for this agent>]
deterministic_findings: <run_dir>/findings.deterministic.json — do not re-emit these ids; add model-judged findings only
return: JSON array only — findings per schema/finding.schema.json, no prose
| Agent | Modules |
|---|---|
technical-auditor | M1, M2 (+M3), M4, M7, M7b (mobile), M7c (headings), M8, M9, M10, M15, M17 — plus M20 (hreflang) when vertical.multilingual |
ai-search-geo-specialist | M6, M11, M12, M14, M21 (AI discovery & agent endpoints, weight 0), M22 (agent-readiness) |
content-eeat-analyst | M13, M16 |
schema-generator | M5 — plus M18 when ecommerce ∈ vertical, M19 when local-business ∈ vertical |
Subagents have no Write/Edit — the audit can never mutate files. If an agent returns prose around the array, keep only the array.
3. Synthesize
- Save each returned array verbatim to
<run_dir>/agents/<agent>.jsonvia a Bash heredoc (mkdir -p "<run_dir>/agents" && cat > "<run_dir>/agents/<agent>.json" <<'EOF' … EOF) — into the plugin data dir, never the project. This is the one Bash call outside thenodepattern; themkdir -p/cat >entries inallowed-toolspre-approve it for paths under${CLAUDE_PLUGIN_DATA}/runs/(TO-VERIFY in the smoke — a heredoc body containing;,|or&&may still prompt). node "${CLAUDE_PLUGIN_ROOT}/scripts/report.mjs" <run_dir> --merge "agents/*.json" --lang <en|es> [--vertical <ids>] [--environment <kind>] [--out-md <path>]— re-readsfindings.deterministic.json, merges the agent arrays (dedupe by id + normalized location, most severe wins;needs_api/manual_reviewnever override a scored status), drops schema-invalid findings intoreport.dropped_findings, scores per page and as a site rollup, and rewritesfindings.json,report.json,report.md. Pass the same--vertical/--environmentyou used in step 1.--mergeis repeatable and accepts a file, a directory, or a*/?glob on the file name only.- Present from
report.json(bands/interpretations perreferences/scoring-model.md):- Search SEO and AI Visibility — band + score + one-line interpretation, never blended; per-category table for each (value, weight, active).
- Coverage:
coverage.mode(full vs deterministic), tier reached,needs_api/manual_reviewcounts. - Sampling table from
crawl.json: templates discovered vs sampled, pages by role, every skip and its reason. - Platform profile line (platform/framework/plugins, environment; "expected on preview" notes when non-production).
- Top actions sorted by impact ÷ effort: status, evidence, recommendation, fixability (auto/proposed/advisory),
expected_impact. - The absolute
report.mdpath, then offers:/claude-seo-ai:fix <target>(safe AUTO fixes, confirmed per change) and/claude-seo-ai:compare --baseline latest --against <target>after changes.
Degraded mode
If node is missing, or a skills-only install ships no scripts/ directory: say so first. Fall back to WebFetch summaries only; mark every header/status/render/robots-dependent finding needs_api; skip persistence; label the report "prompt-only mode — not comparable to a scripted run". Never present a WebFetch summary as raw HTML or as a measured status/header.