Source available on GitHub: MrMatt57/MrMatt.io
Design Philosophy
- Minimal and fast — no JS frameworks, no bloat, static HTML/CSS
- Content-first — the site publishes writing and serves as a professional presence
- Zero dependencies — vanilla JS, no npm, no external libraries anywhere
- Own your stack — static files you control, no platform lock-in
- Low maintenance — no comment systems, no dynamic backends
- AI as a collaborator — Claude generates, the human reviews and refines
- Spec-driven development — plan before you build, every feature documented
- Automation where it matters — AI and APIs handle the tedious parts so publishing stays frictionless
Static Site
- Hugo (extended) with PaperMod theme (git submodule)
- Custom CSS with Roboto Slab typography
- No npm, no build tools — Hugo’s built-in asset pipeline handles everything
Development
- Spec-driven workflow — every feature starts with a numbered spec in
.specs/before any code is written - Claude Code for interactive development —
/featurecreates a spec + git worktree,/shipcommits, pushes, opens a PR with auto-merge, and cleans up - Git worktree isolation keeps the main checkout clean while features are in progress
Serverless Backend
- Cloudflare Pages Functions (three endpoints)
/api/describe-photo— Claude Vision proxy with CORS locked to mrmatt.io/api/oauth-exchange— GitHub OAuth token exchange/api/oauth-client-id— serves the OAuth client ID to the frontend
CI/CD
- GitHub Actions — builds Hugo with submodules, compiles Cloudflare Functions, and deploys on every push to main
- Pull requests run build checks before merge, including Pages Functions validation
- Concurrency controls cancel in-progress deploys when a new push arrives
Hosting & DNS
- Cloudflare Pages (free tier)
- Cloudflare DNS
- Cloudflare Web Analytics — server-side, no JavaScript tag
Security
- Content Security Policy with deny-by-default baseline (
default-src 'none') and SHA-256 script hashes — no'unsafe-inline'in script-src - HSTS with preload, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy
- CORS locked to
mrmatt.ioon all API endpoints — API keys stay server-side in Cloudflare encrypted environment variables - OAuth CSRF protection via cryptographic state parameter, single-user whitelist authorization
- CodeQL static analysis on every PR via GitHub Actions
- security.txt (RFC 9116) for vulnerability disclosure
Automated Publishing
- GitHub OAuth authentication scoped to the repo owner
- Upload creates a feature branch (
photo/YYYY-MM-DD-slug), commits the image and Hugo content file, opens a PR, and enables auto-merge — all from the phone - GitHub REST API for branches, blobs, trees, and commits; GraphQL API for the auto-merge mutation
- Photo goes from camera roll to live on the site with no terminal, no laptop
Photo Upload
- Vanilla JS progressive web app at
/upload— no frameworks, no dependencies - Android share target — share a photo directly from the camera roll to the site
- Service Worker with network-first caching and cached share-target handoff between the browser and upload page
- Native EXIF parsing from raw JPEG bytes to extract photo dates — no libraries
- Client-side image conversion and resizing via Canvas API before sending to AI
AI-Powered Descriptions
- Anthropic Claude Haiku 4.5 vision model generates photo titles, alt text, and descriptions from uploaded images
- Cloudflare Pages Function proxies requests to the Anthropic API, keeping the API key server-side
- Feedback loop — review the AI output, provide guidance, and regenerate until it’s right
- Structured JSON output parsed directly into Hugo front matter fields