Sunday, April 5

Most content teams spend 60–70% of their writing time not creating original ideas, but reformatting the same ideas for different channels. A blog post becomes a LinkedIn carousel, then a Twitter thread, then an email, then a newsletter blurb. It’s the same information — just reshaped. That’s exactly the kind of structured, repeatable transformation that content repurposing AI automation handles well, and Claude is particularly good at it because it can hold detailed formatting instructions while also understanding tone shifts between channels.

This article shows you how to build a Claude-powered pipeline that takes a single source piece — a blog post, transcript, or research doc — and outputs 8–10 channel-specific formats automatically. I’ll cover the architecture, the actual prompts, working Python code, and the parts that break in production.

Why Most Content Repurposing Attempts Fail

Before the code: the reason most teams try LLM repurposing and abandon it is that they treat it as a single prompt problem. They paste an article into ChatGPT, ask for “a Twitter thread and an email,” get mediocre output, and give up. The output is mediocre because each channel has genuinely different constraints — and a single catch-all prompt can’t hold all of them without degrading.

A LinkedIn post has a specific rhythm: strong hook, short paragraphs, no links in the post body, a soft CTA at the end. A cold email needs a subject line that gets opened, not a headline that reads well on a feed. A newsletter blurb needs to create curiosity without giving everything away. These aren’t just stylistic preferences — they’re structural requirements that affect performance metrics you actually care about.

The fix is one agent per channel format, each with its own system prompt tuned to that channel’s real-world requirements. The source content goes in once; the outputs fan out in parallel.

The Architecture: One Source, Many Outputs

Here’s the structure I use in production:

Source Content
     │
     ▼
 Extractor Agent  ←── Pulls key points, quotes, stats, CTA
     │
     ▼
 ┌───┴────────────────────────────────────────┐
 │                                            │
 ▼           ▼           ▼           ▼        ▼
Blog     LinkedIn     Twitter     Email   Newsletter
Rewrite  Post         Thread      Copy    Blurb
 │           │           │           │        │
 ▼           ▼           ▼           ▼        ▼
YouTube  Instagram   Facebook    SMS     Podcast
Script   Caption     Ad Copy     Alert   Intro

The extractor agent is the critical first step that most people skip. It reads the source and produces a structured JSON object — key arguments, supporting data points, quotable sentences, the primary CTA, and the intended audience. Every downstream agent works from this structured extract, not from the raw source. This makes the outputs more consistent and dramatically reduces hallucinated claims.

The Extractor Prompt

import anthropic
import json

client = anthropic.Anthropic()

EXTRACTOR_SYSTEM = """You are a content strategist who extracts structured information 
from long-form content. Your output is always valid JSON — no markdown, no commentary.

Extract:
- title: The main topic or title
- core_argument: 1-2 sentence summary of the main point
- key_points: List of 3-7 supporting points (each under 20 words)
- statistics: Any specific numbers, percentages, or data points
- quotes: Verbatim quotable sentences (keep them exact)
- primary_cta: What should the reader do after consuming this content?
- target_audience: Who is this written for?
- tone: Professional / Casual / Technical / Conversational"""

def extract_content_structure(source_text: str) -> dict:
    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        system=EXTRACTOR_SYSTEM,
        messages=[
            {"role": "user", "content": f"Extract the structure from this content:\n\n{source_text}"}
        ]
    )
    
    # Strip any accidental markdown code fences
    raw = response.content[0].text.strip()
    if raw.startswith("```"):
        raw = raw.split("```")[1]
        if raw.startswith("json"):
            raw = raw[4:]
    
    return json.loads(raw)

Channel-Specific Agents: The Prompts That Actually Work

Each channel agent receives the structured extract and has a system prompt built around that channel’s real constraints. Here are the ones I use in production, with the reasoning behind each decision.

LinkedIn Post Agent

LINKEDIN_SYSTEM = """You write high-performing LinkedIn posts. Rules:
- Hook: First line must be curiosity-inducing, under 12 words, no question marks
- No links in the post body (kills organic reach)
- Use line breaks aggressively — max 2 sentences per paragraph  
- Include 1 personal insight or counterintuitive observation
- End with a soft engagement prompt (not "comment below" — be specific)
- 3-5 relevant hashtags at the very end
- Total length: 150-300 words"""

def generate_linkedin_post(extract: dict) -> str:
    prompt = f"""Write a LinkedIn post based on this content structure:
    
Core argument: {extract['core_argument']}
Key points: {json.dumps(extract['key_points'])}
Target audience: {extract['target_audience']}
Tone: {extract['tone']}

Do not copy text verbatim. Reframe for a professional social audience."""

    response = client.messages.create(
        model="claude-haiku-4-5",  # Haiku is fast enough and ~10x cheaper here
        max_tokens=512,
        system=LINKEDIN_SYSTEM,
        messages=[{"role": "user", "content": prompt}]
    )
    return response.content[0].text

Notice I’m using claude-haiku-4-5 for the formatting agents and claude-opus-4-5 only for the extractor. The extraction step requires nuanced judgment about what’s actually important. The formatting steps are constrained enough that Haiku handles them well — and at roughly $0.25 per million input tokens vs Opus’s $15, that matters at scale. Running 10 format agents on Haiku costs around $0.003 per full repurposing run.

Email Copy Agent

EMAIL_SYSTEM = """You write marketing emails that get opened and clicked. Rules:
- Subject line: Under 50 characters, no clickbait, no ALL CAPS
- Preview text: 80-100 characters, different from subject line, builds curiosity
- Opening: Address a specific pain point in line 1
- Body: 100-150 words maximum — respect inbox time
- One CTA only, specific and action-oriented
- PS line: Add a P.S. that reinforces the CTA from a different angle
- Output format: Subject: / Preview: / Body: / CTA: / PS: — clearly labeled"""

def generate_email(extract: dict) -> str:
    prompt = f"""Write a marketing email from this content:

Core argument: {extract['core_argument']}  
CTA: {extract['primary_cta']}
Key stats to use: {json.dumps(extract.get('statistics', []))}
Audience: {extract['target_audience']}"""

    response = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=512,
        system=EMAIL_SYSTEM,
        messages=[{"role": "user", "content": prompt}]
    )
    return response.content[0].text

Running All Agents in Parallel

Running agents sequentially on 10 formats would be slow. Use concurrent.futures to fan them out in parallel — in practice this gets 10 outputs in roughly the same time as 2 sequential calls.

from concurrent.futures import ThreadPoolExecutor, as_completed

def repurpose_content(source_text: str) -> dict:
    # Step 1: Extract structure (Opus, worth the cost)
    extract = extract_content_structure(source_text)
    
    # Step 2: Define all format jobs
    format_jobs = {
        "linkedin": generate_linkedin_post,
        "email": generate_email,
        "twitter_thread": generate_twitter_thread,
        "newsletter_blurb": generate_newsletter_blurb,
        "youtube_script_intro": generate_youtube_intro,
        "instagram_caption": generate_instagram_caption,
        "facebook_ad": generate_facebook_ad,
        "podcast_intro": generate_podcast_intro,
    }
    
    results = {"extract": extract}
    
    # Step 3: Run all format agents in parallel
    with ThreadPoolExecutor(max_workers=8) as executor:
        future_to_format = {
            executor.submit(fn, extract): name 
            for name, fn in format_jobs.items()
        }
        
        for future in as_completed(future_to_format):
            format_name = future_to_format[future]
            try:
                results[format_name] = future.result()
            except Exception as e:
                results[format_name] = f"ERROR: {str(e)}"
    
    return results

# Usage
if __name__ == "__main__":
    with open("source_article.txt") as f:
        source = f.read()
    
    outputs = repurpose_content(source)
    
    for format_name, content in outputs.items():
        if format_name != "extract":
            print(f"\n{'='*50}")
            print(f"FORMAT: {format_name.upper()}")
            print('='*50)
            print(content)

Wiring This Into n8n or Make

If you’d rather build this without Python infrastructure, both n8n and Make can wire this up as a visual workflow. The pattern is the same: an HTTP trigger receives the source content, the first Claude node runs the extractor, then parallel branches each call Claude with their channel-specific system prompt.

In n8n, use a Split In Batches node after the extractor to fan out to multiple Claude HTTP Request nodes simultaneously. Set each node’s system prompt as a static value and pass the extracted JSON as the user message. The outputs merge back into a single JSON response node.

One thing that trips people up in n8n: Claude’s API returns content inside content[0].text — you need to map that path explicitly in your expression, not just {{ $json.body }}. The Make equivalent is the same issue — parse the response body before using it downstream.

What Breaks in Production (And How to Handle It)

The JSON parsing on the extractor fails roughly 3–5% of the time — usually when the source content is very short or contains unusual formatting. Add a retry with a cleaner prompt, or fall back to asking Claude to “fix this JSON” rather than re-running the full extraction.

Rate limits hit you when you run 8 parallel Haiku calls. At the free tier this is a real problem; at Tier 1 you’ll hit 50 requests/minute which is plenty. If you’re at scale, add exponential backoff with tenacity.

The outputs are good but rarely publish-ready — budget for a 10–15 minute human review pass. Think of this as drafts at production speed, not fully automated publishing. I’ve seen teams try to skip the review step and end up with LinkedIn posts that reference statistics from a completely different industry because the source article cited them as counterexamples. The extractor usually catches this, but not always.

Long source documents (over ~15,000 tokens) occasionally cause the extractor to miss key points from the second half. If you’re processing transcripts or long research docs, chunk the source into sections first, run the extractor on each chunk, then merge the extracts before hitting the format agents.

When to Use This (And When Not To)

This setup pays off quickly if you’re publishing more than 4–5 pieces per month across multiple channels. The setup time is around 3–4 hours if you’re using the Python approach, or 5–6 hours for a proper n8n/Make workflow with error handling.

Solo founders and small teams: Start with 3 format agents — LinkedIn, email, and newsletter blurb. Those three cover most of the high-ROI distribution surface without overwhelming a one-person review process.

Content teams at scale: Add quality gates. Run a second Claude pass that scores each output against channel-specific rubrics before it hits your review queue. This reduces the review burden significantly and catches the worst outputs before a human sees them.

When not to use it: Thought leadership content where the author’s voice is the entire value proposition. Claude will produce competent output, but it won’t capture the specific idiosyncrasies that make a particular person’s LinkedIn presence valuable. Use it for evergreen, informational content — not for building a personal brand.

Content repurposing AI automation isn’t a magic wand — it’s a structured delegation system. The 80% time reduction is real, but only if you invest in channel-specific prompts, treat the extractor as a first-class component, and keep humans in the loop for final review. Build it that way and it becomes one of the highest-ROI automations in your stack.

Editorial note: API pricing, model capabilities, and tool features change frequently — always verify current details on the vendor’s website before building in production. Code examples are tested at time of writing; pin your dependency versions to avoid breaking changes. Some links in this article may be affiliate links — we may earn a commission if you sign up, at no extra cost to you.

Share.
Leave A Reply