My blog has no CMS. I write in Obsidian, type /publish-post, and it's live in 30 seconds.
My blog has no CMS, no editor, no upload step. I write in Obsidian, type /publish-post, and it’s live in 30 seconds.
This is how I built it - and how you can too.
If you haven’t seen the Obsidian + Claude setup this builds on, start here: I Built an Obsidian Second Brain That Thinks Alongside My Mind.
The stack
Obsidian - where posts are written. Each post is a plain markdown file with YAML frontmatter in a Drafts folder inside the vault.
Astro - the blog framework. Fast, static, content-first. Takes markdown and turns it into a site.
GitHub - the bridge. The Astro project lives here. Every push triggers a deploy.
Cloudflare Pages - hosts the blog. Auto-deploys on every GitHub push. The site rebuilds in about 30 seconds.
A Node.js sync script - the piece that ties everything together. It watches the Obsidian Drafts folder. When a post’s frontmatter says status: published, it converts the markdown to Astro’s format, commits to GitHub, and pushes. Cloudflare picks that up and deploys.
How Claude sets it up
Open Claude Code from the Terminal plugin inside Obsidian. Because Claude is running inside your vault, it has full context of your folder structure and conventions from the start.
The Astro blog: Give Claude your blog name and a few design references. It scaffolds the Astro project, configures the content schema, sets up routing, and gets a local preview running. Theme and layout tweaks are yours to adjust, but the foundation is done in one session.
Connecting to Cloudflare Pages: Create a GitHub repo and push the project. Then connect it to Cloudflare Pages through the dashboard - it’s a few clicks to link your repo and set the Astro build command. From that point, every git push deploys automatically.
The sync script: Ask Claude to write a Node.js script that watches your Obsidian Drafts folder, detects when a post’s frontmatter changes to status: published, converts the markdown to Astro MDX, and pushes a git commit. It handles frontmatter mapping, tag registration, and wikilink cleanup so the output is clean Astro content.
Run the script in the background. That’s the only ongoing step.
Writing and publishing
Ideas collect in my daily notes throughout the day. My evening skill reflects on the day, extracts what’s meaningful, and files content into the right documents in my vault with links back to the source. Over time, thoughts accumulate where they belong.
When something substantial takes shape, I run /craft-post from the terminal. Claude knows my vault - it finds the relevant thinking, drafts an outline, and writes a first pass with everything woven in. I go through it, add notes, redirect where needed. We co-write until it’s right.
When I’m ready to publish, I run /publish-post.
The skill validates the frontmatter and shows a confirmation:
Ready to publish:
Title: My blog has no CMS... Description: How I set up an Obsidian-to-Cloudflare pipeline... Tags: tools, building, productivity Date: 2026-03-04 URL: https://leafl.ing/blog/my-blog-has-no-cms/
Go ahead? (yes / no)I say yes. It sets status: published in the frontmatter. The sync script detects the change, converts the file, commits to GitHub, and pushes. Cloudflare deploys. The post is live before I’ve switched windows.
The honest bit
Some parts need manual intervention - the initial Cloudflare Pages connection, theme adjustments, a few config tweaks. Claude handles the rest.
The Astro and sync script setup took an afternoon. I haven’t touched either since they started working.
Takeaway
I write where I think. Ideas flow. I set a status on a post, it commits to GitHub, Cloudflare deploys it, and it’s live.
No duplicate files to maintain. No server to babysit. No tool to context-switch into.
I genuinely did not expect this to feel as different as it does.
← Back to blog