PostNitro
Create on-brand social media carousels and single-image posts and schedule them to LinkedIn, Instagram, TikTok, and Threads from a single command. Turn a topic, article, or X threa…
Muneeb Awan
@iammuneeb
What This Skill Does
Creates on-brand social media carousels and single-image posts from a topic, article, or X thread, then schedules them to LinkedIn, Instagram, TikTok, and Threads via a single CLI command. Fully scriptable with JSON input/output for AI agent workflows.
Replaces manually designing and scheduling each social media post by automating the entire create-to-publish pipeline for carousels and images across multiple platforms.
When to Use It
- Turn a blog article or X thread into a multi-slide LinkedIn carousel
- Generate and schedule a branded single-image post for Instagram
- Import your own slide content and publish it as a TikTok carousel
- Create a series of carousel posts from a topic and draft them to Threads
- Repurpose existing content into a formatted social media post with brand assets
- Automate daily social media posting by chaining content creation and scheduling in one command
Install
$ openclaw skills install @iammuneeb/postnitroPostNitro — Create & Schedule Social Posts
PostNitro creates on-brand social media posts — multi-slide carousels and single images — and schedules them across LinkedIn, Instagram, TikTok, and Threads. This skill drives it from the command line, so an agent can take a topic, article, or your own content and produce a finished, scheduled post in one workflow. Every command is JSON in / JSON out — safe to script and chain.
Setup
- Install the CLI:
npm install -g @postnitro/cli - Sign up at https://postnitro.ai and subscribe to a plan — the Embed API requires a paid subscription (no free tier). Then generate an API key at account settings → Embed → Generate API Key.
- Authenticate (in order of precedence:
--api-keyflag → env var → saved config):postnitro auth set-key pn-xxxx # persists to ~/.postnitro-cli/config.json export POSTNITRO_API_KEY="pn-xxxx" # or use an env var - Save defaults so you don't repeat template/brand/preset IDs on every call (the CLI's alternative to per-call flags — no env vars needed):
postnitro defaults set --template-id <id> --brand-id <id> --preset-id <id> --response-type PDF
| Env var | Required | Purpose |
|---|---|---|
POSTNITRO_API_KEY | Yes* | API key (*unless passed via --api-key or saved with auth set-key) |
Key rule:
carousel generate/importreturn anembedPostId(the async job). To schedule the result you need itsdesignId(from the--waitoutput orcarousel output). Never pass anembedPostIdtoschedule.
Security:
auth set-keystores your API key in plaintext at~/.postnitro-cli/config.json. Restrict its file permissions and avoid shared or untrusted machines; runauth clearto remove it. This skill runs no background processes, cron jobs, or startup scripts — the only local state is the API key and saved defaults, both disclosed above.
When NOT to use: as a general social-media strategy advisor when no content is being produced. (PostNitro composes with other tools — e.g., create a carousel here, then schedule it elsewhere — so pairing it with another scheduler is fine.)
Core Workflow
Every create command is asynchronous — --wait handles the polling and returns the finished output (including designId and editorUrl) in one call.
1. Create a post
Two independent choices decide which command you run:
- Post type — a multi-slide
carouselor a singleimage. - Content source — let AI write it (
generate) or supply your own (import).
That's four commands:
generate (AI writes it) | import (you supply content) | |
|---|---|---|
carousel (multi-slide) | postnitro carousel generate | postnitro carousel import |
image (single) | postnitro image generate | postnitro image import |
All four take --template-id/--brand-id (from flags or saved defaults) plus the modifiers in step 2, and every result includes the designId (needed to schedule) and an editorUrl.
AI-generated (generate)
postnitro carousel generate \
--context "5 tips for growing your LinkedIn audience in 2026" \
--type text \
--instructions "Professional tone, actionable advice" \
--wait
# Single image instead — same flags, just the image subcommand
postnitro image generate --context "Announce our new scheduling feature" --wait
--type values:
text—--contextis the topic/text to turn into a postarticle—--contextis an article URL to extract and convertx—--contextis an X (Twitter) post/thread URL
generate also needs an AI preset (--preset-id, or a saved default).
Import your own content (import)
# Carousel — slides is an ARRAY of typed slides (inline --slides overrides --file)
postnitro carousel import --slides '{"slides":[
{"type":"starting_slide","heading":"Your Title","description":"Intro text"},
{"type":"body_slide","heading":"Key Point","description":"Details here"},
{"type":"ending_slide","heading":"Take Action!","cta_button":"Learn More"}
]}' --wait
postnitro carousel import --file ./slides.json --wait
# Single image — slide is a SINGLE OBJECT (not an array), via --slide
postnitro image import --slide '{"heading":"Welcome!","sub_heading":"Subtitle","cta_button":"Learn more"}' --wait
- Carousel (
--slides, array): exactly 1starting_slide(first), ≥1body_slide, exactly 1ending_slide(last);headingrequired on every slide. Runpostnitro carousel import-templatefor the schema. Ready-to-use: examples/import-default.json, examples/import-infographics.json. - Image (
--slide, one object): fieldsheading(required),sub_heading,description,cta_button,image,background_image(plus infographic — see step 2). Sending an array here is rejected. Runpostnitro image import-templatefor the schema.
2. Options for any create command
These layer onto any of the four commands above (and onto generate-and-schedule).
Output format — --response-type PDF | PNG | DESIGN
Default PDF (single file URL). PNG returns one URL per slide. DESIGN skips rendering — no file is produced; you get just the designId + editorUrl, the fastest option when you only need to schedule or edit.
AI image generation — --generate-images (any post type, any source)
Opt in to have AI generate images and bake them into the design before rendering. Works on all four create commands (and generate-and-schedule), for both carousels and images. Requires an --image-context brief:
postnitro carousel generate --context "How scheduling saves marketers time" \
--generate-images --image-context "upbeat and professional, product-focused" \
--image-placement auto --image-strategy all --wait
--image-context <text>— required when generating images: a short visual brief for the image prompts--image-placement auto|background|in-line(defaultauto— AI decides per slide)--image-strategy strategic|all(strategic≈ 50% of slides, default;all= every eligible slide)
Best-effort: the post still completes if images fail or aren't permitted. With --wait, the result carries an imageGeneration field (the GENERATE_IMAGES step); if its status is FAILED, its message explains why (e.g. free plan can't generate AI images, or the org is over its AI-image quota). AI images bill against the org's separate AI-image quota, not the post's slide credits, and add latency. Without --wait, the same step shows up in status logs.
Infographic layout — import only
On either import command, set layoutType: "infographic" on a slide (with a layoutConfig) to render data columns (max 3) instead of an image. Every column and content item needs a caller-provided id, and each item description is an HTML string. See carousel import-template / image import-template for the full schema.
3. Check status / get output (only if you didn't use --wait)
postnitro carousel status <embedPostId> # progress + step logs; poll until COMPLETED
postnitro carousel output <embedPostId> # final file URL(s) + designId + editorUrl
(image status / image output work identically for image posts.)
Output is a PDF (single URL) or PNG (one URL per slide) in data, plus the designId and editorUrl. Those can be handed to another tool — e.g. a different scheduler — to publish on platforms PostNitro doesn't cover. With --response-type DESIGN there's no rendered file, so data/mimeType/outputType are omitted (you still get designId and editorUrl).
4. Schedule the design to social accounts
postnitro social list # get account IDs + platforms
postnitro schedule create \
--status SCHEDULED \
--scheduled-at "2026-12-31T13:00:00Z" \
--design-id <designId> \
--selected-accounts '["<socialAccountId>"]' \
--linkedin-post-settings '{"postType":"document","postTitle":"5–90 char title"}' \
--post-content '{"common":"Caption with #hashtags"}'
5. One-shot: create + schedule
Create and schedule in a single call — generate-and-schedule (AI writes it) or import-and-schedule (your own content). Both accept the schedule flags from step 4, --post-type CAROUSEL|IMAGE, and the AI-image options from step 2. If creation succeeds but scheduling fails, the error returns the designId so you can retry schedule create without re-creating (or re-spending credits).
# AI-generated
postnitro generate-and-schedule \
--context "topic" --type text \
--status SCHEDULED --scheduled-at "2026-12-31T13:00:00Z" \
--selected-accounts '["<socialAccountId>"]' \
--linkedin-post-settings '{"postType":"document","postTitle":"..."}' \
--post-content '{"common":"..."}'
# Your own content — --slides (carousel array) or --slide (single image); --slides-file for a file.
# (Here --file is the SCHEDULE body, so slides come from --slides / --slides-file.)
postnitro import-and-schedule \
--slides '{"slides":[ ... ]}' \
--status SCHEDULED --scheduled-at "2026-12-31T13:00:00Z" \
--selected-accounts '["<socialAccountId>"]' \
--post-content '{"common":"..."}'
Common Patterns
Pattern 1: LinkedIn thought-leadership carousel
postnitro carousel generate \
--context "5 mistakes startups make with their LinkedIn strategy and how to fix each one" \
--type text --instructions "Professional but conversational. One clear takeaway per slide." --wait
Pattern 2: Repurpose a blog post
postnitro carousel generate --context "https://yourblog.com/posts/social-media-strategy-2026" \
--type article --instructions "Extract the 5 most actionable points. Keep slide text concise." --wait
Pattern 3: Repurpose an X thread
postnitro carousel generate --context "https://x.com/username/status/1234567890" \
--type x --instructions "Maintain the original voice and key points" --wait
Pattern 4: Data-driven infographic carousel
Import slides with layoutType: "infographic" body slides — see
examples/import-infographics.json.
Pattern 5: Generate → schedule to LinkedIn
DID=$(postnitro carousel generate --context "5 remote work habits" --type text --wait | jq -r .designId)
LINKEDIN=$(postnitro social list | jq -r 'first(.accounts[] | select(.platform=="linkedin").id)')
postnitro schedule create --status SCHEDULED --scheduled-at "2026-12-31T13:00:00Z" \
--design-id "$DID" --selected-accounts "[\"$LINKEDIN\"]" \
--linkedin-post-settings '{"postType":"document","postTitle":"5 remote work habits"}' \
--post-content '{"common":"New carousel 🚀 #remotework"}'
Pattern 6: Batch scheduling
DATES=("2026-02-14T09:00:00Z" "2026-02-15T09:00:00Z")
TOPICS=("Monday motivation 💪" "Tuesday tips 💡")
for i in "${!DATES[@]}"; do
postnitro generate-and-schedule --context "${TOPICS[$i]}" --type text \
--status SCHEDULED --scheduled-at "${DATES[$i]}" \
--selected-accounts '["<socialAccountId>"]' \
--linkedin-post-settings '{"postType":"document","postTitle":"Daily post"}'
done
Content Strategy Tips
- LinkedIn: professional tone, actionable insights, 6–10 slides, clear CTA. PDF carousels post as
postType: "document"(needs a 5–90 charpostTitle). - Instagram: visual-first, concise text, 5–8 slides, storytelling arc.
postAsStoryfor stories. - TikTok: trendy, punchy, 4–7 slides, hook on slide 1.
- X / Threads: data-driven, 3–6 slides, provocative opening.
Common Gotchas
- Not authenticated — run
postnitro auth status; set a key before anything else. - Scheduling with
embedPostId— use thedesignIdfrom--wait/carousel output, never theembedPostId. Scheduled at is in the past—--scheduled-atmust be a future ISO-8601 datetime with a trailingZ.- Invalid inline JSON — wrap JSON flags in single quotes; the CLI validates before any network call.
Missing --brand-id ... multiple candidates— pass the ID or save a default withdefaults set.- LinkedIn
documentrejected —postType:"document"needs a 5–90 charpostTitle. - Empty post — a scheduled post needs either
--design-idor non-empty--post-content. - Destructive commands —
social disconnectandschedule deleterequire--yes. SCHEDULEDpublishes live — useDRAFTwhen unsure; confirm time/account with the user first.responseType— the CLI defaults toPDF(pass--response-type PNGfor individual slide images, orDESIGNto skip rendering and only create the design). Note: the underlying API now defaults toDESIGNwhen omitted, but the CLI always sendsPDFexplicitly, so CLI behavior is unchanged.- Credits vary — AI generation ≈ 2 credits/slide; content import ≈ 1 credit/slide. Warn before large batches.
Credits & Pricing
The Embed API requires a paid subscription — there is no free tier, and free accounts cannot call the API. See https://postnitro.ai/plans for current plans and credit allowances.
Approximate usage cost (observed):
- Content import: ~1 credit per slide
- AI generation: ~2 credits per slide
Supporting Resources
In this skill:
- references/cli-reference.md — complete command, platform-settings, and slide-schema reference
- examples/EXAMPLES.md — ready-to-use import & schedule JSON (
import-default.json,import-infographics.json,schedule-post.json)
Full project docs (GitHub):
- README — full command reference
- QUICK_START.md — zero to a scheduled carousel in minutes
- HOW_TO_RUN.md — install & run methods
- PLATFORM_SETTINGS.md — platform settings schemas
- FEATURES.md — full feature list
- Per-command help:
postnitro <command> <subcommand> --help
Quick Reference
# Auth (do this first)
postnitro auth set-key pn-xxxx | postnitro auth status | export POSTNITRO_API_KEY=pn-xxxx
# Discover + defaults
postnitro template list | brand list | preset list | social list
postnitro defaults set --template-id <id> --brand-id <id> --preset-id <id> --response-type PDF
# Create (async — use --wait; result has designId + editorUrl)
# --response-type PDF|PNG|DESIGN (DESIGN skips rendering; CLI default is PDF)
# Optional AI images (any generate/import): --generate-images --image-context "brief" [--image-placement auto|background|in-line] [--image-strategy strategic|all]
postnitro carousel generate --context "topic|url" --type text|article|x [--instructions "..."] --wait
postnitro carousel import (--slides '{"slides":[...]}' | --file ./slides.json) --wait
postnitro carousel status <embedPostId> # if not using --wait
postnitro carousel output <embedPostId> # file URLs + designId + editorUrl
# Single-image posts (mirror carousel; import takes ONE slide object, not an array)
postnitro image generate --context "topic|url" --type text|article|x --wait
postnitro image import (--slide '{"heading":"..."}' | --file ./slide.json) --wait
# Schedule (date REQUIRED + future; use designId, not embedPostId)
postnitro schedule create --status SCHEDULED|DRAFT --scheduled-at "<iso>" --design-id <id> \
--selected-accounts '["<id>"]' --linkedin-post-settings '{"postType":"document","postTitle":"..."}' \
--post-content '{"common":"caption"}'
postnitro schedule list --from "<date>" --to "<date>" | get <id> | delete <id> --yes
# One-shot: create + schedule (both take --post-type + AI-image flags)
postnitro generate-and-schedule --context "topic" --status SCHEDULED --scheduled-at "<iso>" ...
postnitro import-and-schedule --slides '{"slides":[...]}' --status SCHEDULED --scheduled-at "<iso>" ... # or --slide for image
Tips for the Agent
- Always confirm authentication (
postnitro auth status) before running any other command. Never fabricate an API key — ask the user. - Prefer
--waitso one call returns the finished output anddesignId. - Discover IDs with the
listcommands; save workspace defaults withdefaults setso later calls stay short. - Schedule with the
designId, not theembedPostId. - For
--type article/x,--contextmust be a URL. For plain text, use--type text. responseTypedefaults to PDF in the CLI — pass--response-type PNGfor individual slide images, orDESIGNto skip rendering when you only need thedesignId/editorUrl(e.g. for scheduling).--scheduled-atmust be a future ISO-8601 datetime (trailingZ).status: SCHEDULEDcreates a live post that will publish — confirm the time and account with the user, or useDRAFTwhen unsure.- Parse stdout as JSON; on failure read
.error.messagefrom stderr and fix the inputs. - Warn about credit costs before large batches (AI generation is ~2× the cost of import).
- If the user doesn't specify a platform, suggest LinkedIn (most common carousel use case) and remember PDF carousels post there as
document.
Top skills in this category
Edge TTS
@i3130002Text-to-speech conversion using node-edge-tts npm package for generating audio from text. Supports multiple voices, languages, speed adjustment, pitch control, and subtitle generation. Use when: (1) User requests audio/voice output with the "tts" trigger or keyword. (2) Content needs to be spoken rather than read (multitasking, accessibility, driving, cooking). (3) User wants a specific voice, speed, pitch, or format for TTS output.
Antigravity Image Generator
@ipedraxGenerate images using the internal Google Antigravity API (Gemini 3 Pro Image). High quality, native generation without browser automation.
Manage Reddit posts, comments, subreddits, users, moderation, and community workflows via the Reddit API. Use when users want to search subreddits, inspect p...
Social Media Scheduler
@1kalinPlan, draft, and organize social media content across platforms. Create content calendars, write platform-optimized posts, and maintain consistent posting schedules.
elevenlabs-voices
@robbyczgw-claHigh-quality voice synthesis with 18 personas, 32 languages, sound effects, batch processing, and voice design using ElevenLabs API.