social-posts
Social Posts
You orchestrate social media publishing: take a topic from the user, write platform-optimized copy, generate AI visuals, and open each platform in Chrome so the user can review and post. You do 95% of the work -- the user just reviews, attaches images, and clicks publish.
The user always reviews before anything goes live. Never post silently.
Before Starting
-
Check for a product/brand context file. Look for a file named
product-marketing-context.mdin the project's.claude/directory (or ask the user where it is). This file contains brand voice, products, audience, content pillars, and guidance on weaving product mentions into posts. If it exists, read it -- every post should be informed by this context. If it doesn't exist, ask the user to briefly describe their brand/product/audience before proceeding. -
Check for a config file. Look for a
config.jsonin the skill directory or project. It tells you which Chrome profile to use (where social accounts are logged in), which platforms are active, default tone, and image preferences. -
Check for a platforms reference. Look for platform character limits, image specs, and posting best practices in a reference file.
-
Ensure image generation is available. This skill uses the
nanobananaskill (Gemini image generation) for AI images. Check thatGEMINI_API_KEYis set. If not, warn the user and proceed with copy-only output. -
Check published articles / reference material. If the brand context file has a list of published articles, check if any cover the current topic -- use them as source material for post angles.
-
Ask the user for anything not already provided:
- Topic: What is the post about?
- Context/angle: Specific news, data, or event? Reference material?
- Tone: Override default? (casual, professional, provocative, educational)
- Visual direction: Specific image style or existing assets?
- Platforms to skip: YouTube is always skipped unless explicitly requested.
Workflow
Phase 1: Think Strategically
Before writing a single word, consider:
- Hook formula: What's the opening line that stops the scroll? Use curiosity gaps ("I was wrong about..."), contrarian takes ("X is wrong, here's why"), story hooks ("3 years ago I..."), or value hooks ("How to X without Y"). The first line determines whether anyone reads the rest.
- Psychological angle: What makes this compelling? Social proof (numbers, testimonials), curiosity gap (incomplete information), loss aversion (what they'll miss), authority (expertise signal), or reciprocity (giving value first).
- Copy principles: Clarity over cleverness. Benefits over features. Specificity over vagueness. Customer language over company language. "Cut reporting from 4 hours to 15 minutes" beats "streamline your workflow."
- Content pillar: Does this fit an existing pattern -- educational, behind-the-scenes, personal story, industry insight, or promotional? Keep promotional under 5% of posts.
Product Integration
If a product/brand context file exists, the user's products should appear naturally -- not forced into every post, but present when genuinely relevant.
The test: Would a reader find the mention helpful, or would they roll their eyes? If helpful, include it. If eye-roll, skip it and just deliver value.
- ~60% of posts: mention a product as natural context (example, lesson, origin story)
- ~20% of posts: pure value, no product mention (builds trust and reach)
- ~15% of posts: directly about a product (releases, milestones, features)
- ~5% of posts: personal/humanizing, zero product angle
Phase 2: Write Platform-Optimized Copy
Write copy for each active platform. Each platform post is different -- same topic, different voice, format, and length. Adapt, don't copy-paste.
Key differences:
- LinkedIn: Professional depth (1,200-1,500 chars), links in comments not post body, 3-5 hashtags at end
- Twitter/X: Punchy compression (under 280 chars), or threads for longer value, 1-2 hashtags max
- Instagram: Visual-first captions (hook before "more" fold at ~125 chars), hashtags in first comment
- TikTok: Ultra-short captions (under 100 chars), pair with video script
- Facebook: Conversational, question-based discussion starters, under 250 words
- Threads: Casual, conversational, 500 char limit, 3-5 hashtags
Save each platform's copy to individual files in generated-assets/copy/:
generated-assets/copy/linkedin.txt
generated-assets/copy/twitter.txt # or twitter-thread.txt for threads
generated-assets/copy/instagram.txt
generated-assets/copy/tiktok.txt
generated-assets/copy/facebook.txt
generated-assets/copy/threads.txt
generated-assets/copy/first-comments.txt # links, hashtags for first comments
Also show all copy in the conversation so the user can review without opening files.
Phase 3: Generate AI Images
Use the nanobanana skill (or direct Gemini API calls) for image generation. Generate platform-specific images with correct aspect ratios.
Image generation via Gemini API (direct):
import json, base64, os, urllib.request
api_key = os.environ['GEMINI_API_KEY']
model = 'gemini-3-pro-image-preview'
url = f'https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent?key={api_key}'
payload = {
'contents': [{'parts': [{'text': 'PROMPT_HERE'}]}],
'generationConfig': {'responseModalities': ['TEXT', 'IMAGE']}
}
req = urllib.request.Request(url, data=json.dumps(payload).encode(),
headers={'Content-Type': 'application/json'}, method='POST')
with urllib.request.urlopen(req, timeout=120) as resp:
result = json.loads(resp.read())
for part in result['candidates'][0]['content']['parts']:
if 'inlineData' in part:
img_data = base64.b64decode(part['inlineData']['data'])
with open('output.png', 'wb') as f:
f.write(img_data)
Per-platform image specs:
| Platform | Ratio | Size | Style |
|---|---|---|---|
| 16:9 | 1200x627 | Professional, clean | |
| Twitter/X | 16:9 | 1200x675 | Bold, eye-catching |
| Instagram feed | 1:1 | 1080x1080 | Aesthetic, vibrant |
| Story/TikTok | 9:16 | 1080x1920 | Dynamic vertical |
| 16:9 | 1200x630 | Warm, community-oriented |
Carousel creation (Instagram/TikTok):
For multi-slide content, generate background images and composite text overlays using Pillow:
- Generate 4-5 photorealistic backgrounds via Gemini (1024x1024)
- Resize/crop to target dimensions (1080x1080 for IG, 1080x1920 for TikTok)
- Add dark gradient overlay at bottom for text readability
- Composite: accent color bar + slide number + title + body text
- Optimize as JPEG (quality=92, optimize=True) -- target under 500KB per slide
from PIL import Image, ImageDraw, ImageFont, ImageFilter
img = Image.open('background.png').convert('RGBA').resize((1080, 1080), Image.LANCZOS)
overlay = Image.new('RGBA', img.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(overlay)
# Dark gradient at bottom 45%
for y in range(594, 1080):
alpha = int(40 + 200 * ((y - 594) / 486))
draw.rectangle([(0, y), (1080, y+1)], fill=(0, 0, 0, min(alpha, 230)))
img = Image.alpha_composite(img, overlay)
# Add text with ImageFont
If GEMINI_API_KEY is not set, skip image generation -- tell the user to export GEMINI_API_KEY="your-key" and provide copy-only output.
IMPORTANT -- Always use full absolute paths and specify per-platform.
After generation, present a clear table with full absolute paths and which platform each image is for. Show images inline using the Read tool so the user can review without opening Finder.
Phase 4: Video Generation
For content that benefits from video (especially TikTok and Instagram Reels), use Veo 3.1 via the Gemini API for AI-generated cinematic video clips.
Option A: AI Video with Veo 3.1 (Recommended)
Model: veo-3.1-generate-preview
Endpoint: POST https://generativelanguage.googleapis.com/v1beta/models/veo-3.1-generate-preview:predictLongRunning
Auth: Same GEMINI_API_KEY used for image generation
Step 1: Generate video clips (one per slide)
import json, urllib.request
api_key = os.environ['GEMINI_API_KEY']
endpoint = 'https://generativelanguage.googleapis.com/v1beta/models/veo-3.1-generate-preview:predictLongRunning'
payload = {
"instances": [{"prompt": "Cinematic scene description here"}],
"parameters": {
"aspectRatio": "9:16", # 9:16 for TikTok/Reels, 16:9 for landscape
"resolution": "720p", # 720p or 1080p
"durationSeconds": 6 # 4, 6, or 8 seconds (MUST be number, not string)
}
}
req = urllib.request.Request(
f'{endpoint}?key={api_key}',
data=json.dumps(payload).encode(),
headers={'Content-Type': 'application/json'}, method='POST')
with urllib.request.urlopen(req, timeout=60) as resp:
result = json.loads(resp.read())
operation_name = result['name'] # e.g. "models/veo-3.1-generate-preview/operations/xxxxx"
Step 2: Poll for completion (2-5 minutes)
poll_url = f'https://generativelanguage.googleapis.com/v1beta/{operation_name}?key={api_key}'
# GET request, check result['done'] == True
# Video URI at: result['response']['generateVideoResponse']['generatedSamples'][0]['video']['uri']
Step 3: Download video
download_url = f"{video_uri}&key={api_key}" # Append API key to download URL
Step 4: Scale up + text overlays with ffmpeg
Veo outputs 720x1280. Upscale to 1080x1920 and add text using drawtext filter:
ffmpeg -y -i veo-clip.mp4 -vf "
scale=1080:1920:flags=lanczos,
drawbox=x=0:y=ih*0.55:w=iw:h=ih*0.45:color=black@0.55:t=fill,
drawbox=x=60:y=ih*0.60:w=4:h=80:color=0xD4A04A@0.9:t=fill,
drawtext=fontfile='/System/Library/Fonts/Avenir Next.ttc':text='01':fontcolor=white@0.9:fontsize=52:x=80:y=h*0.60+10,
drawtext=fontfile='/System/Library/Fonts/Avenir Next.ttc':text='Title Here':fontcolor=white:fontsize=46:x=60:y=h*0.72,
drawtext=fontfile='/System/Library/Fonts/Avenir Next.ttc':text='Body text here':fontcolor=white@0.8:fontsize=28:x=60:y=h*0.84
" -c:v libx264 -preset slow -crf 20 -pix_fmt yuv420p -c:a aac -b:a 128k -movflags +faststart output.mp4
Step 5: Concatenate with crossfade transitions
ffmpeg -y -i slide1.mp4 -i slide2.mp4 -i slide3.mp4 -i slide4.mp4 -i slide5.mp4 \
-filter_complex "
[0:v][1:v]xfade=transition=fade:duration=0.8:offset=5.2[v01];
[v01][2:v]xfade=transition=fade:duration=0.8:offset=10.4[v02];
[v02][3:v]xfade=transition=fade:duration=0.8:offset=15.6[v03];
[v03][4:v]xfade=transition=fade:duration=0.8:offset=20.8[vout];
[0:a][1:a]acrossfade=d=0.8[a01];
[a01][2:a]acrossfade=d=0.8[a02];
[a02][3:a]acrossfade=d=0.8[a03];
[a03][4:a]acrossfade=d=0.8[aout]
" -map "[vout]" -map "[aout]" \
-c:v libx264 -preset slow -crf 20 -pix_fmt yuv420p -c:a aac -b:a 128k \
-movflags +faststart final-video.mp4
Key Veo 3.1 details:
- Generates native audio (ambient soundscape) automatically
- Output: h264 + AAC, 24fps
- 720x1280 (9:16) or 1280x720 (16:9) native resolution
- Fire all 5 clip generations in parallel (async API), poll all at once
- Typical generation time: 2-5 minutes per clip
durationSecondsMUST be a number (not string) or you get 400 error- Download URLs require
&key=API_KEYappended
Prompt tips for cinematic results:
- Describe camera movement: "slow aerial drift", "dolly forward", "push-in", "camera drift backward"
- Include atmosphere: "moody storm clouds", "warm Edison lights", "volumetric lighting"
- Specify color grading: "teal and amber", "cold desaturated", "golden hour"
- Keep prompts specific and visual -- Veo excels at photorealistic scenes
Option B: Ken Burns Slideshow (Fallback)
If Veo is unavailable, create a Ken Burns zoom slideshow from still images using ffmpeg:
ffmpeg -loop 1 -t 5 -i slide.jpg -vf "zoompan=z='1+0.0006*on':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d=150:s=1080x1920:fps=30" output.mp4
This is simpler but produces static-feeling results compared to Veo.
Option C: UGC Script
Give the user a filming script:
- Hook (0-2s): pattern interrupt or bold claim
- Setup (2-5s): context
- Value (5-25s): the actual content
- CTA (25-30s): follow/engage/share
Phase 5: Review & Publish
This is the most important phase. The goal: user just reviews and clicks submit.
-
Present everything in a clear summary:
- All copy (shown in conversation + saved to files with full absolute paths)
- Generated image table (platform, full absolute path, dimensions)
- Video script or generated video path (if applicable)
-
Ask for approval: "Ready to open all platforms? I'll open Chrome with your profile."
-
Open platforms in Chrome. Use the configured Chrome profile (from config.json) where social accounts are logged in. Open each platform's compose page as a separate tab.
On macOS:
open -na "Google Chrome" --args --profile-directory="PROFILE_DIR" "COMPOSE_URL"Order: LinkedIn, Twitter/X, Facebook, TikTok, Instagram (via Meta Business Suite).
-
Per-platform posting guide -- for each tab, tell the user exactly:
- Copy from: full absolute path to the .txt file
- Attach image: full absolute path to the image file
- First comment: if applicable, what to paste after publishing
- The user pastes, attaches, reviews, and clicks publish. That's it.
Phase 6: Post-Publishing (Optional)
After the user confirms everything is posted:
- Log the post to
post-history/YYYY-MM-DD-topic.mdwith the content, platforms, and asset paths. - Suggest follow-up: Respond to comments within the first hour (this is when algorithms decide reach). Check analytics in 24-48 hours.
Platform Defaults
| Platform | Default | Notes |
|---|---|---|
| Active | Always | |
| Twitter/X | Active | Always |
| Active | Image/Reel focus | |
| TikTok | Active | Video focus |
| Active | Community focus | |
| Threads | Active | Casual text focus |
| YouTube | Skip | On-demand only |
Override per post by telling the skill which platforms to skip or include.
When Things Go Wrong
| Problem | What to do |
|---|---|
No GEMINI_API_KEY |
Deliver copy only, skip images/video, tell user how to set the key |
| Image generation fails | Suggest user creates images manually or tries alternative prompts |
| Veo generation fails or times out | Fall back to Ken Burns slideshow (Option B) or provide UGC script (Option C) |
| Veo returns 400 on durationSeconds | Ensure value is a number (6) not a string ("6") |
| Veo download returns 403 | Append &key=API_KEY to the download URI |
| Browser won't open | Print the platform URLs so user can open manually |
| A platform is down or needs re-auth | Skip it, note it, the user handles auth during review |
| No product context file | Ask the user for basic brand/audience info, or proceed with generic copy |
Related Skills
This skill orchestrates across the marketing ecosystem. When you need deeper strategy, invoke the relevant skill:
- social-media-posting -- full posting automation, engagement engine, deduplication, scheduling, 11 platforms
- social-content -- platform strategies, content pillars, hook formulas, engagement tactics
- copywriting -- landing page-quality copy principles (clarity, benefits, specificity)
- ad-creative -- headline formulas, value propositions, scaled creative production
- marketing-psychology -- cognitive biases, persuasion principles, behavioral triggers
- copy-editing -- polish, conciseness, tone consistency
- content-strategy -- pillar planning, calendar structure, audience mapping
- nanobanana -- AI image generation via Gemini (used directly by this skill)