How I built a fully automated blog writing pipeline with n8n
I have dozens of half-baked ideas sitting in my local Obsidian vault. They are mostly messy scribbles, terminal outputs, and random code snippets that I paste while trying to fix a bug at 2 AM. Turning these raw notes into a coherent draft takes more activation energy than I usually have after a long day of client work here in Kathmandu.
So I decided to automate the boring parts. I built an asynchronous pipeline using n8n and the Anthropic API that takes a rough markdown file from a specific folder, processes it, structures it, and dumps a formatted markdown draft straight into my website’s content directory.
Here is how the setup works, why I chose n8n, and the exact prompt logic I use to avoid making my blog sound like a generic corporate newsletter.
Why n8n instead of a custom script?
I initially started writing a Node.js script with fs-extra and the @google/generative-ai SDK to handle this. But managing state, retries, and file system triggers in a plain script gets messy quickly.
I run a self-hosted instance of n8n on a cheap Hetzner VPS. It has a native Local File Trigger node. This node watches a specific directory on my disk. The moment I save a file ending in .todo.md in that directory, the workflow kicks off. If the API rate limits me or the network drops, n8n handles the retries automatically. I do not have to write boilerplate error-handling code.
The workflow architecture
The pipeline consists of five main nodes:
- Local File Trigger: Monitors
/data/obsidian/draftsfor any new files matching*.todo.md. - Read Binary File: Loads the actual content of the markdown file into the n8n execution context.
- Extract Metadata: A simple JavaScript code node that splits the YAML frontmatter from the actual messy notes.
- Anthropic Chat Node: Passes the raw notes to Claude 3.5 Sonnet with a highly restrictive system prompt.
- Write Binary File: Saves the output as a clean
.mdfile directly into my Astro project’ssrc/content/blog/directory, then deletes the original.todo.mdfile to prevent infinite loops.
The prompt that prevents generic AI garbage
If you ask an LLM to “write a blog post,” you get a wall of text filled with words like delve, testament, foster, and landscape. It sounds incredibly fake. To combat this, my n8n OpenAI/Anthropic node uses a system prompt that actively bans these linguistic patterns.
Here is the exact instruction set I pass to the model:
You are an experienced systems developer. You are converting rough notes into a technical blog post.
Follow these strict rules:
- Write in a direct, first-person, casual tone.
- Do not use words like: delve, pivotal, testament, seamless, robust, leverage, or key takeaways.
- Avoid starting paragraphs with transitions like "First and foremost," "In conclusion," or "Furthermore."
- Keep code snippets exactly as they are in the source notes. Do not optimize them unless specifically asked.
- If the source notes contain a specific error message, keep that error message intact.
By restricting the vocabulary, the model has to write like a normal person. It cannot fall back on its default corporate-safe training data patterns.
Handling the file system sync
Since my n8n instance runs inside a Docker container, it cannot access my host machine’s files by default. I had to mount my local Obsidian vault directory and my website’s project folder as Docker volumes in my docker-compose.yml file:
volumes:
- /home/nayan/vaults/personal:/data/obsidian
- /home/nayan/projects/nayan135.xyz:/data/website
This gives n8n direct read and write access. When I save tailscale-routing.todo.md in Obsidian, n8n grabs it, runs the LLM chain, and outputs tailscale-routing.md into my website’s blog directory.
The human in the loop
I do not auto-publish these files. That would be a disaster. The workflow places the generated files into my local Git working directory as untracked files.
When I run git status, I see the new draft. I open it in VS Code, read through it, fix any weird assumptions the LLM made, and format the code blocks. Once I am happy with it, I run a git commit and push it to production.
This setup saves me about an hour of formatting and structuring per post. I do the rough thinking, n8n does the heavy lifting of organizing the raw output, and I do the final editorial pass.