Skip to content

Case study

AI Social-Content Pipeline

A pipeline that drafts a brand's daily post and publishes it across every channel once a human approves.

Year
since 2025
Status
live
Role
Architect & Implementer
Stack
Python, n8n, OpenAI, Gemini, Notion API, Meta Graph API

The business problem

Keeping a brand's social presence alive is a daily grind, and it falls on whoever runs the business. Find a usable image and judge whether it is even good enough to post. Write the caption, devise a title, hashtags and emojis. Then post it by hand on each platform separately.

Skip a few days and the account stalls. Do it properly and it eats the time that was not there in the first place.

The solution

A scheduler starts one post a day. A text model writes the draft, a second model checks it against written brand rules, and an image model produces the visual. The draft then waits in an approval queue in Notion, and only after a human signs off does a separate process publish it to Instagram, Facebook and Google Business Profile.

At a glance: a daily scheduler feeds an AI draft-and-critic step; a human approves; the post auto-publishes to every platform.
At a glance

Before → after

Daily post
Beforeimage, caption, hashtags, posting: all by hand
Afterauto-drafted; a human only approves

3 platforms

Instagram · Facebook · GBP

since 2025

in production

The outcome

Running daily in production since 2025. The real value is that the daily production burden is gone: sourcing an image, writing the caption, devising title and hashtags, posting across every platform. The account publishes consistently without anyone finding time to make each post by hand.

Over the same window the account grew from ~350 to ~1,200 followers. That is a correlational signal across the period the pipeline ran, not a controlled result, and not the headline claim.

The engineering behind itExpand · ~3 min

The architecture

A pipeline orchestrated by n8n on a self-hosted server, with the publishing workflows code-generated from Python so they are versioned and reproducible from source rather than hand-wired in a UI.

The daily pipeline: a feed-rotation scheduler starts a copywriter LLM fed by a deduplicated lesson memory, a critic LLM enforces brand rules with a one-shot revision loop, an image model produces the visual, the draft lands in a Notion approval queue for a human to sign off, and only then does an auto-poster publish to Instagram, Facebook and Google Business Profile.
The daily pipeline: a feed-rotation scheduler starts a copywriter LLM fed by a deduplicated lesson memory, a critic LLM enforces brand rules with a one-shot revision loop, an image model produces the visual, the draft lands in a Notion approval queue for a human to sign off, and only then does an auto-poster publish to Instagram, Facebook and Google Business Profile.

A daily run rotates the post type, so the same type never runs two days straight, and picks a publish time from a date-seeded jitter. Re-running a day reproduces the identical schedule instead of a random one.

A copywriter LLM drafts the caption. A separate critic LLM judges it against explicit brand rules and, where it objects, sends exactly one revision back. An image model produces the visual where the post type calls for it; some types use a human photo brief instead.

The finished draft lands in a Notion approval queue. A human approves there or via a Telegram bot. Only then does a separate auto-poster, polling the queue every ten minutes, publish to Instagram (feed and reels), Facebook and Google Business Profile.

A critic is a different role, not the same question asked twice. And the generator never holds the keys to publish.

Lesson memory that compounds. Every critic correction is normalized, hashed to a stable id, deduplicated and counted. The five most recent go into the copywriter's prompt on the next run. The system stops repeating the same mistakes without any retraining: the prompt carries the institutional memory. One entry says never to open with a particular cliché phrase, flagged four times.

Approval state machine: a draft goes under critic review; on objections it revises once and returns; once the critic approves it becomes ready; a human then publishes it or drops it.
Approval state machine: a draft goes under critic review; on objections it revises once and returns; once the critic approves it becomes ready; a human then publishes it or drops it.

Decisions & trade-offs

The generator never holds the publish button. Everything lands in the approval queue as a draft, and a separate auto-poster publishes only what a human approved. It is the cheapest insurance a brand-facing LLM system can buy. It costs one daily human touchpoint, and that touchpoint is what keeps it honest.

Code-generate the workflows from Python. The publishing graphs are built by Python from source, not clicked together in the n8n UI, so they are diffable and reproducible. The trade-off is a build step between you and the running workflow. The worst bug lived exactly there.

Deterministic scheduling. Post times come from a date-seeded jitter, so re-running a day is idempotent and debuggable while the feed still looks human-timed, and nothing double-fires from a re-run.

What broke

Duplicate posts went live, in public. The workflow generator reused identical node names for two steps, and because n8n keys its connections by node name, the generated graph accumulated duplicate edges. The same post published twice to Instagram and four times to Facebook and Google Business Profile before anyone caught it.

The fix was structural: unique node names, a build-time validation pass with explicit structural checks, a dry-run workflow variant, and a real test suite. That turned "looks right in the UI" into "fails the build if the graph is malformed".

Hardening the prompt crashed the model. After tightening the copywriter's system prompt with a ban-list and hard rules, the first run crashed with a length error. Handed a long, rule-laden prompt plus a strict JSON-schema constraint, the model spun trying to satisfy every rule and hit its ~16K output ceiling without ever closing the JSON. Capping the output tokens only moved the cliff. The real fix was condensing the prompt itself.

More rules made the output less reliable, not more. Past a point, prompt weight is a cost rather than a safeguard.

Getting images to the platforms was its own saga. The social APIs could not fetch the temporary upload URLs, so every image has to be pre-staged in dedicated public storage before posting.

Same problem in your own operation?

What I do for companies

Hiring for an applied-AI or solutions-architecture role?

The full track record