End-to-end publish + Typefully draft pipeline for a single demo. Use when the user says "draft", "create draft", "typefully draft", or wants to publish a demo and create social thread drafts in one go.
npx skills add https://github.com/vercel-labs/workflow-campaign-demos --skill draft
Full pipeline: select a demo, publish to v0, generate snippet image, and create Typefully thread drafts.
Discover demos by listing directories in the project root that contain a package.json (skip directories starting with .). Present them with AskUserQuestion so the user can pick one.
git status. If changes touch the selected demo's prefix, warn the user and ask whether to continue. git fetch workflow-{slug} main
git rev-parse workflow-{slug}/main → remote SHA
git subtree split --prefix={slug} → local SHA
If SHAs differ, offer to push: git subtree push --prefix={slug} workflow-{slug} main
.posts/{slug}.md exists. If not, tell the user and abort — the Typefully pipeline requires it.V0_API_KEY is set and TYPEFULLY_API_KEY exists in .env.local.Run:
bun .scripts/typefully-publish.ts {slug} --validate
If any tweets exceed the 280-character limit, show which ones are over and by how much. Help the user edit .posts/{slug}.md to fix them, then re-validate until it passes.
Ask the user which variant(s) to draft using AskUserQuestion:
The typefully-publish script handles v0 publish, image generation, and Typefully draft creation in one run:
bun .scripts/typefully-publish.ts {slug} --variant {variant}
Or without --variant for all variants.
This will:
From the script output, extract and report:
https://v0.app/chat/...)https://typefully.com/?d=...)https://typefully.com/t/...).posts/ directory contains social media thread contenttypefully-publish.ts calls v0-publish-public.ts internally — do NOT run v0-publish separately{v0_link} placeholder in post markdown gets replaced with the live v0 URL at publish timepuppeteer (headless Chrome for ray.so screenshots).posts/{slug}.png if presentTake vercel-labs/draft from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.