Introduction
Clean input, a Voice Profile ready to go — today you build the actual generators. Six of them, one at a time, each tested against a real input before you move to the next: blog post, Twitter/X thread, LinkedIn post, newsletter section, YouTube script outline, and email.
Objective
The shared shape every generator uses
def generate_twitter_thread(source_text: str, voice_profile: str) -> str:
prompt = f"""{voice_profile}
Using the writing style shown in the examples above, write a 6-8 tweet Twitter/X
thread based on this source material:
{source_text}
Constraints:
- Each tweet under 280 characters
- First tweet must hook attention without needing the thread's context
- Number each tweet (1/, 2/, etc.)
- End with a summary or call-to-action tweet
"""
return call_claude(prompt, model="claude-haiku-4-5-20251001", temperature=0.7)
Three things every generator in this lesson will reuse: the Voice Profile goes FIRST in the prompt (models weight earlier context differently, and you want voice established before the model starts drafting, not bolted on after), the platform constraints are an explicit bulleted list (not folded into prose, which models follow less reliably), and the model/temperature are chosen per format -- a fast, cheaper model at higher temperature for something short and casual like a tweet thread, versus what you'll use for the longer blog-post generator below.
Constraints that actually get enforced vs. constraints that don't
"Under 280 characters" is a suggestion, not a guarantee
LLMs are unreliable at precise character counting -- ask for "under 280 characters" and you'll occasionally get 295. For a real pipeline, add a post-generation check: split the output into tweets, measure each one, and either truncate or re-prompt for any that violate the limit. Don't discover this in Lesson 5 when you're staring at a broken thread in Notion -- build the length check into the generator itself, today.
Model choice: not every generator needs the same model
Speed and cost matter differently per format
A tweet thread and an email are short, disposable-feeling, and generated in bulk -- a fast, cheap model (this course uses claude-haiku-4-5-20251001) is the right call. A blog post is the piece someone might actually publish and needs the strongest reasoning about structure and argument -- worth spending more on a stronger model for that one generator specifically. Using the same model for all 6 either overspends on the throwaway formats or underserves the one piece that matters most; Lesson 4's orchestrator will run all 6 in parallel regardless, so model choice per generator is pure quality/cost tuning, not an architecture decision.
You test your LinkedIn generator and it produces content that's on-topic, correctly formatted, and completely generic-sounding -- despite the Voice Profile being included in the prompt exactly like the working Twitter generator. What's the first thing to check?
When 5 of 6 generators share one pattern and one doesn't, the most likely explanation is a copy-paste gap, not a fundamental format limitation -- check that voice_profile is actually an argument to this specific function and actually appears in its prompt string, not left out when this generator was written last (a very common mistake when building 6 near-identical functions in sequence).
What you're building
generators.py: all 6 generator functions (blog, Twitter thread, LinkedIn, newsletter, YouTube script, email), each including the Voice Profile as a few-shot fixture, each with explicit platform constraints, tested one at a time against a real preprocessed input from Lesson 2 before moving to the next.