Skip to content

Releases: integrallis/rankcli

v0.0.58: five findings from dogfooding, fixed

Choose a tag to compare

@bsbodden bsbodden released this 03 Nov 19:01

v0.0.58: five findings from dogfooding, fixed

Found by auditing a plain static site with 0.0.56 and 0.0.57 and reading the source behind each finding.

  • An inline <style> is not a render-blocking resource (#19). RENDER_BLOCKING_RESOURCES recommended inlining critical CSS and then counted the inline block, so a page with any CSS at all was flagged for good. An inline style costs no network round-trip before first paint; it is no longer counted, and the recommendation names the actual remedies.
  • A 401, 403, 405 or 429 is not a broken external link (#21). HEAD is refused by many hosts and a 403 or 429 is bot protection or a rate limit; Medium answers 403 to every crawler and every link to it was "broken". Those statuses are retried once with a browser-like GET and, if still refused, treated as indeterminate, like a timeout. A definite 4xx or 5xx on either request still counts.
  • /index.html is the homepage (#23). A site whose brand link points at index.html had its homepage keyed two ways, the link graph looked up the one the crawl had not stored, and NAV_NOT_IN_HTML reported zero links over ten static ones. canonicalPageUrl folds /index.html into /, the graph falls back to the first audited page when the entry URL is not among the keys, and a page's link to itself is not a link to another page.
  • Two recommendations now say what the checks accept (#24). FAQ_SCHEMA_MISSING asks for FAQPage only where each question heading is followed by its answer; a question mark is not evidence of a FAQ, and Google restricts the markup to real FAQ content. PLAINTEXT_EMAIL recommends a mailto: link with descriptive text instead of name[at]domain.com, which breaks the link for readers and screen readers.
  • The auto-fixer's structured-data fix states only what the page states (#20). It wrote a SoftwareApplication with a free Offer into every page that lacked schema. It now writes a WebSite for the site root and a WebPage elsewhere, named from the page's own title with its meta description, and never an Offer.
  • A lazy-loaded image's origin does not need a preconnect. MISSING_PRECONNECT no longer counts an origin used only by an image with loading="lazy" or fetchpriority="low", which the browser fetches after the critical path.

Packages: @rankcli/cli 0.0.58, @rankcli/agent-runtime 0.0.46, @rankcli/mcp-server 0.0.31.

Install

npm install -g @rankcli/cli    # or: brew install integrallis/tap/rankcli

Standalone binaries for macOS, Linux and Windows and the Claude Desktop extension (.mcpb) are attached below.

v0.0.57: the second pass over the always-on findings

Choose a tag to compare

@bsbodden bsbodden released this 03 Nov 16:20

v0.0.57: the second pass over the always-on findings

0.0.55 removed the 25 findings the npm corpus showed on nearly every site, which took the audit from 56 codes per site to 42 on the same 367 sites. This release takes the next tier: ten findings on a third to two thirds of sites, each a heuristic with no evidence behind it.

Gone Share of the corpus Why
NO_AGENT_EXPERIENCE_SURFACE 64% "none of the emerging conventions found" (llms-full.txt, SKILL.md, an MCP server, OpenAPI); the llms.txt finding already says what the evidence says about that family
AI_NO_TESTIMONIALS, AI_NO_REVIEW_PLATFORMS, AI_WEAK_REVIEW_ECOSYSTEM, AI_NO_REVIEW_INTEGRATION 59% "AI looks for social proof" has no source, and a library's documentation site has no testimonials to add
LOW_AI_CITATION_READINESS 53% a composite of the freshness findings the check already reports one by one
POPUP_BOUNCE_RISK 51% a dialog element in the HTML, called an intrusive interstitial; documentation sites have search dialogs
LOW_CTR_POTENTIAL (was a warning) 47% a click-through estimate from the title and the description, next to the title and description findings themselves
GSC_VERIFICATION_MISSING 44% Search Console verifies through DNS on the apex, a file, Analytics or Tag Manager; a missing meta tag proves nothing, as with Bing in 0.0.55
AI_NO_USP 40% "no unique selling proposition detected"
NO_HIGH_PRIORITY_PLATFORMS 35% "no links to YouTube, TikTok, Twitter/X, LinkedIn or Reddit"

What stays from that tier, on purpose: the security headers, DMARC and SPF, SCHEMA_MISSING, the performance findings Lighthouse also reports (render-blocking resources, preconnect, image dimensions, hero preload), LLMS_TXT_MISSING as framed in 0.0.54, NO_SOCIAL_PROOF (a conversion notice) and BOFU_NO_SOCIAL_PROOF (only on a bottom-of-funnel page), and AI_NO_REVIEW_SCHEMA, which only fires on a page that has testimonials.

The analyzers keep computing their data; only the findings go. Removed codes drop out of a 0.0.56 baseline silently; LOW_CTR_POTENTIAL was a warning, so a gate on warnings may pass where it failed.

Packages: @rankcli/cli 0.0.57, @rankcli/agent-runtime 0.0.45, @rankcli/mcp-server 0.0.30.

Install

npm install -g @rankcli/cli    # or: brew install integrallis/tap/rankcli

Standalone binaries for macOS, Linux and Windows and the Claude Desktop extension (.mcpb) are attached below.

v0.0.56: a disallowed training crawler is policy, not a critical finding

Choose a tag to compare

@bsbodden bsbodden released this 03 Nov 03:48

v0.0.56: a disallowed training crawler is policy, not a critical finding

A fix to rankcli geo and the MCP server's seo_geo_check, left over from the one bot table in 0.0.55. The geo analyzer took its crawler list from the audit's table but still treated every disallowed crawler the same way: GEO_AI_CRAWLERS_BLOCKED (critical) for any of them, ten GEO points off per crawler, "URGENT: Unblock AI crawlers", and a fix that told the site to allow Claude-Web. A site that disallows the training crawlers, which OpenAI and Anthropic document as costing no visibility, lost fifty points and got a critical finding for it.

By class now, the same way the audit reports it:

Disallowed Finding GEO score
search, AI search (Googlebot, bingbot, OAI-SearchBot, Claude-SearchBot, PerplexityBot, YouBot) GEO_AI_CRAWLERS_BLOCKED, critical, with the Allow group for those crawlers as the fix -10 each
user-triggered fetchers (ChatGPT-User, Claude-User, Perplexity-User) GEO_AI_USER_FETCH_BLOCKED, warning (new) -5 each
training (GPTBot, ClaudeBot, CCBot, Google-Extended, Bytespider, Applebot-Extended, meta-externalagent, Amazonbot, cohere-ai) listed, with a line saying it costs no visibility none

In the JSON, aiCrawlerAccess.byClass carries the split and robotsTxtAllowsAI is true when nothing that costs visibility or a user's fetch is disallowed; blockedCrawlers and allowedCrawlers keep their shape. The geo command and the MCP tool print the three disallowed rows by class. The audit (rankcli audit, the GitHub Action) is unchanged: it already reported crawler access by class.

Packages: @rankcli/cli 0.0.56, @rankcli/agent-runtime 0.0.44, @rankcli/mcp-server 0.0.29.

Install

npm install -g @rankcli/cli    # or: brew install integrallis/tap/rankcli

Standalone binaries for macOS, Linux and Windows and the Claude Desktop extension (.mcpb) are attached below.

v0.0.55: a finding that fires on nearly every site is a default, not a finding

Choose a tag to compare

@bsbodden bsbodden released this 03 Nov 03:26

v0.0.55: a finding that fires on nearly every site is a default, not a finding

The first run of the npm corpus (the homepages of the 400 most popular npm packages, 367 audited with 0.0.54, published at https://rankcli.dev/data/npm-sites) counted 56 codes per site on average, and 30 of them fired on 60 percent or more of the best-built documentation sites on the web. A notice every site gets carries no information and costs the credibility of the ones that do.

Gone, with the share of the corpus each fired on: AI_INCOMPLETE_BRAND_COVERAGE (95%), NO_SNIPPET_BAIT_HEADERS (92%), BING_VERIFICATION_MISSING, BING_NOT_VERIFIED and BING_PLACES_MISSING (92%), NO_RELATED_CONTENT (89%), INVERTED_PYRAMID_MISSING (88%), AI_LOW_CITATION_QUALITY (88%), AI_NO_ORIGINAL_DATA (87%), GTM_MISSING (86%), NO_EXPERIENCE_SIGNALS and AI_NO_EXPERIENCE_SIGNALS (81%), RAG_CHUNK_SIZE_MISMATCH (80%), NO_ENTITY_IDENTIFIED and NO_ENTITY_DEFINITION (79%), AI_NO_BRAND_DEFINITION and AI_LOW_BRAND_SCORE (78%), LOW_DWELL_TIME_SIGNALS (78%), GA4_MISSING (76%), AI_LOW_CITATION_WORTHINESS (71%), NO_ENGAGEMENT_TRIGGERS (69%), HIGH_BOUNCE_RISK (62%), plus REVIEW_NO_VIDEO, COMMERCIAL_NO_CTA and NEW_SITE_STRATEGY, which fired regardless of content. Not using Google's tag manager or Bing's webmaster tools is a choice; the rest were heuristics with no evidence behind them. The analyzers keep computing their data (brand, entity, chunk and engagement scores stay in the report's data); only the findings go.

Conditioned: NO_BREADCRUMBS (98%) never fires on the homepage, which has nothing to lead back to. INDEXNOW_NOT_IMPLEMENTED (100%) is dropped when the site has no sitemap, since Bing's advice is an accurate lastmod paired with IndexNow.

What stays from the high end of the table: the security-header notices, DMARC and SPF, the Apple touch icon. Each describes something a standard asks for and a site can add in a line.

One bot table. The analyzer behind rankcli geo, the MCP server's seo_robots_ai, seo_generate_robots and seo_ai_crawlers, and the robots.txt the auto-fix writes kept a second crawler list from before the bot classes: it still called Anthropic's crawler Claude-Web, told a site that disallowing GPTBot meant its content would not appear in ChatGPT answers (OpenAI documents the opposite), and generated a robots.txt that allowed "all AI crawlers" as one undivided group. All of it now derives from the audit's table: the robots analysis reports by class (search, AI search, user-triggered, training) with the advice worded for what blocking each class costs, and the generated robots.txt writes one group per class, training allowed but marked as the group to turn into Disallow when that is the policy. The table gains the robots-only tokens the old list knew (Applebot-Extended, meta-externalagent, Amazonbot and cohere-ai as training; YouBot as AI search), so AI_TRAINING_BOTS_DISALLOWED and AI_SEARCH_BOTS_DISALLOWED name them too.

Removed codes drop out of a 0.0.54 baseline silently; AI Readiness scores rise by the notices a site no longer gets.

Packages: @rankcli/cli 0.0.55, @rankcli/agent-runtime 0.0.43, @rankcli/mcp-server 0.0.28.

Install

npm install -g @rankcli/cli    # or: brew install integrallis/tap/rankcli

Standalone binaries for macOS, Linux and Windows and the Claude Desktop extension (.mcpb) are attached below.

v0.0.54: the AI checks say what the evidence says

Choose a tag to compare

@bsbodden bsbodden released this 03 Nov 02:15

v0.0.54: the AI checks say what the evidence says

The AI-readiness checks now follow what the crawler operators document and what the citation studies measure, and the audit reads two things a browser never shows: the metadata in the initial HTML, and the link graph before any script runs.

AI crawler access by bot class. OpenAI documents GPTBot as training-only and says a site opted out of OAI-SearchBot "will not be shown in ChatGPT search answers"; Anthropic documents the same split (ClaudeBot, Claude-SearchBot) plus Claude-User, which fetches one page because a user asked. The checks group bots that way and word each finding for its consequence, from robots.txt and from a live fetch as each bot:

Class Bots robots.txt disallowed Refused at the edge
search Googlebot, bingbot crawlability checks SEARCH_CRAWLER_BLOCKED_AT_EDGE error
AI search OAI-SearchBot, Claude-SearchBot, PerplexityBot AI_SEARCH_BOTS_DISALLOWED warning AI_SEARCH_CRAWLER_BLOCKED_AT_EDGE warning
user-triggered ChatGPT-User, Claude-User, Perplexity-User AI_USER_FETCH_DISALLOWED warning AI_USER_FETCH_BLOCKED_AT_EDGE warning
training GPTBot, ClaudeBot, CCBot, Google-Extended, Bytespider AI_TRAINING_BOTS_DISALLOWED notice AI_TRAINING_CRAWLER_BLOCKED_AT_EDGE notice

A challenge interstitial counts as a refusal even when it answers 200; the live fetch asks once per origin per run. Gone: AI_CRAWLER_BLOCKED_AT_EDGE, AI_BOT_GPTBOT_BLOCKED, AI_BOT_CLAUDEBOT_BLOCKED, AI_BOT_PERPLEXITY_BLOCKED, AI_BOT_GOOGLE_EXTENDED_BLOCKED.

Metadata placement. A fetch as Googlebot tells Next.js streaming metadata (METADATA_STREAMED_FOR_BOTS: the title, description and canonical reach Googlebot but arrive later, inside the body, for everyone else, including the AI search crawlers) from metadata rendered into the body for everyone (METADATA_OUTSIDE_HEAD). The fix names htmlLimitedBots.

The link graph without JavaScript. Each page's HTML links build a graph: linkGraph in the JSON report (homepage links, depth per page, unreachable pages, orphans, coverage) and depth on every page summary. NAV_NOT_IN_HTML (warning) when the homepage's HTML links to two pages or fewer on a site with ten or more; ORPHAN_PAGES and DEEP_PAGES only once every sitemap page was audited, so a five-page audit of a four-hundred-page site claims nothing it cannot see.

Content findings with their evidence. The comparison-table, direct-answer and uncited-statistics findings cite the studies behind them (tables +69 percent odds of citation; 23 versus 14 percent of pages opening with a direct answer; statistics with sources +29 percent, quotations +40 percent); the freshness findings cite Ahrefs and SE Ranking in place of an unsourced percentage. Gone: AI_NO_QA_FORMAT, AI_NO_DEFINITIONS, AI_QUESTIONS_NO_DIRECT_ANSWERS, AI_STOCK_IMAGE_HEAVY. Now notices, never a failed build: AI_LOW_STRUCTURE_SCORE, AI_LOW_CONCISENESS, AI_NO_REPUTABLE_CITATIONS, AI_NO_EXTERNAL_CITATIONS. Fixed: the table finding fired on any page containing "vs" as a substring. New: SITEMAP_LASTMOD_UNIFORM, when every URL carries the build time as its date.

llms.txt, as the evidence has it. A convention for coding agents and documentation sites, audited by Lighthouse, read by no search or answer engine. Missing stays a notice, framed for docs sites; invalid is a notice.

Structured data counts in the on-page score, at a third of the weight of the on-page essentials. Measured on six reference sites: 0 to 1 overall point.

The AI Readiness score, stated for what it is. It measures hygiene on the levers the citation evidence supports and does not predict citations; no published score does. The JSON report says so under notes.aiReadiness, the console under the score, the README in its own section.

Also fixed: a footer image is never reported as a lazy-loaded hero.

Codes that changed name show as new against a 0.0.53 baseline once; removed codes drop out of it silently.

Packages: @rankcli/cli 0.0.54, @rankcli/agent-runtime 0.0.42, @rankcli/mcp-server 0.0.27.

Install

npm install -g @rankcli/cli    # or: brew install integrallis/tap/rankcli

Standalone binaries for macOS, Linux and Windows and the Claude Desktop extension (.mcpb) are attached below.

v0.0.53: the audit as a CI gate

Choose a tag to compare

@bsbodden bsbodden released this 02 Nov 19:48

v0.0.53: the audit as a CI gate

One rule syntax for the gate, in the CLI, in a config file and in the GitHub Action, with baselines so an existing site can adopt it without first fixing every old finding, SARIF and JUnit output, build-directory audits and protected previews.

One rule syntax. --fail-on takes rules: error, warning or notice fails on any issue at or above that severity; score<80 on the overall score; score:aiReadiness<70 on a category (crawlability, indexability, onPage, content, links, performance, security, aiReadiness, social, localSeo, accessibility). Rules combine, comma-separated or with the flag repeated. --min-score 80 is the same as score<80 and still works. The exit codes have not changed: 0 completed, 1 a gate tripped, 2 bad invocation or an invalid config or baseline file, 3 no real audit (unreachable site, error status).

Baselines. Save a report once and commit it; the severity rule then counts only findings that are not in it. Old findings stay listed but do not fail the build until you fix them. Score rules stay absolute.

rankcli audit -o json > .rankcli/baseline.json      # once; commit the file
rankcli audit --fail-on error --baseline .rankcli/baseline.json

A finding is identified by its code and the page's path. The console and the JSON report list what is new since the baseline, what was fixed and what stayed. rankcli diff before.json after.json compares any two saved reports, with --fail-on and -o json.

SARIF and JUnit. -o sarif writes SARIF 2.1.0 for GitHub Code Scanning (github/codeql-action/upload-sarif) and other SARIF readers: one rule per code, one result per page, baselineState when a baseline is given, file locations with --dir. -o junit writes JUnit XML for test reporters. Every machine format is one document on stdout, on failure too.

Audit the build before deploying. rankcli audit --dir dist --url https://example.com --fail-on error serves the directory locally the way a static host would and audits it as the named site, so canonical and sitemap checks compare against the real origin. Host checks (TLS, security and caching headers, redirects, crawler access, canonical domain) are skipped. With -o sarif, findings point at the files.

Protected previews. --header "Name: value" and --cookie "name=value", both repeatable, go with every request to the audited site and to no other host.

Project config. rankcli.config.json (rankcli init writes it with the url) now carries the CI settings, read the same way by audit and the Action: maxPages, checkLinks, failOn, minScore, budgets (minimum category scores), baseline, ignore (by code, by page glob, or both, with a reason; ignored findings are counted and listed, never dropped silently), headers (values may use ${ENV_VAR}) and dir. Flags win over the file. An invalid file is exit 2, never ignored. --config <file> names another file.

Page discovery. The sitemap seeds the page list and homepage links fill the rest (default 5 pages); the JSON report says where each page came from (discovery) and adds ignored, baseline and gate.

The GitHub Action, v1.2.0 (integrallis/rankcli-action@v1), takes the same rules in fail-on, plus baseline, config, dir, max-pages (default 5), headers, report-file and annotations (findings annotated on the run, with file locations when dir is used). comment-on-pr is now regressions (the default: only when the gate fails or there are new findings against the baseline), always or never; the Action keeps one comment and updates it in place. New outputs: new-issues-count, fixed-issues-count, report-file. fail-on-error, fail-on-errors and score-threshold keep working. rankcli setup --github-action --url https://yoursite.com [--sync] writes a workflow that uses the Action.

Packages: @rankcli/cli 0.0.53, @rankcli/agent-runtime 0.0.41 (the gate, baselines, SARIF, JUnit, the config loader and auditSite() live in the engine), @rankcli/mcp-server 0.0.26 (the same engine).

Install

npm install -g @rankcli/cli    # or: brew install integrallis/tap/rankcli

Standalone binaries for macOS, Linux and Windows and the Claude Desktop extension (.mcpb) are attached below.

v0.0.52: the source is published

Choose a tag to compare

@bsbodden bsbodden released this 30 Oct 20:09

v0.0.52: the source is published

The source of the CLI, the audit engine, the MCP server, the GitHub Action and the framework plugins now lives here, with its history since January. Build it with Node and pnpm; there is no Rust toolchain or build key any more.

License. The engine, the CLI, the MCP server and the Action are under the Functional Source License, Version 1.1, MIT Future License (FSL-1.1-MIT): read it, run it, change it, redistribute it, embed it in your own tools and pipelines, all free; the one thing it does not permit is building a product or service that competes with RankCLI. Each version becomes MIT two years after its release. The three framework plugins are MIT. Versions published before this one stay MIT.

The 21 checks that were encrypted into the CLI are ordinary engine code. They lived in a private package, were bundled into a WASM binary and decrypted at run time with a passphrase that shipped in the same tarball. Every plan runs every check, so @rankcli/agent-runtime 0.0.40 exports them (premiumChecks) and runFullAudit runs them by default. The GitHub Action, which used to leave them out, now runs the same audit as rankcli audit and gives the same score.

The JSON report says when, which version, and page by page. -o json carries timestamp, cliVersion, checksRun, checksPassed and pages (one entry per audited page with its url, score and error, warning and notice counts).

No account box under a gate. The "keep this site audited" box after a console audit no longer prints under --fail-on or --min-score, or when CI is set.

Every published package links its source. The npm pages for @rankcli/cli, @rankcli/agent-runtime, @rankcli/mcp-server, @rankcli/github-action, astro-rankcli, next-rankcli and vite-plugin-rankcli point at this repository, as does the MCP registry entry.

Packages: @rankcli/cli 0.0.52, @rankcli/agent-runtime 0.0.40, @rankcli/mcp-server 0.0.25.

Install

npm install -g @rankcli/cli    # or: brew install integrallis/tap/rankcli

Standalone binaries for macOS, Linux and Windows and the Claude Desktop extension (.mcpb) are attached below.