xurl

star 1

Interact with X (Twitter) via xurl, the official X API CLI: post, reply, quote, delete, search, read timelines/mentions, like, repost, bookmark, follow, DM, upload media, raw v2 endpoints. Triggers on "post to X", "tweet this", "reply to [X post]", "search X for", any x.com/status URL, or "xurl". Do NOT trigger on bare "X" meaning the letter, a variable, or an unknown.

chrisliu298 By chrisliu298 schedule Updated 6/12/2026

effort: high name: xurl description: | Interact with X (Twitter) via xurl, the official X API CLI: post, reply, quote, delete, search, read timelines/mentions, like, repost, bookmark, follow, DM, upload media, raw v2 endpoints. Triggers on "post to X", "tweet this", "reply to [X post]", "search X for", any x.com/status URL, or "xurl". Do NOT trigger on bare "X" meaning the letter, a variable, or an unknown. user-invocable: true allowed-tools: Bash(xurl:*)

xurl — X (Twitter) API via the Official CLI

xurl is the X developer platform's official CLI for the X API. It has shortcut commands for common actions AND raw curl-style access to any v2 endpoint. All commands return JSON to stdout.

Use this skill for:

  • posting, replying, quoting, deleting posts
  • searching posts and reading timelines/mentions
  • liking, reposting, bookmarking
  • following, unfollowing, blocking, muting
  • direct messages
  • media uploads (images and video)
  • raw access to any X API v2 endpoint
  • multi-app / multi-account workflows

Secret Safety (MANDATORY)

Critical rules when operating inside an agent/LLM session:

  • Never read, print, parse, summarize, upload, or send ~/.xurl to LLM context.
  • Never ask the user to paste credentials/tokens into chat.
  • The user fills ~/.xurl with secrets manually on their own machine.
  • Never recommend or execute auth commands with inline secrets in agent sessions.
  • Never use --verbose / -v in agent sessions — it can expose auth headers/tokens.
  • To verify credentials exist, only use: xurl auth status.

Forbidden flags in agent commands (they accept inline secrets): --bearer-token, --consumer-key, --consumer-secret, --access-token, --token-secret, --client-id, --client-secret

App credential registration and rotation must be done by the user manually, outside the agent session. Tokens persist to ~/.xurl in YAML. Each app has isolated tokens. OAuth 2.0 tokens auto-refresh.


Installation

Installed via Homebrew on this machine:

brew install --cask xdevplatform/tap/xurl

Other options: curl -fsSL https://raw.githubusercontent.com/xdevplatform/xurl/main/install.sh | bash, npm install -g @xdevplatform/xurl, or go install github.com/xdevplatform/xurl@latest.

Verify:

xurl --help
xurl auth status

One-Time User Setup (user runs these outside the agent)

These steps involve pasting secrets and must be done by the user directly. Direct the user to this block; do not execute it for them.

  1. Open an app at https://developer.x.com/en/portal/dashboard (redirect URI http://localhost:8080/callback if using OAuth 2.0).
  2. Register the app locally (user runs this):
    xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
    
  3. Authenticate with one of:
    • xurl auth oauth2 — browser PKCE flow (recommended; auto-refreshing tokens)
    • xurl auth app --bearer-token ... — app-only reads
    • xurl auth oauth1 --consumer-key ... --consumer-secret ... --access-token ... --token-secret ... — user-context v1.1
  4. Verify: xurl auth status and xurl whoami.

Quick Reference

Action Command
Post xurl post "Hello world!"
Reply xurl reply POST_ID "Nice post!"
Quote xurl quote POST_ID "My take"
Delete a post xurl delete POST_ID
Read a post xurl read POST_ID
Search posts xurl search "QUERY" -n 10
Who am I xurl whoami
Look up a user xurl user @handle
Home timeline xurl timeline -n 20
Mentions xurl mentions -n 10
Like / Unlike xurl like POST_ID / xurl unlike POST_ID
Repost / Undo xurl repost POST_ID / xurl unrepost POST_ID
Bookmark / Remove xurl bookmark POST_ID / xurl unbookmark POST_ID
List bookmarks / likes xurl bookmarks -n 10 / xurl likes -n 10
Follow / Unfollow xurl follow @handle / xurl unfollow @handle
Following / Followers xurl following -n 20 / xurl followers -n 20
Block / Unblock xurl block @handle / xurl unblock @handle
Mute / Unmute xurl mute @handle / xurl unmute @handle
Send DM xurl dm @handle "message"
List DMs xurl dms -n 10
Upload media xurl media upload path/to/file.mp4
Media status xurl media status MEDIA_ID
List apps xurl auth apps list
Remove app xurl auth apps remove NAME
Set default app xurl auth default APP_NAME [USERNAME]
Per-request app xurl --app NAME /2/users/me
Auth status xurl auth status

Notes:

  • POST_ID accepts full URLs too (e.g. https://x.com/user/status/1234567890) — xurl extracts the ID.
  • Usernames work with or without a leading @.

Command Details

Posting

xurl post "Hello world!"
xurl post "Check this out" --media-id MEDIA_ID
xurl post "Thread pics" --media-id 111 --media-id 222

xurl reply 1234567890 "Great point!"
xurl reply https://x.com/user/status/1234567890 "Agreed!"
xurl reply 1234567890 "Look at this" --media-id MEDIA_ID

xurl quote 1234567890 "Adding my thoughts"
xurl delete 1234567890

Reading & Search

xurl read 1234567890
xurl read https://x.com/user/status/1234567890

xurl search "golang"
xurl search "from:elonmusk" -n 20
xurl search "#buildinpublic lang:en" -n 15

Reading X long-form articles. When a post contains a long-form X article (the body is just a t.co link to x.com/i/article/...), xurl read returns only the title and a 500-status link — the article body isn't in the default response. Use raw mode and request the article tweet field:

xurl "/2/tweets/POST_ID?tweet.fields=article"

The response includes data.article with:

  • title — article headline
  • preview_text — short snippet
  • plain_text — full article body (this is what read is missing)
  • cover_media, media_entities — embedded image media keys; resolve via ?expansions=attachments.media_keys&media.fields=url

Not gated — don't mistake the thin response for a permissions block. The status: 500 on the t.co link and the title-only xurl read output look like the article is gated/blocked, but they are not. The body is simply absent from the default tweet fields; requesting tweet.fields=article returns plain_text in full with the same auth (no extra scope, no paid tier). If xurl read gives you only a title for an x.com/i/article/... link, always retry with the raw ?tweet.fields=article call before concluding it can't be read.

Users, Timeline, Mentions

xurl whoami
xurl user elonmusk
xurl user @XDevelopers

xurl timeline -n 25
xurl mentions -n 20

Engagement

xurl like 1234567890
xurl unlike 1234567890

xurl repost 1234567890
xurl unrepost 1234567890

xurl bookmark 1234567890
xurl unbookmark 1234567890

xurl bookmarks -n 20
xurl likes -n 20

Social Graph

xurl follow @XDevelopers
xurl unfollow @XDevelopers

xurl following -n 50
xurl followers -n 50

xurl following --of elonmusk -n 20
xurl followers --of elonmusk -n 20

xurl block @spammer
xurl unblock @spammer
xurl mute @annoying
xurl unmute @annoying

Direct Messages

xurl dm @someuser "Hey, saw your post!"
xurl dms -n 25

Media Upload

# Auto-detect type
xurl media upload photo.jpg
xurl media upload video.mp4

# Explicit type/category
xurl media upload --media-type image/jpeg --category tweet_image photo.jpg

# Videos need server-side processing — check status (or poll)
xurl media status MEDIA_ID
xurl media status --wait MEDIA_ID

# Full workflow
xurl media upload meme.png                  # returns media id
xurl post "lol" --media-id MEDIA_ID

Raw API Access

For anything not covered by shortcuts, use raw curl-style mode against any X API v2 endpoint:

xurl /2/users/me

xurl -X POST /2/tweets -d '{"text":"Hello world!"}'

xurl -X DELETE /2/tweets/1234567890

xurl -H "Content-Type: application/json" /2/some/endpoint

xurl -s /2/tweets/search/stream

xurl https://api.x.com/2/users/me

Global Flags

Flag Short Description
--app Use a specific registered app (overrides default)
--auth Force auth type: oauth1, oauth2, or app
--username -u Which OAuth2 account to use (if multiple exist)
--verbose -v Forbidden in agent sessions — leaks auth headers
--trace -t Add X-B3-Flags: 1 trace header

Streaming

Streaming endpoints are auto-detected. Known ones include /2/tweets/search/stream, /2/tweets/sample/stream, /2/tweets/sample10/stream. Force streaming on any endpoint with -s.


Output Format

All commands return JSON to stdout. Structure mirrors X API v2:

{ "data": { "id": "1234567890", "text": "Hello world!" } }

Errors are also JSON:

{ "errors": [ { "message": "Not authorized", "code": 403 } ] }

Error Handling

  • Non-zero exit code on any error.
  • API errors are still printed as JSON to stdout, so you can parse them.
  • Auth errors → have the user re-run xurl auth oauth2 (or the relevant auth subcommand) outside the agent session.
  • Commands that need the caller's user ID (like, repost, bookmark, follow, etc.) will auto-fetch it via /2/users/me. An auth failure there surfaces as an auth error.

Agent Workflow

  1. Verify prerequisites: xurl --help and xurl auth status.
  2. If auth is missing, stop and direct the user to the "One-Time User Setup" section — do NOT attempt to register apps or pass secrets yourself.
  3. Start with a cheap read (xurl whoami, xurl user @handle, xurl search ... -n 3) to confirm reachability.
  4. Confirm the target post/user and the user's intent before any write action (post, reply, like, repost, DM, follow, block, delete).
  5. Use JSON output directly — every response is already structured.
  6. Never paste ~/.xurl contents back into the conversation.

Notes

  • Rate limits: X enforces per-endpoint rate limits. A 429 means wait and retry. Write endpoints have tighter limits than reads.
  • Scopes: OAuth 2.0 tokens use broad scopes. A 403 on a specific action usually means the token is missing a scope — have the user re-run xurl auth oauth2.
  • Token refresh: OAuth 2.0 tokens auto-refresh.
  • Multiple apps: Each app has isolated credentials/tokens. Switch with xurl auth default or --app.
  • Multiple accounts per app: Select with -u / --username, or set a default with xurl auth default APP USER.
  • Token storage: ~/.xurl is YAML. Never read or send this file to LLM context.
  • Cost: X API access is typically paid for meaningful usage. Many failures are plan/permission problems, not code problems.

Attribution

Install via CLI
npx skills add https://github.com/chrisliu298/dotfiles --skill xurl
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator