This website for people and agents

Static pages with Astro, content in Git, publication on Cloudflare Pages: the choices behind the site we have published since October 2026, and the checks that hold them up.

What changed from the previous site?

The previous site is described in Our website: Nuxt and Vue.js for the interface, Prismic for the content. The one you are reading was rewritten from scratch and published in October 2026, under a constraint that settled many of the later choices: the 120 addresses of the old site had to stay exactly as they were. The one declared exception is the frequently asked questions page, moved with a permanent redirect.

At every build a check compares the sitemap with the list of those addresses and verifies that each one matches a file the build really wrote. If one is missing, publication stops.

Why a static site?

The site is built with Astro: during the build every page becomes an HTML file, Italian at the root and English under /en, and Cloudflare Pages serves those files. In production there is no application server and no database. A small function at the edge of the network does only the three things a file cannot do: the 404 page in the right language, the Markdown version of a page for whoever asks for it, and the header that announces it. It does not rewrite pages, uses no cookies and keeps no state.

The result is that you, Googlebot and an AI agent receive the same HTML. There are no third-party scripts: the Content Security Policy accepts only those from our own domain, and that is also where the statistics from Plausible, which uses no cookies, come from.

Who updates the content, if there is no database?

Every page, article and case study is a YAML file in the repository, one per language with the same name. Editors see neither files nor git: they use Sveltia CMS, an open-source CMS that writes those files for them. Every save is a commit on a working branch, from which a preview site is rebuilt, and opens a review request towards the public site.

Pages are composed of blocks, like the Prismic slices we used before. The blocks are defined once, and both the schema that validates content during the build and the fields the CMS shows come from that definition. Content that breaks a rule, for example a link to a page that does not exist, stops the build with the name of the file and the field instead of going online.

Diagram of the publishing flow: Sveltia CMS makes a commit on the draft branch, and from there two paths start. On every push the build, with its checks on HTML, JSON-LD and URLs, publishes the preview site on Cloudflare Pages. With the pull request the change moves to the main branch, where build and audit (WCAG AAA, axe, Lighthouse) must pass before volcanicminds.com goes to production.
From a save in the CMS to the published site

How does an AI agent read the site?

A language model that has to answer questions about us does not need the menu, the animations or the footer. For it the site has four layers, and each one has a check that fails if a page is left out.

The first is the Markdown twin. Every indexable address has a Markdown version at the same address with the .md extension, with no navigation and no markup. The same version is served at the original address to whoever asks for it with the Accept header, and every HTML response announces it with a Link header. For example, the page of the tools for agents:

console
$ curl -sH 'Accept: text/markdown' https://volcanicminds.com/en/webmcp | head -12---title: "WebMCP · Volcanic Minds"description: "The WebMCP tools of volcanicminds.com: eight read-only tools and the contact form, what they return, what guarantees they carry and how to try them in Chrome."url: "https://volcanicminds.com/en/webmcp"lang: "en"type: "first_level_page"updated: "2026-10-06"alternate: "https://volcanicminds.com/webmcp"summary: "This site offers AI agents eight read-only tools and a contact form through WebMCP, a browser interface still in draft. Here you find what they do, what guarantees they come with and how to try them."---# The tools for agents

The second is llms.txt, the index meant for language models, with llms-full.txt and the full text beside it, one of each per language. The check starts from the sitemap, the list of what exists, and for every address verifies that the twin is there and appears in both files.

The third is structured data: every page has a single JSON-LD graph, with its nodes joined by stable identifiers. The company is one node, complete on the two home pages and on About us and referenced everywhere else, so whoever merges the graphs of different pages never receives two versions of the same company. A node is written only where what it describes is visible: FAQPage only where the questions are on the page. An excerpt from the article about the previous site:

json
{  "@type": "ProfessionalService",  "@id": "https://volcanicminds.com/#identity",  "name": "Volcanic Minds",  "url": "https://volcanicminds.com"}{  "@type": "TechArticle",  "@id": "https://volcanicminds.com/en/insights/making-of#article",  "author": { "@id": "https://volcanicminds.com/#identity" },  "publisher": { "@id": "https://volcanicminds.com/#identity" },  "isPartOf": { "@id": "https://volcanicminds.com/en/insights/making-of#webpage" }}

The fourth is WebMCP, a draft of the W3C Web Machine Learning Community Group through which a page declares tools that an agent in the browser can call. Every page of the site registers eight of them, all read-only: an overview, search across applications, case studies, articles and frequently asked questions, the details of a service, the definition of a glossary term and the company details. The only tool that writes is the contact form. Names and descriptions live in one place in the code, read by the browser and by the page that documents them.

Accessibility and weight, measured to the pixel

The target is WCAG 2.2 level AAA, which the W3C itself advises against requiring of a whole site, because some criteria cannot be met for some content. So we do not claim it: the accessibility statement says the site conforms to level AA and meets 19 of the 22 AAA criteria that apply to it, and explains the three that are missing, all about language: unusual words, abbreviations, reading level.

The rest is measured by a machine, on every page and in both languages, in a real browser, in the light and the dark theme, at four widths and at 320 pixels as well. Text contrast has to reach 7:1, over gradients too. Every clickable area is at least 44 pixels on each side. Lines of reading text stay within 80 characters, counted one by one on the page, with line spacing of at least 1.5. The page must not scroll sideways at any width, at any moment of the animations, and no text may be cut when the spacing of criterion 1.4.12 is forced. A block that spills over or an image drawn wider than its file is an error; a word left alone at the end of a heading is flagged. Then come the axe-core rules for levels A, AA and AAA.

Without JavaScript the page reads in full: reveal animations only switch on when the script is there. If the system asks for reduced motion the animations do not start, and wherever something moves there is a control to stop it.

Weight has thresholds that stop the build: 30 KB of compressed HTML per page, 15 KB of our own JavaScript, not one byte of third-party JavaScript. The one exception is the frequently asked questions page, with a 33 KB ceiling, because dropping its structured data to fit would cost more than the weight it saves. Lighthouse measures every page template on mobile and desktop with 1 as the bar for the four categories; the one exception, written in the code with its reason, is a 0.95 floor for mobile performance. In the Agentic Browsing category, still experimental, no audit may fail.

The Italian home page of the site at 400 pixels wide, on the left in the light theme and on the right in the dark theme, with the same text and the same layout.
The same page in both themes, both checked

How do we stop a change from making the site worse?

With a pipeline that reads the built site, not just the code. Beyond the checks above, the W3C Nu HTML Checker runs with zero errors as the bar, and so do our own HTML rules: one h1, headings that never skip a level, every navigation with its own name.

A separate check breaks each of these safeguards on purpose, on a copy of the build, and fails if the safeguard does not notice. A check nobody has ever seen fail is a check nobody knows works.

What did we leave out?

Cookies and banners, third-party scripts and iframes, Google Analytics, a server that builds pages on every request, a database to keep updated and to protect. There is a price: the preview arrives after a couple of minutes, and a page changes only when a file changes. For a site made of editorial content, the same for everyone who reads it, it is worth paying.

Sources and further reading

Questions

Frequently asked questions

All frequently asked questions
Is the code of this site public?

No, the code of this site is not public. Other open-source Volcanic Minds projects are on our GitHub profile, from the backend to examples of AI agents.

Why content in Git instead of a headless CMS as before?

Because content and code share the same history. Every change is a commit that can be reread and reverted, and wrong content stops the build instead of going online.

Is a static site right for every project?

No. It fits when content changes through editorial work and is the same for everyone. A reserved area, a cart or pages that differ for each user need a server and a database, and in that case we design them. The stack is chosen starting from the problem.

Taking this technique into production?

If your team has to make it work on a real project, under security and cost constraints, we can work alongside it or build it together.