···11# Agent Instructions
2233-This file provides guidance to AI coding agents (including Claude Code) when working with code in this repository.
33+This file provides guidance to AI coding agents (including Claude Code) when working with code in this repository. `CLAUDE.md` is a symlink to this file — edit either path; both point to the same content.
4455## What this is
66···3434 template.ejs # EJS template for the post listing on the homepage
3535html/
3636 analytics.html # Simple Analytics script injection
3737- a11y.html # Accessibility enhancements (ARIA landmarks, roles)
3737+ a11y.html # Runtime JS patches for Quarto template a11y bugs (main-content focus, navbar role, code-copy focus restore)
3838 skip-link.html # Skip-to-content link injected into every page
3939posts/ # Blog posts, each in its own subdirectory with index.qmd
4040 _metadata.yml # Shared frontmatter defaults for all posts (freeze: auto)
4141404.qmd # Custom 404 page
4242-.well-known/ # PGP key (pgp-key.txt) and security.txt
4242+.well-known/ # PGP key (pgp-key.txt), security.txt, OpenPGP Web Key Directory files
4343_redirects # Cloudflare redirect rules
4444-_headers # Cloudflare response header rules
4444+_headers # Cloudflare response header rules (global security headers + OpenPGP headers)
4545wrangler.jsonc # Cloudflare Workers deployment config
4646package.json # Node deps (just wrangler)
4747renv.lock # Locked R package versions
4848-.github/workflows/
4949- deploy.yml # Build and deploy pipeline
4848+.Rprofile # Sources renv/activate.R (auto-snapshot + pak enabled)
4949+.github/
5050+ workflows/deploy.yml # Build and deploy pipeline
5151+ dependabot.yml # Weekly npm + GitHub Actions dependency updates
5052```
51535254Output goes to `_site/` (generated, not committed). The `_freeze/` directory (computational cache) is also not committed — it is restored from the GitHub Actions cache between runs.
···8082- Sorted by date descending; no categories, search, filters, or sort UI
81838284When changing look and feel, `assets/custom.scss` and `_quarto.yml` are the two files to focus on. Do not introduce a Quarto theme — the site intentionally uses `theme: none`.
8585+8686+**Bootstrap caveat**: `theme: none` disables the *Quarto* theme layer, but Quarto still ships Bootstrap's CSS/JS in the rendered output. That's why `custom.scss` uses `!important` in a few navbar/layout rules to override Bootstrap defaults — it's expected, not technical debt.
83878488---
8589···1031073. Run `quarto render` → outputs to `_site/`
1041084. Run `wrangler deploy` → uploads `_site/` to Cloudflare Workers
105109106106-**Runner**: `blacksmith-4vcpu-ubuntu-2404-arm` (4-core ARM Ubuntu 24.04)
110110+**Runner**: `blacksmith-4vcpu-ubuntu-2404` (4-core x86 Ubuntu 24.04 on Blacksmith)
107111108112**Secrets required**: `CLOUDFLARE_ACCOUNT_ID`, `CLOUDFLARE_API_TOKEN` (stored in GitHub Actions).
109113···119123- Static assets served from `_site/`
120124- `not_found_handling: "404-page"` — unmatched routes serve the rendered `404.html`
121125- `html_handling: "auto-trailing-slash"` — URL normalisation (nested under `assets`)
122122-- Custom domains: `rorylawless.com` and `www.rorylawless.com` (both route to the same Worker)
123123-- Observability: full logs and traces enabled at 100% head sampling rate with persistence (viewable in the Cloudflare dashboard)
126126+- Custom domain: `rorylawless.com` only (apex). This is the single entry in `routes`.
127127+- No `observability` block — Cloudflare defaults apply (view logs/traces in the Cloudflare dashboard)
128128+129129+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 for global security headers (`Strict-Transport-Security`, `Content-Security-Policy: frame-ancestors 'none'`, `X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`, and `Permissions-Policy`) plus CORS and `Content-Type` headers for the OpenPGP Web Key Directory endpoint at `/.well-known/openpgpkey/`. The HSTS header intentionally omits `includeSubDomains` and `preload`. `www.rorylawless.com` is 301'd to the apex by a Cloudflare Redirect Rule configured in the dashboard (not in this repo, and not in `wrangler.jsonc`).
124130125125-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.
131131+---
132132+133133+## Dependencies
134134+135135+- **Node**: Only `wrangler` (devDependency). `package.json` sets `"type": "module"`. Dependabot bumps it weekly.
136136+- **R**: Pinned in `renv.lock` (R 4.5.3, CRAN + R-Multiverse). `.Rprofile` sources `renv/activate.R` and enables `renv.config.auto.snapshot` and `renv.config.pak.enabled`.
137137+- **GitHub Actions**: Versions bumped weekly by Dependabot (`.github/dependabot.yml`).
126138127139---
128140