Releases
Release history and changelogs
All releases up to v0.1 will be in the stable channel.
Release History
Release Notes
Two rules about the difference between a page that is linked and a page that is supported. A site's navigation links every page from every other page, which makes the whole site look evenly connected when most of it is not: a page whose only inbound links are the ones repeated in the header and footer carries no signal about what it is for or why it matters. The same template logic cuts the other way for the site's own assets, where one shared layout should give every page the same favicon and share image, and a page that disagrees is usually running an older template nobody remembers owning.
The engine is now at 278 rules across 21 categories.
Added
-
links/no-contextual-inboundreports pages whose only internal inbound links come from sitewide chrome: the nav, header, footer or sidebar. Those links help discovery, but they are identical on every page, so they say nothing about the page they point at. The fix is a link from the body copy of a related article, hub or category page with anchor text that describes the destination, which is what passes topical relevance. The minimum count is configurable for sites that treat a single contextual link as enough. -
social/asset-divergencereports pages whose favicon, theme-color or fallback share image differs from the rest of the site. These come from one layout, so every page should carry the same three, and the ones that do not are a section that missed a redesign or a second layout still in service. The visible cost is a tab icon that changes as visitors move around and link previews that do not match. Per-page share images on articles and products are correct and are not reported: the comparison is against the fallback the rest of the site shares.
Changed
- Custom request headers are available on every plan. Auditing a staging site behind an auth header is how you check work before it ships, and it was gated behind Pro. It is not any more.
Fixed
-
squirrel creditslinked to a page that did not exist. The top-up link it printed had never resolved to anything. It now lands on the billing page for your account, and older versions of the CLI that still print the old address are redirected there too. -
Running out of credits during an audit now says what to do about it. The CLI printed a bare warning with no price and nowhere to go. It now reports the balance, what the audit needed, and where to top up or upgrade.
-
Reinstalling over a stale
squirrelsymlink no longer fails. If~/.local/bin/squirrelpointed at a release that had been cleaned up, the installer refused to replace it. It now does. The install script also no longer dies part way through on systems whereshis dash, which is the default on Debian and Ubuntu.
Downloads
Release Notes
A reliability fix for long audits. An audit is not just its crawl: once the last page is fetched there is still link checking, rule evaluation, scoring, rendering and publishing to do, and on a large site that second half can take longer than the first. The CLI reported its progress only while pages were being crawled, so for the whole of that second half it went quiet, and a run that was working normally became indistinguishable from one that had died. Past a point the server concluded it had died and marked it failed, discarding a completed crawl and delivering no report.
The bigger the site, the more likely this was, which is the wrong way round.
Fixed
-
A long audit is no longer given up on while it is still running. The CLI now reports that it is alive for the entire run rather than only during the crawl, so the time spent on rules, scoring and rendering no longer counts against it. Audits of large sites that previously failed near the end, after the crawl had already finished, should now complete and publish. If one of yours did this, re-running it on this version is worth a try.
-
Interrupting a crawl now tells you how to resume it. Crawls have always been saved as they go, and an interrupted one can be picked up where it stopped with
--resumeinstead of started again. Nothing said so, so a cancelled crawl of a few hundred pages looked like lost work. Cancelling now reports how many pages are saved and prints the exact command to continue.
Release Notes
Three rules about the gap between what your markup claims and what your pages
actually show. Structured data is a promise made to a machine that never reads
the page, so nothing in a per-page validity check can tell you the promise is
false: a rating block is well-formed whether or not anyone can see a rating, and
a lastmod is a valid date whether or not anything changed that day. These
rules ask the second question.
The engine is now at 275 rules across 21 categories.
Added
-
schema/rating-scopereportsAggregateRatingmarkup that is not about the page it sits on.schema/reviewvalidates the shape of a rating block, so one sitewide rating emitted by a template passes on every page of a site, including the privacy policy. Two checks: whether a rating is visible anywhere in the page's own text, and whether the rated entity is the subject of a page where a rating could apply at all. A third-party review widget clears the first, since its badge is injected client-side and a raw crawl cannot see it. The finding names the page type and the rated entity, and frames the risk as a structured-data manual action rather than a validation error, because that is what it is. -
crawl/sitemap-lastmod-driftreports sitemaplastmodvalues that disagree with the page's own date. Two directions, because they come from different mistakes: alastmodolder than the page'sdateModifiedusually means a stale sitemap or an inverted published/updated precedence, and one newer by more than a month usually means the field is stamped when the site builds. Each finding reports both dates and the gap in days. Pages carrying no date of their own are skipped rather than guessed at. -
crawl/sitemap-lastmod-churnreportslastmodvalues that have collapsed onto one or two days across the whole sitemap, which means they are stamped at build time and carry no freshness signal at all. Google News sitemaps are excluded: they hold about 48 hours of articles by design, so their dates are supposed to cluster.
Fixed
- Anchor text is judged per destination, not per link. A card that links to the same page twice, once from its image and once from its headline, was reported as having empty anchor text for the image link. Only one link in such a group needs to describe the destination, and screen readers announce the group together, so the checks now evaluate links to a target as a unit.
Release Notes
Five new rules that grade a page against the rest of your own site instead of
against a fixed threshold. Every audit rule until now asked the same question of
every site on the internet: is this title too long, is this page too thin. That
works for the rules where one right answer exists, and it is useless for the
much larger class of problem where the only evidence something is wrong is that
one page disagrees with the other nine hundred. A 200 word page is thin on a
documentation site and normal on a news site. A product page missing Product
markup only matters because its siblings have it.
These rules learn the norm from your crawl and report the deviants, which means they need a crawl big enough to have a norm. All five stay silent below 10 crawled pages, and stay silent when no clear majority exists, reporting a skipped check that says which condition was not met rather than guessing. A site that is legitimately heterogeneous should see nothing from them, and that is the intended result, not a failure.
The engine is now at 272 rules across 21 categories.
Added
-
content/thin-vs-site-normreports pages far shorter than comparable pages on the same site. Pages are grouped by section first, so a terse tag listing is not measured against your long-form posts, and the outlier test uses a robust spread rather than a mean, so a handful of very long pages cannot drag the threshold up and hide the thin ones. -
content/title-pattern-outlierlearns your title template and reports the titles that break it. Most sites settle on one shape,Page | BrandorBrand: Page, usually because a template emits it. The pages that do not match are usually the ones a human wrote by hand or a migration missed: brand missing entirely, brand on the wrong end, a different separator. -
schema/coverage-outlierreports pages missing the structured-data markup their siblings have. If 90% of your product pages carryProductand a dozen do not, those dozen lose rich results, and nothing in a per-page check can see it because each page is individually valid. -
url/slug-conventionreports URLs that break your site's own conventions: case, word separator, trailing slash, file extension. Mixed conventions usually mean two generations of routing coexisting, which is where duplicate content comes from. -
core/canonical-form-driftreports canonical URLs that disagree in form across the site, for example some absolute and some relative, or some with thewwwhost and some without. Each one is individually valid, so per-page validation passes while search engines see an inconsistent story about which URL is the real one.
Fixed
-
A site behind a WAF challenge is no longer reported as unreachable. Adding a domain probed it first and accepted only a normal response. A site sitting behind Vercel's Attack Challenge Mode, Cloudflare's, or any similar protection answers that probe with a challenge rather than the page, and the domain was refused as if the site were down. The probe now treats any HTTP response as proof the site is there, because it is.
-
A crawl that lost its handshake no longer disappears. If the network dropped the call that registers a run, the CLI retried and the server treated the retry as a second, unrelated run. The original became an orphan: work that had been done, could not be found, and showed up later as a failed audit. The registration now carries an idempotency key, so a retry resolves to the same run, and an orphaned run is adopted when its report is published.
-
Long crawls are no longer killed while they are working. The job that cleans up abandoned runs measured age alone, so a genuinely slow crawl of a large site could be marked failed while it was still making progress. It now looks at progress before deciding a run is dead, and audits that were reaped and then delivered anyway are repaid.
-
Renders you did not get are no longer charged. A page render that failed was still billed, and a run could spend past the estimate it quoted you when it started. Failed renders are refunded and spend is capped at the run's own quote.
-
Cloud audits run every rule you are paying for. Audits started from a website or from the GitHub integration were dispatched without the flag that enables the paid services the rules depend on, so eight rules quietly skipped while the audit billed in full. Both paths now dispatch with those services enabled and a bounded credit cap.
-
A failed audit refunds the organization that was actually charged. When a run failed after its base charge, the refund was aimed at the organization named in the request rather than the one billed. If you had not named one explicitly, those two were different and nothing was refunded at all.
-
A missing
robots.txtis reported as an error, not a warning. Norobots.txtmeans no place to declare a sitemap and no control over crawling. That is not a nice-to-have. -
Report issues are ordered by severity across the whole report. Sorting happened inside each category, so a critical issue in the last category sat below a warning in the first, and the top of the report was not the worst of the findings.
-
Windows installs no longer fail with a permission error. The installer linked the binary with a symlink, which needs Developer Mode or an elevated shell on Windows, and failed with
EPERMotherwise. It now falls back to a copy. A failingsquirrel self installalso prints what actually went wrong instead of a bare exit code.
Release Notes
A crawl-correctness release. squirrelscan was requesting URLs your site never links and then reporting the redirects it had caused. On any site whose URLs end in a slash, which is the default on WordPress, Hugo and Jekyll, that invented findings, and on some hosts it also spent part of the page budget on redirect pages instead of your content.
Fixed
-
The crawler no longer asks for a URL your site never linked. URL normalization dropped the trailing slash before the request went out, so a site whose every internal link ends in
/was asked for/aboutwhen it only publishes/about/. Two things followed from that, and both are fixed.First, the origin answered with a redirect, and
links/redirect-chainsandcrawl/canonical-chainreported it: a redirect that existed only because we asked for it. Those findings were wrong rather than merely noisy, and they fanned out, because the check for links pointing at redirecting URLs then blamed nearly every page that linked the correct form. If your report listed pages redirecting to themselves with a slash added, that section should now be empty. Genuine redirects are unaffected: a page you really do link at a URL that really does redirect is still reported.Second, and only on some hosts: a few sites answer the no-slash URL with a
200and a small JavaScript redirect page rather than an HTTP redirect. There is no redirect for the crawler to follow, so that page was stored and graded as though it were your article, and title, charset and word count were judged against a few hundred bytes of redirect script. In one 15 page crawl of a blog hosted this way, 12 of the 15 stored pages were redirect pages rather than posts. Sites that answer with an ordinary HTTP redirect were never affected this way, because the crawler followed it and stored the real page. If your site is in the first group, expect finding counts and scores to move in both directions: some checks stop failing because they had been grading a redirect page, and others start reporting because your content is finally being read. -
A redirect chain no longer shows a status the hop never returned. When a page is rendered in the cloud, the render service reports the page it landed on, never the statuses of the redirects that got it there. Those unseen statuses were filled in with the landing page's own status, producing chains that read
(200) → (200). A first hop that returned 200 did not redirect at all. Hops squirrelscan did not observe are now recorded as unknown and shown without a status, and no chain can claim a hop redirected while also reporting that it returned 200. -
squirrel auth statusexplains an organization API key instead of blaming it. Ansq_organization API key works for audits, publishing and credits, but the identity lookup behindsquirrel auth statusandsquirrel auth whoamiaccepts only the login token thatsquirrel auth loginissues. That rejection was reported as the key being invalid, revoked, expired or from the wrong environment, none of which was usually true. It now says what actually happened, and tells you to unsetSQUIRRELSCAN_API_KEYafter logging in, since an environment key takes precedence over a session for every cloud call.
Changed
- A site that links both
/aboutand/about/now has both crawled. They are different URLs, and only a request can tell you which one redirects, so collapsing them into one meant the answer depended on which form the crawler happened to see first. Sites that link a single consistent form, which is nearly all of them, crawl exactly as before.
Release Notes
Three new rules, a rebuilt local-SEO check, and a crawl-correctness fix for seeds that redirect off your site. The rule set is now 267.
Added
content/hidden-textflags text and links hidden from visitors but left visible to crawlers. Google's spam policies treat this as deceptive, and pages doing it can lose rankings or drop out of search entirely. The rule looks for the techniques that have no innocent explanation: an off-screentext-indent, a zero font size, same-on-same colour, a zero-size clip. It deliberately does not accuse you overdisplay:noneoropacity:0on their own, because that is what every accordion, modal, and scroll-reveal library writes. Content revealed inside a@mediablock, by a transition on a compound selector, or alongside a transform is read as UI rather than concealment. It is a warning at weight 6, and escalates to a failure only when hidden links are involved, which is the stronger spam signal.a11y/autocomplete-tokenschecks that fields collecting a person's own data carry the right autofill token. Name, email, phone, address, and payment fields with the correct WHATWG token fill in one tap, which is the difference between a completed checkout and an abandoned one, and WCAG 2.1 success criterion 1.3.5 requires it. Section and shipping/billing prefixes are understood. A token the browser does not recognise is ignored outright, so a typo likefirstnameis worse than nothing, andautocomplete="off"on personal data does not stop autofill in modern browsers, it only stops the accurate kind.a11y/input-typeschecks that fields use the right input type and keyboard hint.type="email",type="tel",type="url", andtype="number"each summon the right mobile keyboard and bring free browser validation with them. The rule also flagstype="number"on digit strings such as postal codes, phone numbers, and card numbers, where it strips leading zeros and silently discards anything that is not a valid float, andnovalidateon a form that still declaresrequiredorpatternand ships no replacement validation.
Changed
local/nap-consistencynow compares your business details across the whole site. It used to judge one page at a time. It now collects the name, address, and phone from every crawled page and reports when the same value is rendered several different ways, which is the drift that actually costs you local citations. Phone numbers declared intel:links count alongside JSON-LD, so a footer that formats the number differently from your markup is visible. The cross-page half only fires once enough pages declare a signal, and the rule still skips sites with no local-business signal at all.security/form-httpsnow separates a real downgrade from an already-insecure page. Actions are resolved against the page URL, so a relative or protocol-relativeactioninherits the page's scheme instead of being guessed at, andformactionon submit buttons is read too. An HTTPS page posting tohttp://now fails: the padlock tells the user they are safe while the submission travels in the clear. An HTTP page posting tohttp://stays a warning, and a page with nothing to submit reports as info rather than passing silently.
Fixed
- A seed that redirects off-site no longer re-bases the whole audit. If the
URL you passed redirected to another site, that target became the audit's base:
every root probe (robots.txt, llms.txt, sitemap discovery, the
.well-knownand agent-manifest sweep) went to a host you never named, and the target's content was stored and reported under your seed's name. A site redirecting to a CDN or a parked domain produced a report describing the target while claiming to describe the seed. The base is now pinned to the seed. A redirect is adopted only when it stays on the same registrable domain and port, sohttptohttpsupgrades and apex towwwbounces still work; one that leaves is refused, and the refused target is recorded as the report'sfinalUrlso you can still see it. The same rule applies per page: a page whose redirects landed off-site is dropped rather than filed under your audit, unless your own scope config admits it. - Building objects from untrusted keys is hardened. Keys taken from crawled content can no longer reach an object's prototype.
- The install endpoint always serves the current release. Release channel metadata and the install scripts are now published as part of the release itself and verified against the live endpoint before the run is allowed to finish, so a new version cannot be announced while the installer still hands out the previous one.
Release Notes
Follow-ups to the v0.0.81 security release, plus two crawl-correctness fixes. Pages listed in a sitemap with query strings are now crawled at the right URL, and a single network blip no longer takes down a whole audit.
Fixed
- Sitemap URLs with query strings are crawled correctly. XML requires
&to be written&inside a<loc>, and that escape was surviving into the URL the crawler enqueued. A sitemap entry for?a=1&b=2was fetched literally, so those pages 404'd or were audited as the wrong URL, and on a site that paginates or filters through query strings that can be most of the sitemap. All five predefined XML escapes are now decoded, in a urlset and in the child entries of a sitemap index. - A single network blip no longer aborts the audit. The pre-flight reachability probe had no retry, so one transient DNS failure, connection reset, or timeout ended the run before the crawl started. It now makes up to three attempts with a short backoff, inside a 20 second overall budget so a genuinely unreachable site still fails quickly. Only transient failures are retried: a refused connection or an HTTP error is still reported on the first attempt.
- The bounded-read guard now covers every path. v0.0.81 bounded untrusted
response bodies as they stream. On the fallback path taken when a runtime
hands back no readable stream, the limit was still applied only once the body
was in memory. That path now refuses an over-declared
content-lengthbefore reading anything, and truncates by bytes rather than characters, so a multi-byte character cannot split at the boundary. - Builtin crypto imports are explicit. The crawler and the fetchers imported
cryptounqualified. That is an undeclared dependency which can resolve to a deprecated npm stub instead of the runtime builtin, depending on what else is installed. Both now importnode:crypto.
Release Notes
A security release, plus two new content rules. Audits now treat everything a
site tells them to fetch, and everything a site tells them to print, as
untrusted, and squirrel self settings no longer prints your credentials.
Everyone should update. If you audit sites you do not control, or you use
-H/--header to pass authenticated headers, update before your next run.
Added
content/stale-copyrightflags a footer year that has fallen behind. A copyright year stuck in the past is the most common "this site is abandoned" signal a visitor sees, and it costs nothing to fix. It is a warning at low weight, so one templated footer repeated across every page cannot dominate your content score.content/mojibakeflags encoding corruption in visible text. Catches garbled sequences like’andé, and replacement characters, in the text your visitors actually read. These almost always mean a template, export, or CMS migration lost the original encoding, and the same corruption is usually sitting in fields you cannot see, such as meta descriptions and alt text.
Fixed
- Redirects can no longer change protocol. Every fetch derived from page
content, including redirect targets, sitemap and RSL references,
Linkheaders, and client-side meta refresh, is now restricted tohttpandhttps. Previously a site could redirect an audit to a non-http URL and have the result stored in the report. - Custom headers stay on their origin. Values passed with
-H/--headerare now scoped to the origin you sent them to and are dropped when a redirect crosses to another origin, on auxiliary probe requests as well as page fetches. These values are documented as secrets, so this closes a path where a redirect could forward them to a host you did not choose. - A hostile response can no longer exhaust an audit's memory. Every read of
an untrusted response body is now bounded as it streams and cancelled at the
limit: robots.txt, sitemaps,
llms.txt,.well-knowndocuments, RSL, fetched scripts, and page bodies. The previous guards could not do this. Acontent-lengthheader is absent on a chunked response and reports the compressed size on an encoded one, and the size limit was otherwise applied only once the whole body was already in memory. A small compressed file that expands to gigabytes now stops at the limit instead. - A site can no longer repaint your terminal. Page text reaches the console
report and the
textandllmoutputs through many fields, and it could carry terminal control sequences: a site could embed an escape that clears your screen and prints its own "0 issues found" over the real result. Control characters are now stripped where the report is written. The console keeps colour codes, which can only change how text looks and never move the cursor or clear the screen, so the report itself is unchanged. squirrel self settingsredacts credentials. The command printed the stored auth token, and any provider keys held in the plaintext fallback used when the OS keychain is unavailable. Output is now redacted. If you have pasted this output anywhere, rotate the token withsquirrel auth login.- Project names cannot escape their directory. A
[project] nameinsquirrel.tomlis now contained before it is used to build the local database path. - Repo-local settings are limited to safe keys. A
settings.jsoninside a checkout can now only influence the documented writable settings, so cloning an untrusted repository cannot redirect where the CLI installs updates. - Consistent lowercase branding. The product is "squirrelscan" everywhere, including the text report title and the database lock warning.
Release Notes
The CLI is now open source under MIT, with the public repo set up as the canonical home for the CLI and docs. This release also hardens the public surface and makes sure the telemetry opt-out is honored everywhere.
Added
- MIT licensed CLI.
squirrelscanis now open source under MIT. - Public repo source of truth. CLI builds and docs now come from the public repository.
- Telemetry opt-out respected everywhere.
NO_TELEMETRYis honored by the CLI and install flow.
Fixed
- Public-repo hardening. Release and update paths were tightened to avoid command injection, traversal, unsafe URL handling, and Markdown injection issues.
- Parser and sanitizer performance issues. Several regex-heavy paths were rewritten to avoid ReDoS-style slowdowns.
- Secret and scheme filtering tightened. Unsafe URLs and non-http(s) inputs are now rejected more consistently.
Release Notes
Clearer page limits, more armor for audits of slow or messy sites, and a lot of under-the-hood groundwork for auditing much bigger sites. More on that soon.
Added
- Audits tell you when they hit your plan's page limit. If a site has more pages than your plan covers in one cloud audit, the report and your audit listings now say the crawl was capped and at what count, instead of quietly auditing a subset. Coding agents get the same notice through the MCP server, so your agent knows it saw part of the site, not all of it.
squirrel crawlgets the speed controls. The--concurrencyand--per-hostflags and the localhost fast path thatsquirrel auditgained in v0.0.74 now work on the standalone crawl command too.
Fixed
- Very slow or bot-hostile sites can no longer stall a cloud audit. Analysis of each asset and network probe now runs under its own time budget, and sites that drip-feed bytes to waste crawler time are detected and cut off. An audit of a hostile site finishes with what it could get instead of hanging until the overall timeout.
- More publish hardening for messy sites. Absurdly long URLs are skipped during the crawl instead of gumming up the works later, every remaining free-text field is trimmed at publish time, and size limits are now enforced byte-accurately so emoji and other multi-byte characters can't split at a boundary. This closes out the class of failures where one extreme page could sink an otherwise good report.
A reliability release for cloud audits. Heavy sites that used to kill the audit engine outright now complete, the easiest way for a good audit to die at the finish line is gone, failed audits always refund, and audits show you they are alive while they work.
Fixed
- Audits of heavy sites complete instead of dying silently. Sites with very large pages could exhaust the audit engine's memory mid-analysis: the audit went quiet and eventually showed up as timed out, with no report after multiple retries. Audit engines now run with 16x the memory and 8x the CPU, and the exact audits that failed this way now run to completion. If the engine ever does die, the audit is marked failed within moments, with a clear message and an automatic refund, instead of hanging in silence.
- Audits no longer fail because a page has very long text. A single oversized headline, or any absurdly long string anywhere on a site, could fail the whole audit at publish time: no report, just a refund and a shrug. Publishing now trims display text to fit instead of rejecting the report, across every field, and the same guard covers long lists (a site with issues on more than a thousand pages could trip it too). Big messy sites are exactly the ones that need auditing, so this one mattered.
- Blocked-site audits refund automatically. When a site blocks the crawler outright (bot protection, 403s at the door), the audit failed but kept its base charge, because the failure notice it published counted as a delivered report. Refunds now check what the report actually says. Every failure path, blocked, down, errored, cancelled, or stalled, nets zero credits.
- Post-crawl steps have hard deadlines. One audit sat for 52 minutes in a stuck enrichment call after its crawl had already finished. Every post-crawl step now has a deadline: a hung enrichment is dropped, its section is omitted, and the audit finishes with everything else intact. An overall backstop bounds the whole run even if a future step misbehaves.
- Deleted websites stay deleted. If a bookkeeping step failed during a delete, the site could keep showing up in your website listings until you deleted it again. The record now retries durably until it lands.
Added
- Live heartbeat while an audit works. The audit feed now shows "still working" progress every 30 seconds through the slow parts, so a long analysis is visibly alive instead of frozen, and a genuinely stuck audit is caught and refunded much sooner.
Release Notes
A reliability release for cloud audits. Heavy sites that used to kill the audit engine outright now complete, the easiest way for a good audit to die at the finish line is gone, failed audits always refund, and audits show you they are alive while they work.
Fixed
- Audits of heavy sites complete instead of dying silently. Sites with very large pages could exhaust the audit engine's memory mid-analysis: the audit went quiet and eventually showed up as timed out, with no report after multiple retries. Audit engines now run with 16x the memory and 8x the CPU, and the exact audits that failed this way now run to completion. If the engine ever does die, the audit is marked failed within moments, with a clear message and an automatic refund, instead of hanging in silence.
- Audits no longer fail because a page has very long text. A single oversized headline, or any absurdly long string anywhere on a site, could fail the whole audit at publish time: no report, just a refund and a shrug. Publishing now trims display text to fit instead of rejecting the report, across every field, and the same guard covers long lists (a site with issues on more than a thousand pages could trip it too). Big messy sites are exactly the ones that need auditing, so this one mattered.
- Blocked-site audits refund automatically. When a site blocks the crawler outright (bot protection, 403s at the door), the audit failed but kept its base charge, because the failure notice it published counted as a delivered report. Refunds now check what the report actually says. Every failure path, blocked, down, errored, cancelled, or stalled, nets zero credits.
- Post-crawl steps have hard deadlines. One audit sat for 52 minutes in a stuck enrichment call after its crawl had already finished. Every post-crawl step now has a deadline: a hung enrichment is dropped, its section is omitted, and the audit finishes with everything else intact. An overall backstop bounds the whole run even if a future step misbehaves.
- Deleted websites stay deleted. If a bookkeeping step failed during a delete, the site could keep showing up in your website listings until you deleted it again. The record now retries durably until it lands.
Added
- Live heartbeat while an audit works. The audit feed now shows "still working" progress every 30 seconds through the slow parts, so a long analysis is visibly alive instead of frozen, and a genuinely stuck audit is caught and refunded much sooner.
Release Notes
Fixed issues now actually clear themselves. If you fixed something on a page that a later crawl never revisited, the finding used to sit there open forever and drag your score down. Three separate causes, all fixed. Reports also tell you what they scanned, label anything carried over from an earlier crawl, and five false positives are gone.
Added
- Reports disclose their scan scope. Every report now states what it actually looked at: how the run started, how deep it crawled, how many pages it covered, and how to run a full scan when you want the rest. No more guessing whether a clean report means "clean" or "barely looked".
- Carried-forward findings are labeled everywhere. A finding on a page that wasn't re-crawled this run is now marked as carried, with per-rule rollups ("4 of 12 pages carried from previous crawls") in the cloud report, the dashboard, and
get_reportover MCP. When a rule is clean on every page checked this run and stays red only because of carried pages, it says so, so you can tell "still broken" from "probably fixed, not re-checked yet". - "Was on N pages" expands to the actual URLs. In both the cloud report and the dashboard you can open the affected-page list, show all of them when it's long, copy the lot as plain text, and see which URLs were checked this run versus carried over.
- Agent clients get tool hints over MCP. Tools now advertise whether they only read, whether they change anything, and whether they touch the outside world, so agents can decide what's safe to call without asking first.
Fixed
- Fixed issues clear instead of piling up. Findings on pages that a later crawl never revisited stayed open indefinitely, and the accumulating warnings kept pushing the health score down. Three causes, all fixed: crawls now seed the frontier with pages that have open carried findings (and stop wasting budget on URLs that are known to be gone), reports over 100 affected pages per check can now resolve pages that were clipped from the published sample, and a page confirmed still failing this run gets a fresh "last seen" stamp instead of looking unconfirmed. On a large site with thousands of stale carried warnings, this is the difference between a score that recovers and one that only ever falls.
- One health score, not two. The score in your terminal and the score on the published report could disagree on the same run (84 in one place, 56 in the other). The published score is now authoritative everywhere.
- A burst of cloud audits no longer wedges dispatch. Stopped audit containers held onto their instance slots, so five audits in quick succession could block new runs for up to an hour. Containers are now torn down properly when a run ends.
- Privacy policy pages are found where they actually live. A
/privacypage titled "Privacy Policy" and linked from the footer was reported missing. It's detected now. - No more phantom Angular on Tailwind sites. Class names like
tracking-tightandleading-relaxedcontainng-, which was enough to report Angular on sites that have never seen it. Detection now requires real framework signals. - Cookie-consent checks read the page, not the prose. A page that merely mentions GDPR or cookies (a privacy policy, for instance) was treated as if it had a consent banner. The check now looks for actual consent machinery.
- Soft 404s confirm before warning. A page that briefly served an error shell during the crawl could produce a finding you couldn't reproduce a minute later. Findings are now confirmed before they're reported.
- Honeypot fields stop failing accessibility. Hidden anti-spam form fields were reported as focusable hidden content with no useful advice. They're now recognized, downgraded, and told exactly what to add (
tabindex="-1"). - Malformed publish dates are caught. A raw database timestamp in
datePublishedpassed validation silently. Structured-data dates are now validated as real ISO 8601. squirrel self doctorstops suggesting you delete your settings. A permission error reading the user settings file was reported as corruption, complete with a destructive "delete this file" hint. Permission problems are now reported as permission problems.- The updater speaks up when it keeps failing. If background auto-updates fail repeatedly, the CLI now tells you plainly to run
squirrel self updaterather than quietly staying out of date. Commands also wait for a pending update to settle before exiting, so an update in flight isn't cut off mid-write.
Faster
- Probe responses stream with a hard size cap. Checks that fetch supporting files no longer read an entire oversized response into memory before deciding they don't need it, which trims both time and memory on sites with large assets.
Release Notes
Big audits publish again, and two false positives are gone. Reports now stay under the publish limit no matter how many pages you crawl, you get warned before starting a cloud audit you can't afford, and a failed publish refunds the whole audit. Plus a new check: soft 404s.
Added
- New check: soft 404s. Pages that return HTTP 200 but actually render "page not found" content (framework error shells, not-found titles) now get flagged. Search engines treat these as thin or duplicate content, and they usually mean a route is silently broken. Detection is conservative: it requires multiple strong signals before flagging, so a short page with an unlucky title won't trip it.
- Content and legal checks skip error pages. Rules like cookie consent and content quality no longer judge a page that is really a 404 in disguise. That was the source of phantom "missing GDPR consent" warnings on sites whose error pages leaked into the crawl. Skipped pages are shown as skipped, not silently dropped.
- Know the cost before you spend. Cloud audits now estimate their credit cost up front (flat base plus per page) and warn you, or ask for confirmation in a terminal, when your balance won't cover it, instead of burning credits on a run that can't finish the way you wanted.
Fixed
- Large reports publish again. Publishing a big audit (hundreds of pages) could fail with "report exceeds 5MB" even though the real limit is 20MB. Two bugs, both fixed: the error message quoted a stale limit, and site-wide findings embedded every crawled URL, so payload size grew with crawl size. Findings are now sampled (up to 100 pages per finding, with a count of how many more there are), which keeps any report, from 10 pages to thousands, comfortably under the limit. The CLI also checks the size before uploading and trims further instead of failing after the crawl.
- Cloudflare Turnstile is no longer invisible. Forms protected by Turnstile (and other CAPTCHAs) using the explicit-render or preloaded loader pattern were flagged as unprotected. The check now recognizes preload hints and empty widget mount points, so protected forms pass.
- Failed publishes refund the audit. If your report can't be published because of a size limit or a server error, the entire audit's credits are refunded automatically instead of leaving you charged for a report you never got.
Release Notes
Credits stop being a mystery: every audit now shows exactly what it cost and why, and your org gets a full transaction log. Also the first release to arrive on Windows through the repaired self-updater: if you're on 0.0.74, this update installs itself.
Added
- See exactly what every audit cost. Cloud audit reports now include a cost breakdown: the flat audit base, each rendered page, cache hits, and any refunds. It appears on the report page in the dashboard, and agents get it too:
get_reportover MCP includes a cost summary, and a newlist_credit_transactionstool pages through your org's full credit ledger. There's also a new Transactions view in dashboard settings showing every grant, debit, and refund. If your per-audit cost seems to swing, this is where you see why: only pages whose source changed get re-rendered, so audits right after a deploy render (and bill) more pages than audits of a quiet site. squirrel feedbacklearned categories. An interactive picker (or the--categoryflag) files your note as a bug report, feature request, praise, confusion, missing data, or tool ergonomics, and records which CLI version it came from. The same categories run through the CLI, MCP, dashboard, and website, so feedback lands in one place no matter where you send it.- Delete websites for real. A new
delete_websiteMCP tool (with dashboard support) removes a site and immediately frees the slot against your website cap. - Dashboard polish. Tracked issues can be filtered by how they were found (full crawl vs smart audit), and page-limit settings now show the effective cap when a plan ceiling clamps a custom value.
Fixed
squirrel self doctorno longer cries corruption over a permission error. Running doctor from a directory it can't read (locked-down CI images, restricted shells) misreported healthy settings as corrupt and exited non-zero. Permission problems on the working directory are now reported as exactly that, and the rest of the checkup runs normally.- MCP sessions no longer drop when tokens refresh concurrently. Two clients refreshing the same session at the same time could race and knock each other out; a short reuse window now lets both land on the rotated token.
Faster
- Repeat cloud audits skip redundant summary work. Summaries for pages unchanged since the last run are served from a content-keyed cache instead of being recomputed, so re-audits finish sooner.
Release Notes
Pick your rules and skim your results: audits gain include/exclude filters and a summary mode, local dev crawls get dramatically faster, and Windows self-updates stop dying mid-download. Plus a batch of sharp-edge fixes across auth warnings, settings handling, and cloud publishing.
Added
- Filter which rules run with
--rule-include/--rule-exclude.squirrel audit --rule-include ax,performanceruns only those categories;--rule-exclude imagesskips them. Bare names cover a whole category,category/ruletargets a single rule. The report is marked partial and the health score recomputes from what ran. Typos, contradictory filters, and--fail-ongates against excluded categories all error before crawling instead of wasting a run. --summaryfor a quick score check. Console output trims to the score, category breakdown, and issue counts with no per-issue detail: handy for CI logs and fast re-checks. Works onsquirrel auditandsquirrel report.- Localhost audits are much faster. Plain-HTTP loopback targets (your dev server) automatically skip the polite per-host crawl delay, and new
--concurrency/--per-hostflags control parallel fetches. Public sites keep the respectful defaults.
Fixed
- Windows self-updates no longer die mid-download. The background updater ran as a detached child that Windows kills the moment the parent command exits (Job Object semantics), so updates silently never landed. The update now runs in-process with a bounded grace period at exit, and downloads are atomic: a killed update just retries next run.
- A corrupt or unreadable session file now warns loudly in every command. Cloud-touching commands explain the session could not be loaded and how to check it, instead of silently running anonymous. When an environment token authenticates the run anyway, the warning is suppressed entirely: no more false "running anonymous" on authenticated CI runs.
- Settings lookup no longer mistakes permission errors for missing files. An unreadable parent directory now surfaces a clear error instead of silently skipping your local settings.
- Windows users get pointed at the right installer. Running install.sh from Git Bash or MSYS now prints the PowerShell one-liner instead of a dead end.
- Cloud publish reliability: oversized robots.txt content is clamped instead of rejecting the whole report, and a timing window where a just-published report's run could still be reaped and refunded is closed.