HomeSpecialized Use CasesContent Generation Pipeline
intermediate12 min read· Module 13, Lesson 3

✏️Content Generation Pipeline

Automate blog posts, social media, emails, and marketing content at scale

Content Generation Pipeline

Building a reliable content generation pipeline means more than calling an API once and hoping for the best. A production-grade system breaks the creative process into discrete, repeatable stages — each with its own prompt, quality gate, and feedback loop. This lesson walks through every layer of that architecture, from blog posts and social media to email campaigns and batch operations.


1. Pipeline Architecture Overview

A content pipeline is a directed graph of stages. Each stage receives structured input, applies a specialised prompt, and produces structured output that feeds the next stage.

Output
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ BRIEF │ ──▶ │ OUTLINE │ ──▶ │ DRAFT │ ──▶ │ EDIT │ └────────────┘ └────────────┘ └────────────┘ └────────────┘ ┌────────────┐ │ SEO / QA │ └────────────┘ ┌────────────┐ │ PUBLISH │ └────────────┘

Key principles:

  • Single responsibility — each stage does one thing well.
  • Structured I/O — every stage reads and writes JSON, never free-form text between stages.
  • Idempotency — re-running a stage with the same input produces a consistent result.
  • Traceability — every output carries the prompt version and model parameters that produced it.
TypeScript
interface PipelineStage<TIn, TOut> { name: string; promptTemplate: string; run(input: TIn): Promise<TOut>; validate(output: TOut): boolean; } interface ContentBrief { topic: string; audience: string; tone: string; keywords: string[]; wordCountTarget: number; platform: "blog" | "social" | "email"; }

2. Blog Post Generation — Outline to Published Article

Stage 1: Outline Generation

The outline stage transforms a brief into a hierarchical structure with headings, sub-points, and estimated word counts per section.

TypeScript
const outlinePrompt = ` You are a content strategist. Given the brief below, produce a JSON outline. Each section must include: heading, subPoints (array), estimatedWords (number). Brief: {{brief}} Rules: - Include an introduction and conclusion. - Target total word count: {{wordCount}}. - Optimise heading hierarchy for the keywords: {{keywords}}. `;

Stage 2: Draft Generation

Feed the outline to a drafting prompt. This prompt receives the full outline plus the brand voice guidelines and produces the raw article.

TypeScript
const draftPrompt = ` You are a professional writer. Expand the outline below into a full article. Follow the brand voice: {{brandVoice}}. Use the keywords naturally: {{keywords}}. Write exactly one section per outline entry. Do not skip sections. Outline: {{outline}} `;

Stage 3: Editing Pass

A separate editing prompt reviews the draft for clarity, grammar, redundancy, and adherence to the brand voice. This prompt never sees the original brief — it judges the draft on its own merits.

TypeScript
const editPrompt = ` You are a senior editor. Review the draft below. Fix grammar, remove redundancy, improve transitions. Return the edited article plus a JSON array of changes you made with reasons. Draft: {{draft}} `;

Stage 4: SEO Optimisation

The SEO stage adds meta descriptions, checks keyword density, suggests internal links, and generates alt text for images.

TypeScript
interface SEOResult { metaTitle: string; metaDescription: string; keywordDensity: Record<string, number>; suggestedInternalLinks: string[]; readabilityScore: number; finalArticle: string; }

3. Social Media Content — Platform-Specific Formatting

Each social platform has unique constraints. A pipeline stage maps a single core message to multiple platform-specific outputs.

TypeScript
interface SocialPost { platform: "twitter" | "linkedin" | "instagram" | "facebook"; text: string; hashtags: string[]; characterCount: number; mediaPrompt?: string; // description for image generation } const socialPrompt = ` You are a social media manager. Given the core message below, create one post for each platform. Respect character limits: - Twitter/X: 280 characters - LinkedIn: 3000 characters (professional tone) - Instagram: 2200 characters (casual, emoji-friendly, hashtag-rich) - Facebook: 500 characters (conversational) Core message: {{message}} Brand voice: {{brandVoice}} Hashtag pool: {{hashtags}} Return a JSON array of SocialPost objects. `;

Platform-specific tips encoded in the prompt:

  • Twitter/X — lead with a hook, use threads for longer content, limit to 3 hashtags.
  • LinkedIn — open with a bold statement or statistic, use line breaks, end with a question.
  • Instagram — front-load the caption before the fold, use 20-30 hashtags in a comment.
  • Facebook — keep it conversational, ask for engagement, use 1-2 hashtags at most.

4. Email Campaign Generation

Email pipelines add personalisation and A/B testing as first-class concepts.

Personalisation with Variables

TypeScript
interface EmailTemplate { subject: string; preheader: string; bodyHtml: string; variables: string[]; // e.g. ["firstName", "companyName", "lastPurchase"] } const emailPrompt = ` You are an email marketing expert. Write an email for the campaign below. Use the variables in double curly braces: {{variables}}. Campaign goal: {{goal}} Audience segment: {{segment}} Tone: {{tone}} Return JSON with: subject, preheader, bodyHtml. Include at least 2 personalisation variables in the body. `;

A/B Testing Variants

Generate multiple subject lines and opening paragraphs to test:

TypeScript
const abTestPrompt = ` Generate 4 subject-line variants for the email below. Vary along these axes: - Variant A: curiosity-driven - Variant B: benefit-driven - Variant C: urgency-driven - Variant D: personalisation-driven Email body: {{emailBody}} Return JSON array of { variant: string, subjectLine: string, openingLine: string }. `;

5. Content Templates with Variables

Templates are reusable prompt skeletons with typed placeholders.

TypeScript
interface ContentTemplate { id: string; name: string; description: string; promptTemplate: string; variables: TemplateVariable[]; outputSchema: Record<string, unknown>; } interface TemplateVariable { name: string; type: "string" | "number" | "enum" | "array"; required: boolean; default?: unknown; enumValues?: string[]; description: string; } // Example template registry const templates: ContentTemplate[] = [ { id: "product-description", name: "Product Description", description: "Generate product copy for e-commerce listings", promptTemplate: "Write a {{tone}} product description for {{productName}}...", variables: [ { name: "productName", type: "string", required: true, description: "Product name" }, { name: "tone", type: "enum", required: true, enumValues: ["professional", "casual", "luxury"], description: "Writing tone" }, { name: "features", type: "array", required: true, description: "Key features list" }, ], outputSchema: { title: "string", shortDesc: "string", longDesc: "string", bulletPoints: "string[]" }, }, ];

6. Tone and Brand Voice Control

Brand voice is not a single adjective — it is a multi-dimensional profile.

TypeScript
interface BrandVoice { name: string; personality: string[]; // e.g. ["confident", "approachable", "witty"] vocabulary: { preferred: string[]; // words to use avoided: string[]; // words to never use }; sentenceStyle: string; // e.g. "Short and punchy. Fragments allowed." formality: "casual" | "neutral" | "formal"; exampleParagraph: string; // gold-standard sample for few-shot } const brandVoicePrompt = ` You must write in the following brand voice: Personality: {{personality}} Preferred words: {{preferred}} Avoided words: {{avoided}} Sentence style: {{sentenceStyle}} Formality: {{formality}} Example of the desired voice: "{{exampleParagraph}}" Now write the following content matching this voice exactly: {{contentRequest}} `;

A post-generation validation step checks that none of the avoided words appear and that the tone matches the personality descriptors.


7. Batch Content Generation

When you need 50 social posts or 20 email variants, batch processing keeps costs predictable and throughput high.

TypeScript
interface BatchJob { id: string; template: ContentTemplate; inputs: Record<string, unknown>[]; concurrency: number; status: "pending" | "running" | "completed" | "failed"; results: BatchResult[]; } async function runBatch(job: BatchJob): Promise<BatchResult[]> { const results: BatchResult[] = []; const queue = [...job.inputs]; // Process in parallel with concurrency limit const workers = Array.from({ length: job.concurrency }, async () => { while (queue.length > 0) { const input = queue.shift()!; try { const output = await generateContent(job.template, input); const qualityScore = await reviewContent(output); results.push({ input, output, qualityScore, status: "success" }); } catch (error) { results.push({ input, output: null, qualityScore: 0, status: "error", error }); } } }); await Promise.all(workers); return results; }

Batch best practices:

  • Set concurrency to 3-5 to avoid rate limits.
  • Log every request/response pair for audit.
  • Implement exponential back-off on failures.
  • Store intermediate results so a partial failure does not lose completed work.

8. Quality Control with Review Prompts

Every piece of generated content should pass through an automated review before it reaches a human approver.

TypeScript
const reviewPrompt = ` You are a content quality reviewer. Score the content below on a 1-10 scale for each criterion. Return JSON. Criteria: - accuracy: Are all facts correct and verifiable? - relevance: Does it address the target audience's needs? - tone: Does it match the brand voice description? - grammar: Is it free of grammatical errors? - engagement: Would the target audience find this compelling? - seo: Are the keywords used naturally and sufficiently? Content: {{content}} Brand voice description: {{brandVoice}} Target audience: {{audience}} `; interface QualityScore { accuracy: number; relevance: number; tone: number; grammar: number; engagement: number; seo: number; overall: number; suggestions: string[]; approved: boolean; // true if overall >= 7 }

If the overall score falls below the threshold, the content re-enters the editing stage with the reviewer's suggestions appended to the prompt. This creates a self-correcting feedback loop.


9. Scheduling and Publishing Workflow

The final pipeline stage handles timing, approvals, and distribution.

TypeScript
interface PublishSchedule { contentId: string; platform: string; scheduledAt: Date; status: "draft" | "review" | "approved" | "scheduled" | "published"; approvedBy?: string; publishedUrl?: string; } interface ContentCalendar { weekStart: Date; entries: PublishSchedule[]; generateWeekPlan(topics: string[], platforms: string[]): Promise<PublishSchedule[]>; } // Automated scheduling based on platform best-practice posting times const optimalPostTimes: Record<string, string[]> = { twitter: ["09:00", "12:00", "17:00"], linkedin: ["08:00", "10:30", "17:30"], instagram: ["11:00", "14:00", "19:00"], facebook: ["09:00", "13:00", "16:00"], };

10. Practical Example — Generate a Week of Social Posts

Let us put everything together. This example generates seven days of social media content across three platforms.

TypeScript
async function generateWeekOfPosts( topics: string[], brandVoice: BrandVoice, platforms: string[] ): Promise<PublishSchedule[]> { const calendar: PublishSchedule[] = []; for (let day = 0; day < 7; day++) { const topic = topics[day % topics.length]; // Step 1: Generate core message for the day const coreMessage = await generateContent(coreMessageTemplate, { topic, brandVoice: brandVoice.name, dayOfWeek: getDayName(day), }); // Step 2: Adapt to each platform for (const platform of platforms) { const post = await generateContent(socialTemplate, { message: coreMessage, platform, brandVoice, hashtags: getHashtagPool(topic), }); // Step 3: Quality review const review = await reviewContent(post); if (!review.approved) { const revised = await reviseContent(post, review.suggestions); calendar.push(createScheduleEntry(revised, platform, day)); } else { calendar.push(createScheduleEntry(post, platform, day)); } } } return calendar; } // Usage const weekPlan = await generateWeekOfPosts( ["AI productivity tips", "Customer success stories", "Product updates", "Industry trends", "Behind the scenes", "User tips", "Weekend inspiration"], myBrandVoice, ["twitter", "linkedin", "instagram"] ); console.log("Generated", weekPlan.length, "posts for the week"); // Output: Generated 21 posts for the week

Key Takeaways

  1. Break content creation into stages — outline, draft, edit, SEO, publish.
  2. Use structured I/O between stages — JSON objects, not loose text.
  3. Encode brand voice as a multi-dimensional profile, not a single adjective.
  4. Automate quality control — review prompts catch issues before humans see them.
  5. Batch intelligently — respect rate limits, log everything, handle partial failures.
  6. Platform-specific formatting is not optional — each channel has its own rules.
  7. A/B test systematically — generate variants along defined axes.
  8. Schedule with data — use optimal posting times per platform.
  9. Build feedback loops — low-scoring content goes back through editing automatically.
  10. Keep templates versioned — prompt changes affect output quality; track them.