agentsclimarketplace

Post content

Skill NovateStudioGit/novate-studio-skills/creative-production/post-content

Single-command video distribution. Locates a video on disk, transcribes the audio with Whisper, writes a platform-appropriate caption in the matching creator/brand voice, picks a cover, queues it to Buffer, and schedules to IG Reels + TikTok + YouTube Shorts (LinkedIn/Threads optional). Use this skill whenever the user wants to publish, post, ship, schedule, queue, or cross-post a video to social — including phrases like "post that video", "ship the latest reel", "send to Buffer", "queue for IG", "post to shorts", "publish the Example Creator clip", or any natural-language post request that names a video file, a Downloads target, or a creator/brand folder. Also trigger when the user mentions a specific reel/short by name and asks for it to go live anywhere.From its SKILL.md

Install
npx -y skills add NovateStudioGit/novate-studio-skills --skill post-content

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

7.5 KB, ~1.8k tokens by cl100k_base, as published. Nobody here has run it

/post-content

One command, raw video in → scheduled posts out. The model drives — the scripts do the deterministic parts (find file, transcribe, upload). Will approves before anything ships to Buffer.

Flow

  1. Parse intent — pull from the user's prompt: which video, which channels, when to post, any caption hints.
  2. Locate the videoscripts/find_video.py with the intent.
  3. Transcribescripts/transcribe.py (local whisper.cpp — no API key, runs on-device. Cached next to the video as .transcript.txt).
  4. Detect voice — from the video's path (see voice map below). Read the matching persona doc(s) before writing.
  5. Draft caption + hashtags — in that voice, max 5 hashtags.
  6. Pick coverscripts/extract_cover.py. Default: frame at 0.5s. If /virality was run on this video, pull the peak-hook frame instead. Offer /thumbnail for a designed cover.
  7. Approval gate — show Will the caption, cover, channels, scheduled time. Wait for ship, tweak X, or cancel. Never auto-post.
  8. Publishscripts/buffer_post.py fans out to the selected Buffer channels.
  9. Log — write a one-line confirmation note to the relevant Obsidian project's sessions/YYYY-MM-DD.md.

Voice detection — read the persona docs, don't infer

The video's parent path determines voice. Always read the persona doc before drafting — caption voice is too easy to get wrong from filename guessing alone.

Path patternVoice source
STUDIO/1-WillSchwx.io/**Will's locked voice — see references/voice-will.md AND ~/notes/your-brand/index.md
STUDIO/[creator]/** (other)~/notes/[creator-slug]/ persona/voice docs
ECOMMERCE/[brand]/**~/notes/[brand-slug]/ brand voice docs
~/Downloads/** or anywhere elseAsk Will which creator/brand this is for — don't guess

For Will: typographic discipline (command form, parallel structure, one idea per line, memorable metaphor allowed). For Example Creator specifically, the /caption-IG-Example Creator skill already encodes the voice — invoke it instead of recreating it.

Hashtag rule — locked, never override

Max 5 hashtags per caption. Compose them as: 1 niche + 1 broad + 2 thesis + 1 shareability. Never more, regardless of platform best-practice claims. (Will's standing rule.)

Never fabricate

Captions may only reference what's in the transcript or what Will provided in this turn. No invented stats, names, dates, or claims. If a number/quote feels persuasive but isn't sourced, leave it out — don't fill the gap.

Channels — defaults and flags

Default: IG Reels + TikTok + YouTube Shorts.

  • +linkedin / +threads to add.
  • only ig / only tiktok / only shorts to restrict.
  • LinkedIn and Threads use rephrased copy (LinkedIn = pro framing + first-person; Threads = conversational, no hashtags).

Timing

  • No timing said → immediate post.
  • queue → next available Buffer slot.
  • at 7pm / tomorrow 9am → specific time (interpret in Will's local tz; today's date is in context).

Cover

  1. If ~/Desktop/STUDIO/**/virality/[video-stem]/score.json exists → pull peak_hook_timestamp and grab that frame via extract_cover.py --at <ts>.
  2. Else → grab --at 0.5.
  3. Always offer: "Want me to run /thumbnail for a designed cover instead?" — if Will says yes, invoke /thumbnail and use that output.

Approval gate format

Show this exact structure before calling Buffer:

Ready to ship:

Video:      <basename> (<duration>s, <w>x<h>)
Cover:      <path>      ← reply "thumbnail" to upgrade
Channels:   <ig/tiktok/shorts/...>
Time:       <immediate | YYYY-MM-DD HH:MM tz | "next queue slot">

Caption (IG/TikTok primary):
<caption>

#tag1 #tag2 #tag3 #tag4 #tag5

LinkedIn (if selected):
<rephrased copy>

Reply: ship  |  tweak <what>  |  cancel

Script contracts

All scripts live in scripts/ and read flags from CLI. None of them call Buffer or Whisper unless invoked — safe to dry-run.

  • find_video.py <intent-string> → prints absolute path of the resolved video. Resolution order: 1) explicit path in intent, 2) newest .mp4/.mov/.mkv in ~/Downloads (≤ 7 days old), 3) newest in ~/Desktop/STUDIO/**/content/, 4) newest in ~/Desktop/ECOMMERCE/**/content/. Errors clearly if ambiguous.
  • transcribe.py <video-path> → writes <video>.transcript.txt and prints the transcript. Skips if cache exists. Uses local whisper.cpp; auto-downloads the small.en model on first run.
  • extract_cover.py <video-path> [--at <seconds>] → writes <video>.cover.jpg next to the video.
  • buffer_post.py --video <path> --cover <path> --caption-file <path> --channels ig,tiktok,shorts --when <immediate|ISO8601> → posts via Buffer's GraphQL API at api.buffer.com. Requires BUFFER_ACCESS_TOKEN and ~/.claude/skills/post-content/config.json shaped {"organization_id": "...", "channels": {"ig": "<channelId>", "tiktok": "<channelId>", "shorts": "<channelId>"}}. Buffer's API has no upload endpoint, so the script either spins up a cloudflared tunnel automatically (default) or accepts --public-url-base <https-url> if you host the files yourself.

Run pip install -r ~/.claude/skills/post-content/scripts/requirements.txt the first time.

First-time setup (only if not done)

  1. ~/.claude/skills/post-content/config.json must exist with organization_id + channels map. If missing, run python scripts/buffer_post.py --write-config once (after channels are connected in Buffer) — it auto-detects the org and maps services to keys (ig, tiktok, shorts, linkedin, threads).
  2. BUFFER_ACCESS_TOKEN must be exported (check ~/.zshrc or project .env). If missing, stop and tell Will exactly what to set and where.
  3. whisper-cpp must be on PATH — brew install whisper-cpp if missing. (No API key, no per-minute cost — runs locally.)
  4. cloudflared must be on PATH — brew install cloudflared if missing. Used to expose the local video file to Buffer's servers for the duration of the post-creation call. Skip if passing --public-url-base (you host the files yourself).

Composes with

  • /virality — run BEFORE posting to score the hook; reuse its peak_hook_timestamp for cover.
  • /thumbnail — designed cover overlay; use when Will accepts the upgrade.
  • /caption-IG-Example Creator — Example Creator captions live there; defer to it instead of duplicating voice rules.
  • /vysionary-carousel — Will's @yourbrand.ai posts that are carousels, not reels — route those over there instead.

When NOT to use this skill

  • Carousels / static image posts → use /vysionary-carousel or post manually.
  • Editing an already-scheduled Buffer post → ask Will to do it in Buffer's UI; this skill only creates new posts.
  • Stories / live streams → out of scope.

What ships with it: 7 files

26.5 KB alongside SKILL.md, 4 of them executable

references/

scripts/

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.