How this site is built

I run this site on explicit agent contracts. Every change to copy, content, or code moves through a small named task with its own context, its allowed paths, and its gates. Language models help inside scheduled automation loops, never inside the production build. Their output reaches the site only through a pull request: deterministic checks review every proposal, and anything flagged waits for my review. What follows is the real machinery, in the order a change travels through it.

Principles

Smallest sufficient context

I give each task the least context it needs, generated from the manifest, so a run reasons over a few files instead of the whole repository.

A deterministic build

The production build never calls a model. With the same committed inputs and toolchain, it produces the same output, so a deploy is reproducible and easier to inspect.

Generation is a proposal

Model-written copy is a draft, not a commit. Deterministic gates decide whether it can ship. Anything they flag remains in the pull request until I review it.

The gates decide the merge

An automation pull request merges only with every deterministic gate green, and only while the auto-merge switch is on. Whatever a gate flags — a judge-flagged article, a rescue fix — stops at a labelled PR and waits for me.

One voice, two languages

Site-owned copy stays in the first person. English and Italian ship together on paired surfaces; the parity gate also records deliberate exceptions such as the English-only public audit register.

Workflows

The eight workflows a change can travel through, from contract to production deploy.

01

Agent contracts

A manifest, a set of roles, and one file per task define who does what, where they may write, and when they must stop.

  1. The manifest lists the stack, the source ownership, the roles, the tasks, and the gates in one place.
  2. Each task names its allowed paths, its commands, and the conditions that stop the run.
  3. A check validates the manifest, the roles, the tasks, and the brand rules before any work begins.
npm run agent:checknpm run agent:context

02

Copy and tone of voice

Deterministic linting keeps the writing in my voice; an optional model pass humanizes drafts, and the gates decide what stays.

  1. The copy check runs one-pattern rules plus a density-weighted anti-slop audit across English and Italian.
  2. A fix step applies the safe, deterministic replacements without touching meaning.
  3. An AI review lets a model propose rewrites; copy-lint, frontmatter, and parity choose whether to keep them.
npm run copy:checknpm run copy:ai-review -- --changed --write

03

Full automation loops

Scheduled GitHub Actions jobs refresh content, draft articles, and propose SEO changes. They open pull requests — never direct commits to main.

  1. The weekly refresh translates missing articles, fills Italian UI keys, generates grounded FAQ and takeaways, humanizes drafts, rebuilds feeds, and runs content health on the built site.
  2. Monthly loops draft one grounded article behind originality gates and an advisory judge, and turn Search Console demand into SEO meta proposals plus topic-gap briefs.
  3. A showcase loop proposes case studies from public repositories, and merges one only with every gate green; CI rescue attempts fixes on ci-failure issues with Codex and never merges its own work.
  4. Automation pushes through a GitHub App token so Flash CI runs on the PR; dirty runs get needs-human, and every automation PR carries needs-translation-review.
npm run content:mapnpm run copy:ai-review:full -- --writenpm run article:judge

04

Publication pipeline

Archived software releases live in a separate repository. The site consumes Zenodo concept DOIs through a registry, sync script, and drift gate — never auto-updated in build.

  1. The software repo publishes a GitHub release, reserves a new Zenodo version DOI, and syncs CITATION.cff from release.toml.
  2. publications.json is the site registry: concept DOI for public copy, version DOI and publishedVersion for drift checks.
  3. publication:sync refreshes the registry from Zenodo and GitHub, propagates concept DOIs into catalog and project copy, and regenerates landing JSON-LD.
  4. publication:check fails CI when github-stats, consumer files, or Zenodo metadata drift; a human reviews the PR before merge.
npm run publication:syncnpm run publication:check

05

SEO and GEO

The sitemap and llms.txt index derive from the route registry. Structured data combines those canonical paths with the identity, publication, and project registries, and deterministic checks keep the surfaces aligned.

  1. Static routes live in a single shared list that feeds both the sitemap and the llms.txt index.
  2. Every page carries JSON-LD: a person, the breadcrumb trail, and a type that fits the page.
  3. A Search Console loop and a topic-gap report point me at what to write next; a manual GEO baseline tracks mentions and citations in AI answers.
npm run seo:checknpm run topic:gap

06

Quality gates

One command runs the full pre-merge gate: types, lint, format, tests, content health, parity, and generated-output drift.

  1. The quality check is the local equivalent of the gate that CI runs on every change.
  2. Generated files are regenerated and compared, so stale output fails the build instead of slipping through.
  3. A governance check guards the public docs against claims I no longer make.
npm run quality:check

07

Deterministic build

The production build is pure: it prerenders every route, writes markdown mirrors for readers and models, and calls no external model.

  1. Vite builds the app, then a prerender step writes static HTML for each localized route.
  2. Markdown mirrors of each article ship next to the HTML for machine readers.
  3. The container serves the result; nothing on this path depends on an API key.
npm run build

08

CI and deploy

Flash CI builds the site, scans rendered pages, and runs browser checks; a green main run triggers a supersede-safe deploy to production.

  1. After the pre-merge gates pass, CI runs a production build, content:scan on dist/, and a bundle-size budget check.
  2. A separate browser job downloads that build and runs contrast and visual-regression checks before merge is allowed.
  3. Deploy follows a successful Flash CI run on main, pushes arm64 images to GHCR, and verifies production serves the new commit.
npm run buildnpm run content:scannpm run perf:budget

Quality gates

Every change clears the pre-merge gates before merge. Flash CI repeats the same set, then runs post-build checks on the downloaded dist/.

Pre-merge

Agent contractsagent:checkFrontmattervalidateRead timereadtime:checkOG assetsog:checkEN/IT parityi18n:check:strictArticle structurei18n:articlesTone of voicecopy:checkContent healthcontent:healthPublication driftpublication:checkShowcase schemashowcase:checkGenerated driftgenerated:checkSEOseo:checkSEO ledgerseo:ledger:checkGovernancegovernance:checkTypestypecheckLintlintCSS lintlint:cssWorkflow lintlint:actionsFormatformat:checkTeststest:run

Post-build (CI)

Rendered page scancontent:scanBundle budgetperf:budgetContrast + visual regressionbrowser checks

Have a project in mind?

Write to info@gianlucamazza.it with the operational problem and the systems involved. When a working prototype already exists, the first step is the production readiness review. That review does not include code changes.

Write by email