About personal-presence-os
· Updated
The problem
Platforms optimise for themselves, not for creators. Your reach depends on algorithms you don't control. Your audience is scattered across Twitter, LinkedIn, Substack, Threads — each demanding a different format, each limiting how much of your own audience you actually reach. And when you want to leave, your content is buried inside systems designed to make moving on hard.
Meanwhile, a growing share of high-influence decision makers get their information from AI assistants, not search engines. If your expertise isn't structured where models can find it, you're invisible to that audience entirely.
What it does
personal-presence-os is a static content engine that runs multiple websites from a single codebase. Each site gets its own domain, its own content directory, and its own llms.txt file — a plain-text index designed for LLM crawlers to read.
You write Markdown with YAML frontmatter. The engine prerenders it to semantic HTML at build time. At runtime, a Hono server routes requests by Host header to the right site's static files. That's it.
The strategy
Your domains are the canonical home for everything you write. Platforms are distribution channels — you engage wherever your audience is, adapt to each format, but always link back to content you own and control.
This means cross-posting to Substack with canonical URLs, writing native posts on LinkedIn, sharing sharp takes on X — all driving traffic back to your sovereign content. If a platform changes or disappears, nothing is lost.
See the full distribution strategy for the playbook.
Goals
- Own the content, own the audience. Publish across your own domains. Use platforms for reach, but never depend on them for durability.
- Be findable by AI. Structured HTML, Schema.org JSON-LD, and
llms.txton every site — so your expertise gets cited when someone asks an AI assistant about your topic. - Measure before building. Self-hosted analytics (GoatCounter) across all domains tells you what resonates before you invest in engagement features. See the analytics setup.
- Get fluent with Claude Code. The entire project is built with Claude Code as the primary development tool — architecture, implementation, content, deployment.
- Practice extreme pragmatism. Ship fast. Learn in public. Every decision delayed is feedback not received.
Architecture
sites.yamlis the single source of truth. Every domain, content path, status, and feature is declared there.- Build phase:
bun run buildprerenders all active sites todist/<domain>/. - Serve phase: Hono reads from
dist/and routes by Host header. One process, all domains. - Content: Markdown files with frontmatter. Pages, docs, log entries, decision records.
- Analytics: Self-hosted GoatCounter on the same VPS — privacy-friendly, no cookies, covers all domains.
- No frameworks: Vanilla JS web components only. No React, Vue, or Svelte.
- No cloud lock-in: Runs in any Docker host. Currently deployed on a Hetzner VPS behind Cloudflare.
Principles
The full list lives in PRINCIPLES.md. The short version:
- Prerender at build time, serve static files at runtime
sites.yamldrives everything — never hardcode a domain- Semantic HTML, Schema.org JSON-LD,
llms.txton every site - Record non-obvious decisions; never delete history
- No frontend frameworks, no bundlers by default, no cloud-specific APIs
Stack
| Layer | Choice |
|---|---|
| Runtime | Bun |
| Server | Hono |
| Content | Markdown + gray-matter + marked |
| Analytics | GoatCounter (self-hosted, SQLite) |
| Hosting | Hetzner VPS |
| CDN / TLS | Cloudflare (free tier) |
| DNS | Cloudflare |
| Deploy | GitHub webhook → git pull → rebuild |