# Social Post

> Use when the user wants to draft social media posts for LinkedIn or X (Twitter) from a blog post, case study, or raw topic. Drafts by default; optionally publishes via LinkedIn or X API when credentials are configured.

- Skill: `busyeugene/social-post` (Agent Skill)
- Install (CLI): `npx skillmds@latest add busyeugene/social-post`
- Raw SKILL.md: https://api.skillmd.com/api/skills/busyeugene/social-post/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Integrations & APIs
- License: MIT
- Author: busyeugene (https://skillmd.com/u/busyeugene)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/busyeugene/social-post

---


# Social Post

Draft high-signal LinkedIn and X posts from a source article or topic. Always drafts to a local file; optionally publishes if the user explicitly asks and credentials are set.

## Setup

No required keys (draft-only mode). Optional:

- **LinkedIn publish:**
  - `LINKEDIN_ACCESS_TOKEN` — OAuth2 access token with `w_member_social` (personal) or `w_organization_social` (company page) scope
  - `LINKEDIN_AUTHOR_URN` — `urn:li:person:xxxx` or `urn:li:organization:xxxx`
- **X publish:**
  - `X_API_KEY`, `X_API_SECRET`, `X_ACCESS_TOKEN`, `X_ACCESS_TOKEN_SECRET` — OAuth1.0a user-context creds.
  - **Posting requires the Basic tier ($100/month) or higher.** The Free tier cannot call `POST /2/tweets` and returns 403. If the user only has Free, this skill drafts locally and skips publish.

Neither set is required for drafting.

## Inputs

1. **Source** — either a path to a blog post (preferred) or a raw topic/brief.
2. **Platforms** — `linkedin`, `x`, or `both`. Multi-select via `AskUserQuestion`.
3. **Format per platform:**
   - LinkedIn: `short` (≤600 chars, hook + punchline), `long` (800–1300 chars, 4–6 short paragraphs), `carousel-teaser` (post that points to a LinkedIn carousel).
   - X: `single` (one tweet ≤280 chars), `thread` (5–10 tweets), `long-tweet` (one post up to 25,000 chars for X Premium accounts).
4. **Number of variants** — default 3 per platform.
5. **CTA** — optional: link, lead magnet, demo booking, reply prompt.
6. **Publish or draft only** — default draft. Ask via `AskUserQuestion`.

## Process

### 1. Load context

- Read `editorial-guidelines.md` if present (fall back to shared voice reference).
- If the source is a blog post file, read it in full.
- If the source is a URL, fetch it via the scraping fallback chain.
- If the source is a raw topic, ask 2–3 quick questions to pin down angle and audience.

### 2. Extract angles

From the source, pull 5–8 candidate angles:
- The single strongest data point or number
- The most contrarian claim
- The one practical tactic a reader could apply today
- A surprising failure story (if present)
- A named opinion the author is willing to be wrong about
- A short framework (3–5 steps)

Rank angles by "would a tired practitioner stop scrolling for this?".

### 3. Draft per platform

For each requested platform and format, produce the requested number of variants using the top-ranked angles. Each variant must:

- **Open with a hook** (first line must be able to stand alone in the feed).
- **Never bury the lede** — the payoff is in line 1–2.
- **Obey the editorial guidelines** on voice, banned words, emoji policy, and POV.
- **Respect platform limits:**
  - LinkedIn short ≤600, long 800–1300 (before the "see more" cutoff is ~210 chars on mobile — make those first 210 chars hook the reader).
  - X single ≤280. Thread: each tweet ≤280, no "1/" numbering unless the user asks, end with a "why it matters" tweet and optional CTA tweet.
- **CTA placement:** LinkedIn → last 2 lines. X thread → final tweet. Never in the middle.
- **Hashtags:** LinkedIn 3–5 at the end, relevant not trendy. X 0–2 inline if they read naturally.
- **Emoji:** per guidelines; default none unless the brand voice allows it.

### 4. Output

Write to `social/<slug>-<platform>.md`. One file per platform. Structure:

```markdown
# Social — {slug} — {platform}

**Source:** {path or URL}
**Generated:** {YYYY-MM-DD}

---

## Variant 1 — {format}

{post body}

**Char count:** {n}
**Hook (first line):** {first line}
**Angle:** {which angle from step 2}

---

## Variant 2 — {format}
{…}
```

For X threads, write each tweet on its own line prefixed with `T1:`, `T2:`, etc., and include a char count per tweet.

### 5. Optional publish

Only if the user explicitly confirmed publish AND credentials are set.

**LinkedIn** — use the Posts API (`/rest/posts`). The old `/v2/ugcPosts` endpoint is deprecated.

```
POST https://api.linkedin.com/rest/posts
Authorization: Bearer ${LINKEDIN_ACCESS_TOKEN}
LinkedIn-Version: 202501
X-Restli-Protocol-Version: 2.0.0
Content-Type: application/json

{
  "author": "${LINKEDIN_AUTHOR_URN}",
  "commentary": "<post body>",
  "visibility": "PUBLIC",
  "distribution": {
    "feedDistribution": "MAIN_FEED",
    "targetEntities": [],
    "thirdPartyDistributionChannels": []
  },
  "lifecycleState": "PUBLISHED",
  "isReshareDisabledByAuthor": false
}
```

Use the current `LinkedIn-Version` header value (monthly `YYYYMM` format). Handle the `x-restli-id` response header as the post URN. Print the URN and the derived `https://www.linkedin.com/feed/update/{urn}/` URL.

**X:**

```
POST https://api.x.com/2/tweets
Authorization: OAuth <signed with OAuth1.0a>
Content-Type: application/json

{ "text": "<tweet body>" }
```

For threads, post sequentially and set `reply.in_reply_to_tweet_id` on each subsequent tweet. Stop on any 4xx and surface the error.

Confirm with the user one more time before the first publish call in any session.

### 6. Report

After drafting (and optional publishing), print:
- Files written
- Variants per platform
- If published: URNs/tweet IDs with direct links

## Fallbacks

- **Source fetch fails:** ask the user to paste the content or point to a local file.
- **No editorial guidelines:** use shared voice reference, note it.
- **LinkedIn/X API 401:** report the error, keep the local drafts, never retry silently.
- **Rate limited:** stop the thread, save progress, print which tweets posted and which didn't.

## Verification

1. One file per requested platform under `social/`.
2. Each variant respects platform character limits.
3. No banned words from editorial guidelines.
4. Every variant has an explicit hook identified.
5. If publish was requested, the report shows the real post URL or a clear error.

