adrian-altner.com/CLAUDE.md

6.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Prerequisites

Node.js >= 22. Package manager is pnpm (enforced via preinstall script). Husky pre-commit hook runs pnpm check.

Commands

pnpm dev               # Start dev server (localhost:4321)
pnpm build             # astro check + build + copy-sw (use this to verify changes)
pnpm build:production  # Production build (skips astro check, uses --mode production)
pnpm check             # Type check + Biome lint
pnpm check:fix         # Type check + Biome lint with auto-fix
pnpm stylelint         # Lint CSS/Astro styles
pnpm stylelint:fix     # Fix style issues
pnpm generate:icons    # Regenerate PWA icon assets

There are no automated tests. Verification is done via pnpm build (0 errors required) and the preview MCP tools.

Architecture

Astro 6 site running in SSR mode (Node.js standalone adapter) with static output for most routes. Pure Astro components — no React/Vue/Svelte. TypeScript strict mode (astro/tsconfigs/strictest). Path alias @/*src/*.

Formatter/linter: Biome (not ESLint/Prettier). Run check:fix after larger edits. Biome config disables some rules for .astro files (useConst, useImportType, noUnusedVariables, noUnusedImports).

Markdown plugins: remarkObsidianLinks (custom, src/lib/remark-obsidian-links.mjs) for [[wiki-link]] syntax, rehypeExternalLinks for target="_blank" on external links.

Content Collections (src/content.config.ts)

Seven collections defined with Zod schemas:

Collection Loader Path Notes
blog glob src/content/blog/posts/ Series support (seriesParent, seriesOrder), tags, category ref, syndication URLs
categories glob src/content/blog/categories/ Referenced by blog posts
notes glob src/content/notes/ Short-form with optional cover image
links_json file src/content/links/links.json JSON file with auto-generated IDs (json/date/slug)
projects glob src/content/projects/project/ Portfolio items with optional URL/GitHub links
projects_categories glob src/content/projects/categories/ Referenced by projects
collections_photos glob src/content/photos/collections/ Matches **/index.{md,mdx}; photos as JPG + JSON sidecar files in img/ subdirs

Key Routing Patterns

  • /blog/[...slug] — Blog posts use the full content path as slug (e.g. 2026/03/01/post-name)
  • /og/blog/[...slug].png — OG images generated server-side via Satori (src/lib/og.ts)
  • /rss/blog.xml, /rss/notes.xml, /rss/links.xml, /rss/photos.xml — Separate RSS feeds per content type
  • /photos/collections/[...slug] — Nested photo collections with breadcrumb navigation
  • /projects/[...slug], /projects/category/[...slug] — Project portfolio
  • /tags/[slug] — Cross-content-type tag pages
  • /archives/ — Timeline of all content
  • /api/webmentions.json — Webmention data endpoint

Lib Utilities (src/lib/)

  • collections.ts — Photo collection helpers: collectionSlug(), buildCollectionPhotos(), buildBreadcrumbs(), getChildCollections()
  • og.ts — OG image generation using Satori (buildArticleVNode, renderOgImage)
  • webmentions.ts — Fetch and filter webmentions from webmention.io (includes Mastodon/Bluesky validation)
  • photo-albums.ts — Photo album organisation utilities
  • links.ts — Link collection helpers
  • remark-obsidian-links.mjs — Custom remark plugin for Obsidian-style [[links]]

Scripts (scripts/)

  • mastodon-syndicate.mjs — POSSE: scans blog/notes for posts without syndication field, posts to Mastodon, writes status URL back to frontmatter. Env vars: MASTODON_BASE_URL, MASTODON_ACCESS_TOKEN, MASTODON_VISIBILITY, MASTODON_DRY_RUN, MASTODON_LIMIT
  • vision.ts — Uses Claude Vision API to auto-generate EXIF sidecars + metadata for photo collections. Requires ANTHROPIC_API_KEY
  • publish-all.sh — Full deploy orchestration: rsync content to VPS → rebuild container → send webmentions → run mastodon-syndicate. Per-collection variants: publish-blog.sh, publish-notes.sh, publish-links.sh, publish-photos.sh, publish-projects.sh
  • new-post.sh, new-note.sh — Content scaffolding templates
  • copy-sw.js — Post-build service worker copy

IndieWeb / Syndication

Blog posts support POSSE via mastodon-syndicate.mjs. After posting, the Mastodon status URL is written to frontmatter as syndication: ["https://..."]. The SyndicationLinks component renders u-syndication microformat links. Webmentions are fetched at build time from webmention.io and displayed via WebMentions.astro.

Deployment

Multi-stage container build (Containerfile): Node 22 with pnpm for build, Node 22 slim for runtime. Runs node dist/server/entry.mjs on port 4321. Orchestrated via compose.yml. Deploy scripts rsync content to VPS and rebuild the container.


Workflow

1. Plan First

  • Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
  • If something goes sideways, STOP and re-plan immediately - don't keep pushing
  • Write plan to tasks/todo.md with checkable items (not just TodoWrite tool)
  • Check in before starting implementation

2. Subagent Strategy

  • Use subagents liberally to keep main context window clean
  • Offload research, exploration, and parallel analysis to subagents
  • For complex problems, throw more compute at it via subagents

3. Self-Improvement Loop

  • After ANY correction from the user: update tasks/lessons.md with the pattern
  • Review tasks/lessons.md at session start
  • Write rules that prevent the same mistake from recurring

4. Verification Before Done

  • Never mark a task complete without proving it works
  • Run pnpm build — must complete with 0 errors
  • Use preview MCP tools to visually verify UI changes

5. Demand Elegance (Balanced)

  • For non-trivial changes: pause and ask "is there a more elegant way?"
  • Skip for simple, obvious fixes — don't over-engineer

6. Autonomous Bug Fixing

  • When given a bug report: just fix it. Point at logs/errors, then resolve them.

Core Principles

  • Simplicity First: Make every change as simple as possible. Impact minimal code.
  • No Laziness: Find root causes. No temporary fixes. Senior developer standards.
  • Minimal Impact: Changes should only touch what's necessary.