BundledSocial MediaVersion 1.1.3

Xurl: Official X/Twitter API CLI for Hermes Agent

X/Twitter via xurl CLI: raw post search, posting, DM, media.

Written by Neura Market from the official Hermes Agent documentation for Xurl. Commands, paths, and version numbers are reproduced from the source unchanged.

Read the official documentation

xurl: X API v2 CLI Reference

xurl is the official command-line tool for the X (Twitter) API v2. It provides shortcut commands for common actions and raw curl-style access to any endpoint. All commands output JSON to stdout. Errors also return JSON with a non-zero exit code.

Setup

Prerequisites

Before using xurl, you must complete a one-time setup manually on your own machine. The tool stores credentials in ~/.xurl in YAML format. Never read, print, parse, summarize, upload, or send ~/.xurl to any LLM context.

Installation

Choose one of these methods:

# Shell script (installs to ~/.local/bin, no sudo, works on Linux + macOS)
curl -fsSL https://raw.githubusercontent.com/xdevplatform/xurl/main/install.sh | bash

# Homebrew (macOS)
brew install --cask xdevplatform/tap/xurl

# npm
npm install -g @xdevplatform/xurl

# Go
go install github.com/xdevplatform/xurl@latest

Docker Considerations

In Docker, the HOME environment variable must be /opt/data/home for Hermes tool subprocesses. The file ~/.xurl resolves to /opt/data/home/.xurl, not /opt/data/.xurl. If HOME=/opt/data xurl auth status succeeds but HOME=/opt/data/home xurl auth status shows no apps or tokens, Hermes tool calls will not see credentials. Use the following commands for Docker setup:

HOME=/opt/data/home xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
HOME=/opt/data/home xurl auth oauth2 --app my-app YOUR_USERNAME
HOME=/opt/data/home xurl auth default my-app YOUR_USERNAME
HOME=/opt/data/home xurl auth status

One-Time User Setup

This setup must be done manually, outside any agent session.

  1. Create or open an app at https://developer.x.com/en/portal/dashboard.
  2. Set the redirect URI to http://localhost:8080/callback.
  3. Copy the Client ID and Client Secret from the dashboard. Note: if you see two "Client Secret" values, the first is actually the Client ID. Confirm on the "Keys and tokens" page; a Client ID ends in MTpjaQ.
  4. Register the app locally:
    xurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
    
  5. Authenticate with OAuth 2.0 PKCE:
    xurl auth oauth2 --app my-app
    
    This opens a browser for the OAuth flow. If you get UsernameNotFound or a 403 error, use the explicit username form (v1.1.0+):
    xurl auth oauth2 --app my-app YOUR_USERNAME
    
  6. Set the app as default:
    xurl auth default my-app
    
  7. Verify everything works:
    xurl auth status
    xurl whoami
    

Authentication

Authentication Management

Multiple Apps

Each registered app has isolated credentials and tokens. Switch between apps with xurl auth default or the --app flag.

xurl auth default prod alice               # prod app, alice user
xurl --app staging /2/users/me             # one-off against staging

Multiple Accounts Per App

Use -u or --username to select a specific OAuth2 account when multiple exist for an app. Set a default user with xurl auth default APP USER.

Auth Status

xurl auth status

List and Remove Apps

xurl auth apps list
xurl auth apps remove NAME

Auth Type Override

Use the --auth flag to force a specific auth type: oauth1, oauth2, or app.

Agent Workflow

When using xurl in an automated agent session, follow these rules:

  • Verify prerequisites with xurl --help and xurl auth status.
  • Before using xurl search, confirm the task needs actual post objects, authenticated context, or leads to a write action.
  • Check the default app has credentials by parsing auth status output. The default app is marked with ▸. If the default app shows oauth2: (none) but another app has a valid oauth2 user, tell the user to run xurl auth default <app>.
  • If authentication is missing entirely, stop and direct the user to the One-Time User Setup. Do not attempt to register apps or pass secrets.
  • Start with a cheap read command (xurl whoami, xurl user @handle, xurl search ... -n 3) to confirm reachability.
  • Confirm the target post/user and the user's intent before any write action (post, reply, like, repost, DM, follow, block, delete).
  • Only xurl command output (or raw X API response) proves a state-changing X action happened. Never report a write as done based on search results, summaries, or prior context.
  • Use JSON output directly.
  • Never paste ~/.xurl contents into the conversation.

Forbidden Flags in Agent Sessions

Never use --verbose or -v in agent sessions, as they can leak auth headers or tokens. The following flags that accept inline secrets are also forbidden: --bearer-token, --consumer-key, --consumer-secret, --access-token, --token-secret, --client-id, --client-secret.

Post Operations

Create a Post

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

Reply to a Post

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

The shorthand xurl reply POST_ID "Nice post!" also works.

Quote a Post

xurl quote 1234567890 "Adding my thoughts"

The shorthand xurl quote POST_ID "My take" also works.

Delete a Post

xurl delete 1234567890

The shorthand xurl delete POST_ID also works.

Read a Post

Accepts either a post ID or a full URL like https://x.com/user/status/1234567890. The tool extracts the ID automatically.

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

The shorthand xurl read POST_ID also works.

Search Posts

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

The shorthand xurl search "QUERY" -n 10 also works.

X Articles

For X Articles, use raw API mode instead of the read shortcut. Request the article tweet field and ingest data.article.plain_text.

xurl --app APP_NAME '/2/tweets/2057909493250539891?expansions=author_id,attachments.media_keys,referenced_tweets.id&tweet.fields=created_at,lang,public_metrics,context_annotations,entities,possibly_sensitive,conversation_id,in_reply_to_user_id,referenced_tweets,article'

User Operations

Whoami (Current User)

xurl whoami

User Lookup

Usernames work with or without the leading @.

xurl user elonmusk
xurl user @XDevelopers

Timeline and Mentions

xurl timeline -n 25
xurl mentions -n 20

The shorthand xurl mentions -n 10 also works.

Engagement Operations

Like and Unlike

xurl like 1234567890
xurl unlike 1234567890

The shorthand xurl unlike POST_ID also works.

Repost and Undo Repost

xurl repost 1234567890
xurl unrepost 1234567890

The shorthand xurl repost POST_ID and xurl unrepost POST_ID also work.

Bookmark and Unbookmark

xurl bookmark 1234567890
xurl unbookmark 1234567890

The shorthand xurl bookmark POST_ID and xurl unbookmark POST_ID also work.

List Bookmarks and Likes

xurl bookmarks -n 20
xurl likes -n 20

The shorthand xurl bookmarks -n 10 and xurl likes -n 10 also work.

Social Graph Operations

Follow and Unfollow

xurl follow @XDevelopers
xurl unfollow @XDevelopers

The shorthand xurl follow @handle and xurl unfollow @handle also work.

Following and Followers Lists

Use --of to specify another user.

xurl following -n 50
xurl followers -n 50

# Another user's graph
xurl following --of elonmusk -n 20
xurl followers --of elonmusk -n 20

The shorthand xurl following -n 20 and xurl followers -n 20 also work.

Block and Unblock

xurl block @spammer
xurl unblock @spammer

The shorthand xurl block @handle and xurl unblock @handle also work.

Mute and Unmute

xurl mute @annoying
xurl unmute @annoying

The shorthand xurl mute @handle and xurl unmute @handle also work.

Direct Messages

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

The shorthand xurl dm @handle "message" and xurl dms -n 10 also work.

Media Upload

Upload Media

Auto-detects type from file extension. Use --media-type and --category for explicit control.

# 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

The shorthand xurl media upload path/to/file.mp4 also works.

Check Media Status

Videos need server-side processing. Check status with or without polling.

xurl media status MEDIA_ID
xurl media status --wait MEDIA_ID

Raw API Access

Access any X API v2 endpoint directly. Supports GET, POST, DELETE, PUT, and PATCH methods.

GET

xurl /2/users/me

POST with JSON Body

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

DELETE, PUT, PATCH

xurl -X DELETE /2/tweets/1234567890

Custom Headers

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

Force Streaming Mode

Use -s for streaming endpoints like /2/tweets/search/stream, /2/tweets/sample/stream, or /2/tweets/sample10/stream.

xurl -s /2/tweets/search/stream

Full URLs

Full URLs also work:

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

Workflows

Full Workflow: Post with Image

xurl media upload photo.jpg
xurl post "Check out this photo!" --media-id MEDIA_ID

Full Workflow: Reply to a Conversation

xurl read https://x.com/user/status/1234567890
xurl reply 1234567890 "Here are my thoughts..."

Full Workflow: Search and Engage

xurl search "topic of interest" -n 10
xurl like POST_ID_FROM_RESULTS
xurl reply POST_ID_FROM_RESULTS "Great point!"

Full Workflow: Check Your Activity

xurl whoami
xurl mentions -n 20
xurl timeline -n 20

Parameters Reference

ParameterMeaningRequired
--appUse a specific registered app (overrides default)No
--authForce auth type: oauth1, oauth2, or appNo
--username / -uWhich OAuth2 account to use (if multiple exist)No
--verbose / -vForbidden in agent sessions (leaks auth headers)No
--trace / -tAdd X-B3-Flags: 1 trace headerNo
-nNumber of results (search, timeline, mentions, bookmarks, likes, following, followers, dms)No
--media-idMedia ID to attach to a post or reply (can be repeated)No
--media-typeExplicit media type (e.g., image/jpeg) for uploadNo
--categoryMedia category (e.g., tweet_image, amplify_video) for uploadNo
--waitPoll media status until processing completeNo
--ofSpecify another user for following/followers listNo
-XHTTP method for raw API (GET, POST, DELETE, PUT, PATCH)No
-dJSON body for raw API POSTNo
-HCustom header for raw APINo
-sForce streaming mode for raw API endpointNo

Output Format

Successful responses look like this:

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

Error responses look like this:

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

Failure Modes and Troubleshooting

Auth Errors After Successful OAuth Flow

The token may have been saved to the default app (which has no client-id/secret) instead of the named app. Fix: run xurl auth oauth2 --app my-app then xurl auth default my-app.

unauthorized_client During OAuth

The app type is set to "Native App" in the X dashboard. Change it to "Web app, automated app or bot" in User Authentication Settings.

UsernameNotFound or 403 on /2/users/me After OAuth

X does not reliably return the username. Re-run with explicit username: xurl auth oauth2 --app my-app YOUR_USERNAME (v1.1.0+).

401 on Every Request

The token may be expired or the wrong default app is selected. Check xurl auth status and verify the ▸ points to an app with oauth2 tokens.

client-forbidden or client-not-enrolled

This is an X platform enrollment issue. Go to Dashboard, Apps, Manage, and move to the "Pay-per-use" package in the Production environment.

CreditsDepleted

Your X API account has a $0 balance. Buy credits (minimum $5) in Developer Console under Billing.

Media Processing Failed on Image Upload

The default category is amplify_video. Add --category tweet_image --media-type image/png for images.

Rate Limits

X enforces per-endpoint rate limits. A 429 response 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 a missing scope. Have the user re-run xurl auth oauth2.

Token Refresh

OAuth 2.0 tokens auto-refresh. No action needed.

Cost

X API access is typically paid for meaningful usage. Many failures are plan or permission problems, not code problems.

Important Constraints

  • Never read, print, parse, upload, or send ~/.xurl to any LLM context.
  • Never ask the user to paste credentials or tokens into chat.
  • App credential registration and rotation must be done by the user manually, outside an agent session.
  • After credentials are registered, the user authenticates with xurl auth oauth2, also outside an agent session.
  • Tokens persist to ~/.xurl in YAML. Each app has isolated tokens.
  • OAuth 2.0 tokens auto-refresh.
  • POST_ID accepts full URLs (e.g., https://x.com/user/status/1234567890) and xurl extracts the ID.
  • Usernames work with or without the leading @.
  • All commands return JSON to stdout. Errors also return JSON with a non-zero exit code.
  • Commands needing the caller's user ID (like, repost, bookmark, follow, etc.) auto-fetch via /2/users/me. An auth failure there surfaces as an auth error.
  • Never paste ~/.xurl contents back into the conversation.
  • The environment variable HERMES_HOME is used by the Hermes tool subprocesses; ensure it is set correctly for Docker deployments.
  • The xitter command is an alias for xurl in some contexts; use xurl for consistency.
  • The raw API path /2/tweets/... is used for direct tweet operations.
  • The xurl auth default APP_NAME [USERNAME] command sets the default app and optionally the default user.

More Social Media skills