Forked and extended from bird by @steipete (now private). Uses cookie auth extracted from your browser — no API key required.
Note: xcli uses X's internal, undocumented GraphQL API. It may break without notice. Use responsibly.
curl -fsSL https://raw.githubusercontent.com/gupsammy/xcli/main/install.sh | sudo shPin a specific version:
curl -fsSL https://raw.githubusercontent.com/gupsammy/xcli/main/install.sh | sudo VERSION=0.9.2 shirm https://raw.githubusercontent.com/gupsammy/xcli/main/install.ps1 | iexsudo rm /usr/local/bin/xcligit clone https://github.com/gupsammy/xcli
cd xcli
pnpm install
pnpm run build:binaryThe compiled binary will be at ./xcli. Move it to a directory on your $PATH.
# Show the logged-in account (verifies auth is working)
xcli whoami
# Post a tweet
xcli tweet "hello from xcli"
# Read a tweet by URL or ID
xcli read https://x.com/user/status/1234567890123456789
xcli 1234567890123456789 --json
# Fetch your home timeline
xcli home -n 20| Command | Description |
|---|---|
xcli tweet "<text>" |
Post a new tweet |
xcli reply <tweet-id-or-url> "<text>" |
Reply to a tweet |
xcli read <tweet-id-or-url> |
Fetch tweet content as text |
xcli <tweet-id-or-url> |
Shorthand for xcli read |
xcli replies <tweet-id-or-url> |
List replies to a tweet |
xcli thread <tweet-id-or-url> |
Show the full conversation thread |
xcli home |
Fetch your home timeline (For You or Following) |
xcli search "<query>" |
Search for tweets matching a query |
xcli mentions |
Find tweets mentioning you (or another user via --user) |
xcli user-tweets <@handle> |
Get tweets from a user's profile timeline |
xcli bookmarks |
List your bookmarked tweets |
xcli unbookmark <tweet-id-or-url...> |
Remove one or more bookmarks |
xcli likes |
List your liked tweets |
xcli news |
Fetch news and trending topics from X's Explore tabs |
xcli trending |
Alias for news |
xcli lists |
List your Twitter Lists (owned or memberships) |
xcli list-timeline <list-id-or-url> |
Get tweets from a list timeline |
xcli following |
List users you follow |
xcli followers |
List users who follow you |
xcli follow <username-or-id> |
Follow a user |
xcli unfollow <username-or-id> |
Unfollow a user |
xcli about <@handle> |
Get account origin and location metadata for a user |
xcli whoami |
Print which X account your cookies belong to |
xcli check |
Show which credentials are available and where they came from |
xcli query-ids |
Inspect or refresh the cached GraphQL query IDs |
xcli help [command] |
Show help (or help for a specific subcommand) |
Most list commands support --all, --max-pages <n>, --cursor <string>, and --delay <ms> for paginating through results. --max-pages requires --all or --cursor.
Query operator shortcuts for xcli search "<query>":
--from <username>— restrict to tweets from this user (shorthand forfrom:username; leading@is stripped)--since <period>— time window:1h,3h,12h,1d,7d(injects a precisesince_time:Unix timestamp)--min-likes <n>— minimum likes (min_faves:Noperator)--min-retweets <n>— minimum retweets--min-replies <n>— minimum replies--no-replies— exclude replies (-filter:repliesoperator)--quality— shorthand formin_faves:10; ignored if--min-likesis set
Result control:
--sort <order>—recent(default, chronological),top(Twitter's ranking),likes,retweets(client-side sort)--pages <n>— fetch N pages (20 tweets/page); shorthand for--all --max-pages N--limit <n>— cap results displayed after fetch and sort--markdown— print results as a research document to stdout--save— write results to~/clawd/drafts/as a markdown file (independent of--markdown)
Example:
xcli search "AI" --from sama --since 7d --min-likes 100 --sort top --limit 10
xcli search "open source" --no-replies --quality --pages 3 --saveThe bookmarks command has additional flags for controlling thread context in the output:
--expand-root-only— expand threads only when the bookmark is a root tweet--author-chain— keep only the bookmarked author's connected self-reply chain--author-only— include all tweets from the bookmarked author within the thread--full-chain-only— keep the entire reply chain connected to the bookmarked tweet--include-ancestor-branches— include sibling branches for ancestors (with--full-chain-only)--include-parent— include the direct parent tweet for non-root bookmarks--thread-meta— add thread metadata fields to each tweet--sort-chronological— sort output oldest to newest (default preserves bookmark order)
Tab filters for xcli news (combinable):
--for-you— For You tab--news-only— News tab--sports— Sports tab--entertainment— Entertainment tab--trending-only— Trending tab--ai-only— Filter to AI-curated headlines only--with-tweets— Include related tweets per news item
| Flag | Description |
|---|---|
--auth-token <token> |
Set the auth_token cookie manually |
--ct0 <token> |
Set the ct0 cookie manually |
--cookie-source <browser> |
Browser to extract cookies from: safari, chrome, firefox (repeatable) |
--chrome-profile <name> |
Chrome profile name (e.g. Default, Profile 2) |
--chrome-profile-dir <path> |
Chrome/Chromium profile directory or cookie DB path (for Arc, Brave, etc.) |
--firefox-profile <name> |
Firefox profile name for cookie extraction |
--cookie-timeout <ms> |
Timeout for cookie extraction via keychain/OS helpers |
--timeout <ms> |
Abort HTTP requests after this many milliseconds |
--quote-depth <n> |
Max quoted tweet depth in JSON output (default: 1; 0 disables) |
--plain |
Stable output: no emoji, no color |
--no-emoji |
Disable emoji output |
--no-color |
Disable ANSI colors |
--human |
Force human-readable output even when stdout is piped |
--media <path> |
Attach a media file (repeatable, up to 4 images or 1 video) |
--alt <text> |
Alt text for the corresponding --media (repeatable) |
--json |
Output machine-readable JSON |
Config is read in this priority order: CLI flags > env vars > project config > global config.
- Global:
~/.config/xcli/config.json5 - Project:
.xclirc.json5(in current working directory)
Example ~/.config/xcli/config.json5:
{
// Cookie source order for browser extraction (string or array)
cookieSource: ["firefox", "safari"],
// For Chromium variants (Arc, Brave, etc.)
chromeProfileDir: "/path/to/Chromium/Profile",
// Firefox profile name
firefoxProfile: "default-release",
// Timeouts in milliseconds
cookieTimeoutMs: 30000,
timeoutMs: 20000,
// Depth limit for quoted tweet expansion in JSON output
quoteDepth: 1,
// Secondary account for read-only commands (search, bookmarks, etc.)
// Useful to avoid rate-limiting your write account
secondaryCookieSource: "chrome",
secondaryChromeProfile: "Profile 2"
}| Variable | Description | Default |
|---|---|---|
XCLI_TIMEOUT_MS |
HTTP request timeout in milliseconds | 30000 |
XCLI_COOKIE_TIMEOUT_MS |
Cookie extraction timeout in milliseconds | 30000 |
XCLI_QUOTE_DEPTH |
Max quoted tweet depth in JSON output | 1 |
NO_COLOR |
Set to 1 to disable ANSI colors |
— |
xcli uses your existing X/Twitter web session — no API key or password prompt required. It reads the auth_token and ct0 cookies directly from your browser.
Credentials are resolved in this order:
- CLI flags:
--auth-tokenand--ct0 - Environment variables:
AUTH_TOKENandCT0(fallbacks:TWITTER_AUTH_TOKEN,TWITTER_CT0) - Browser cookies, extracted automatically from the sources configured via
--cookie-sourceorcookieSourcein config
Browser cookie locations:
- Safari:
~/Library/Cookies/Cookies.binarycookies - Chrome:
~/Library/Application Support/Google/Chrome/<Profile>/Cookies - Firefox:
~/Library/Application Support/Firefox/Profiles/<profile>/cookies.sqlite
For Chromium variants (Arc, Brave, etc.), use --chrome-profile-dir to point at a profile directory or cookie DB file directly.
To verify what credentials xcli found and where they came from:
xcli checkTo use a specific browser or profile:
xcli --cookie-source firefox whoami
xcli --cookie-source safari --cookie-source chrome whoami
xcli --chrome-profile-dir "/Users/you/Library/Application Support/Arc/User Data/Default" whoamiAdd --json to most commands for machine-readable JSON output. When using --json with pagination (--all, --cursor, --max-pages), output is { tweets, nextCursor }.
Add --json-full to include the raw API response in a _raw field (tweet commands only).
Use --plain for stable, script-friendly output with no emoji and no ANSI color codes.
| Field | Type | Description |
|---|---|---|
id |
string | Tweet ID |
text |
string | Full tweet text (includes Note/Article content when present) |
author |
object | { username, name } |
authorId |
string? | Author's user ID |
createdAt |
string | Timestamp |
replyCount |
number | Number of replies |
retweetCount |
number | Number of retweets |
likeCount |
number | Number of likes |
conversationId |
string | Thread conversation ID |
inReplyToStatusId |
string? | Parent tweet ID (present if this is a reply) |
quotedTweet |
object? | Embedded quote tweet (same schema; depth controlled by --quote-depth) |
| Field | Type | Description |
|---|---|---|
id |
string | User ID |
username |
string | Username/handle |
name |
string | Display name |
description |
string? | User bio |
followersCount |
number? | Followers count |
followingCount |
number? | Following count |
isBlueVerified |
boolean? | Blue verified flag |
profileImageUrl |
string? | Profile image URL |
createdAt |
string? | Account creation timestamp |
| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier for the news item |
headline |
string | News headline or trend title |
category |
string? | Category (e.g., "AI · Technology", "Trending") |
timeAgo |
string? | Relative time (e.g., "2h ago") |
postCount |
number? | Number of posts |
description |
string? | Item description |
url |
string? | URL to the trend or news article |
tweets |
array? | Related tweets (only with --with-tweets) |
Attach media to tweets and replies with --media (repeatable) and optional --alt per item. Up to 4 images/GIFs, or 1 video. Supported formats: jpg, jpeg, png, webp, gif, mp4, mov.
xcli tweet "check this out" --media screenshot.png --alt "A screenshot showing the results"
xcli tweet "two images" --media a.png --alt "first" --media b.png --alt "second"X rotates GraphQL "query IDs" frequently. xcli ships with a baseline mapping and caches a refreshed copy on disk.
- Default cache path:
~/.config/xcli/query-ids-cache.json - Override path:
XCLI_QUERY_IDS_CACHE=/path/to/file.json - Cache TTL: 24 hours
On a GraphQL 404 (stale query ID), xcli automatically refreshes the cache and retries. You can also refresh manually:
xcli query-ids --fresh| Code | Meaning |
|---|---|
0 |
Success |
1 |
Runtime error (network, auth, etc.) |
2 |
Invalid usage or validation error (e.g., bad --user handle) |
git clone https://github.com/gupsammy/xcli
cd xcli
pnpm install
pnpm run build:dist # TypeScript compilation only (outputs to dist/)
pnpm test # Run the test suite
pnpm run build:binary # Compile standalone xcli binary (requires Bun)To run commands during development without building the binary:
pnpm run dev tweet "Test tweet"
pnpm run dev -- --plain checkContributions are welcome. Open issues and pull requests at github.com/gupsammy/xcli.
xcli is a fork of bird by @steipete (now private). Many features were contributed by the bird community — see CHANGELOG for details.
MIT — see LICENSE