Skip to content
Development
Skill

/x-api

Post tweets, build threads, upload media via the X API.

From plugin
vexjoy-agent
421122 skills198 agents11 commands76 hooks
Install
$ npx -y skills add notque/vexjoy-agent --skill x-api --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/x-api

Context preview

The summary Claude sees to decide when to auto-load this skill.

Post tweets, build threads, upload media via the X API.

SKILL.md

x-api.SKILL.md
name: x-api
description: "Post tweets, build threads, upload media via the X API."
user-invocable: false
agent: python-general-engineer
allowed-tools:
  - Read
  - Write
  - Bash
  - Glob
routing:
  triggers:
    - post to X
    - post tweet
    - tweet this
    - build thread
    - post thread
    - twitter thread
    - x api
    - upload media to X
    - read timeline
    - search X
    - search twitter
    - publish to X
    - publish to twitter
  pairs_with:
    - content-calendar
  complexity: Medium
  category: content-publishing

X API Skill

Overview

This skill orchestrates OAuth-authenticated, rate-limit-aware X/Twitter API interactions through a deterministic Python script (`scripts/x-api-poster.py`). The workflow implements a 4-phase pipeline with an explicit confirmation gate (Phase 2) to prevent accidental public posts.

**Core principles**:

  • Always validate credentials and content before any network call
  • The confirm gate is mechanically enforced by the script (refuses write ops without `--confirmed`)
  • Credentials flow from environment variables only; the operator never configures auth mode
  • Rate limits are surfaced immediately if remaining capacity drops below 10

---

Instructions

Phase 1: VALIDATE

**Goal**: Confirm credentials, content, and dependencies before any network call.

**Step 1: Check credentials**

Test credential presence by running a dry-run credential check:

python3 $HOME/.claude/scripts/x-api-poster.py post --dry-run --text "ping"

This confirms all required environment variables are set: `X_API_KEY`, `X_API_SECRET`, `X_ACCESS_TOKEN`, `X_ACCESS_SECRET`, `X_BEARER_TOKEN`.

  • For read-only operations (timeline, search), only `X_BEARER_TOKEN` is required
  • For write operations (post, thread), all five are required
  • If any required variables are missing, the script exits with a clear error; surface it to the user and stop
  • **Important**: Never pass credentials as command arguments or store in files — always read from environment

**Step 2: Validate content length**

The script enforces a 280-character limit per tweet. Before posting, validate your content length:

For a single tweet:

python3 $HOME/.claude/scripts/x-api-poster.py post --dry-run --text "your tweet text here"

For a thread:

python3 $HOME/.claude/scripts/x-api-poster.py thread --dry-run --texts "part 1" "part 2" "part 3"

If `--dry-run` reports a length error, ask the user to shorten the text or approve auto-segmentation into a thread.

**Gate**: Dry run exits 0, content length validates, credentials confirmed present. Proceed only when gate passes.

---

Phase 2: CONFIRM

**Goal**: Show the user exactly what will be posted and require explicit approval before writing.

This gate is mandatory because X posts are public and irreversible. Present a content preview in this format:

CONTENT PREVIEW
================
Tweet 1/1:
  "Your tweet text here"
  Characters: 42/280

Action: POST single tweet

Approve? [yes/no]

For a thread:

CONTENT PREVIEW
================
Tweet 1/3:
  "First part text"
Tweet 2/3:
  "Second part text"
Tweet 3/3:
  "Third part text"

Action: POST thread (3 tweets, chained replies)

Approve? [yes/no]

**Wait for explicit user approval.** The words "yes", "approve", "go ahead", "post it", or equivalent typed in the current conversation turn constitute approval. Do not infer approval from context or prior conversation turns. Do not pass `--confirmed` before the user provides explicit typed approval.

**Gate**: User has typed an explicit approval in this conversation turn. Proceed only when gate passes.

---

Phase 3: POST

**Goal**: Execute the write operation and capture tweet IDs.

Only proceed once Phase 2 approval is confirmed. Pass the `--confirmed` flag when the user approves in this turn.

**Single tweet:**

python3 $HOME/.claude/scripts/x-api-poster.py post \
  --confirmed \
  --text "your tweet text here"

**Thread:**

python3 $HOME/.claude/scripts/x-api-poster.py thread \
  --confirmed \
  --texts "part 1" "part 2" "part 3"

**Tweet with media:**

python3 $HOME/.claude/scripts/x-api-poster.py post \
  --confirmed \
  --text "your tweet text here" \
  --media /absolute/path/to/image.jpg

**Media constraints**: Images must be <= 5 MB (JPG, PNG, GIF); videos must be <= 512 MB (MP4). Media upload is a two-step process; if either step fails, no orphaned media is left behind. Confirm the file exists and is in a supported format before posting.

Watch output for:

  • `[tweet-posted] id=... url=...` — success line per tweet; contains canonical URL (https://x.com/i/web/status/{id})
  • `[rate-limit-warning] remaining=N reset=EPOCH` — surface to user immediately if present
  • Any `ERROR:` line — surface verbatim and stop

**OAuth mode is automatic**: Read operations use Bearer token only; write operations require full OAuth 1.0a. The script selects the mode based on operation type — do not override it.

**Gate**: Script exits 0, at least one `[tweet-posted]` line in output. Proceed only when gate passes.

---

Phase 4: REPORT

**Goal**: Return tweet URLs, IDs, and engagement baseline to the user.

**Step 1: Collect tweet IDs from Phase 3 output**

Parse all `[tweet-posted] id=... url=...` lines from the script output.

**Step 2: Read engagement baseline (optional)**

For each posted tweet, you may optionally read initial engagement metrics via:

python3 $HOME/.claude/scripts/x-api-poster.py read-timeline --user-id me --max-results 5

**Engagement metrics have propagation delay**: X API metrics take time to populate. Reading `public_metrics` immediately after posting with 0 impressions is expected behavior, not failure. Report metrics as baseline at post time and note they will grow asynchronously.

**Step 3: Report to user**

Provide:

  • Tweet URL(s) as clickable links
  • Tweet ID(s) for reference
  • Thread structure if applicable (N tweets, root ID)
  • An
Read more
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. VexJoy Agent connects plain-English requests to specialist agents, skills, and workflows. /do selects the knowledge and tools needed for your task.

Get the whole plugin

Other skills on vexjoy-agent.