How I Built a Content Pipeline That Publishes While I Sleep
The post was live on LinkedIn before I opened my laptop.
I had written a raw idea into Notion the night before, maybe 80 words, a half-formed thought about deal flow. By morning, n8n had picked it up, Claude had drafted it in something close to my voice, I had approved it from my phone, and two separate workflows had fired: one committed a markdown file to GitHub, Vercel deployed it to this site, the other called the LinkedIn API and published the post. I did not touch a keyboard. That felt worth writing about.
The Stack, Plainly Described
The whole thing runs on a Mac Mini at home. Not a cloud server. A Mac Mini, connected to my home network, exposed to the internet through Tailscale so n8n is reachable from anywhere without a static IP or a VPS bill. The Mac Mini stays on. My laptop does not need to be.
Notion is the single intake point. One database, one row per idea. I add a title, a few lines of context, a status field set to “Draft.” That is the trigger. n8n polls the database every 15 minutes looking for rows with that status.
n8n orchestrates everything. Two workflows. The first drafts. It pulls the Notion row, formats the context into a prompt, calls Claude via the Anthropic API, and writes the generated draft back into the Notion row as a text property. It then flips the status to “Review.” I read it, edit if needed, change the status to “Approved.”
The second workflow publishes. It detects “Approved,” pulls the final text, then does two things in parallel: commits a .md file to a GitHub repo (my Astro site lives there), and posts to LinkedIn via the API. Vercel watches the repo and deploys on every push. The post is live in under two minutes from approval.
What Actually Broke
Describing it in sequence makes it sound clean. It was not.
The LinkedIn token was the first wall. I generated an OAuth token through LinkedIn’s developer portal with w_member_social scope, which covers posting. What I did not realise until the workflow errored out: fetching your own member ID to attach to the post requires a separate r_liteprofile scope. Without the member ID you cannot make an authenticated post call. The fix was regenerating the token with both scopes. Twenty minutes of debugging for a permissions checkbox.
n8n snake-cases field names silently. Notion returns a field called “Published Date.” n8n surfaces it in the data object as published_date. Fine once you know it. Not documented prominently. I spent longer than I should like to admit wondering why my expression {{ $json["Published Date"] }} kept returning undefined.
Notion dates are objects, not strings. A date field in Notion comes back as { "start": "2026-06-21", "end": null }. If you pass that object directly into a filename or a markdown frontmatter field, you get [object Object] in your output. You have to parse it: {{ $json.date.start }}. Simple, but silent failures like this cost time.
None of these were catastrophic. All of them were invisible until they were not.
Automation Is Not About Saving Minutes
Here is the antithesis beat that most writing on automation misses.
Automation is not for speed. It is for removing yourself as the bottleneck.
If I had to manually publish every post, the system would run at my pace. Which means it would run when I had energy, when I remembered, when I was not in the middle of something else. Some weeks that is fine. Some weeks I am heads-down on Klixo Studio projects or at a Delhi Angels event doing 100-plus evaluations in a quarter. In those weeks, manual publishing dies.
The pipeline does not care about my week. It keeps moving. The bottleneck now is me adding ideas and approving drafts, which is the part that requires my actual judgement. Everything else is mechanics.
That is the right division of labour.
The Principle This Taught Me
Design your systems so that human input is required only where human judgement is irreplaceable.
I still write the seed idea. I still approve the draft. I still decide what gets published. Those are judgement calls. The formatting, the committing, the API calls, the deployment, the scheduling: none of that requires judgement. It requires consistency. Machines are better at consistency than I am.
The same principle applies to anything I build at Klixo Studio. When we wire up an n8n automation for a client, the question is never “how much can we automate?” The question is: “where does human judgement change the outcome, and where is it just friction?” Strip the friction. Keep the judgement.
If you are building a content habit and it keeps breaking down, ask yourself honestly: is the bottleneck your ideas, or is it the ten steps between idea and published post? Because those ten steps can be wired up in an afternoon.
Related reading: