From Thought to URL in 60 Seconds — The Architecture Behind This Site
Here’s a system design challenge I found interesting: what’s the shortest possible pipeline from a raw thought to a live web page?
Not “short” as in fewer clicks. Short as in fewer concepts. The ideal system has one input (what I want to say), one output (a URL I can share), and nothing in between that requires me to think about the system itself.
This post is the technical story of how I built that pipeline for One Mile Lab.
Design constraints
I started with four requirements:
- Zero JavaScript shipped to the reader. This is a text site. There’s nothing to interact with. Every byte of JS in the bundle is waste.
- No database, no CMS, no auth. Every moving part is a part that can break at 11pm when I want to publish something. The fewer moving parts, the fewer reasons I’ll give up.
- Content must live in Git. Version history for free. Backup for free. Collaboration (with my AI copilot) for free. Portability forever — if I outgrow the stack, the content is just Markdown files in a folder.
- Publishing must be completable in a single conversation. Not “open VS Code, write the file, check the frontmatter schema, commit, push.” One conversation with my copilot. That’s the ceiling.
The stack
Astro was the obvious choice given constraint #1. It generates static HTML by default and doesn’t ship a runtime. The entire site is pre-rendered at build time. There’s no hydration, no client-side routing, no framework overhead. The page you’re reading loaded in under 100ms.
Markdown with frontmatter for content. Each post is a .md file in src/content/garden/. The frontmatter schema is minimal:
title: "The post title"
type: "essay" # essay | insight | dev-log
excerpt: "One-liner for the homepage card"
created: 2026-03-17T00:37:00+08:00
updated: 2026-03-17T00:37:00+08:00
Five fields. I deliberately kept the schema small. Every field you add to a content schema is a decision you have to make before you can publish. Decisions are friction. Friction kills consistency.
Cloudflare Pages for hosting and deployment. Push to main, site rebuilds automatically. No CI config to maintain. Free tier handles everything I need. The deploy pipeline is literally git push.
Tailwind CSS for styling, but barely. The site has one layout, one font (Newsreader), and a handful of color variables. The entire CSS footprint is tiny. I’m not building a design system — I’m building a reading experience.
The interesting part: the AI publishing flow
The stack above is unremarkable. Thousands of sites use the same setup. What makes this system actually work for me is what sits in front of the stack: an AI copilot with a custom publishing skill.
Here’s what a typical publishing session looks like:
Me: "I want to write about why patching feedback
loops don't work — I had this experience with
my AI agent this week..."
AI: [produces a full draft in my voice]
Me: "Good. Tighten the Five Whys section, cut the
last paragraph."
AI: [revises, shows me the final version]
Me: "Publish"
AI: [creates the .md file, commits, pushes to main]
→ Cloudflare Pages auto-deploys
→ Live in ~40 seconds
The copilot has a publishing skill — a set of instructions I wrote that encodes everything about this site’s content model:
- File conventions: kebab-case filenames, placed in
src/content/garden/ - Frontmatter schema: what fields exist, what values are valid, how dates should be formatted
- Voice guide: specific examples of what my writing sounds like vs. what it shouldn’t. The difference between “I decided to optimize my publishing workflow” (corporate) and “I got tired of fighting with YAML frontmatter” (mine)
- Hard rule: never publish without showing the full draft first. The AI proposes. I approve. It’s a collaboration, not delegation
The voice guide was the part that took the most iteration. Early drafts were competent but generic — they read like anyone’s blog. I had to feed the skill concrete examples: “this sentence sounds like me” vs. “this sentence sounds like a LinkedIn post.” That specificity is what makes the output feel like my writing with the friction removed, rather than AI writing with my name attached.
Architecture decision: digital garden, not blog
A blog is a reverse-chronological feed. A digital garden is a collection of notes at various stages of maturity.
I chose the garden model for a specific technical reason: it removes the implicit contract that every post must be “finished.” In a blog, publishing feels like a commitment — you’re putting something on record. In a garden, you’re planting a seed. Some grow. Some don’t. Both are fine.
This matters for the pipeline because it changes the minimum viable post. A blog post needs a beginning, middle, and end. A garden note needs a title and a thought. That lower bar means the pipeline gets used more often, which means more content, which means the system justifies its own existence.
On the homepage, I display entries as a simple index — title, date, one-line excerpt. No thumbnails, no categories, no tags. This is a deliberate information architecture choice: the list itself is the feedback mechanism. Every time I publish, the list grows by one line. That visible accumulation is the intrinsic reward that keeps the pipeline running.
The cross-posting pipeline
Once a post exists as a Markdown file in the repo, it becomes source material for other formats. My copilot has additional skills for:
- 小红书 image carousels: takes an article, generates 8 slides as HTML, screenshots them to PNGs, writes a platform-native caption
- Twitter/X threads: extracts key points and reformats for thread structure
These are downstream consumers of the same source content. Write once, distribute to multiple surfaces. The Markdown file is the single source of truth; everything else is a derived view.
This is the same principle behind headless CMS architectures, just implemented with flat files and an AI agent instead of an API layer. Simpler, but the mental model is the same: separate content from presentation, then generate multiple presentations from one content source.
What I’d change
Two things I got wrong in v1:
No image pipeline. Posts are text-only right now. When I want to include a diagram or screenshot, I have to manually place the file in public/images/posts/ and reference it with a relative path. This breaks the “single conversation” flow. I need a skill that handles image upload as part of the publishing conversation.
No draft state. Every post is either published or it doesn’t exist. I want a draft: true frontmatter flag that hides posts from the homepage index but still generates the page (so I can preview via direct URL). Simple to implement, just haven’t done it yet.
The numbers
- Time from idea to live URL: 3–10 minutes depending on post length
- Files in the content directory: 7 (and counting)
- Total site JavaScript shipped to reader: 0 bytes
- Deployment cost: $0 (Cloudflare Pages free tier)
- Build time: ~2 seconds
If you’re a builder thinking about starting a writing practice, my unsolicited advice: don’t pick a platform. Build a pipeline. The platform is someone else’s system optimized for their goals. A pipeline is your system optimized for the one thing that matters — getting thoughts out of your head and into a URL, with as little resistance as possible.