An AI coding agent can add a Pricing page to an Astro site in a couple of minutes. Building fast isn’t the hard part anymore. The hard part is whether the result holds up: whether the page is accessible, whether its scripts survive the Content Security Policy, whether every language gets its copy, and whether the next upgrade quietly undoes the work.
Most of those failures are invisible. The build passes, the page looks right in English, and the agent reports that it’s done. A week later you find a raw translation key on the Spanish page, or a button that does nothing because CSP blocked its handler.
Velocity 2.1 gave agents the rules. Velocity 2.4 checks that they followed them.
check:agent: an agent-ready check
Every project now has one command that reads the source and the build, and reports what agents typically get wrong:
npm run check:agent
To test it, we planted typical agent mistakes in a fresh project: a Pricing page with a missing translation key, an onclick handler, a link to a page that doesn’t exist, an edited Velocity file and some hardcoded copy. All of them were caught. Here’s part of the output:
✖ i18n/missing-key (1) .agents/velocity.md → Rules → No hardcoded user-facing strings
src/views/PricingView.astro:8 t('pricingPage.title') has no English string, so the page shows "pricingPage.title".
fix: Add pricingPage.title to src/i18n/translations/en.ts (under `pricingPage`), then to each other locale's file.
✖ csp/inline-handler (1) .agents/velocity.md → Rules → CSP is on
dist/client/pricing/index.html:22 <button onclick="…"> is an inline event handler; CSP blocks it.
fix: Remove onclick and add the listener in the component's <script> with addEventListener, guarded for astro:after-swap.
✖ links/broken (1) .agents/velocity.md → Rules → Internal links
dist/client/pricing/index.html:22 <a href="/checkout"> points at a page or file the build doesn't contain.
✖ check:agent: 4 error(s), 6 warning(s)
Every finding names the file and line, the rule in .agents/velocity.md that it breaks, and the fix. That’s written for the agent as much as for you. It can read the output, fix the problem and run the check again, without guessing what “broken” means.
| Rule | What it catches | Severity |
|---|---|---|
i18n/missing-key, i18n/raw-key |
A t() key with no English string, or a raw key rendered in the built page |
error |
csp/inline-handler, csp/unhashed-script, csp/javascript-url |
Inline handlers, javascript: URLs, and inline scripts that don’t match the page’s CSP hashes |
error |
links/broken |
Internal links to pages, files or #anchors the build doesn’t contain |
error |
forms/stub |
Contact and newsletter Actions that still report success without sending anything | warning |
ownership/edited |
Edits to files Velocity replaces on upgrade | warning |
strings/hardcoded |
User-facing text written straight into views, components and layouts | warning |
i18n/untranslated |
Keys an enabled language falls back to English for | warning |
Errors fail the check. Warnings are worth fixing or explaining: every new project starts with stubbed forms, for example, so that one can’t be an error. Add --strict to treat warnings as errors, or --json for machine-readable output.
check:agent runs at the end of npm run validate and in the deploy workflow every project ships with, so a mistake fails CI instead of reaching production. .agents/velocity.md also gains a “Before you say you’re done” section that tells agents to run it.
It found a real bug in Velocity, too: PasswordInput had a hardcoded English aria-label on its show/hide button. In 2.4 it’s translated into English, Spanish and French.
A component reference agents read first
Agents write a new component when they don’t know one already exists. .agents/components.md is a generated reference for all 46 entries in Velocity’s component registry. For each one, it lists:
- What it’s for, and what to use instead when it’s the wrong fit
- Its props with defaults, its variants and its slots
- The import path and a working example
It’s generated from the registry, the variant files and the prop types, so it can’t drift. A stale file fails Velocity’s tests, and every example is compiled in a unit test. The velocity-add-page and velocity-add-component skills read it before they read the source.
Four new skills
2.1 shipped two skills. 2.4 adds four more, for the tasks people ask agents to do most once the pages exist:
| Skill | What it does |
|---|---|
velocity-rebrand |
Brand color, theme, fonts, logo, favicon, site name and share-image color, through design tokens instead of raw colors |
velocity-connect-forms |
Connects the contact and newsletter forms to a real provider (Resend by default), with secrets in astro:env |
velocity-add-locale |
Adds a language with a complete translation file, translated URL slugs and hreflang checks |
velocity-add-content |
Writes a blog post with valid frontmatter, or adds a content collection with its own pages, search indexing and share images |
Two details are worth calling out. velocity-connect-forms never reports a form as working without a real send: with no API key, it stops and asks you for one. And velocity-add-locale closes a real gap. Velocity’s built-in UI strings are only translated into English, Spanish and French, and that file is replaced on upgrade, so for any other language the skill has your agent translate them in your own translations file.
That makes six skills, in both .agents/skills/ and .claude/skills/.
An open agent benchmark
We think these files make agents better at building Velocity sites. That’s a claim, so we built a way to test it, and we’re publishing the harness before the results.
The benchmark in Velocity’s benchmark/ folder gives the same six plain-language requests to an agent in three kinds of project:
- Velocity
- Velocity without its agent files: the same code with
AGENTS.md,.agents/and.claude/removed. Comparing it with the first arm isolates what the agent files add. - Plain Astro, from
npm create astro
The six tasks are a pricing page, an FAQ page, a rebrand, a Spanish version, a working contact form and a blog post. They’re written the way a non-expert would ask, and they never mention Velocity or Astro. Every arm uses the same agent and the same pinned model, with five repeats by default.
An independent scorer grades the built site in a real browser. It doesn’t use check:agent, and it never looks at file paths or Velocity conventions. It reports neutral metrics (task checks, build, axe accessibility on desktop and mobile, broken links and cost) separately from the ones that favor Velocity by construction, such as CSP. A self-test checks the scorer without calling a model. It includes a plain Astro site that solves all six tasks, to show they can be done without Velocity.
We don’t have results yet. When we do, we’ll publish every complete run, including any where Velocity looks worse. Until then, you can run it yourself:
git clone https://github.com/southwellmedia/velocity
cd velocity
pnpm install
pnpm bench:selftest # checks the scorer, no model calls
pnpm bench --model <model-id> # 6 tasks × 3 arms × 5 repeats
The benchmark README covers the requirements, the options and how to read the results. If you think a task or a check favors Velocity, open an issue. Tasks from people outside the project are welcome.
Get it
Start a new project:
npm create velocity-astro@latest
Or upgrade an existing one:
npm create velocity-astro@latest upgrade
The upgrade adds check:agent, the component reference and the new skills, and puts the check at the end of your validate script. If you customized validate, append && node scripts/check-agent.mjs to it yourself.
The upgrade also records .velocity/baseline.json, a fingerprint of the files Velocity owns, so the check can warn when an agent edits one; commit it. That takes create-velocity-astro 2.1, which @latest gives you. With an older CLI, record it yourself once:
npm run check:agent -- --write-baseline
Your contact and newsletter Actions belong to you, so the upgrade leaves them alone. Since 2.3 they forward to CONTACT_FORM_ENDPOINT and NEWSLETTER_ENDPOINT when those are set, and check:agent warns until they are, or until you wire a provider with the velocity-connect-forms skill.
Then ask your agent to build something, and run npm run check:agent before you take its word that it’s done. The AI agents guide covers the rest.