One page. Every engine. Score a site's SEO, AEO and GEO signals against its real HTML, then generate the machine-readable ground truth AI engines can cite.
FAQ
omnirank is a Claude Code plugin with 2 hand-picked skills for marketing work, indexed on Flowy. Install it with the command on its page. It includes audit, geo-artifacts. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
$ npx -y skills add bemoshiur/OmniRank --agent claude-code
Repo: bemoshiur/OmniRank
One page. Every engine.
Score a site's SEO, AEO and GEO signals against its real HTML, then generate the machine-readable ground truth AI engines can cite.
OmniRank scores a website's live HTML against the concrete rules that search engines,
answer engines and generative AI systems use to crawl, quote and cite content, then
generates llms.txt, llms-full.txt and facts.json so the page becomes machine-readable
ground truth an AI engine can cite directly.

Real terminal output from omnirank audit https://example.com โ nothing staged, nothing cropped.
Three audiences parse one document. A crawlable, well-marked-up, machine-readable page wins all three at once โ that is the entire bet OmniRank makes, and why it audits one artifact (your rendered HTML) instead of three separate tools.
| Layer | Audience | What it wants | What OmniRank does |
|---|---|---|---|
| SEO | Googlebot, Bingbot | Crawlable, canonical, correctly sized metadata, valid structured data | Checks h1, canonical, title/description length, OpenGraph, JSON-LD |
| AEO | AI Overviews, Copilot, voice assistants | A short, liftable, factual answer near the top of the page | Checks for a 40โ60 word AnswerBlock, an FAQ section, and speakable markup |
| GEO | ChatGPT, Claude, Perplexity, Gemini | Machine-ingestible ground truth plus explicit permission to cite | Generates and verifies llms.txt, llms-full.txt, facts.json with a citation licence |
The table above is not aspirational copy โ it is also, deliberately, how this README is
written. It has one <h1>, an AnswerBlock-shaped opening paragraph, an FAQ section, and
descriptive headings. If OmniRank asked your page to do these things, it does them too.
OmniRank is not published to PyPI, npm or a container registry โ install it from source
into a virtual environment. Homebrew and other PEP 668-managed Python installs refuse a
bare pip install, so activate a venv first:
git clone https://github.com/bemoshiur/OmniRank.git && cd OmniRank
python3 -m venv .venv && source .venv/bin/activate && make install
python3 -m omnirank.cli audit https://example.com
Real output, captured against https://example.com:
OmniRank 0.2.0 โ https://example.com
overall 76/100 aeo 80 geo 60 perf 100 seo 67
1 URLs checked, 10 findings
[FAIL] seo.canonical.missing https://example.com/
observed: no rel=canonical
fix: Add <link rel="canonical" href="https://example.com/"> to <head>.
[FAIL] seo.description.missing https://example.com/
observed: no meta description
fix: Add a meta description summarising the page.
[WARN] seo.og.missing https://example.com/
observed: missing og:title, og:image
fix: Add the missing OpenGraph tags so social unfurls render.
[FAIL] aeo.answer-block.missing https://example.com/
observed: no element matching '.answer-block'
fix: Add <div class="answer-block" data-speakable> with a 40-60 word plain-prose answer.
[FAIL] aeo.faq.too-few https://example.com/
observed: 0 FAQ pairs
fix: Add FAQs as semantic <dl>/<dt>/<dd> or <details>, mirrored by FAQPage JSON-LD.
[FAIL] seo.schema.absent https://example.com/
observed: no application/ld+json blocks
fix: Emit JSON-LD describing this page and cross-reference the site organisation by stable @id.
[FAIL] geo.llms.missing https://example.com/llms.txt
observed: HTTP 404 at llms.txt
fix: Generate llms.txt at build time and serve it as a static file.
[FAIL] geo.llms-full.missing https://example.com/llms-full.txt
observed: HTTP 404 at llms-full.txt
fix: Generate llms-full.txt at build time and serve it as a static file.
[FAIL] geo.facts.missing https://example.com/facts.json
observed: HTTP 404 at facts.json
fix: Generate facts.json at build time and serve it as a static file.
[FAIL] geo.ai-allowlist.missing https://example.com/robots.txt
observed: HTTP 404 at /robots.txt
fix: Publish a robots.txt that explicitly allows AI crawlers.
report: .omnirank/reports/2026-08-03-audit.json
example.com ships nothing but a static placeholder page, so this is close to a worst
case โ real sites usually clear a handful of these on the first pass. Every finding
carries observed, expected, and fix โ enough to act on without opening the code.
For a configured repo, copy the starter config and gate a build on specific gates:
cp templates/omnirank.config.example.json omnirank.config.json
python3 -m omnirank.cli audit --config omnirank.config.json --fail-on h1 canonical schema
python3 -m omnirank.cli geo --config omnirank.config.json --out public
Exit codes: 0 clean ยท 1 a --fail-on gate failed ยท 2 usage or config error. The
non-zero exit is what makes it a CI gate, not just a report โ see
Use OmniRank as a CI gate below.
| Skill | Status | What it does |
|---|---|---|
audit | Shipped | Scores SEO, AEO, GEO, perf and structured-data gates against a site's real HTML โ including a cross-URL pass over the whole crawled set โ and reports observed / expected / fix for every gap |
geo-artifacts | Shipped | Generates llms.txt, llms-full.txt and facts.json, each with an explicit citation licence |
fix (preview) | Shipped | Resolves a finding's URL to the source file that owns it and prints the unified diff it would apply for the four mechanical findings. Writes nothing โ there is no --write flag in 0.3.0 |
Still exactly two skills. 0.3.0 added the locator โ URL to source file โ plus a
fixTier on every finding and the omnirank fix diff preview. This release writes
nothing to your project. File modification arrives in v0.4.0, deliberately after the
locator has been proven. Everything under Roadmap below is not present in v0.3.0.
| Skill | Target | What it will do |
|---|---|---|
aeo-onpage | v0.2 | Emit JSON-LD by entity type; draft AnswerBlocks and FAQs; Next.js codegen |
indexing | v0.3 | IndexNow, GSC URL Inspection, Bing Submit, Wayback, hash-based freshness |
offsite-entity | v0.4 | sameAs gap analysis, peer mention-gap detection, outreach drafts for human review |
measure | v0.5 | Rank tracking plus real AI-citation testing across engines |
smm-content | v0.6 | Repurpose published pages into platform-native assets |
smm-publish | v0.7 | Gated publishing โ dry-run by default, human approval required |
aeo-onpage's "v0.2" target above predates this plan and has already slipped: 0.2.0
shipped as a site-gates/AnswerBlock-bands/perf release instead, folded into the existing
audit skill rather than a new one. Treat every target version in this table as
directional, not a commitment โ none has a firm date. Adapters for WordPress, Jekyll,
Shopify, Astro, Vue and Svelte land at v1.0. None of the skills in this table exist in the
installed package today โ asking Claude Code to "write our JSON-LD" or "submit this URL to
Google" will not trigger anything, because aeo-onpage and indexing are not built yet.
28 gate names exist in the config schema; 15 can fail a build and 13 are warning-only by
design. (As of v0.2.1, crawl-hygiene โ a gate name that could never actually fire,
since its only source was never called from audit_site() โ was removed from the schema
rather than shipped as a config option that silently did nothing; hygiene.check_sitemap()
was wired into sitemap-health instead, so a redirecting or dead sitemap URL now gets its
own dedicated finding.) Full detail, including which gates can never trip --fail-on, is in
audit-guide.md and
ci-integration.md.
SEO
| Gate | Rule | Severity |
|---|---|---|
h1 | Exactly one <h1> | error |
canonical | Present, absolute, self-referencing | error |
title-length | Present, โค60 characters | error if missing, warning if over |
description-length | Present, โค160 characters | error if missing, warning if over |
og | og:title and og:image present | warning |
hreflang | If any hreflang, an x-default exists | warning |
image-dims | Every <img> has width and height | warning |
AEO
| Gate | Rule | Severity |
|---|---|---|
answer-block | 40โ60 word plain-prose element exists, no lists inside | error |
faq | โฅ3 pairs as <dl>/<dt>/<dd> or <details> | warning |
speakable | Every speakable.cssSelector resolves to real markup | error |
GEO
| Gate | Rule | Severity |
|---|---|---|
llms-txt | /llms.txt returns 200 | error |
llms-full | /llms-full.txt returns 200 | error |
facts-json | /facts.json returns 200 and parses | error |
ai-allowlist | robots.txt does not Disallow: / any AI crawler | error |
citation-licence | llms.txt contains a licence or attribution statement | warning |
Structured data
| Gate | Rule | Severity |
|---|---|---|
schema | At least one valid application/ld+json block with @type | error |
schema-fabrication | AggregateRating has a real ratingCount; every Review has an author | error |
Site-level (cross-URL) โ new in 0.2.0; needs the whole crawled set, not one page
| Gate | Rule | Severity |
|---|---|---|
duplicate-title | Two or more crawled pages share a <title> | warning |
duplicate-description | Two or more crawled pages share a meta description | warning |
noindex-in-sitemap | A crawled noindex page is also listed in sitemap.xml | error |
canonical-cluster | A canonical points at a page that itself canonicalises elsewhere | warning |
hreflang-reciprocity | An hreflang alternate does not link back | warning |
Performance โ new in 0.2.0; derived from one HTTP response, no browser involved
| Gate | Rule | Severity |
|---|---|---|
response-time | Full response โฅ 2000 ms (warning) or โฅ 5000 ms (error) โ OmniRank's own tunable thresholds. This is the complete time for OmniRank's own request (DNS through the last byte of the body), not time-to-first-byte; it measures a full download, not server think-time | warning / error |
page-weight | Raw HTML exceeds 500,000 bytes before any subresource | warning |
compression | No gzip/deflate content-encoding โ the only encodings OmniRank's client ever requests, so br/zstd are matched if present but never verifiable | warning |
render-blocking | More than 2 blocking <script> tags in <head> | warning |
perf never measures Largest Contentful Paint, Cumulative Layout Shift, Interaction to
Next Paint, or a Lighthouse score โ OmniRank has no browser. See
audit-guide.md for the named threshold
constants and faq.md for the full
answer.
Option 1 โ packaged skill for Claude Code, no clone required:
curl -LO https://github.com/bemoshiur/OmniRank/releases/latest/download/omnirank-skill.zip
unzip omnirank-skill.zip -d ~/.claude/plugins/
The archive is built by scripts/build-skill-zip.sh and
published on every v* tag. It contains the plugin manifest, both skills, the Python
package, JSON Schemas and the config template โ everything needed to run the CLI and have
both skills register, without the tests, CI config or Node sources. Build it yourself
instead of downloading it:
./scripts/build-skill-zip.sh # -> dist/omnirank-skill-<version>.zip
Option 2 โ clone, for CLI use or contributing:
git clone https://github.com/bemoshiur/OmniRank.git ~/.claude/plugins/omnirank
This gets the full repository โ tests, CI config, and the Node GEO-artifacts generator โ
and lets you git pull to update instead of re-downloading a release archive. See
claude-code-setup.md for confirming the skills registered and
the real trigger phrases for each.
omnirank audit --fail-on <gates> exits 1 when a named gate has an error-severity
finding and 0 otherwise โ that is the entire integration surface:
name: OmniRank audit
on:
pull_request:
push:
branches: [main]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install OmniRank
run: pip install "omnirank @ git+https://github.com/bemoshiur/OmniRank.git#subdirectory=scripts/py"
- name: Audit
run: |
omnirank audit --config omnirank.config.json --out omnirank-report.json \
--fail-on h1 canonical schema llms-txt llms-full facts-json ai-allowlist
# Fail the build while a mechanical fix is outstanding. Writes nothing.
python3 -m omnirank.cli fix --config omnirank.config.json --root .
Picking --fail-on h1 canonical schema (structural baseline) is a better starting point
than listing all 28 gate names โ 13 of them are warning-only and can never fail a build.
The full reasoning, plus a GitLab CI job and a generic shell script, is in
ci-integration.md.
Real-only. No fabricated statistics, ratings, reviews or testimonials. facts.statistics
carries only entries explicitly marked published; AggregateRating without a real
ratingCount is reported as an error, not a warning.
Never claim an unevaluated gate passed. An unreachable URL is an error. A layer whose gates did not run is absent from the score map rather than scored 100.
Secrets are pointers. Config holds env:NAME only. A missing variable fails loudly โ
a skipped submission is otherwise indistinguishable from a successful one in logs.
Audit diagnoses; it never edits. geo-artifacts writes the three GEO artifacts it
generates and nothing else โ neither skill touches existing site source.
JobPosting and
BroadcastEvent only; misuse earns a manual action.No โ nothing can guarantee a ranking, since search and answer engines rank content using signals no third-party tool controls. OmniRank scores a site against the concrete, checkable signals those engines are known to use and returns a prioritised list of gaps; closing them improves the odds without touching what OmniRank cannot see, such as backlink profile or content quality relative to competitors. See faq.md for the full answer.
No โ OmniRank runs entirely on your machine or CI runner and only makes outbound HTTP
requests to the URL you point it at, fetching pages, sitemap.xml, robots.txt,
llms.txt, llms-full.txt and facts.json from that one site. There is no telemetry and
no third-party API call in the audit or geo-artifacts code paths.
audit reads a site and reports what's wrong, with no side effects. geo-artifacts writes
three new files (llms.txt, llms-full.txt, facts.json) and nothing else. They compose:
run geo-artifacts to generate the files, deploy them, then run audit to confirm they
actually serve in production โ the GEO layer checks exactly that.
No โ audit only diagnoses; SKILL.md states directly that "Audit only diagnoses. It
never edits the site." geo-artifacts does write files, but only the three GEO artifacts
it generates into the output directory you specify, never existing site source.
No, not as of v0.2.0. Install the Python CLI from source โ clone the repository and pip install -e ./scripts/py inside a virtual environment, or install directly from git with
pip install "omnirank @ git+https://github.com/bemoshiur/OmniRank.git#subdirectory=scripts/py".
The Node generator is likewise unpublished; import scripts/node/src/generate.ts directly
or copy it into your project.
Python 3.11 or newer is required for the CLI and both skills (pyproject.toml sets
requires-python = ">=3.11"; CI tests 3.11, 3.12 and 3.13). Node 22 or newer is needed only
if you use the in-repo Node GEO-artifacts generator instead of the Python crawl path โ Node
is not required at all for the CLI.
No โ publishing llms.txt, llms-full.txt and facts.json follows the community
llms.txt convention and grants an explicit citation licence, which
removes a real barrier to a model quoting the content, but no engine's retrieval or
citation behaviour is under OmniRank's control. Publishing them is a low-cost,
evidence-backed bet, not a guarantee.
Yes, for both commands โ omnirank audit <url> and omnirank geo <url> both work with
just a URL, using an in-memory default config. Since the in-memory default config has no
geo section, a bare omnirank geo <url> has no configured geo.license either โ as of
v0.2.1 that generates the artifacts anyway, stating plainly that no reuse licence is
granted, and prints a one-line notice to stderr saying so (a config's generated files are
published to your site, so OmniRank tells you rather than silently choosing "no rights"
on your behalf). Write a config with geo.license set to a real licence and pass it with
--config to actually grant reuse rights, or set it to "none" explicitly to make that
choice permanent and silence the notice; see
geo-artifacts-guide.md. Beyond
that, a config file is also needed for CI gating with a committed audit.failOn,
first-party facts (nap, identifiers, statistics), or anything the roadmap skills
will eventually read from secrets.
As of v0.2.1, each GATE's contribution to its layer is capped at GATE_CAP = 15
(min(15, 10*errors + 3*warnings)), so one gate failing on every page of a large site
can no longer alone drag a layer to 0 โ that would conflate issue COUNT with issue
SEVERITY (one broken template is one problem, not fifty). A layer still reaches 0 when
enough DISTINCT gates are broken for their capped costs to sum past 100 โ seven or more
independently-broken gates is enough on its own. A brand-new site missing a <title>,
canonical tag, JSON-LD, and llms.txt will commonly hit this on the GEO layer, since
each missing artifact is a separate broken gate.
More questions, including secrets handling and where the JSON report schema lives, are answered in docs/faq.md.
Every page is verified against the v0.2.0 source, generated from the JSON Schema where applicable, and every command shown was actually run.
| Guide | Covers |
|---|---|
| docs/README.md | Documentation index and reading order by task |
| getting-started.md | Zero-to-first-audit: install, run, read the result, exit codes |
| configuration.md | Every omnirank.config.json field, with a complete example |
| audit-guide.md | The audit skill in depth: every gate, the scoring formula, a worked example |
| geo-artifacts-guide.md | Generating the three GEO artifacts and the OpenNext/CloudFront 403 trap |
| ci-integration.md | GitHub Actions, GitLab CI, shell examples, and choosing --fail-on gates |
| claude-code-setup.md | Installing as a Claude Code plugin and the real trigger phrases per skill |
| troubleshooting.md | Real error text for likely failures, with the fix for each |
| faq.md | 17 direct, honest answers, including what OmniRank does not do |
Read CONTRIBUTING.md before opening a pull request โ it covers
the non-negotiables (real-only data, never claiming an unevaluated gate passed, env:
secrets only) and the test-driven workflow this project enforces on itself.
If OmniRank caught something on your site that you'd otherwise have shipped broken, a star helps the next person searching "AEO audit tool" find it too โ that's the only ask.
OmniRank implements and builds on public standards and published research:
Correlations from that research are observational, drawn largely from English-language B2B datasets, and are treated as directional. Validate empirically per site.
Built and maintained by S M Moshiur Rahman at Public Pulse Agency, Dhaka โ across publicpulse.com.bd, tenderpulse.com.bd and pulsetoday.com.bd.
S M Moshiur Rahman โ Director of Business & Operations, Public Pulse Agency
| ๐ฌ WhatsApp | +880 1717 714676 โ fastest for project discussion |
| โ๏ธ Email | moshiur@publicpulse.com.bd |
| ๐ Web | publicpulse.com.bd |
| ๐ป GitHub | @bemoshiur |
For bugs and feature requests, use Issues rather than direct message โ it keeps the answer searchable for the next person. For consulting, partnerships, or anything project-specific, WhatsApp gets the quickest reply.
Code is MIT. Documentation and the content corpus exposed via llms.txt and
llms-full.txt are CC BY 4.0.
.claude-plugin/
plugin.json
.github/
assets/
demo.gif
og-template.svg
og.png
README.md
CODE_OF_CONDUCT.md
CODEOWNERS
CONTRIBUTING.md
dependabot.yml
ISSUE_TEMPLATE/
adapter_request.yml
bug_report.yml
config.yml
feature_request.yml
PULL_REQUEST_TEMPLATE.md
SECURITY.md
SUPPORT.md
workflows/
ci.yml
release.yml
.gitignore
CHANGELOG.md
CITATION.cff
docs/
audit-guide.md
ci-integration.md
claude-code-setup.md
configuration.md
faq.md
fix-preview.md
geo-artifacts-guide.md
getting-started.md
README.md
research/
2026-08-04-automation-architecture.md
2026-08-04-competitive-gap-analysis.md
2026-08-04-fixability-classification.md
superpowers/
plans/
2026-08-03-omnirank-v0.1.0.md
2026-08-03-omnirank-v0.2.0.md
2026-08-04-omnirank-v0.3.0.md
specs/
2026-08-03-omnirank-design.md
troubleshooting.md
wiki/
_Footer.md
_Sidebar.md
Audit-Skill.md
CI-Recipes.md
Claude-Code-Setup.md
Configuration-Reference.md
FAQ.md
Finding-Reference.md
Fix-Preview.md
Fix-Tiers-and-Applicability.md
GEO-Artifacts-Skill.md
Glossary.md
Home.md
Quick-Start.md
Report-Schema.md
Research-and-Evidence.md
Roadmap.md
The-Locator.md
Troubleshooting.md
LICENSE
LICENSE-CONTENT
Makefile
README.md
schemas/
omnirank.config.schema.json
report.schema.json
scripts/
build-skill-zip.sh
fixtures/
demo-site/
about/
index.html
facts.json
index.html
llms-full.txt
llms.txt
pricing/
index.html
sitemap.xml.tmpl
node/
package.json
pnpm-lock.yaml
src/
generate.test.ts
generate.ts
tsconfig.json
py/
omnirank/
__init__.py
applicability.py
audit.py
bands.py
cli.py
config.py
fetch.py
fixes/
__init__.py
base.py
canonical.py
schema.py
framework.py
gates/
__init__.py
aeo.py
geo.py
hygiene.py
jsonld.py
perf.py
seo.py
site.py
geo_artifacts.py
html.py
locator.py
page.py
registry.py
report.py
pyproject.toml
render-demo-gif.py
render-og.sh
setup-repo.sh
skills/
audit/
references/
crawl-hygiene.md
gates.md
SKILL.md
geo-artifacts/
references/
facts-json.md
serving-gotchas.md
SKILL.md
templates/
omnirank.config.example.json
tests/
__init__.py
_patch.py
conftest.py
fixtures/
aeo_clean.html
clean.html
test_applicability.py
test_audit.py
test_bands.py
test_build_skill_zip.py
test_cli.py
test_community_health.py
test_config_schema.py
test_config.py
test_demo_gif.py
test_docs.py
test_fetch.py
test_fixes_canonical.py
test_fixes_patchability.py
test_fixes_schema.py
test_framework.py
test_gates_aeo.py
test_gates_geo.py
test_gates_hygiene.py
test_gates_jsonld.py
test_gates_perf.py
test_gates_seo.py
test_gates_site.py
test_geo_artifacts.py
test_html.py
test_locator.py
test_og_asset.py
test_page.py
test_plugin_manifest.py
test_registry.py
test_repo_docs.py
test_report.py
test_setup_repo.py
test_skills_frontmatter.py
test_workflows.pyยฉ 2026 Flowy ยท Free and open source
Built for Claude Code ยท Not affiliated with Anthropic