skills/typefully-draft/SKILL.md
Draft and queue social posts via the Typefully v2 API across X, LinkedIn, Threads, Bluesky, Mastodon, and any other connected account in a Typefully social set. Creates a draft you review in the Typefully app/web before it auto-posts, optionally schedules to a specific time, queues into the next free slot, returns a shareable preview link, or scopes to specific platforms via --targets. Supports single posts and threads. Reads TYPEFULLY_API_KEY and TYPEFULLY_SOCIAL_SET_ID from ~/.claude/.env. Use when user wants to schedule, queue, draft, or cross-post to any Typefully-connected platform.
npx skillsauth add RonanCodes/ronan-skills typefully-draftInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Draft a post into Typefully so it stays in your review loop before it goes live. Threads, scheduling, shareable preview links, and per-platform targeting are first-class. Posts never bypass the Typefully approval gate, which keeps connected accounts (e.g. @ronancodes) clear of bot-flag risk.
This skill wraps the Typefully v2 API. Drafts are scoped to a social set — a collection of connected platform accounts (X, LinkedIn, Threads, Bluesky, Mastodon). One draft can target one platform or all of them.
# Single post, all four platforms (default targets: x,linkedin,threads,bluesky)
/ro:typefully-draft "shipped a 16:9 promo for connectionshelper.app today. PH next month."
# Single post, scheduled for a specific time (UTC)
/ro:typefully-draft "good morning EU" --schedule "2026-04-26T07:00:00Z"
# Queue into the social set's next free slot
/ro:typefully-draft "build-in-public day 3: shipped k6 load tests" --queue-next
# Thread on X + Bluesky only
/ro:typefully-draft --thread "Day 1 of launching connectionshelper.app.\n---\nThe stack: TanStack Start, Cloudflare Workers, D1, Drizzle.\n---\nWhat I'm watching this week: r/NYTConnections." --targets x,bluesky
# Get a shareable preview URL (for showing a friend before approval)
/ro:typefully-draft "thinking about a new tagline" --share
# LinkedIn-only post (different rhythm than X; don't blanket cross-post)
/ro:typefully-draft "engineering deep-dive on D1 caching" --targets linkedin
Typefully account at https://typefully.com. Free plan supports the API.
API key from Typefully → Settings → API → New API Key.
Social set ID (the group of connected accounts) — find it via:
curl -H "Authorization: Bearer $TYPEFULLY_API_KEY" \
https://api.typefully.com/v2/social-sets | jq
Add both to ~/.claude/.env:
# Typefully
TYPEFULLY_API_KEY=<your-key>
TYPEFULLY_SOCIAL_SET_ID=<numeric-id>
curl, jq, and python3 (all standard on macOS).
Typefully v2 uses the standard bearer-token format:
Authorization: Bearer <your-key>
(Earlier v1 used X-API-Key; that version is no longer the recommended path.)
/ro:write-copy.POST /2/tweets — that path has bot-flag risk on a personal-brand account and requires a Twitter Developer app. Same calculus for LinkedIn (their OAuth posts API) or Bluesky (the AT Protocol).--schedule or --queue-next to schedule, but you should still eyeball in the Typefully app before the scheduled time hits.POST /v2/social-sets/{id}/media/upload; that's a future addition.set -a && source "$(ro context env)" && set +a
[ -n "$TYPEFULLY_API_KEY" ] && [ -n "$TYPEFULLY_SOCIAL_SET_ID" ] || {
echo "Missing TYPEFULLY_API_KEY or TYPEFULLY_SOCIAL_SET_ID in ~/.claude/.env" >&2
exit 1
}
The wrapper script handles this. Schema:
{
"platforms": {
"x": { "enabled": true, "posts": [{ "text": "..." }] },
"linkedin": { "enabled": true, "posts": [{ "text": "..." }] },
"threads": { "enabled": true, "posts": [{ "text": "..." }] },
"bluesky": { "enabled": true, "posts": [{ "text": "..." }] }
},
"publish_at": "2026-04-26T09:00:00Z",
"share": false
}
Threading: posts is an array. The script splits the input on \n---\n (a clearer human marker than four-newlines) and emits one { "text": ... } per part.
Optional fields:
| Field | Use |
|---|---|
| publish_at | ISO 8601 UTC, or "now", or "next-free-slot" for queued posting |
| share | true to receive a public preview URL in the response |
curl -sS -X POST "https://api.typefully.com/v2/social-sets/${TYPEFULLY_SOCIAL_SET_ID}/drafts" \
-H "Authorization: Bearer $TYPEFULLY_API_KEY" \
-H "Content-Type: application/json" \
-d "$payload" | jq
The response includes id, private_url, share_url (if share=true), and per-platform *_published_url fields once published. Open https://typefully.com/?d=<id> to review and approve.
scripts/draft.sh is the entry point invoked by the slash command.
bash scripts/draft.sh "<text>" # all 4 platforms
bash scripts/draft.sh "<text>" --targets x # X only
bash scripts/draft.sh --thread "p1\n---\np2\n---\np3" --targets x # X-only thread
bash scripts/draft.sh "<text>" --schedule "2026-04-26T09:00:00Z"
bash scripts/draft.sh "<text>" --queue-next
bash scripts/draft.sh "<text>" --share
--targets controls which platforms.<name>.enabled flags get flipped to true. Without --targets the default is x,linkedin,threads,bluesky (all four flipped on).
If you target a platform that isn't connected to your social set, the API returns 400. Connect the platform in Typefully first or scope --targets to the ones you have.
When Claude composes the post text inside the conversation, load /ro:write-copy first. The rules that bite hardest on social:
--schedule or --queue-next. Default is "draft only"; user should approve in the Typefully UI before publish.--share with --schedule. Pick one: a preview link is for "show a friend, then I'll publish manually"; a schedule is for "publish at this time, no further intervention." Combining them implies a workflow that doesn't exist.--targets to scope a draft to one platform when the voice doesn't translate./ro:write-copy — voice rules (em-dashes, AI-tells, scroll-stop hooks)/ro:x-scan — read-only X scraper for trend / competitor research/ro:linkedin-scan — read-only LinkedIn scraper for competitor analysis/ro:trend-scan — find what's trending before draftingdevelopment
Close the loop on a Linear ticket when its work ships - move the status and post a deploy comment with the PR link, what shipped, and a try-it link, mentioning the collaborator. Used as the tail of /ro:linear-nightshift for every merged mirror, or manually after an ad-hoc build. Triggers on "linear update", "update the linear ticket", "mark NUT-x done", "tell eoin it shipped", "/ro:linear-update".
devops
Run a night-shift against a collaborator's Linear board. Pulls the team's Grilled tickets (/ro:linear-grill moves a ticket to Grilled once its questions are answered), VERIFIES the questions were actually answered (unanswered → bounce the ticket to the "Question for <name>" state), mirrors verified tickets to ephemeral GitHub issues with ready-for-agent, then runs the standard /ro:night-shift machinery on GitHub. Tail-calls /ro:linear-update for everything that merged + deployed. Triggers on "linear nightshift", "nightshift linear", "drain the linear board", "run the shift off linear", "/ro:linear-nightshift".
development
Grill a collaborator's Linear tickets and move every processed ticket to where it belongs. Resolves the board from the repo's .ro-linear.json, reads the collaborator's Backlog / Ready-for-agent issues, then per ticket either posts 3-5 decision-extracting questions (state moves to "Question for <name>") or confirms it build-ready (state moves to "Grilled", the gate /ro:linear-nightshift consumes); shipped-and-confirmed tickets close as Done. The async-collaborator counterpart of /ro:day-shift for people who never touch GitHub. Triggers on "grill linear", "grill eoin's tickets", "linear grill", "add questions to the linear tickets", "/ro:linear-grill".
development
--- name: about-page description: Add a standard About page to any web app, what it is, the tech stack, and an FAQ, wired into a footer link with a sticky footer. Built with Spartan + Tailwind (the canonical component layer) and falls back to semantic HTML so it ships reliably. Use whenever building, polishing, or shipping an app, every app should have one. Triggers on "add an about page", "about page", "footer about link", or as a standard step in app build/polish. category: frontend argument-h