Skip to content

varo

Every static site exists twice: the copy in the folder and the copy people load. They start identical and come apart quietly. Most tooling checks the folder. varo is a Claude Code plugin that checks what the host is serving, because that is the copy visitors get and the one nobody looks at. It is written in Python, licensed GPL-3.0, and its repository topics name GitHub Pages and Cloudflare Pages as the hosts it knows.

Each of these was found on a site that was already online, serving real visitors, while every local check stayed green.

  • An endpoint that exists in the code and answers 405 in production. Its folder was set aside during a move between hosts and never came back. The form still submits, the page still says thank you, and nothing arrives.
  • A developer’s own address hardcoded where config belongs. The site sends its mail correctly, to the wrong person.
  • Security headers written for a host that does not serve the site. The config file reads correctly and the live host has never opened it.
  • A build step pointing at a folder the host never creates. The minifier finds zero files, reports success, exits 0.

Plus work committed, pushed, and never deployed, because the branch is not the one the host builds.

No servers, no databases, no build system of its own. It works on files a host serves, plus the small functions a host runs alongside them. When something needs a real backend, it says so instead of stretching.

It also does not deploy on its own initiative. Publishing stays a step somebody asks for.

The auditor reads and never writes. It does not send real messages either, so a finding about mail stops at the address and does not claim delivery.

Terminal window
claude plugin marketplace add nerln/varo
claude plugin install varo@varo

Or clone it and load it for a single session:

Terminal window
git clone https://github.com/nerln/varo.git
claude --plugin-dir ./varo

Nothing to build. The only dependencies are Python 3 and git.

Context cost is about 264 tokens per session, which is the skill and the agent announcing that they exist. The hook runs in the harness and adds nothing to the model’s context. That number comes from claude plugin details varo.

Open Claude Code in a folder holding a site. The hook reports first. From there:

  • “publish it” runs the deploy and then checks that the deploy landed
  • “audit the site” hands it to the auditor agent
  • “why is my change not showing” usually has its answer in the hook output

Three pieces.

A skill that knows the hosts and their traps: which config file belongs to which host, why GitHub Pages silently drops folders starting with an underscore, how to tell a deploy that succeeded from a deploy that served the old build.

An auditor agent that reports only what the live site confirmed. It fetches before it claims, and it is read-only, so pointing it at a client’s site in production is safe.

A SessionStart hook that reports where you stand before you ask: which host, the public address, which branch deploys, how many commits are pushed and not published. It reads locally and touches no network, so it costs milliseconds and stays quiet in sessions about something else.

The rule underneath all three is: fetch it, do not infer it. A file in a functions folder does not mean the endpoint is deployed. A header in a config file does not mean the host sends it. A build script exiting 0 does not mean it did anything. A finding counts when the live site answered, and counts for nothing when it came from reading code and reasoning about what the code probably does.

Terminal window
python3 tools/prova.py

Twenty-nine checks, a few seconds, run against throwaway repositories built on the spot. They cover the plugin manifest and the hook’s behaviour in four situations: on a site, on a folder that is not a site, outside git, and on a path that does not exist. They also run the prose through tools/stylecheck.py, which enforces the writing rules mechanically instead of by rereading.

On its first run against a live site, the auditor fetched every file the site serves and diffed it against the working tree, filled the form in a headless browser and caught the address before anything was sent, checked that address for a mail server, and loaded the site at phone width. It reported no drift between repository and production, which was true, then found a folder reachable on the live site, returning 200, and permanently broken there: its dependencies are in .gitignore, so they never reach the host, while the page that needs them ships every time. It works locally and can never work on the deployed site.

It also listed what it could not close, including the fact that it never sent a real message to anybody.

github.com/nerln/varo