How to Build a Content Repurposing Pipeline
Turn one piece of content into 10+ formats automatically across platforms.
Jay Banlasan
The AI Systems Guy
I published a tutorial on building AI request prioritization. It was 900 words of specific, useful, tested content. Then I did nothing else with it. Two weeks later I realized that tutorial contained a LinkedIn post, three Twitter threads, an email nurture sequence, and a YouTube script. All sitting unused because I had no content repurposing automation pipeline. Now when I publish anything, the repurposing runs automatically and I have a week's worth of derivative content queued up before I've finished my morning coffee.
Content repurposing is not copying and pasting. It's extracting the insight for each platform's native format and audience expectation. The LinkedIn post from a tutorial hits different than the tutorial itself. The pipeline handles that transformation, not just the distribution.
What You Need Before Starting
- Python 3.10+
anthropicSDK- Source content (blog post, podcast transcript, video transcript, case study)
- Knowledge of which platforms you publish to and their format requirements
- Optional: platform APIs for direct publishing
Step 1: Define Your Platform Output Formats
Each platform has its own rules. Define them explicitly so the AI knows what it's producing.
from dataclasses import dataclass
from typing import Optional
@dataclass
class PlatformFormat:
platform: str
format_name: str
max_chars: Optional[int]
structure: str
tone_notes: str
example_hook_style: str
cta: str
PLATFORM_FORMATS = {
"linkedin_post": PlatformFormat(
platform="LinkedIn",
format_name="LinkedIn Text Post",
max_chars=3000,
structure="Hook (2 lines) > Line break > Value paragraph > Line break > Takeaway list or story > CTA",
tone_notes="Professional but personal. First person. Share the insight, not just the link.",
example_hook_style="One counterintuitive claim or specific result on its own line",
cta="Follow for more or comment with a question"
),
"twitter_thread": PlatformFormat(
platform="Twitter/X",
format_name="Twitter Thread",
max_chars=280, # per tweet
structure="Tweet 1: Hook/claim. Tweets 2-7: one point each. Final tweet: summary + CTA",
tone_notes="Short sentences. No hedging. Each tweet standalone valuable.",
example_hook_style="'[Number] things I learned building [X]:'",
cta="Follow and RT if this helped"
),
"email_nurture": PlatformFormat(
platform="Email",
format_name="Email Newsletter",
max_chars=None,
structure="Subject line > Personal opener > Main insight (2-3 paragraphs) > Practical tip > CTA",
tone_notes="One-to-one tone. Like writing to a smart friend. No corporate language.",
example_hook_style="Short story or specific problem scenario",
cta="Reply or click to read the full tutorial"
),
"youtube_script": PlatformFormat(
platform="YouTube",
format_name="Short Tutorial Script",
max_chars=None,
structure="Hook (15s) > Problem setup (30s) > Solution steps (3-5 min) > Recap + CTA (30s)",
tone_notes="Spoken word. Contractions everywhere. Direct address. Pause cues.",
example_hook_style="'If you're doing X, you're leaving Y on the table'",
cta="Subscribe and comment with your question"
),
"instagram_carousel": PlatformFormat(
platform="Instagram",
format_name="Carousel Post",
max_chars=2200,
structure="Slide 1: Hook. Slides 2-7: one insight per slide. Slide 8: CTA slide",
tone_notes="Short sentences. Bold claims. Visual-first thinking. Each slide standalone.",
example_hook_style="Question or bold statement that creates curiosity",
cta="Save this for later. Follow for more."
),
"newsletter_snippet": PlatformFormat(
platform="Email",
format_name="Newsletter Quick Hit",
max_chars=400,
structure="Headline > 2-3 sentence summary > Link",
tone_notes="Tease the value without giving it all away. Make them click.",
example_hook_style="Lead with the most surprising result or counterintuitive point",
cta="Read the full tutorial"
),
}
Step 2: Build the Content Extractor
Before repurposing, extract the core insights so the AI understands what's valuable.
import anthropic
import json
_client = anthropic.Anthropic()
def extract_core_insights(source_content: str) -> dict:
prompt = f"""Analyze this content and extract what's most valuable for repurposing.
Content:
{source_content[:4000]}
Return JSON:
{{
"main_insight": "the single most valuable takeaway in one sentence",
"surprising_fact": "the most counterintuitive or unexpected point",
"practical_steps": ["step 1", "step 2", "step 3"],
"specific_results": ["any specific numbers, timeframes, or outcomes mentioned"],
"pain_point_addressed": "the reader problem this solves",
"quotable_lines": ["memorable phrasing from the original"],
"target_audience": "who this is for",
"hook_angles": [
"result-based hook idea",
"problem-based hook idea",
"counterintuitive hook idea"
]
}}"""
response = _client.messages.create(
model="claude-sonnet-4-5", max_tokens=800,
messages=[{"role": "user", "content": prompt}]
)
return json.loads(response.content[0].text.strip())
Step 3: Build the Format-Specific Generator
Each format gets its own generation prompt, informed by the extracted insights.
def generate_for_platform(
format_key: str,
insights: dict,
source_title: str,
source_url: str = "",
author_voice: str = "Direct, first-person, practical. No hedging. Grade 5-6 reading level."
) -> str:
fmt = PLATFORM_FORMATS.get(format_key)
if not fmt:
raise KeyError(f"Unknown format: {format_key}")
prompt = f"""Create {fmt.format_name} content for {fmt.platform}.
Source: "{source_title}"
{f"URL: {source_url}" if source_url else ""}
Core insights to draw from:
- Main insight: {insights['main_insight']}
- Surprising fact: {insights.get('surprising_fact', '')}
- Practical steps: {', '.join(insights.get('practical_steps', [])[:3])}
- Specific results: {', '.join(insights.get('specific_results', [])[:2])}
- Pain point: {insights['pain_point_addressed']}
Voice: {author_voice}
Format requirements:
Structure: {fmt.structure}
Tone: {fmt.tone_notes}
Max length: {f"{fmt.max_chars} characters" if fmt.max_chars else "No limit"}
Hook style: {fmt.example_hook_style}
CTA: {fmt.cta}
Rules:
- Do NOT just summarize the source — extract the insight and present it in the native format
- Use the hook angles from the insights above
- Make it valuable as standalone content, not just a pointer to the original
- First person where possible
- No em dashes
Write the full {fmt.format_name} now:"""
response = _client.messages.create(
model="claude-sonnet-4-5", max_tokens=1200,
messages=[{"role": "user", "content": prompt}]
)
return response.content[0].text.strip()
Step 4: Build the Full Repurposing Pipeline
One function takes a source post and generates all formats.
import time
from pathlib import Path
def repurpose_content(
source_content: str,
source_title: str,
source_url: str = "",
formats: list[str] = None,
output_dir: str = "repurposed"
) -> dict[str, str]:
if formats is None:
formats = list(PLATFORM_FORMATS.keys())
# Create output directory
Path(output_dir).mkdir(exist_ok=True)
print(f"Extracting insights from: {source_title}")
insights = extract_core_insights(source_content)
print(f"Insights extracted. Main: {insights['main_insight'][:80]}...")
results = {}
for fmt_key in formats:
print(f"Generating {fmt_key}...")
try:
content = generate_for_platform(
format_key=fmt_key,
insights=insights,
source_title=source_title,
source_url=source_url
)
results[fmt_key] = content
# Save each format
filename = f"{output_dir}/{source_title[:40].replace(' ','-').lower()}-{fmt_key}.md"
Path(filename).write_text(f"# {fmt_key}\nSource: {source_title}\n\n{content}")
time.sleep(0.5) # small delay between API calls
except Exception as e:
print(f"Failed {fmt_key}: {e}")
results[fmt_key] = None
successful = sum(1 for v in results.values() if v)
print(f"\nRepurposed into {successful}/{len(formats)} formats")
return results
Step 5: Build a Content Quality Checker
Check that each repurposed piece actually sounds human and matches the platform format.
def check_repurposed_quality(content: str, format_key: str) -> dict:
fmt = PLATFORM_FORMATS[format_key]
prompt = f"""Rate this {fmt.format_name} content on 3 criteria. Return JSON.
Content:
{content[:1500]}
Criteria:
1. Platform fit (0-1): Does it match {fmt.platform}'s native format and expectations?
2. Value density (0-1): Does it deliver insight, not just tease the source?
3. Voice quality (0-1): Does it sound human, direct, first-person? No AI fragments?
Return: {{"platform_fit": 0.0, "value_density": 0.0, "voice_quality": 0.0, "notes": "one line"}}"""
response = _client.messages.create(
model="claude-haiku-3", max_tokens=150,
messages=[{"role": "user", "content": prompt}]
)
try:
scores = json.loads(response.content[0].text.strip())
scores["overall"] = round(sum([scores.get("platform_fit",0),
scores.get("value_density",0),
scores.get("voice_quality",0)]) / 3, 2)
return scores
except Exception:
return {"overall": 0.5}
Step 6: Build a Scheduling Queue
When content is generated, queue it for publishing rather than dumping everything at once.
import sqlite3
from datetime import datetime, timedelta
def queue_for_publishing(results: dict[str, str], source_title: str):
conn = sqlite3.connect("content_queue.db")
conn.execute("""
CREATE TABLE IF NOT EXISTS content_queue (
id INTEGER PRIMARY KEY, source TEXT, platform TEXT,
format_key TEXT, content TEXT, status TEXT,
scheduled_at TEXT, created_at TEXT
)
""")
# Stagger publish dates — one per day
base_date = datetime.utcnow() + timedelta(days=1)
priority_order = ["linkedin_post", "email_nurture", "twitter_thread",
"newsletter_snippet", "instagram_carousel", "youtube_script"]
scheduled = 0
for i, fmt_key in enumerate(priority_order):
if fmt_key in results and results[fmt_key]:
publish_date = (base_date + timedelta(days=i*2)).isoformat()
platform = PLATFORM_FORMATS[fmt_key].platform
conn.execute("INSERT INTO content_queue VALUES (NULL,?,?,?,?,?,?,?)",
(source_title, platform, fmt_key, results[fmt_key],
"queued", publish_date, datetime.utcnow().isoformat()))
scheduled += 1
conn.commit()
conn.close()
print(f"Queued {scheduled} pieces for publishing")
What to Build Next
- Build a direct LinkedIn API publisher that takes from the queue and posts scheduled content automatically
- Add an image brief generator for each repurposed piece so you can create matching visuals without briefing someone separately
- Build a performance tracker that measures engagement per repurposed format so you know which transformations drive the best results
Related Reading
- How to Build an AI Blog Post Generator - generate the source content that feeds this repurposing pipeline
- How to Build an AI Product Description Generator - product pages can also feed repurposing pipelines for testimonials and feature highlights
- How to Create an AI FAQ Generator - FAQs from blog posts are one of the most valuable repurposing outputs for SEO
Want this system built for your business?
Get a free assessment. We will map every system your business needs and show you the ROI.
Get Your Free Assessment