“Just write me a blog post” produces generic content — so I built a skill pipeline instead
Writing a blog post is harder than it sounds. I have a topic but no direction. I have a direction but no personal story. I have a personal story but I can’t find where I left it.
Telling AI “write a post on this topic” gives you generic content. The kind anyone could find with a search. Nothing that really needs your name on it.
So I built a skill pipeline. You give it a direction, AI pulls your story from your own wiki and drafts it, you review it, and it ships in both Korean and English. This post went through that exact pipeline.
/blog-series — Planning the Next Post
For a series post, this is where you start. /blog-series scans all published posts, builds a series status table (series-map.md), and shows which arc slots are still open.
Series follow a four-act structure.
- intro — Why did you start? The context and spark.
- build-N — How did you build it? The work and the wrong turns.
- use-N — How does it actually get used?
- wrap — What did you gain? What would you do differently?
This post is the use-1 slot in the slowloop-lab series. Before writing it, I ran /blog-series slowloop to check where things stood, locked in the next arc slot, then moved to /blog-draft.
For a standalone post, skip this step — go straight to /blog-draft.
/blog-draft — From a Single Sentence to a Full Draft
The old workflow had two steps: create a seed first, then expand it into a draft. In practice, that extra stop was just friction.
Now it’s just /blog-draft. Give it a description, get a draft.
/blog-draft write the slowloop lab blog build post ← series post
/blog-draft summarize the claude-code 4-lever method ← standalone
Internally, it does two things in sequence.
Read the raw source directly. The core rule: read the original raw files, not the wiki summaries. Wiki pages are already distilled — the raw expressions, the moment things clicked or went wrong, the specific numbers — those live in the raw/ originals. Skip that and AI fills the gaps convincingly. Convincingly invented is the problem. Every file it reads gets logged in the frontmatter’s raw_sources: field.
Write the draft. With material from raw in hand, it locks in a direction and writes the body. Anywhere the source doesn’t support a claim — anywhere the author’s direct experience would make it stronger — it leaves a ⚠️[what's needed here] inline marker instead of making something up. The author fills those in Obsidian before publishing. This connects to the same principle behind how natural language becomes logic — a skill is just behavior defined in plain language.
The draft saves to export/slowloop/content-drafts/ with status: draft and stops there. Publishing waits for the author’s review.
/blog-publish — Publishing
Once the draft is reviewed, it’s time to publish. Not just moving a file — there’s a 7-step gate.
① Metadata validation — Checks title, content_type, format, and date format. Stops if a fix: field is still present.
② Raw cross-check — Any ⚠️ marker left in the body means publish is blocked. Nothing ships with unfilled markers.
③ Link generation — Scans the full published corpus for slugs that share topic, tags, or key concepts. Fills in the references field and adds inline links where they fit naturally in the body.
④ Link validation — Every [[...]] wikilink in the body and every slug in references is checked against the actual published files. Dead links trigger a warning before proceeding.
⑤ Body extraction — Pulls only the content under ## 📝 본문 (draft). Meta sections, ⚠️ markers, and review notes are stripped out.
⑥ Save the published file — Written to export/slowloop/blog/<series>/<slug>.md.
⑦ English translation — The Korean post is translated and published simultaneously to blog_en/. No literal translation — rewritten in natural English while keeping the author’s voice.
Seven steps sounds like a lot. When nothing triggers, it takes thirty seconds. When something does trigger, there’s a real problem worth catching.
/blog-lint, /blog-archive — Maintenance
As posts accumulate, metadata drifts. A content_type that slipped into a multi-value format. A references slug pointing to something that got archived. Korean and English versions that no longer match. /blog-lint catches these periodically.
To hide a published post, /blog-archive adds status: archived to the frontmatter — the post returns a 404 on the site but the file stays on disk. Git means nothing is ever really gone.
Here’s the whole pipeline in one sentence.
Give it a direction, AI pulls your story from raw, you review it, and KO + EN ship together.
Less like writing a post. More like releasing one.