X (Twitter) API client for posting, reading, and managing tweets. Authenticate with OAuth 2.0 (PKCE), post and delete tweets, read your timeline, search, and look up users — all from the command line.
aux4 aux4 pkger install community/x
Node.js is required (used by post, reply, and thread) and is installed automatically as a system dependency if missing.
Posting images/media is not supported yet.
You need an X Developer account and an app with OAuth 2.0 enabled:
Read and write (required to post)Native App — a public client, so no client secret is neededhttp://localhost:9876/callbackThe OAuth 2.0 Client ID is not the same as the Consumer Key (OAuth 1.0a) or the Bearer Token (app-only) — those cannot post on your behalf.
Posting also requires credits on your X API account; without them every call returns 402 credits depleted.
# Authenticate with X (opens browser for OAuth)
aux4 x login --clientId YOUR_CLIENT_ID
# Post a tweet
aux4 x post "Hello from aux4!"
# Post a whole thread from a file
aux4 x thread thread.md
# Read your timeline
aux4 x timeline
# Search tweets
aux4 x search "aux4 cli"
# Get your profile
aux4 x me
You can set credentials as environment variables to avoid passing them on every login:
| Variable | Description | |----------|-------------| | X_CLIENT_ID | X API client ID | | X_CLIENT_SECRET | X API client secret | | X_API_URL | X API base URL (default: https://api.x.com) |
aux4 x loginAuthenticate with X using OAuth 2.0 with PKCE. Opens a local callback server and prints a URL to authorize in the browser. After authorization, tokens are saved locally.
aux4 x login --clientId <id> [--clientSecret <secret>] [--scopes <scopes>] [--callbackPort <port>]
| Flag | Description | Default | |------|-------------|---------| | --clientId | OAuth 2.0 Client ID | required (or X_CLIENT_ID env) | | --clientSecret | Client secret — leave unset for a Native/public app | optional (or X_CLIENT_SECRET env) | | --scopes | Space-separated OAuth scopes | tweet.read tweet.write users.read offline.access | | --callbackPort | Local callback server port | 9876 |
Note: The redirect URL in your X app settings must match http://localhost:<port>/callback.
Drop tweet.write to grant a token that can read but never post, reply, or delete:
aux4 x login --clientId YOUR_CLIENT_ID --scopes "tweet.read users.read offline.access"
Keep offline.access so the token can refresh itself. Scopes are capped by your app's App permissions setting, and changing them requires logging in again.
aux4 x logoutRemove stored X credentials.
aux4 x logout
aux4 x statusShow X authentication status, including token expiry and scopes.
aux4 x status
aux4 x meGet your X profile information.
aux4 x me
aux4 x postPost a tweet. Pass the text directly — the request body is built for you.
aux4 x post <text>
| Flag | Description | Default | |------|-------------|---------| | text | The text of the tweet (positional argument) | required |
aux4 x post "Hello world!"
aux4 x replyReply to a tweet. Give the target tweet ID and the reply text; the reply is wired to the tweet for you.
aux4 x reply <tweetId> --text <text>
| Flag | Description | Default | |------|-------------|---------| | tweetId | ID of the tweet to reply to (positional argument) | required | | --text | The text of the reply | required |
aux4 x reply 1234567890 --text "Great post!"
aux4 x threadPost a whole thread from a file. Each post is published in order and chained as a reply to the previous one.
aux4 x thread <file> [--dryRun <true|false>]
| Flag | Description | Default | |------|-------------|---------| | file | Path to the thread file (positional argument) | required | | --dryRun | Print each request body instead of posting | false |
The file is split into posts on lines beginning with --- (for example --- Post 1); trailing metadata such as [attach: banner.png] or (chars: 230) on that line is ignored. This matches the format produced by the aux4-thread writing workflow, so a generated thread file can be posted as-is. Image attachments are not supported yet and are skipped with a note. If a post fails, the command stops and reports how many posts were already published.
# Preview the whole thread before posting
aux4 x thread thread.md --dryRun true
# Post it
aux4 x thread thread.md
aux4 x readRead a specific tweet by ID. Returns tweet text, author, creation date, and public metrics.
aux4 x read <tweetId>
aux4 x deleteDelete a tweet. Prompts for confirmation before deleting.
aux4 x delete <tweetId>
aux4 x timelineRead your home timeline.
aux4 x timeline [--maxResults <n>]
| Flag | Description | Default | |------|-------------|---------| | --maxResults | Number of tweets to return (1-100) | 10 |
aux4 x searchSearch recent tweets (up to 7 days).
aux4 x search <query> [--maxResults <n>]
| Flag | Description | Default | |------|-------------|---------| | query | Search query (positional argument) | required | | --maxResults | Number of results to return (10-100) | 10 |
# Simple search
aux4 x search "aux4 cli"
# Search with hashtag
aux4 x search "#opensource"
# Search from a user
aux4 x search "from:username"
aux4 x userLook up a user by username.
aux4 x user <username>
aux4 x user elonmusk
Tokens are stored in .oauth/x.json in the current directory. Add .oauth/ to your .gitignore. Tokens are automatically refreshed when expired.