How to Automate Content Calendar Planning with AI
Let AI analyze trends and plan your content calendar months in advance.
Jay Banlasan
The AI Systems Guy
Every month I used to spend three hours planning what content to produce. I'd look at keyword tools, check what competitors were publishing, think through what questions clients were asking, and try to build a coherent schedule. Now that same three hours produces a 90-day content calendar. The ai content calendar planning automation system I built pulls from keyword trends, competitor analysis, and your existing content library to generate a structured, prioritized calendar in about 20 minutes.
The bigger gain is strategic consistency. Manual planning produces content that reacts to what happened last month. AI-assisted planning looks 90 days out and builds topical clusters that compound in search authority over time.
What You Need Before Starting
- Python 3.10+
anthropicSDK- A list of your published posts (titles and URLs)
- Core topics and keywords for your business
- Optional: Google Search Console data export for existing performance data
Step 1: Define Your Content Strategy Parameters
The AI needs strategic context before it can plan. Without this, you get generic suggestions.
# content_strategy.py
CONTENT_STRATEGY = {
"brand": "Jay Banlasan / AI Systems Guy",
"audience": "Business owners and marketing managers running paid ads and AI workflows",
"primary_goal": "Generate leads for AI systems consulting engagements",
"content_pillars": [
{
"pillar": "AI Model Operations",
"description": "How to run AI APIs efficiently, reliably, and cost-effectively",
"target_intent": "informational, how-to",
"examples": ["rate limiting", "cost tracking", "failover", "caching"]
},
{
"pillar": "Paid Advertising Automation",
"description": "Using AI to automate Meta and Google Ads workflows",
"target_intent": "how-to, tutorial",
"examples": ["ad copy generation", "CPA tracking", "reporting automation"]
},
{
"pillar": "Business AI Systems",
"description": "Practical AI integrations for business operations",
"target_intent": "informational, case study",
"examples": ["lead enrichment", "CRM automation", "reporting"]
}
],
"publish_cadence": "2x per week",
"preferred_formats": ["tutorial", "case-study", "how-to"],
"avoid_formats": ["listicle", "opinion-only"],
"existing_content_gaps": [
"Advanced Meta Ads automation",
"AI cost optimization case studies",
"Content marketing with AI"
]
}
Step 2: Build the Trend Analysis Input
Feed in current trend signals for the AI to factor into planning.
import anthropic
import json
from datetime import date, timedelta
_client = anthropic.Anthropic()
def analyze_content_trends(pillar: str, period: str = "Q4 2024") -> list[str]:
"""
Ask AI to identify current trends in a content pillar area.
Returns a list of trending topics/questions.
"""
prompt = f"""You are a content strategist specializing in B2B tech content.
Identify the top 8-10 trending topics and questions that business owners and
marketing managers are currently searching for in this area:
Pillar: {pillar}
Period: {period}
Focus on:
- Questions they're actively searching for
- Problems they're trying to solve right now
- Emerging techniques or tools they want to learn
- Pain points that have grown in the past 6 months
Return a JSON list of strings: ["topic 1", "topic 2", ...]
Be specific. No generic topics."""
response = _client.messages.create(
model="claude-sonnet-4-5", max_tokens=500,
messages=[{"role": "user", "content": prompt}]
)
try:
return json.loads(response.content[0].text.strip())
except Exception:
return []
def build_topic_pool(strategy: dict) -> dict[str, list[str]]:
"""Build a pool of potential topics per pillar."""
pool = {}
for pillar_info in strategy["content_pillars"]:
pillar = pillar_info["pillar"]
trends = analyze_content_trends(pillar)
pool[pillar] = trends
print(f"Got {len(trends)} topics for: {pillar}")
return pool
Step 3: Build the Content Calendar Generator
Take the topic pool and strategy parameters, and generate a structured calendar.
def generate_content_calendar(
strategy: dict,
topic_pool: dict,
weeks: int = 12,
existing_posts: list[str] = []
) -> list[dict]:
existing_summary = "\n".join(existing_posts[:20]) if existing_posts else "None provided"
topics_formatted = json.dumps(topic_pool, indent=2)
prompt = f"""You are a content strategist. Create a {weeks}-week content calendar.
Brand: {strategy['brand']}
Audience: {strategy['audience']}
Business goal: {strategy['primary_goal']}
Cadence: {strategy['publish_cadence']}
Preferred formats: {', '.join(strategy['preferred_formats'])}
Available topics by pillar:
{topics_formatted}
Existing posts (avoid duplicating):
{existing_summary}
Strategy rules:
1. Alternate between pillars for topic diversity
2. Build topical clusters: group 2-3 related posts in consecutive weeks
3. Start with highest-traffic-potential topics first
4. Mix tutorial and case-study formats
5. Each post should link naturally to 1-2 others in the calendar
Return a JSON list of {weeks * 2} posts:
[{{
"week": 1,
"publish_date": "YYYY-MM-DD",
"title": "exact proposed title",
"pillar": "pillar name",
"format": "tutorial|case-study|how-to",
"target_keyword": "primary keyword phrase",
"hook": "first sentence idea",
"why_now": "why this topic is timely",
"links_to": ["title of related post in calendar"]
}}]
Start dates from: {(date.today() + timedelta(days=7)).isoformat()}"""
response = _client.messages.create(
model="claude-sonnet-4-5", max_tokens=3000,
messages=[{"role": "user", "content": prompt}]
)
try:
return json.loads(response.content[0].text.strip())
except json.JSONDecodeError:
# Try to extract JSON from response
text = response.content[0].text
start = text.find("[")
end = text.rfind("]") + 1
if start >= 0 and end > start:
return json.loads(text[start:end])
raise
Step 4: Score and Prioritize the Calendar
Not all topics are equally valuable. Score each post by potential impact.
def score_content_piece(piece: dict, strategy: dict) -> float:
"""Score 0-1 based on strategic value."""
score = 0.5 # baseline
# Bonus for matching content gaps
keyword = piece.get("target_keyword", "").lower()
for gap in strategy.get("existing_content_gaps", []):
if any(word in keyword for word in gap.lower().split()):
score += 0.15
break
# Bonus for linking to other calendar posts (compound value)
if piece.get("links_to"):
score += 0.1
# Penalty for duplicate-adjacent pillars in the same week
# (handled by generator prompt, this is a safety check)
return min(1.0, score)
def prioritize_calendar(calendar: list[dict], strategy: dict) -> list[dict]:
scored = [(piece, score_content_piece(piece, strategy)) for piece in calendar]
# Sort by week first, then by score within each week's batch
from itertools import groupby
result = []
for week, items in groupby(sorted(scored, key=lambda x: x[0]["week"]),
key=lambda x: x[0]["week"]):
week_items = sorted(items, key=lambda x: x[1], reverse=True)
for piece, score in week_items:
piece["priority_score"] = round(score, 2)
result.append(piece)
return result
Step 5: Export to a Usable Format
Generate a Markdown calendar document and a CSV for your project management tool.
import csv
def export_calendar_markdown(calendar: list[dict], output_path: str = "content_calendar.md"):
lines = [f"# Content Calendar\n\nGenerated: {date.today().isoformat()}\n"]
current_week = None
for item in calendar:
if item["week"] != current_week:
current_week = item["week"]
lines.append(f"\n## Week {current_week}")
lines.append(
f"\n**{item['publish_date']}** | {item['format'].title()}\n"
f"- Title: {item['title']}\n"
f"- Keyword: `{item['target_keyword']}`\n"
f"- Pillar: {item['pillar']}\n"
f"- Hook: {item['hook']}\n"
)
if item.get("links_to"):
links = ", ".join(item["links_to"])
lines.append(f"- Links to: {links}\n")
with open(output_path, "w") as f:
f.write("\n".join(lines))
print(f"Calendar saved to {output_path}")
def export_calendar_csv(calendar: list[dict], output_path: str = "content_calendar.csv"):
fields = ["week", "publish_date", "title", "pillar", "format",
"target_keyword", "hook", "why_now", "priority_score"]
with open(output_path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fields, extrasaction="ignore")
writer.writeheader()
writer.writerows(calendar)
print(f"CSV saved to {output_path}")
Step 6: Run the Full Pipeline
def generate_90_day_calendar():
print("Building topic pool from trends...")
topic_pool = build_topic_pool(CONTENT_STRATEGY)
print("\nGenerating 12-week calendar...")
calendar = generate_content_calendar(
strategy=CONTENT_STRATEGY,
topic_pool=topic_pool,
weeks=12,
existing_posts=[
"How to Build a Multi-Model AI Router",
"How to Implement AI Request Prioritization",
]
)
print(f"Generated {len(calendar)} content pieces")
prioritized = prioritize_calendar(calendar, CONTENT_STRATEGY)
export_calendar_markdown(prioritized)
export_calendar_csv(prioritized)
print("\nTop 5 Priority Posts:")
top5 = sorted(prioritized, key=lambda x: x["priority_score"], reverse=True)[:5]
for p in top5:
print(f" Week {p['week']}: {p['title']} (score: {p['priority_score']})")
if __name__ == "__main__":
generate_90_day_calendar()
What to Build Next
- Add a Google Search Console integration that pulls your top performing keywords and seeds them into the next calendar cycle
- Build a content brief template that auto-populates from the calendar item so writers can start immediately without briefing meetings
- Add a competitor content gap analysis that checks what your top 3 competitors published last month and identifies topics they're winning that you haven't covered
Related Reading
- How to Build an AI Blog Post Generator - execute the calendar with an AI writer for each post
- How to Build an AI Product Description Generator - extend the same content pipeline to product pages
- How to Create an AI FAQ Generator - fill FAQ sections from the same topic pool used for the calendar
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