| name | xurl |
| description | Use this skill when the user wants to do something on X with xurl, especially when they talk in task language like send a tweet, create an X post, reply to a post, send a DM, search posts, upload media, check mentions, or switch between X app accounts. Also use it for xurl sign-in and app setup problems such as OAuth, redirect URI, who-am-I checks, or managing multiple xurl apps. Prioritize user goals over technical wording: trigger even if the user never says CLI, command line, terminal, or script. Do not use it for general X API development in Python, Node.js, raw curl, mobile apps, or generic OAuth theory.
|
xurl — Agent Skill Reference
xurl is a CLI tool for the X API. It supports both shortcut commands (human/agent‑friendly one‑liners) and raw curl‑style access to any v2 endpoint. All commands return JSON to stdout.
Installation
Homebrew (macOS)
brew install --cask xdevplatform/tap/xurl
npm
npm install -g @xdevplatform/xurl
Shell script
curl -fsSL https://raw.githubusercontent.com/xdevplatform/xurl/main/install.sh | bash
Installs to ~/.local/bin. If it's not in your PATH, the script will tell you what to add.
Go
go install github.com/xdevplatform/xurl@latest
Prerequisites
This skill requires the xurl CLI utility: https://github.com/xdevplatform/xurl.
Before using any command you must be authenticated. Run xurl auth status to check.
First-Time Setup
If xurl auth status shows no apps registered, walk the user through these three steps before doing anything else. Each step requires the user to act manually outside the agent session — never pass credentials inline through the agent.
Step 1 — Register your app (user runs this manually, outside agent/LLM context):
xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
The user must obtain CLIENT_ID and CLIENT_SECRET from the X developer portal.
Step 2 — Set it as the default app:
xurl auth default my-app
Step 3 — Authenticate via OAuth 2.0:
xurl auth oauth2
This opens a browser for the OAuth flow. After completing it, tokens are saved to ~/.xurl and all subsequent commands will use them automatically.
Confirm setup is complete by running xurl auth status and xurl whoami before proceeding with the user's actual task.
Secret Safety (Mandatory)
- Never read, print, parse, summarize, upload, or send
~/.xurl (or copies of it) to the LLM context.
- Never ask the user to paste credentials/tokens into chat.
- The user must fill
~/.xurl with required secrets manually on their own machine.
- Do not recommend or execute auth commands with inline secrets in agent/LLM sessions.
- Warn that using CLI secret options in agent sessions can leak credentials (prompt/context, logs, shell history).
- Never use
--verbose / -v in agent/LLM sessions; it can expose sensitive headers/tokens in output.
- Sensitive flags that must never be used in agent commands:
--bearer-token, --consumer-key, --consumer-secret, --access-token, --token-secret, --client-id, --client-secret.
- To verify whether at least one app with credentials is already registered, run:
xurl auth status.
Register an app (recommended)
App credential registration must be done manually by the user outside the agent/LLM session.
After credentials are registered, authenticate with:
xurl auth oauth2
For multiple pre-configured apps, switch between them:
xurl auth default prod-app
xurl auth default prod-app alice
xurl --app dev-app /2/users/me
Other auth methods
Examples with inline secret flags are intentionally omitted. If OAuth1 or app-only auth is needed, the user must run those commands manually outside agent/LLM context.
If X does not return your username reliably through /2/users/me, pass an explicit handle to keep the token correctly associated:
xurl auth oauth2 YOUR_USERNAME
Tokens are persisted to ~/.xurl in YAML format. Each app has its own isolated tokens. Do not read this file through the agent/LLM. Once authenticated, every command below will auto‑attach the right Authorization header.
Clear Authentication
xurl auth clear --all
xurl auth clear --oauth1
xurl auth clear --oauth2-username USERNAME
xurl auth clear --bearer
Redirect URI Management
When working with multiple apps or custom callback URLs, you can inspect and update stored redirect URIs without touching credentials:
xurl auth apps redirect-uri get my-app
xurl auth apps redirect-uri set my-app http://localhost:8080/callback
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 | xurl like POST_ID |
| Unlike | xurl unlike POST_ID |
| Repost | xurl repost POST_ID |
| Undo repost | xurl unrepost POST_ID |
| Bookmark | xurl bookmark POST_ID |
| Remove bookmark | xurl unbookmark POST_ID |
| List bookmarks | xurl bookmarks -n 10 |
| List likes | xurl likes -n 10 |
| Follow | xurl follow @handle |
| Unfollow | xurl unfollow @handle |
| List following | xurl following -n 20 |
| List followers | xurl followers -n 20 |
| Block | xurl block @handle |
| Unblock | xurl unblock @handle |
| Mute | xurl mute @handle |
| Unmute | 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 |
| Media status (wait) | xurl media status --wait MEDIA_ID |
| App Management | |
| Register app | Manual, outside agent (do not pass secrets via agent) |
| List apps | xurl auth apps list |
| Update app creds | Manual, outside agent (do not pass secrets via agent) |
| View redirect URI | xurl auth apps redirect-uri get APP_NAME |
| Set redirect URI | xurl auth apps redirect-uri set APP_NAME URL |
| Remove app | xurl auth apps remove NAME |
| Set default (interactive) | xurl auth default |
| Set default (command) | xurl auth default APP_NAME [USERNAME] |
| Use app per-request | xurl --app NAME /2/users/me |
| Auth status | xurl auth status |
| Clear all tokens | xurl auth clear --all |
| Clear OAuth2 user token | xurl auth clear --oauth2-username USERNAME |
| Clear bearer token | xurl auth clear --bearer |
| Webhooks | |
| Start local webhook | xurl webhook start |
| Webhook with custom port | xurl webhook start -p 8081 -o events.log |
Post IDs vs URLs: Anywhere POST_ID appears above you can also paste a full post URL (e.g. https://x.com/user/status/1234567890) — xurl extracts the ID automatically.
Usernames: Leading @ is optional. @elonmusk and elonmusk both work.
Command Details
Posting
xurl post "Hello world!"
xurl media upload photo.jpg
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
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
User Info
xurl whoami
xurl user elonmusk
xurl user @XDevelopers
Timelines & Mentions
xurl timeline
xurl timeline -n 25
xurl mentions
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
xurl dms -n 25
Media Upload
xurl media upload photo.jpg
xurl media upload video.mp4
xurl media upload --media-type image/jpeg --category tweet_image photo.jpg
xurl media status MEDIA_ID
xurl media status --wait MEDIA_ID
xurl media upload meme.png
xurl post "lol" --media-id MEDIA_ID
Global Flags
These flags work on every command:
| Flag | Short | Description |
|---|
--app | | Use a specific registered app for this request (overrides default) |
--auth | | Force auth type: oauth1, oauth2, or app |
--username | -u | Which OAuth2 account to use (if you have multiple) |
--verbose | -v | Forbidden in agent/LLM sessions (can leak auth headers/tokens) |
--trace | -t | Add X-B3-Flags: 1 trace header |
Raw API Access
The shortcut commands cover the most common operations. For anything else, use xurl's raw curl‑style mode — it works with 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 -X POST -F path/to/file.mp4 '/2/media/upload?command=APPEND&media_id=MEDIA_ID&segment_index=0'
xurl https://api.x.com/2/users/me
Raw API Flags
| Flag | Short | Description |
|---|
-X METHOD | | HTTP method: GET, POST, PUT, DELETE, … |
-d BODY | | Request body (JSON string) |
-H HEADER | | Add a header (repeatable) |
-F FILE | | Multipart form-data file (for binary uploads) |
--stream | -s | Force streaming mode for any endpoint |
Direct Media Upload (Advanced)
For large or non-standard media, you can drive the chunked upload API directly with raw mode:
xurl -X POST '/2/media/upload?command=INIT&total_bytes=FILE_SIZE&media_type=video/mp4&media_category=tweet_video'
xurl -X POST -F path/to/file.mp4 '/2/media/upload?command=APPEND&media_id=MEDIA_ID&segment_index=0'
xurl -X POST '/2/media/upload?command=FINALIZE&media_id=MEDIA_ID'
xurl '/2/media/upload?command=STATUS&media_id=MEDIA_ID'
xurl media status --wait MEDIA_ID
For most images and short videos, the xurl media upload shortcut handles all of this automatically.
Streaming
Streaming endpoints are auto‑detected. Known streaming endpoints include:
/2/tweets/search/stream
/2/tweets/sample/stream
/2/tweets/sample10/stream
/2/tweets/firehose/stream/lang/en
/2/tweets/firehose/stream/lang/ja
/2/tweets/firehose/stream/lang/ko
/2/tweets/firehose/stream/lang/pt
You can force streaming on any endpoint with -s:
xurl -s /2/some/endpoint
Webhooks
xurl can spin up a temporary local webhook server backed by ngrok for development and testing:
xurl webhook start
xurl webhook start -p 8081 -o webhook_events.log
The command outputs a public ngrok URL (e.g. https://abc123.ngrok-free.app/webhook). Use that URL to register a webhook with the X API:
xurl --auth app /2/webhooks -d '{"url": "https://abc123.ngrok-free.app/webhook"}' -X POST
xurl webhook start handles the CRC handshake automatically and logs incoming POST events. Set NGROK_AUTHTOKEN in the environment to skip the interactive ngrok authtoken prompt.
Output Format
All commands return JSON to stdout, pretty‑printed with syntax highlighting. The output structure matches the X API v2 response format. A typical response looks like:
{
"data": {
"id": "1234567890",
"text": "Hello world!"
}
}
Errors are also returned as JSON:
{
"errors": [
{
"message": "Not authorized",
"code": 403
}
]
}
Common Workflows
Post with an image
xurl media upload photo.jpg
xurl post "Check out this photo!" --media-id MEDIA_ID
Reply to a conversation
xurl read https://x.com/user/status/1234567890
xurl reply 1234567890 "Here are my thoughts..."
Search and engage
xurl search "topic of interest" -n 10
xurl like POST_ID_FROM_RESULTS
xurl reply POST_ID_FROM_RESULTS "Great point!"
Check your activity
xurl whoami
xurl mentions -n 20
xurl timeline -n 20
Set up multiple apps
xurl auth default prod
xurl auth oauth2
xurl auth default staging
xurl auth oauth2
xurl auth default prod alice
xurl --app staging /2/users/me
Error Handling
- Non‑zero exit code on any error.
- API errors are printed as JSON to stdout (so you can still parse them).
- Auth errors suggest re‑running
xurl auth oauth2 or checking your tokens.
- If a command requires your user ID (like, repost, bookmark, follow, etc.), xurl will automatically fetch it via
/2/users/me. If that fails, you'll see an auth error.
Notes
- Rate limits: The X API enforces rate limits per endpoint. If you get a 429 error, wait and retry. Write endpoints (post, reply, like, repost) have stricter limits than read endpoints.
- Scopes: OAuth 2.0 tokens are requested with broad scopes. If you get a 403 on a specific action, your token may lack the required scope — re‑run
xurl auth oauth2 to get a fresh token.
- Token refresh: OAuth 2.0 tokens auto‑refresh when expired. No manual intervention needed.
- Multiple apps: Each app has its own isolated credentials and tokens. Configure credentials manually outside agent/LLM context, then switch with
xurl auth default or --app.
- Multiple accounts: You can authenticate multiple OAuth 2.0 accounts per app and switch between them with
--username / -u or set a default with xurl auth default APP USER.
- Default user: When no
-u flag is given, xurl uses the default user for the active app (set via xurl auth default). If no default user is set, it uses the first available token.
- Token storage:
~/.xurl is YAML. Each app stores its own credentials and tokens. Never read or send this file to LLM context.
client-forbidden / client-not-enrolled errors: If OAuth succeeds but reads (like xurl whoami) fail with these errors, the fix is to move the app to the Pay-per-use package in the Production environment via the X developer console (Apps → Manage apps → Move to package). This is an X platform enrollment issue, not a local xurl issue.
- Username not returned by
/2/users/me: On some X developer accounts, /2/users/me may not reliably return your username after auth. Work around this by authenticating with an explicit handle: xurl auth oauth2 YOUR_USERNAME.