An open-source set of go-to-market skills for solo technical founders — positioning, first users, launch and pricing, sequenced into a roadmap your agent works with you.
Typefully Social PublishingSkill
Summary
Typefully's official skill for drafting, scheduling and publishing to X, LinkedIn, Threads, Bluesky, Mastodon and Substack Notes from your agent or terminal.
Features
- Draft, schedule and publish to X, LinkedIn, Threads, Bluesky, Mastodon and Substack Notes
- Zero-dependency Node.js CLI with JSON output for every command
- Resolves dropped Typefully draft URLs to the right API call
- Draft comments, replies and resolution workflows
- Explicit auth-failure handling: stop and ask, never scrape or guess credentials
Install This Skill
Add this skill to your favorite AI agent in a few steps.
This skill is plain instructions — it works with any assistant that accepts custom instructions or system prompts.
- Copy the skill content with the button below.
- Paste it into your agent's instruction file or system prompt (for example
AGENTS.md,.cursorrules, or a custom instructions field). - Ask the agent to apply the skill whenever the task matches.
Claude loads skills automatically from its skills directory.
Claude Code
- Create a skill folder — personal:
~/.claude/skills/typefully-social-publishing/, or per-project:.claude/skills/typefully-social-publishing/ - Save the skill content as
SKILL.mdinside that folder. - Claude Code picks it up automatically and invokes it when relevant.
mkdir -p ~/.claude/skills/typefully-social-publishingClaude.ai / Claude Desktop
Enable Skills under Settings → Capabilities, then
upload the skill (a folder or zip containing SKILL.md).
Use the skill as custom instructions or a Custom GPT.
- Copy the skill content with the button below.
- For a dedicated assistant: open My GPTs → Create a GPT and paste the content into the Instructions field.
- For an existing chat or Project: paste the content into Custom Instructions (or the Project's instructions) and ask ChatGPT to follow it.
Paste this prompt into any agent with web access and it will install the skill for you.
Install the "Typefully Social Publishing" skill from Onei AI. Fetch https://onei.ai/skills/typefully-social-publishing, extract the full skill content from the page, and save it where you load skills from (for Claude Code: .claude/skills/typefully-social-publishing/SKILL.md). From now on, apply this skill whenever it is relevant to my request. Skill Content
Copy this content and use it with your preferred AI agent
---
name: typefully
description: >
Create, schedule, and manage social media posts via Typefully. ALWAYS use this
skill when asked to draft, schedule, post, or check tweets, posts, threads, or
social media content for Twitter/X, LinkedIn, Threads, Bluesky, Mastodon, or
Substack Notes, or when the user drops a Typefully draft URL such as
https://typefully.com/?a=<social_set_id>&d=<draft_id>.
last-updated: 2026-07-29
allowed-tools: Bash(./scripts/typefully.js:*)
---
# Typefully Skill
Create, schedule, and publish social media content across X, LinkedIn, Threads, Bluesky, Mastodon, and Substack Notes using [Typefully](https://typefully.com). Run everything through `./scripts/typefully.js` (Node.js 18+, no dependencies). All commands output JSON.
> **Script paths** below are relative to this skill's directory. Resolve them based on where the skill is installed.
>
> **Freshness check**: If more than 30 days have passed since the `last-updated` date above, tell the user the skill may be outdated and point them to the update methods in [`references/setup.md`](references/setup.md).
>
> **Authentication failures**: If the CLI returns **"API key not found"**, **"Authentication failed"**, **"HTTP 401"**, or any invalid/expired-key message, tell the user to run `./scripts/typefully.js setup` or update `TYPEFULLY_API_KEY`, then stop. Do not hunt for credentials or fall back to the Typefully web UI, browser scraping, or a localhost dev server. See [`references/setup.md`](references/setup.md).
## Dropped Typefully draft URLs
When the user gives you a Typefully draft URL, use this skill instead of browsing or scraping the Typefully web UI.
- `https://typefully.com/?a=<social_set_id>&d=<draft_id>` maps to:
```bash
./scripts/typefully.js drafts:get <social_set_id> <draft_id>
```
- `https://typefully.com/?d=<draft_id>` can use the configured default social set:
```bash
./scripts/typefully.js drafts:get <draft_id> --use-default
```
For draft comments, replies, resolving, or edits on a dropped draft URL, first fetch the draft with the mapping above, then load [`references/comments.md`](references/comments.md) when comment workflow details are needed.
## Reference guides
Load these only when the task needs them:
| Guide | Use when you need to... |
|-------|-------------------------|
| [`references/setup.md`](references/setup.md) | Configure the API key, fix an "API key not found" error, set up CI, or check whether the skill is up to date |
| [`references/comments.md`](references/comments.md) | Add, reply to, resolve, or delete comments on a draft, or edit a draft that already has comments |
| [`references/platforms/x.md`](references/platforms/x.md) | Pull X (formerly Twitter) analytics, quote or reply to a post, post to a community, or add disclosure labels |
| [`references/platforms/linkedin.md`](references/platforms/linkedin.md) | Mention a company or person on LinkedIn |
| [`references/platforms/x-articles.md`](references/platforms/x-articles.md) | Write or edit a long-form X Article (standalone platform) |
---
## 1. Choose a social set
A "social set" is what users call an "account" — the connected platforms for one identity. Most commands work without a `social_set_id` once a default is configured. Pass it positionally (`drafts:list 123`) or as `--social-set-id 123`.
To decide which social set to use:
1. Run `config:show`. If `default_social_set` is set, the CLI uses it automatically — proceed.
2. Otherwise run `social-sets:list`. If only one exists, use it.
3. If multiple exist with no default, ask the user, then offer to save it: `config:set-default`.
4. Reuse a social set already resolved earlier in the session without asking again.
---
## 2. Create drafts
```bash
./scripts/typefully.js drafts:create --text "Your post"
```
- If `--platform` is omitted, the first connected platform is auto-selected. Named platforms: `x`, `linkedin`, `threads`, `bluesky`, `mastodon`, `substack` (Substack Notes), `x_article`.
- Split a thread with `---` on its own line. Exception: `substack` takes a single post per draft — no threads. For a thread plus a Substack Note, use the one-draft pattern below to give `substack` its own single-post content.
- Substack Notes media: images and GIFs only (up to 6) — video is rejected.
- Attach media with `--media`, tags with `--tags`, internal notes with `--scratchpad`, an internal name with `--title`.
- Read content from a file with `--file ./post.txt` instead of `--text`.
### One draft per post — always
For the same content on several platforms, pass multiple platforms to a **single** draft:
```bash
./scripts/typefully.js drafts:create --platform x,linkedin --text "Big announcement!"
./scripts/typefully.js drafts:create --all --text "Posting everywhere!" # all connected platforms
```
When content should differ per platform (e.g. an X thread plus a tailored LinkedIn post), **still use one draft** — create with the first platform, then `drafts:update` to add another with different content:
```bash
./scripts/typefully.js drafts:create --platform linkedin --text "Excited to share..." # -> id draft-123
./scripts/typefully.js drafts:update draft-123 --platform x --text "🧵 Thread time!" --use-default
```
Never create multiple drafts unless the user explicitly wants separate drafts per platform.
> `--all` excludes `x_article`. X Articles are standalone and cannot be combined with any other platform — see [`references/platforms/x-articles.md`](references/platforms/x-articles.md).
>
> `--all` includes `substack` when connected. Since Substack Notes take a single post, `--all` with thread content errors — exclude `substack` via `--platform`, or give it its own single-post content with `drafts:update`.
### Scratchpad notes
When the user asks to add notes, ideas, or context to a draft, use `--scratchpad` — **do NOT write to local files.** Scratchpad notes attach to the draft in Typefully, are visible in the UI, stay private, and are never published.
```bash
./scripts/typefully.js drafts:create --text "My post" --scratchpad "Ideas: 1) Add stats 2) Include quote"
```
### Link previews
When a post contains a URL, Typefully automatically fetches Open Graph metadata for the last URL in the text and publishes a rich link-preview card on **LinkedIn, Threads, Bluesky, and Substack Notes**. No flag is needed — it just works. X and Mastodon unfurl links themselves after publishing. On Substack Notes the card is skipped when the note has images (images and the link card are mutually exclusive there).
To publish the URL as plain text with no card, pass `--hide-link-preview`. Suppression is supported on **LinkedIn, Threads, and Substack Notes only** (matching the Typefully editor); the flag errors if none of these platforms is targeted, and is ignored for other platforms in a mixed-platform draft:
```bash
./scripts/typefully.js drafts:create --platform linkedin,threads --text "Read this https://example.com" --hide-link-preview
./scripts/typefully.js drafts:update draft-123 --hide-link-preview --use-default # hide the card on an existing draft
```
---
## 3. Schedule & publish
```bash
./scripts/typefully.js drafts:create --text "..." --schedule next-free-slot # or an ISO time, or "now"
./scripts/typefully.js drafts:schedule <draft_id> --time next-free-slot --use-default
./scripts/typefully.js drafts:publish <draft_id> --use-default
./scripts/typefully.js drafts:create --text "..." --plan next-free-slot # planned: dated but inert
./scripts/typefully.js drafts:plan <draft_id> --time next-free-slot --use-default
```
- `next-free-slot` lets Typefully pick the optimal time.
- **Publishing is irreversible and public** — unless the user says "publish now" / "post immediately", confirm first. Creating a draft is safe.
- **Planned drafts** sit on the queue/calendar at their date but never auto-publish. Confirm one into a real schedule with `drafts:schedule` (or publish it with `drafts:publish`). A planned draft whose date has passed is **not overdue and not a failure** — it simply hasn't been confirmed; replan or confirm it. `--plan`/`--schedule` are mutually exclusive; `drafts:update --plan null` returns the draft to plain draft status.
- Single-arg commands require `--use-default` when a default social set is configured (see the [safety note](#commands) below).
---
## Common actions
| User says... | Action |
|--------------|--------|
| "Draft a tweet about X" | `drafts:create --text "..."` |
| "Post this to LinkedIn" | `drafts:create --platform linkedin --text "..."` |
| "Post a Substack Note" | `drafts:create --platform substack --text "..."` (single post, no threads) |
| "Post to X and LinkedIn" (same content) | `drafts:create --platform x,linkedin --text "..."` |
| "X thread + tailored LinkedIn post" | One draft, then `drafts:update` to add the platform |
| "What's scheduled?" / "Recent posts?" | `drafts:list --status scheduled` / `--status published` |
| "Schedule this for tomorrow" | `drafts:create --text "..." --schedule "<ISO time>"` |
| "Post this now" | `drafts:create --text "..." --schedule now` or `drafts:publish <id> --use-default` |
| "Pencil this in for Tuesday" (no commitment to publish) | `drafts:create --text "..." --plan "<ISO time>"`, confirm later with `drafts:schedule` |
| "Check available tags" | `tags:list` |
| "Check my publishing quota" | `social-sets:get` → `publishing_quota` |
| "Draft an X Article" | See [`references/platforms/x-articles.md`](references/platforms/x-articles.md) |
| "Mention a company on LinkedIn" | See [`references/platforms/linkedin.md`](references/platforms/linkedin.md) |
| "Show my X analytics / followers" | See [`references/platforms/x.md`](references/platforms/x.md) |
| "Comment on / resolve a comment" | See [`references/comments.md`](references/comments.md) |
---
## Commands
All commands output JSON. Every `[social_set_id]` is optional and falls back to the configured default.
> **Safety note**: `drafts:get`, `drafts:update`, `drafts:delete`, `drafts:schedule`, `drafts:plan`, and `drafts:publish` require `--use-default` when you pass a single argument (the draft_id) while a default social set is configured.
Platform- and workflow-specific commands live in their guides: [`platforms/x.md`](references/platforms/x.md) (analytics, quotes, replies, communities, disclosures), [`platforms/linkedin.md`](references/platforms/linkedin.md) (mentions), [`platforms/x-articles.md`](references/platforms/x-articles.md), [`comments.md`](references/comments.md), and [`setup.md`](references/setup.md).
### User & social sets
| Command | Description |
|---------|-------------|
| `me:get` | Get authenticated user info |
| `social-sets:list` | List all social sets you can access |
| `social-sets:get <id>` | Social set details including connected platforms and `publishing_quota` |
`social-sets:get` returns a `publishing_quota` object when available: `used`, `remaining` (or `"unlimited"`), and `resets_at`. Check it before publishing/scheduling when the user asks about capacity or when a publish/schedule fails with quota copy.
### Drafts
Every draft command accepts an optional leading `[social_set_id]` that falls back to the configured default. The four base commands:
| Command | Description |
|---------|-------------|
| `drafts:list [social_set_id]` | List drafts. Filter with `--status scheduled\|published\|...`, order with `--sort` |
| `drafts:get [social_set_id] <draft_id>` | Get a draft with full content. Add `--exclude-comment-markers` to render `posts[*].text` without comment anchors (display only) |
| `drafts:create [social_set_id] --text "<post text>"` | Create a draft (auto-selects platform if `--platform` omitted) |
| `drafts:update [social_set_id] <draft_id> --text "<post text>"` | Replace a draft's content |
Add any of these flags to a `drafts:create` or `drafts:update` command. The **Applies to** column shows where each is valid:
| Flag | Effect | Applies to |
|------|--------|-----------|
| `--platform x,linkedin` | Target specific platform(s), comma-separated | create, update |
| `--all` | All connected platforms (excludes `x_article`) | create |
| `--file <path>` | Read content from a file instead of `--text` | create, update |
| `--append --text "<text>"` | Append to an existing thread | update |
| `--media <media_ids>` | Attach media (comma-separated) | create, update |
| `--tags "tag1,tag2"` | Set tags (content stays unchanged if this is the only change on update) | create, update |
| `--title "<internal title>"` | Internal draft title (not posted) | create, update |
| `--scratchpad "<notes>"` | Attach internal notes (see [Scratchpad notes](#scratchpad-notes)) | create, update |
| `--share` | Generate a public share URL | create, update |
| `--schedule <iso\|next-free-slot\|now>` | Schedule or reschedule the draft | create, update |
| `--plan <iso\|next-free-slot>` | Plan the draft: dated but inert until confirmed (mutually exclusive with `--schedule`; `null` on update returns it to plain draft) | create, update |
| `--hide-link-preview` | Suppress the link-preview card (LinkedIn/Threads/Substack only — see [Link previews](#link-previews)) | create, update |
| `--exclude-comment-markers` | Render response without anchors (display only; validation still applies) | update |
| `--force-overwrite-comments` | Destructive last resort — see [`comments.md`](references/comments.md) | update |
For example, combine the base command with flags like this:
```bash
./scripts/typefully.js drafts:create --text "Launch day!" --platform x,linkedin --tags product --schedule next-free-slot
./scripts/typefully.js drafts:update 456 --text "Revised copy" --media abc-123 --use-default
```
> X-only draft flags (`--reply-to`, `--quote-post-url`, `--community`, `--paid-partnership`, `--made-with-ai`): see [`platforms/x.md`](references/platforms/x.md). X Article flags (`--content-markdown`, `--cover-media-id`): see [`platforms/x-articles.md`](references/platforms/x-articles.md).
### Scheduling & publishing
Single-arg forms require `--use-default` when a default social set is configured.
| Command | Description |
|---------|-------------|
| `drafts:schedule <social_set_id> <draft_id> --time <iso\|next-free-slot>` | Schedule to a time or the next available slot (also confirms a planned draft) |
| `drafts:plan <social_set_id> <draft_id> --time <iso\|next-free-slot>` | Plan to a date without arming auto-publish; confirm later with `drafts:schedule` |
| `drafts:publish <social_set_id> <draft_id>` | Publish immediately |
| `drafts:delete <social_set_id> <draft_id>` | Delete a draft |
### Queue
The queue is a **social-set-specific timeline**: free queue slots (from the social set's queue schedule) plus scheduled and planned drafts/posts for that same social set. Use `queue:get` when the user asks what is scheduled or free for an account in a date range.
| Command | Description |
|---------|-------------|
| `queue:get [social_set_id] --start-date <YYYY-MM-DD> --end-date <YYYY-MM-DD>` | Queue timeline: free slots + scheduled/planned drafts and posts in a date range (check each draft's `status` — planned drafts never auto-publish) |
| `queue:schedule:get [social_set_id]` | Get queue schedule rules |
| `queue:schedule:put [social_set_id] --rules '[{"h":9,"m":30,"days":["mon","wed","fri"]}]'` | Replace queue schedule rules (full replacement) |
Snake-case date aliases (`--start_date`, `--end_date`) are accepted.
### Tags
Tags are scoped per social set — a tag in one social set doesn't appear in another. Check existing tags before creating.
| Command | Description |
|---------|-------------|
| `tags:list [social_set_id]` | List all tags |
| `tags:create [social_set_id] --name "Tag Name"` | Create a new tag |
### Media
| Command | Description |
|---------|-------------|
| `media:upload [social_set_id] <file_path>` | Upload media, wait for processing, return ready `media_id` |
| `media:upload ... --no-wait` | Upload and return immediately (poll with `media:status`) |
| `media:upload ... --timeout <seconds>` | Custom processing timeout (default 60) |
| `media:status [social_set_id] <media_id>` | Check upload status |
### Examples
```bash
# Create a tweet (default social set)
./scripts/typefully.js drafts:create --text "Hello, world!"
# Explicit social_set_id
./scripts/typefully.js drafts:create 123 --text "Hello, world!"
# Cross-platform, same content
./scripts/typefully.js drafts:create --platform x,linkedin,threads --text "Big announcement!"
./scripts/typefully.js drafts:create --all --text "Posting everywhere!"
# Create and schedule for the next slot
./scripts/typefully.js drafts:create --text "Scheduled post" --schedule next-free-slot
# Create with tags
./scripts/typefully.js drafts:create --text "Marketing post" --tags marketing,product
# List scheduled posts, newest scheduled first
./scripts/typefully.js drafts:list --status scheduled --sort scheduled_date
# Queue view for a date range
./scripts/typefully.js queue:get --start-date 2026-02-01 --end-date 2026-02-29
# Replace queue schedule rules
./scripts/typefully.js queue:schedule:put --rules '[{"h":9,"m":30,"days":["mon","wed","fri"]}]'
# Draft with scratchpad notes
./scripts/typefully.js drafts:create --text "Launching next week!" --scratchpad "Coordinate with marketing before publishing."
# Upload media, then attach it
./scripts/typefully.js media:upload ./image.jpg # -> {"media_id": "abc-123", "status": "ready"}
./scripts/typefully.js drafts:create --text "Check out this image!" --media abc-123
# Add media to an existing draft
./scripts/typefully.js drafts:update 456 --text "Updated post with image" --media xyz --use-default
```
---
## Reference
### Character limits
X 280 · LinkedIn 3000 · Threads 500 · Bluesky 300 · Mastodon 500 · Substack Notes 10000.
### Draft URLs
Typefully draft URLs encode the social set and draft IDs: `https://typefully.com/?a=<social_set_id>&d=<draft_id>` (e.g. `a=12345` → social_set_id, `d=67890` → draft_id). See [Dropped Typefully draft URLs](#dropped-typefully-draft-urls) for the command mapping.
### Automation guidelines
To keep accounts in good standing, especially on X:
- No duplicate content across accounts.
- No unsolicited automated replies — only reply when the user explicitly requests it.
- No trending manipulation, no fake engagement (likes/reposts/follows).
- Respect rate limits; drafts stay private until published or explicitly shared.
When in doubt, create drafts for user review rather than publishing directly.
Usage Instructions
Learn how to use this skill with different AI agents.
As a Claude Code plugin:
/plugin marketplace add typefully/agent-skills
/plugin install typefully@typefully-skillsSettings (Cmd+Shift+J) → Rules & Command → Project Rules → Add Rule → Remote Rule (GitHub), then enter https://github.com/typefully/agent-skills.git.
npx skills add typefully/agent-skillsThen run ./scripts/typefully.js setup (or set TYPEFULLY_API_KEY) to authenticate against your Typefully account.
Description
The official agent skill from Typefully, the writing and scheduling tool used by 200k+ creators and teams. It gives a coding agent a working social-publishing pipeline without leaving the editor.
Everything runs through a bundled Node.js script (scripts/typefully.js, Node 18+, zero dependencies) that wraps the Typefully API and returns JSON, so the agent gets structured output it can act on rather than scraped HTML. Drafts can be created, listed, scheduled, published and threaded across X, LinkedIn, Threads, Bluesky, Mastodon and Substack Notes from one call.
A nice touch: the skill maps dropped Typefully draft URLs. Paste https://typefully.com/?a=<social_set_id>&d=<draft_id> into a conversation and the agent resolves it to the right drafts:get call instead of trying to browse the web UI — the kind of small affordance that decides whether a skill actually gets used.
It is also unusually disciplined about failure. On an authentication error the skill instructs the agent to tell you to re-run setup or refresh TYPEFULLY_API_KEY and stop — explicitly forbidding it from hunting for credentials elsewhere, scraping the web UI, or falling back to a localhost dev server. It carries a last-updated stamp (2026-07-29) and tells the agent to warn you if it is more than 30 days stale. Reference guides for setup, comments and draft workflows are loaded only when a task needs them, keeping the resident context small.
MIT licensed.
Related Skills
Vercel's official skill for reviewing documentation and prose against its writing handbook — voice, structure, code samples and typography, reported as file:line findings.
Drive a HEY account from an agent through the HEY CLI — Imbox and screener, threads, replies, drafts, contacts, calendar, todos, habits, time tracking and journal entries.

Skill: Notion Meeting Intelligence
by Notion
Notion's official meeting-prep skill: searches the workspace for context, enriches it with research, then writes an internal pre-read and an external agenda back into Notion.