en un clic
xurl
X/Twitter via xurl CLI: post, search, DM, media, v2 API.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Menu
X/Twitter via xurl CLI: post, search, DM, media, v2 API.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Basé sur la classification professionnelle SOC
Drive Igor's already-authenticated Google Chrome via AppleScript for login-walled dashboards (Stripe Payment Links, Apollo web, Play Console, LinkedIn, ASC). NEVER use Playwright MCP as the source of truth for "am I logged in?" — Playwright is a separate browser profile without Chrome cookies. Trigger when: Stripe, payment links, buy.stripe.com, dashboard.stripe.com, "logged into Chrome", login wall, Playwright got login page but user says they're signed in, Apollo web UI, or any task needs the real Chrome session. Slash: /drive-logged-in-chrome. Cross-ref: use-existing-browser-sessions.
When Igor pastes ANY credential (password, API key, token, client secret) in chat, immediately ingest it into macOS Keychain, confirm service+account only, never refuse with "don't send passwords / rotate yourself" homework. Auto-invoke on credential paste. Covers App Store Connect Apple ID, Play, Stripe, fleet ENV keys, EAS tokens.
Execute the real cash path for mac-yolo-safeguards / ThumbGate: diagnose funnel, Apollo enrich, Gmail send, live Stripe links from Chrome, pipeline-update, never ship theater. Trigger when: make money, make money today, do everything, cash, revenue, sell, close, outreach, pipeline stuck, $0 revenue, Partner Pilot, diagnostic $499, hardening $1500, or when tempted to build another sales tool instead of sending. Slash: /execute-revenue-cash-path. Do NOT invoke for pure product engineering without a revenue ask.
Use Apollo.io for sales contact discovery and email enrichment on Igor's Mac. CLI: /opt/homebrew/bin/apollo (apollo-io-cli), already authenticated. Trigger when: make money, outreach, prospects, enrich email, find founder email, no public email, pipeline send, Partner Pilot, cold call, leads, Apollo, or when tempted to give up because leads.csv says "no public email." Slash: /apollo-io-sales. NEVER skip Apollo when money depends on a real inbox.
Drive Igor's already-authenticated Google Chrome via AppleScript for login-walled dashboards (Stripe Payment Links, Apollo web, Play Console, LinkedIn, ASC). NEVER use Playwright MCP as the source of truth for "am I logged in?" — Playwright is a separate browser profile without Chrome cookies. Trigger when: Stripe, payment links, buy.stripe.com, dashboard.stripe.com, "logged into Chrome", login wall, Playwright got login page but user says they're signed in, Apollo web UI, or any task needs the real Chrome session. Slash: /drive-logged-in-chrome. Cross-ref: use-existing-browser-sessions.
Audits mac-yolo-safeguards GitHub ship readiness — pushed commits, open/stale PRs, CI workflow conclusions, Dependabot alerts. Use when user asks if everything is merged, CI passed, pushed, or security-clean. Evidence-only; no ship theater.
| name | xurl |
| description | X/Twitter via xurl CLI: post, search, DM, media, v2 API. |
| version | 1.1.1 |
| author | xdevplatform + hermes + Hermes Agent |
| license | MIT |
| platforms | ["linux","macos"] |
| prerequisites | {"commands":["xurl"]} |
| metadata | {"hermes":{"tags":["twitter","x","social-media","xurl","official-api"],"homepage":"https://github.com/xdevplatform/xurl","upstream_skill":"https://github.com/hermes/hermes/blob/main/skills/xurl/SKILL.md"}} |
xurl is the X developer platform's official CLI for the X API. It supports shortcut commands for common actions AND raw curl-style access to any v2 endpoint. All commands return JSON to stdout.
Use this skill for:
This skill replaces the older xitter skill (which wrapped a third-party Python CLI). xurl is maintained by the X developer platform team, supports OAuth 2.0 PKCE with auto-refresh, and covers a substantially larger API surface.
Critical rules when operating inside an agent/LLM session:
~/.xurl to LLM context.~/.xurl with secrets manually on their own machine. In Docker, this must be the ~ seen by Hermes tool subprocesses; see the Docker note below.--verbose / -v in agent sessions — it can expose auth headers/tokens.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 (xurl auth apps add with --client-id / --client-secret) must be done by the user manually, outside the agent session — those flags accept inline secrets.
OAuth2 token completion is agent work when the app is already registered. On Igor's Mac fleet (~/.hermes/SOUL.md No constraints + use-existing-browser-sessions), the agent MUST complete xurl auth oauth2 via terminal + browser/computer_use — never hand terminal homework to the phone user.
When xurl auth status shows a named app with client_id but oauth2: (none):
Run OAuth on the Mac (api_server host), not on the phone:
xurl auth oauth2 --app APP_NAME USERNAME
This opens a local browser on the Mac. If the callback listener times out, use headless + browser tools:
xurl auth oauth2 --headless --app APP_NAME USERNAME
Then browser_navigate to the printed authorize URL (Igor's signed-in Chrome / CDP 127.0.0.1:9222), click Authorize, capture the http://localhost:8080/callback?...&code=... redirect, and paste the full redirect URL (or code) back into the waiting xurl terminal prompt.
Never tell the user to "run this in your local terminal" — especially from Hermes Mobile chat. Phone users cannot run Mac terminal commands. Report progress as agent actions ("Completing X OAuth on your MacBook…") or an honest blocker after browser+terminal attempts fail.
Forbidden wrong flags: --skip-browser does not exist; use --headless when the default browser callback fails.
After OAuth succeeds: xurl auth default APP_NAME USERNAME, then xurl auth status and xurl whoami before any write/DM action.
Only escalate to human when: (a) app not registered yet (needs client-id/secret paste), or (b) X developer portal enrollment/billing blocks the app.
Tokens persist to ~/.xurl in YAML. Each app has isolated tokens. OAuth 2.0 tokens auto-refresh.
Pick ONE method. On Linux, the shell script or go install are the easiest.
# 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
Verify:
xurl --help
xurl auth status
If xurl is installed but auth status shows no apps at all, the user must register the app once (client-id/secret) — see the next section. If the app exists but oauth2: (none), the agent completes OAuth via Fleet operator override above.
Steps 1–4 must be performed by the user directly when no app is registered, because they involve pasting client-id/secret. Do not execute xurl auth apps add with inline secrets in agent sessions.
http://localhost:8080/callbackxurl auth apps add my-app --client-id YOUR_CLIENT_ID --client-secret YOUR_CLIENT_SECRET
xurl auth oauth2 --app my-app YOUR_USERNAME
xurl auth default my-app
xurl auth status
xurl whoami
After this, the agent can use any command below without further setup. OAuth 2.0 tokens auto-refresh.
Common pitfall: If you omit
--app my-appfromxurl auth oauth2, the OAuth token is saved to the built-indefaultapp profile — which has no client-id or client-secret. Commands will fail with auth errors even though the OAuth flow appeared to succeed. If you hit this, re-runxurl auth oauth2 --app my-appandxurl auth default my-app.
Docker HOME pitfall: In the official Hermes Docker layout,
/opt/dataisHERMES_HOME, but Hermes tool subprocesses use/opt/data/homeasHOME. That means~/.xurlresolves to/opt/data/home/.xurlfor Hermes-runxurlcommands, not/opt/data/.xurl. Run the user setup with the same HOME: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 statusIf
HOME=/opt/data xurl auth statussucceeds butHOME=/opt/data/home xurl auth statusshows no apps or tokens, Hermes tool calls will not see the credentials.
| 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.@.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
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
For X Articles, use raw API mode instead of the read shortcut. xurl read
expects a post ID or post URL; do not put read before a /2/tweets/...
endpoint. Request the article tweet field and ingest data.article.plain_text
from the JSON response:
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'
xurl whoami
xurl user elonmusk
xurl user @XDevelopers
xurl timeline -n 25
xurl mentions -n 20
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
xurl follow @XDevelopers
xurl unfollow @XDevelopers
xurl following -n 50
xurl followers -n 50
# Another user's graph
xurl following --of elonmusk -n 20
xurl followers --of elonmusk -n 20
xurl block @spammer
xurl unblock @spammer
xurl mute @annoying
xurl unmute @annoying
xurl dm @someuser "Hey, saw your post!"
xurl dms -n 25
# 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
The shortcuts cover common operations. For anything else, use raw curl-style mode against any X API v2 endpoint:
# 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
xurl -s /2/tweets/search/stream
# Full URLs also work
xurl https://api.x.com/2/users/me
| 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 endpoints are auto-detected. Known ones include:
/2/tweets/search/stream/2/tweets/sample/stream/2/tweets/sample10/streamForce streaming on any endpoint with -s.
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 } ] }
xurl media upload photo.jpg
xurl post "Check out this photo!" --media-id MEDIA_ID
xurl read https://x.com/user/status/1234567890
xurl reply 1234567890 "Here are my thoughts..."
xurl search "topic of interest" -n 10
xurl like POST_ID_FROM_RESULTS
xurl reply POST_ID_FROM_RESULTS "Great point!"
xurl whoami
xurl mentions -n 20
xurl timeline -n 20
xurl auth default prod alice # prod app, alice user
xurl --app staging /2/users/me # one-off against staging
/2/users/me. An auth failure there surfaces as an auth error.xurl --help and xurl auth status.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 <that-app> to fix it. This is the most common setup mistake — the user added an app with a custom name but never set it as default, so xurl keeps trying the empty default profile.xurl auth apps list empty), stop and direct user to app registration (client-id/secret paste only). If app exists but oauth2: (none), execute Fleet operator override — do NOT tell phone user to run terminal commands.xurl whoami, xurl user @handle, xurl search ... -n 3) to confirm reachability.~/.xurl contents back into the conversation.| Symptom | Cause | Fix |
|---|---|---|
| Auth errors after successful OAuth flow | Token saved to default app (no client-id/secret) instead of your named app | xurl auth oauth2 --app my-app then xurl auth default my-app |
unauthorized_client during OAuth | App type set to "Native App" in X dashboard | Change to "Web app, automated app or bot" in User Authentication Settings |
UsernameNotFound or 403 on /2/users/me right after OAuth | X not returning username reliably from /2/users/me | Re-run xurl auth oauth2 --app my-app YOUR_USERNAME (xurl v1.1.0+) to pass the handle explicitly |
| 401 on every request | Token expired or wrong default app | Check xurl auth status — verify ▸ points to an app with oauth2 tokens |
client-forbidden / client-not-enrolled | X platform enrollment issue | Dashboard → Apps → Manage → Move to "Pay-per-use" package → Production environment |
CreditsDepleted | $0 balance on X API | Buy credits (min $5) in Developer Console → Billing |
media processing failed on image upload | Default category is amplify_video | Add --category tweet_image --media-type image/png |
| Two "Client Secret" values in X dashboard | UI bug — first is actually Client ID | Confirm on the "Keys and tokens" page; ID ends in MTpjaQ |
xurl auth oauth2.xurl auth default or --app.-u / --username, or set a default with xurl auth default APP USER.~/.xurl is YAML. In Docker, use the Hermes subprocess HOME (/opt/data/home in the official image) so tokens land under /opt/data/home/.xurl. Never read or send this file to LLM context.