Blog Writing Pipeline
How every post on this site gets made, from idea to deploy
The actual workflow behind these guides: rough notes in, polished posts out, with Claude Code doing the heavy lifting on drafting and a custom voice-restoration step to keep it sounding like me.
Every guide on this site goes through the same pipeline. It starts messy and ends clean, and Claude Code does most of the mechanical work. The interesting part is how I keep the output from reading like AI wrote it.
The pipeline
1. Rough capture
Ideas start as bullet points, comments, or fragments in Obsidian. Sometimes it’s a problem I just solved and want to document while it’s fresh. Sometimes it’s a note that’s been sitting in my inbox for weeks.
The bar for starting is low: if I can explain why someone would care in one sentence, it’s worth writing up.
2. Workshop with Claude
I paste the rough notes into Claude Code and talk through the idea. This is more conversation than dictation - I’m clarifying my own thinking as much as generating text. Claude has access to my vault, so it can cross-reference existing guides, check for consistency with what I’ve already published, and flag gaps in my reasoning.
The key files Claude reads during this phase:
- Context files in
07 System/- my technical setup, preferences, worldview - Existing guides - to avoid contradicting or repeating myself
- Works in Progress - what’s currently in flight
This is where the structure emerges. By the end of a back-and-forth, I usually have a clear outline - the dialogue helps spur creativity, brings in other angles, and develops the post beyond where I’d have taken it solo.
3. Draft generation
Claude writes a full draft based on our conversation. For technical guides, this follows a specific format: a human-readable section up top (the “why” and “what”), then an implementation section below aimed at Claude Code users who want to paste the URL and have it set things up.
I review the draft for technical accuracy - does the code actually work? Are the steps in the right order? Did it miss an edge case I hit during the actual setup?
4. Voice restoration (/de-ai-ify)
This is the step that matters most. AI-generated text has a distinctive sound: too many hedges (“it’s worth noting”), too many transitions (“moreover”, “furthermore”), too many soft qualifiers (“relatively”, “somewhat”). It reads like a corporate blog post.
I run a custom /de-ai-ify slash command that strips these patterns and rewrites in my actual voice. The command knows my preferences: direct statements over hedged ones, short sentences for key points, technical vocabulary without dumbing down, concrete examples from real experience.
Before:
It’s worth noting that this approach offers a relatively robust solution for managing your configuration files, though it may require some initial setup effort.
After:
This handles config files well. Setup takes about 20 minutes.
The ideas stay the same. The delivery changes completely.
5. Proofread and polish
Final read-through for flow, accuracy, and anything that still sounds off. I check that links work, code blocks render correctly, and the frontmatter is right.
6. Build and deploy
./scripts/deploy.sh
One command. Hugo compiles the markdown into static HTML, rsync pushes only the changed files to the server. About 10 seconds start to finish.
Setting this up yourself
What you need to replicate this pipeline with Claude Code.
Prerequisites
- Claude Code installed and working
- A Hugo site (or any static site generator - the pipeline works the same regardless)
- An Obsidian vault (optional - Claude Code works with any directory of markdown files)
Hugo and the build/deploy pipeline
Hugo is a static site generator. You write markdown files, Hugo turns them into a folder of HTML/CSS that any web server can host. No databases, no server-side runtime, no WordPress - just files.
The project structure:
your-site/
βββ config/config.toml β Site settings (title, URL, theme)
βββ content/ β Your posts (markdown files)
β βββ _index.md β Homepage content
β βββ my-post.md β Each post is one .md file
βββ themes/minimal-blog/ β Theme (HTML templates + CSS)
βββ scripts/
β βββ build.sh β Runs Hugo to generate HTML
β βββ deploy.sh β Build + push to server
β βββ deploy.env β Server connection details
βββ CLAUDE.md β Claude Code project instructions
Each post is a markdown file with YAML frontmatter at the top:
---
title: "My Post Title"
subtitle: "Optional subtitle"
date: 2026-02-06
summary: "One-liner that appears on the homepage list."
---
Post content goes here. Standard markdown.
Hugo reads every file in content/, applies your theme’s templates, and outputs a folder of static HTML. The build takes under a second for a site with 20+ posts.
Build script (scripts/build.sh):
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")"
rm -rf dist/public
hugo --source . \
--config config/config.toml \
--destination dist/public \
--themesDir themes \
--minify
Deploy script (scripts/deploy.sh) - builds then pushes to your server via rsync:
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")"
source scripts/deploy.env
./scripts/build.sh
rsync -avz --delete \
--compress-level=9 \
--chmod=D755,F644 \
dist/public/ \
"$VPS_HOST:$VPS_DEST/"
Server config (scripts/deploy.env):
VPS_HOST="your-server" # SSH alias or user@hostname
VPS_DEST="/var/www/your-site" # Where the files go on the server
Hugo compiles markdown to HTML. Rsync diffs the output against what’s on the server and uploads only what changed. The web server (Caddy, Nginx, whatever) serves the static files. You can preview locally with hugo server -D before deploying.
Project CLAUDE.md
Your site’s CLAUDE.md tells Claude Code how your blog works. Put it at the root of the Hugo project:
# Blog Project - Claude Instructions
## Writing Style
- No emojis unless specifically appropriate
- Evidence-based, show your reasoning
- Concise - say it once, well
## Content Workflow
1. Draft in conversation with Claude
2. Claude writes full draft
3. Run /de-ai-ify for voice restoration
4. Proofread and deploy
## Deploy
./scripts/deploy.sh
Adapt the writing style section to your preferences. Claude reads this automatically when you start a session in the project directory.
The /de-ai-ify command
The most important piece. Create ~/.claude/commands/de-ai-ify.md:
---
name: de-ai-ify
aliases: [humanize, voice-check]
description: Remove AI writing patterns and restore the user's authentic voice
---
# De-AI-ify - Voice Restoration
You are a voice editor. Transform AI-generated text into the user's
authentic writing voice.
## AI patterns to remove
**Lexical clichΓ©s:**
- "delve", "dive deep", "unpack", "leverage", "robust"
- "it's worth noting that", "importantly", "essentially"
- "in today's world", "in this modern age"
- Unnecessary hedging ("arguably", "somewhat", "relatively")
**Structural patterns:**
- Generic introduction ("In a world where...")
- Numbered listicles without narrative thread
- Repetitive transitions ("Moreover,", "Furthermore,", "Additionally,")
- Conclusion that restates introduction
## Voice profile
Load the user's voice from their existing writing. Look for:
- Sentence structure (short declarative vs longer analytical)
- Technical vocabulary they use naturally
- Hedging patterns (when do they hedge vs state directly?)
- How they use examples (concrete/personal vs generic)
Check these locations for voice training data:
- Blog posts in the current project
- Notes in Obsidian vault (if accessible)
- Any writing samples the user provides
## Process
1. Identify AI patterns in the text
2. Load voice profile from existing writing
3. Rewrite: preserve ideas, replace AI delivery with user's voice
4. Present original vs rewritten with a summary of changes
This is a simplified version of what I use. The key insight: train it on your writing, not just tell it to remove AI patterns. Point it at your existing blog posts or notes so it learns your actual voice.
Voice training
The command tells Claude to read your existing writing. The more samples it has, the better it works. If you’re starting from scratch with no published writing, give it:
- Emails or messages you’ve written (your natural voice)
- Notes or documentation you’ve authored
- Even social media posts - anywhere you write as yourself
Example session
What writing a post looks like end to end. This is condensed - real sessions have more back-and-forth.
$ claude
> I want to write a guide about setting up restic backups with
> Backblaze B2. Here are my rough notes:
>
> - restic is great because snapshots, dedup, encryption
> - B2 is cheapest cloud storage
> - need to init repo first, then set up systemd timer
> - gotcha: B2 app keys need specific bucket permissions
> - I spent 2 hours debugging because I used a master key
> instead of a bucket-scoped key
Claude reads your CLAUDE.md and any context files, then responds
with questions and suggestions:
A few things to clarify before I draft:
1. Do you want the human/Claude Code split format?
2. Should I check your existing guides for related content?
3. The app key gotcha is a good hook - want to lead with that?
> Yes to all three. Lead with the debugging story, then explain
> the setup. Check if I've covered restic or B2 anywhere else.
Claude searches your vault, finds no conflicts, and drafts the post:
Here's the draft. I led with your B2 key debugging experience,
then walked through init, config, systemd timer, and verification.
The Claude Code section below covers automated setup.
[full draft in your Hugo frontmatter format]
> Looks good but the systemd section is too long. Shorten it
> and just link to the Arch wiki for timer syntax.
Claude revises the draft.
> /de-ai-ify
Claude loads your existing posts, identifies AI patterns in the
draft, and rewrites in your voice:
Key changes:
- Removed: "robust backup solution", "it's worth noting",
"comprehensive guide"
- Shortened: 3 hedged sentences to direct statements
- Restructured: moved the "why restic over duplicity"
paragraph - was burying the lead
[rewritten draft]
> Ship it.
Claude writes the file to content/restic-backups.md and runs
./scripts/deploy.sh.
The whole process takes about 15 minutes for a typical guide. Most of that is me thinking about what to include, not writing.
Why this works
The pipeline separates thinking from writing from editing. Claude handles the parts where volume and recall matter (drafting, cross-referencing, formatting). I handle the parts where judgment matters (what to write about, whether the technical advice is correct, whether it sounds like me).
The /de-ai-ify step is what makes it sustainable. Without it, I’d either spend hours manually rewriting AI output or publish content that sounds generic. With it, I get the speed of AI drafting and the voice of writing it myself.