Building my website in Claude Code
mattcrowl.com — Site Setup
Date: 2026-04-04
Status: Complete — site is live
What Was Built
A personal portfolio site at mattcrowl.com to document AI learning in public. Built for a potential employer audience. Sections:
- /learning — blog-style posts on AI concepts and tools
- /projects — write-ups of things built with AI
- /sops — generic standard operating procedures
- /about — background and skills summary
Tech Decisions
| Decision | Choice | Why |
|---|---|---|
| Framework | Astro 6 | Built for content/markdown sites, zero JS by default, static output |
| Language | TypeScript (strict) | Existing preference |
| Hosting | Cloudflare Pages | Domain already on Cloudflare, free tier, auto-deploys on push |
| Content | Markdown + Content Collections | Matches Obsidian workflow, no CMS needed |
| Design | Full monospace, no framework | Code-like aesthetic, minimal, fast |
Repository
- URL: https://github.com/mattcrowl/mattcrowl.com
- Local:
C:\Users\mattc\projects\ai-learning-site - Default branch:
main - Deploy: Push to
main→ Cloudflare auto-builds and deploys
Setup Process
- Scaffolded with
npm create astro@latest(Astro 6, minimal template, TypeScript strict) - Built content collections for learning, projects, and SOPs
- Built Base layout with monospace type system and dark mode
- Created all pages with dynamic routes for each content type
- Added sample content (transformer explainer post, M365 policy assistant project, M365 offboarding SOP)
- Pushed to GitHub, connected to Cloudflare Pages
Gotchas Encountered
Workers vs Pages: Cloudflare’s dashboard combines Workers and Pages. Initially deployed as a Worker, which has a completely different build model. Had to delete and recreate as a Pages project.
main vs master: Astro scaffolds with master branch. GitHub creates repos with main as default. When I edited the README on GitHub it went to main, which had no code. Cloudflare was deploying main. Fixed by force-pushing master to main and renaming the local branch.
NODE_VERSION: Astro 6 requires Node >=22. Cloudflare doesn’t detect this automatically — needed to add NODE_VERSION=22 as an environment variable in Pages settings AND add a .node-version file to the repo.
DNS: mattcrowl.com had two legacy A records pointing to AWS IPs (leftover from a previous hosting setup). These conflicted with Cloudflare Pages custom domain setup. Deleted both — Microsoft 365 MX/SPF/DKIM records were unaffected.
Adding Content
Drop a .md file in src/content/learning/, src/content/projects/, or src/content/sops/ with the appropriate frontmatter, then push. See docs/setup.md in the repo for full frontmatter schemas.
SOP GitHub Links
Each SOP page automatically shows a “view source on GitHub” link pointing to the raw .md file. SOPs are intentionally generic (no client-specific content) so the public repo link is appropriate.
Related
- Repo: https://github.com/mattcrowl/mattcrowl.com
- Site: https://mattcrowl.com
- Technical docs:
docs/setup.mdin the repo