Install
$ agentstack add skill-mikefluff-skills-post-publisher ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
The last mile. Every other skill in this collection stops at ./generated/...; this one sends what is there to the platform and records that it did.
Input: an output directory from carousel-builder / reel-builder (or a single file, or just text). Output: a live post or a platform-side draft, plus a posted.json receipt.
This skill does NOT:
- Write the content — that is
viral-text/essay-write/carousel-builder/reel-builder. - Schedule anything. There is no queue and no cron. It publishes now, or it stages a draft you finish by hand.
- Post to a platform you have not connected. Credentials are yours; nothing is bundled.
- Guarantee reach, or touch analytics.
ROLE
Resolve a source directory → build one platform-neutral Post → preflight it against each target platform's real limits → show the user exactly what would go where → ask → publish → write a receipt.
Publication is irreversible. Dry-run is the default and --yes is what leaves it. Even with --yes, each platform is confirmed separately: approving an Instagram post is not approval to also post to X.
PIPELINE
- Resolve the source. A directory is inspected in this order:
final.mp4→ video; several images → carousel (sorted numerically, soslide-2precedesslide-10); one image → image; nothing → text post. Override with--kind.
- Resolve the caption. From
--text, else--text-file, elsecaptions.mdin the source directory. The parser looks for a## Main post/## Основной постheading and takes everything up to the next heading; with no such heading it takes the whole file minus headings. Always check the extracted text in the dry-run preview —captions.mdis written by an agent, so its shape is a convention, not a contract.
- Preflight, per platform. Character limits including hashtags, media count, file size, extension, missing alt text, and each platform's own rules (Telegram's 1024-char caption ceiling that does not apply to text posts; Instagram's 24h posting cap; TikTok's audit caveat). A
blockfinding means nothing is sent; awarnmeans it goes but you should know.
- Preview + confirm. Full text, character count, every file with its size and alt text, and whether it is going out live or as a draft.
- Publish, then record. The receipt (
posted.json) is written immediately after each platform succeeds — a crash mid-fan-out cannot cause a re-post of the platforms already done. A later run with identical content is refused unless--force.
PLATFORMS
| Platform | Post kinds | Draft | The thing that will bite you | |---|---|---|---| | telegram | text, image, carousel, video | — | Caption on media caps at 1024 chars (text-only gets 4096). Video ≤50 MB. The only one testable end-to-end without OAuth — start here. | | threads | text, image, carousel, video | container | 500 chars. Text-only posts need no S3 — the easiest real connection. | | instagram | image, carousel, video | container | Business/Creator account required. Media is fetched by URL, so S3 is mandatory. Video publishes as a Reel (≤300 MB, ≤15 min). 100 posts/24h. | | tiktok | video, image, carousel | inbox | Direct publishing needs an audited app; without one, posts are silently forced to SELF_ONLY. Use --draft. | | x | text, image, carousel, video | — | 280 chars. 10,000/24h per app, 100/15min per user; what you may spend depends on the plan. Threads publish incrementally — a failure mid-chain leaves earlier posts live. | | youtube | video | private | 100 uploads/day on their own allocation, drafts included. Cleanest draft of the seven. | | linkedin | text, image, carousel, video | — | 3000 chars. Member posts work with w_member_social; company pages need the partner-gated Community Management API. |
MODES
Source
post-publisher— acarousel-builder/reel-builderoutput directorypost-publisher— a single image or videopost-publisher --kind text --text "..."— no source at all
Targeting
--platform a,b,c— comma-separated; each is confirmed separately--draft— stage instead of publish. A platform without drafts is skipped, not published live--kind text|image|carousel|video|article— override auto-detection
Content
--text/--text-file— caption (overridescaptions.md)--title— YouTube title / LinkedIn article title--hashtags "a,b,c"— kept separate from the body so preflight can count them--alt "..."— repeat once per media file, in order--link— attached where the platform supports it
Article syndication (--kind article)
--canonical— the important one. The URL of the original on your own domain--description— SEO excerpt / subtitle--series— dev.to series name, Hashnode series id--cover-url— cover image, already hosted--packets— write submission packets for the platforms with no API
Execution
- (nothing) — dry-run. Prints what would happen and stops
--yes— leave dry-run. Still asks before each platform--force— publish despite a matching receipt inposted.json--publish-container— publish a Meta container left by an earlier--draft--check --platform X— readiness: credentials present, token usable--list-platforms— everything, with what each is missing
Exit codes
| Code | Meaning | |---|---| | 0 | Everything asked for happened, or was already done | | 1 | At least one platform failed — blocked by preflight, missing credentials, or a platform error | | 2 | Usage error: no --platform, unreadable source |
A skip is not a failure. A platform skipped because it has no drafts, or because posted.json says this content already went out, leaves the code at 0 — in a mixed run (--platform telegram,instagram --draft) Instagram drafting successfully should not be reported as an error because Telegram was skipped. The summary line always states how many proceeded, were skipped and were blocked.
Accounts
python3 -m common.runners.cli.auth --platform— OAuth in a browser... --paste-token— paste a token from the platform's own token tool (the supported route wherever loopback redirects are rejected)... --status/--verify/--revokeskills-keys accounts— the same list, from the credentials skill
REFERENCES (load on demand)
| File | When to load | |---|---| | [references/syndication.md](references/syndication.md) | --kind article — why canonical decides whether syndication helps or hurts, which platforms have an API, and the order to publish in | | [references/oauth-setup.md](references/oauth-setup.md) | First — per-platform app registration, scopes, account type, which env vars go in ~/.skills.env | | [references/platform-limits.md](references/platform-limits.md) | Step 3 — the limit matrix preflight enforces, with what to verify against live docs | | [references/browser-fallback.md](references/browser-fallback.md) | When the API path is closed: unaudited TikTok, personal Instagram, org LinkedIn pages | | [references/troubleshoot.md](references/troubleshoot.md) | A platform returned an error and the message is not self-explanatory | | [viral-text platform budgets](../viral-text/references/platforms.md) | Writing to fit a platform before generating — character budgets and tone per network |
EXAMPLES
See [examples/before-after.md](examples/before-after.md) — three calibration runs: an 8-slide carousel to Instagram as a draft, a reel to TikTok's inbox, and a text post fanned out to Threads + Telegram + X.
CONSTRAINTS
- Dry-run is the default and must stay that way. Every other runner here is safely re-runnable because a wasted generation costs cents. A wasted publish costs an audience.
--yesis the deliberate act.
- Confirm per platform, never in bulk. A single "yes" must not fan out to seven networks.
--draftis a promise. If a platform cannot draft, skip it. Publishing live because the user asked for a draft is the worst possible reading of the flag.
- Never print a token. Masked in
--status, absent from errors, absent from logs.~/.skills-tokens.jsonischmod 600and gitignored.
- Preflight before bytes. Every check that can happen locally happens before the first network call. Staging a 200 MB reel to S3 and waiting a minute for ingestion, only to be refused on a caption length, is a bug.
- Receipts are per (platform, content). Editing the caption makes it a new post and it goes through; re-running the identical command does not.
- Report partial failure as partial. An X thread that publishes 3 of 6 posts is not a failed publish and must not be reported as one — the receipt records what actually went out.
- Verify endpoints before first use. All seven APIs move. Versions are env-overridable (
INSTAGRAM_API_VERSION,LINKEDIN_API_VERSION,THREADS_API_VERSION,X_UPLOAD_URL) precisely so a vendor change does not need a code change.references/platform-limits.mdcarries the last-verified date.
- The browser path is a fallback, not a peer. It is best-effort, it is a grey area under some platforms' terms, and it requires explicit consent every single time. Never drive it silently.
- No engagement automation. This skill posts what the user wrote. It does not follow, like, comment, DM, or run multiple accounts in concert.
INVOCATION HINTS
Triggers:
- "опубликуй / выложи / запость это", "залей в инсту", "выложи карусель в треды", "кинь рил в тикток"
- "post this to X", "publish the carousel", "upload the reel to YouTube", "send it to the channel"
- Immediately after
carousel-builderorreel-builderfinishes, when the user says "и выложи" / "and post it"
Defaults: dry-run, no --draft, caption from captions.md. If the user names no platform, ask once — do not guess a destination.
If nothing is connected yet, route to references/oauth-setup.md and suggest starting with Telegram (no OAuth) or Threads (simplest OAuth), not Instagram.
Upstream: carousel-builder, reel-builder, viral-text, quote-card-maker, meme-card-maker — anything that lands assets in ./generated/.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Mikefluff
- Source: Mikefluff/skills
- License: MIT
- Homepage: https://www.npmjs.com/package/@mikefluff/skills
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.