Install
openclaw skills install talosTalos — God of Automation. Plan and batch your entire social media content calendar — generate a 4-week posting schedule, write platform-optimised captions for Twitter/X, LinkedIn, Instagram, and Threads, apply best-posting-time rules, and export a ready-to-use content calendar.
openclaw skills install talosGenerate a complete 4-week social media content calendar with platform-optimised captions, best posting times, and content pillar rotation — all offline, no API keys required.
Runs entirely locally. No API calls, no data transmitted. Pure offline generation.
pip3 install rich --break-system-packages --quiet
import os, json, re, random
from datetime import date, timedelta
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich import box
console = Console()
TOPIC = os.environ.get("BRAND_TOPIC", "productivity tips")
PLATS_RAW = os.environ.get("PLATFORMS", "twitter, linkedin, instagram")
try:
PPW = int(os.environ.get("POSTS_PER_WEEK", "3"))
except ValueError:
PPW = 3
PILLARS_R = os.environ.get("CONTENT_PILLARS", "education, inspiration, engagement, promotion")
TONE = os.environ.get("BRAND_TONE", "educational")
TODAY = date.today()
PLATFORMS = [p.strip().lower() for p in PLATS_RAW.split(",") if p.strip()]
PILLARS = [p.strip() for p in PILLARS_R.split(",") if p.strip()]
# Guard: clamp PPW to 1-5
PPW = max(1, min(PPW, 5))
# Guard: empty PLATFORMS or PILLARS
if not PLATFORMS:
console.print("[red]⚠️ PLATFORMS is empty — defaulting to 'twitter, linkedin, instagram'[/red]")
PLATFORMS = ["twitter", "linkedin", "instagram"]
if not PILLARS:
console.print("[red]⚠️ CONTENT_PILLARS is empty — defaulting to standard pillars[/red]")
PILLARS = ["education", "inspiration", "engagement", "promotion"]
topic_short = TOPIC.split()[0] if TOPIC else "topic"
console.print(Panel.fit(
f"[bold cyan]📱 ⚡ Talos — Social Media Command[/bold cyan]\n"
f"Topic: [yellow]{TOPIC}[/yellow]\n"
f"Platforms: [green]{', '.join(PLATFORMS)}[/green] | "
f"Posts/week: [green]{PPW}[/green] | Tone: [green]{TONE}[/green]",
border_style="cyan"
))
# ── Best posting times ────────────────────────────────────────────────────────
BEST_TIMES = {
"twitter": [("Mon", "9am"), ("Tue", "9am"), ("Wed", "12pm"), ("Thu", "9am"), ("Fri", "10am")],
"linkedin": [("Tue", "8am"), ("Wed", "10am"), ("Thu", "9am"), ("Mon", "8am"), ("Fri", "9am")],
"instagram": [("Mon", "6am"), ("Wed", "11am"), ("Fri", "10am"), ("Sat", "9am"), ("Tue", "2pm")],
"threads": [("Mon", "9am"), ("Wed", "12pm"), ("Fri", "11am"), ("Tue", "9am"), ("Thu", "2pm")],
}
# ── Caption templates per tone ────────────────────────────────────────────────
TONE_HOOKS = {
"educational": [
"Here's what most people get wrong about {topic}:",
"The {topic} rule nobody talks about:",
"{number} things I wish I knew about {topic}:",
],
"professional": [
"A key insight about {topic} for professionals:",
"What high-performers know about {topic}:",
"The {topic} principle that drives results:",
],
"casual": [
"Real talk about {topic} —",
"Hot take: {topic} is more interesting than you think.",
"Nobody told me {topic} could be this simple.",
],
"inspirational": [
"Your {topic} journey starts with one step.",
"The {topic} mindset that changes everything:",
"What if {topic} was easier than you thought?",
],
}
hooks = TONE_HOOKS.get(TONE, TONE_HOOKS["educational"])
# ── Content type formats ──────────────────────────────────────────────────────
CONTENT_FORMATS = {
"education": ["how-to", "tips-list", "explainer", "myth-busting", "framework"],
"inspiration": ["quote", "success-story", "milestone", "mindset", "reminder"],
"engagement": ["question", "poll", "fill-in-blank", "hot-take", "challenge"],
"promotion": ["feature-spotlight", "testimonial", "case-study", "offer", "behind-scenes"],
"tips": ["quick-tip", "pro-tip", "mistake-to-avoid", "checklist", "framework"],
"portfolio": ["case-study", "before-after", "process", "result", "client-story"],
"tools": ["tool-review", "comparison", "workflow", "integration", "recommendation"],
"product": ["feature", "how-to-use", "benefit", "testimonial", "demo"],
"behind-the-scenes": ["process", "day-in-life", "team", "workspace", "fail"],
}
def get_format(pillar: str) -> str:
for key in CONTENT_FORMATS:
if key.lower() in pillar.lower():
return random.choice(CONTENT_FORMATS[key])
return random.choice(["tip", "story", "question", "fact"])
# ── Offline topic angle generator ─────────────────────────────────────────────
def get_topic_ideas(topic: str) -> list:
return [
f"beginner guide to {topic}",
f"common mistakes in {topic}",
f"how to improve your {topic}",
f"{topic} for professionals",
f"advanced {topic} strategies",
f"{topic} tools and resources",
f"the future of {topic}",
f"{topic} myths debunked",
]
console.print("[dim]Generating topic angles…[/dim]")
topic_ideas = get_topic_ideas(TOPIC)
# ── Platform caption generators ───────────────────────────────────────────────
def gen_twitter(pillar: str, content_form: str, week: int) -> str:
hook = random.choice(hooks).replace("{topic}", topic_short).replace("{number}", str(random.choice([3, 5, 7])))
bodies = [
f"{hook}\n\n→ [insight 1]\n→ [insight 2]\n→ [insight 3]\n\nRT if useful 👇",
f"[Hot take about {topic_short}]\n\nHere's why: [reason]\n\nAgree? 🧵",
f"Stop doing X. Start doing Y.\n\nFor {topic_short}, this means: [specific advice]",
f"The {content_form} that changed how I think about {topic_short}:\n\n[insight]\n\nThread 🧵",
]
body = random.choice(bodies)
hashtags = f"#{topic_short.replace(' ', '').title()} #ContentTips"
result = f"{body}\n\n{hashtags}"
if len(result) > 280:
result = result[:277].rsplit(' ', 1)[0] + "…"
return result
def gen_linkedin(pillar: str, content_form: str, week: int) -> str:
return (
f"The {topic_short} insight that changed everything for me:\n\n"
f"[Hook — one surprising or bold statement]\n\n"
f"Here's what I learned:\n\n"
f"1/ [First point]\n\n"
f"2/ [Second point]\n\n"
f"3/ [Third point]\n\n"
f"The bottom line: [key takeaway]\n\n"
f"What's your experience with {topic_short}? Drop it in the comments 👇\n\n"
f"#{topic_short.replace(' ', '').title()} #ProfessionalGrowth #{pillar.replace(' ', '').title()}"
)
def gen_instagram(pillar: str, content_form: str, week: int) -> str:
hook = random.choice(hooks).replace("{topic}", topic_short).replace("{number}", str(random.choice([3, 5, 7])))
emojis = ["✨", "🔥", "💡", "🎯", "🚀", "💪", "🙌"]
e = random.choice(emojis)
return (
f"{e} {hook.upper()}\n\n"
f"[Main value — 2-3 sentences about {topic_short}]\n\n"
f"Save this post if you found it helpful! ♻️\n\n"
f"👉 Follow for daily {topic_short} tips\n\n"
f"— — — — — — —\n"
f"#{topic_short.replace(' ', '')} #{pillar.replace(' ', '')} #ContentCreator "
f"#InstagramTips #GrowthMindset #OnlineBusiness"
)
def gen_threads(pillar: str, content_form: str, week: int) -> str:
hook = random.choice(hooks).replace("{topic}", topic_short).replace("{number}", str(random.choice([3, 5, 7])))
return (
f"{hook}\n\n"
f"[Your honest take on {topic_short}]\n\n"
f"What do you think? 👇"
)
PLATFORM_GENS = {
"twitter": gen_twitter,
"linkedin": gen_linkedin,
"instagram": gen_instagram,
"threads": gen_threads,
}
# ── Build 4-week calendar ─────────────────────────────────────────────────────
calendar = []
for week in range(1, 5):
for platform in PLATFORMS:
gen_fn = PLATFORM_GENS.get(platform, gen_twitter)
times = BEST_TIMES.get(platform, BEST_TIMES["twitter"])
for day_idx in range(min(PPW, 5)):
pillar = PILLARS[day_idx % len(PILLARS)]
content_form = get_format(pillar)
day_name, best_time = times[day_idx % len(times)]
post_date = TODAY + timedelta(weeks=week - 1, days=day_idx)
caption = gen_fn(pillar, content_form, week)
calendar.append({
"week": week,
"platform": platform,
"date": post_date.strftime("%b %d"),
"day": day_name,
"best_time": best_time,
"pillar": pillar,
"format": content_form,
"caption": caption,
})
# ── Display: Calendar overview ────────────────────────────────────────────────
console.print()
cal_table = Table(
title=f"📅 4-Week Social Calendar — {len(calendar)} posts",
box=box.ROUNDED, border_style="cyan"
)
cal_table.add_column("Wk", style="dim", width=4)
cal_table.add_column("Date", style="cyan", width=8)
cal_table.add_column("Platform", style="yellow", width=12)
cal_table.add_column("Day", style="green", width=5)
cal_table.add_column("Time", style="green", width=6)
cal_table.add_column("Pillar", style="magenta",width=14)
cal_table.add_column("Format", style="white", width=18)
for entry in calendar:
cal_table.add_row(
str(entry["week"]),
entry["date"],
entry["platform"].title(),
entry["day"],
entry["best_time"],
entry["pillar"].title(),
entry["format"],
)
console.print(cal_table)
# ── Display: Sample captions ──────────────────────────────────────────────────
console.print()
for platform in PLATFORMS[:2]:
sample = next((p for p in calendar if p["platform"] == platform), None)
if sample:
console.print(Panel(
sample["caption"],
title=f"[bold]📝 Sample Caption — {platform.title()}[/bold]",
border_style="yellow"
))
# ── Display: Hashtag strategy ─────────────────────────────────────────────────
HASHTAG_GUIDE = {
"twitter": "1-2 hashtags max. Use trending + niche specific. Never in the middle of text.",
"linkedin": "3-5 hashtags at the end. Mix: 1 broad + 2 niche + 1 trending.",
"instagram": "10-15 hashtags. Mix sizes: 3 mega (1M+) + 5 medium (100k-1M) + 7 niche (<100k).",
"threads": "No hashtags currently. Focus on conversation starters.",
}
console.print()
hg_lines = "\n".join([
f"[cyan]{p.title()}:[/cyan] {guide}"
for p, guide in HASHTAG_GUIDE.items() if p in PLATFORMS
])
console.print(Panel(hg_lines, title="[bold]# Hashtag Strategy[/bold]", border_style="blue"))
# ── Display: Topic angles ─────────────────────────────────────────────────────
if topic_ideas:
console.print()
ti_lines = "\n".join([f"[dim]{i + 1}.[/dim] {idea}" for i, idea in enumerate(topic_ideas)])
console.print(Panel(ti_lines, title="[bold]💡 Content Angle Ideas[/bold]", border_style="magenta"))
# ── Save outputs ──────────────────────────────────────────────────────────────
topic_slug = re.sub(r"[^a-z0-9]", "_", TOPIC[:20].lower())
json_path = f"social_calendar_{topic_slug}_{TODAY}.json"
md_path = f"social_calendar_{topic_slug}_{TODAY}.md"
with open(json_path, "w", encoding="utf-8") as f:
json.dump({"topic": TOPIC, "platforms": PLATFORMS, "calendar": calendar,
"generated": str(TODAY)}, f, indent=2)
with open(md_path, "w", encoding="utf-8") as f:
f.write(f"# Social Media Calendar — {TOPIC}\n\n")
f.write(f"**Platforms:** {', '.join(p.title() for p in PLATFORMS)} ")
f.write(f"**Posts/week:** {PPW} **Generated:** {TODAY}\n\n")
f.write("## Content Angles\n\n")
for idea in topic_ideas:
f.write(f"- {idea}\n")
f.write("\n## Calendar\n\n")
f.write("| Wk | Date | Platform | Day | Time | Pillar | Format |\n")
f.write("|----|------|----------|-----|------|--------|--------|\n")
for e in calendar:
f.write(f"| {e['week']} | {e['date']} | {e['platform'].title()} | {e['day']} | {e['best_time']} | {e['pillar'].title()} | {e['format']} |\n")
f.write("\n## Sample Captions\n\n")
shown = set()
for e in calendar:
if e["platform"] not in shown:
shown.add(e["platform"])
f.write(f"### {e['platform'].title()}\n\n```\n{e['caption']}\n```\n\n")
console.print()
console.print(Panel(
f"[green]✅ Done![/green]\n\n"
f"📄 [cyan]{json_path}[/cyan] — full calendar data\n"
f"📝 [cyan]{md_path}[/cyan] — markdown calendar\n\n"
f"[dim]Import either file into Buffer, Hootsuite, Later, or any scheduling tool.[/dim]",
title="[bold]📤 Exports[/bold]",
border_style="green"
))