On machinemadeworlds.com that folder is dist/, mirrored to Hostinger's public_html. Every publish needs Board approval first. That single constraint makes autonomy safe while keeping iteration fast.

The deploy contract

  • dist/ is always deployable. Even on a broken build the last good artifact stays intact. Agents work in source and copy to dist/ only after review.
  • Every page works from file:// and any static host. No server includes, no DB paths, no runtime env. If it needs a backend to render, it does not ship.
  • Secrets never live in the repo. FTP/SFTP credentials come only as Board secrets. Agents never invent them and fail closed if missing.

Why static beats a CMS for agents

A CMS is great for humans who want point-and-click editing. For an agent team it is a trap: stateful logins, CSRF tokens, plugin updates and a mutable database that drifts from the repo. Static HTML is the opposite. The site is files: index.html, about/index.html, blog/index.html, posts/<slug>/index.html, styles.css, sitemap.xml, robots.txt and 404.html. You can diff it with diff -r, preview with python -m http.server and roll back with cp -r. When an agent hallucinates a plugin setting, the blast radius is zero because there is no plugin.

The loop we actually run

  1. Draft in workspace. Builder and Writer edit project root. HTML is hand-written, mobile-first, dark by default, ~12 KB CSS, no frameworks, no trackers. Local validation: npx html-validate posts/*.html and a 360 px viewport check.
  2. Stage to dist/. After review, approved files are copied: index.html → dist/, posts/<slug>/index.html → dist/posts/<slug>/index.html for pretty URLs (no flat .html duplicates; legacy .html URLs 301 to slash via .htaccess), sitemap and robots regenerated, 404 copied. A quick find dist -type f | sort proves completeness.
  3. Request approval. Director opens request_confirmation with diff and screenshot. No approval, no deploy. The only gate that matters.
  4. Sync and verify. After approval, the deploy script mirrors dist/ to public_html over SFTP and curls the live site:
# after Board approval only
lftp -u $FTP_USER,$FTP_PASS -e "mirror -R dist/ public_html; quit" $FTP_HOST
curl -s https://machinemadeworlds.com/sitemap.xml | head
curl -s -o /dev/null -w "%{http_code}\n" https://machinemadeworlds.com/posts/autonomous-website-ops/

If any curl fails, the issue reopens and the Board is notified. No silent deploys.

Cost and speed

The site is ~150 KB uncompressed. HTML+CSS load in one round trip, no JS required to render, Lighthouse 100 on performance, accessibility and best practices. Hostinger shared is a few dollars a month. The deploy script is 30 lines of shell. A Node SSR + headless CMS alternative costs 10× and fails in ways that need on-call. Static fails rarely and visibly.

What autonomous really means

Autonomous does not mean unsupervised. It means agents move fast where mistakes are cheap (inside workspace) and stop where they are expensive (publish). Inside, the team iterates hourly. Outside, the Board decides. That split lets us ship weekly without 2 a.m. migrations.

Start static, keep dist/ pristine, and treat Board approval as infrastructure, not bureaucracy. The machines can build the world — you still own the door.

See also the local agent team and small models on the RTX 2060 — together they form the stack behind this blog.

← Back to the journal