Add Markdown blog server
Branch feature/initial · merged 2026-10-24 · version (none; later called 0.1.0)
What changed
- Blog server: a Go app that serves each
content/*.mdfile as a blog post./lists all posts, newest first, with title, date and summary./posts/<slug>shows one post, with links to the newer and older posts./feed.xmlis an RSS feed of the 20 newest posts.- Any other URL gets a styled 404 page.
- Posts: named
YYYY-MM-DD-slug.md, with an optional front-matter block fortitle,date,summaryanddraft. If the title is missing, the first# Headingis used, then the slug. If the date is missing, it comes from the filename. - Live content: posts are re-read whenever a file in the content directory is added, changed or removed, so new posts appear without a restart.
- Fault tolerance: a post with a bad filename or broken front matter is skipped and logged; the rest of the site keeps working.
- Markdown: rendered with goldmark (CommonMark plus GitHub-style tables, strikethrough, task lists and autolinks). Raw HTML in posts is left out.
- Templates and CSS: built into the binary. The layout is minimal, with automatic dark mode.
- Security: URLs can only reach posts that have been indexed, so
../paths get a 404. Responses carry a strict Content-Security-Policy (no scripts),nosniffand a referrer policy. The server binds to127.0.0.1with request timeouts. - Configuration: set by environment variables
PORT,CONTENT_DIRandSITE_URL. - First post:
content/2026-10-24-hello-world.md, a guide to writing posts covering file names, the header block, publishing, and what Markdown is supported.
Testing
go vetis clean and all tests pass with the race detector (go test -race ./...), with 81% coverage.- Tests cover front-matter parsing and fallbacks, CRLF files, drafts, ordering, newer/older links, 404s including path-traversal attempts, the RSS feed, static files, security headers, and picking up added and removed posts.
- Built and ran locally against the real
content/, then checked the index, the post and the feed.
Screenshots
Taken afterwards from a build of the branch's final commit (0bd42c4).
| Desktop | Mobile |
|---|---|
![]() |
![]() |
🤖 Generated with Claude Code

