···2626 key: ${{ runner.os }}-deps-${{ hashFiles('**/package-lock.json', '**/*.qmd') }}
2727 restore-keys: |
2828 ${{ runner.os }}-deps-
2929- - name: Run worker tests
3030- run: npm test
3129 - name: Set up R
3230 uses: r-lib/actions/setup-r@v2
3331 with:
+6-12
AGENTS.md
···1616|---|---|
1717| Site framework | Quarto |
1818| Styling | Custom SCSS (`assets/custom.scss`), no Quarto theme (`theme: none`) |
1919-| Hosting | Cloudflare Workers (static assets via Wrangler) |
1919+| Hosting | Cloudflare Workers static assets (deployed via Wrangler, no Worker script) |
2020| CI/CD | GitHub Actions (`.github/workflows/deploy.yml`) |
2121| R environment | renv |
2222| Analytics | Simple Analytics |
···3636 analytics.html # Simple Analytics script injection
3737 a11y.html # Accessibility enhancements (ARIA landmarks, roles)
3838 skip-link.html # Skip-to-content link injected into every page
3939-src/
4040- index.js # Cloudflare Worker entry point — lowercases URL paths before serving assets
4141-tests/
4242- index.test.js # Worker unit tests (Node.js built-in runner); run with `npm test`
4339posts/ # Blog posts, each in its own subdirectory with index.qmd
4440 _metadata.yml # Shared frontmatter defaults for all posts (freeze: auto)
4541404.qmd # Custom 404 page
···10399The site is **never built locally** — CI handles it. The full pipeline runs on every push to `main`:
1041001051011. Restore cached `_freeze/` and `node_modules/` (keyed by OS + hash of `package-lock.json` and all `.qmd` files)
106106-2. Run `npm test` — Node.js built-in test runner, tests in `tests/index.test.js`
107107-3. Set up R + renv (restores packages from `renv.lock`)
108108-4. Run `quarto render` → outputs to `_site/`
109109-5. Run `wrangler deploy` → uploads `_site/` to Cloudflare Workers
102102+2. Set up R + renv (restores packages from `renv.lock`)
103103+3. Run `quarto render` → outputs to `_site/`
104104+4. Run `wrangler deploy` → uploads `_site/` to Cloudflare Workers
110105111106**Runner**: `blacksmith-4vcpu-ubuntu-2404-arm` (4-core ARM Ubuntu 24.04)
112107···124119- Static assets served from `_site/`
125120- `not_found_handling: "404-page"` — unmatched routes serve the rendered `404.html`
126121- `html_handling: "auto-trailing-slash"` — URL normalisation (nested under `assets`)
127127-- Custom domain: `rorylawless.com`
128128-- `run_worker_first: true` — `src/index.js` intercepts every request before the assets binding responds; it lowercases URL paths and issues a 301 redirect, then falls through to `env.ASSETS.fetch()`
122122+- Custom domains: `rorylawless.com` and `www.rorylawless.com` (both route to the same Worker)
129123- Observability: full logs and traces enabled at 100% head sampling rate with persistence (viewable in the Cloudflare dashboard)
130124131131-URL redirects live in `_redirects` (Cloudflare syntax). Response headers live in `_headers` — currently used to set CORS headers and `Content-Type` for the PGP key endpoint at `/.well-known/openpgpkey/`.
125125+There is no Worker script — the deployment is static assets only. URL redirects live in `_redirects` (Cloudflare syntax). Response headers live in `_headers` — currently used to set CORS headers and `Content-Type` for the PGP key endpoint at `/.well-known/openpgpkey/`. A Cloudflare Redirect Rule (configured in the dashboard, not the repo) 301s `www.rorylawless.com` to the apex.
132126133127---
134128