bird is a fast X CLI for tweeting, replying, and reading via X/Twitter GraphQL (cookie auth).
This project uses X/Twitter’s undocumented web GraphQL API (and cookie auth). X can change endpoints, query IDs, and anti-bot behavior at any time — expect this to break without notice.
npm install -g @steipete/bird
# or
pnpm add -g @steipete/bird
# or
bun add -g @steipete/bird
# one-shot (no install)
bunx @steipete/bird whoamiHomebrew (macOS, prebuilt Bun binary):
brew install steipete/tap/bird# Show the logged-in account
bird whoami
# Discover command help
bird help whoami
# Read a tweet (URL or ID)
bird read https://x.com/user/status/1234567890123456789
bird 1234567890123456789 --json
# Thread + replies
bird thread https://x.com/user/status/1234567890123456789
bird replies 1234567890123456789
# Search + mentions
bird search "from:steipete" -n 5
bird mentions -n 5
bird mentions --user @steipete -n 5
# Refresh GraphQL query IDs cache (no rebuild)
bird query-ids --freshbird tweet "<text>"— post a new tweet.bird reply <tweet-id-or-url> "<text>"— reply to a tweet using its ID or URL.bird help [command]— show help (or help for a subcommand).bird query-ids [--fresh] [--json]— inspect or refresh cached GraphQL query IDs.bird read <tweet-id-or-url> [--json]— fetch tweet content as text or JSON.bird <tweet-id-or-url> [--json]— shorthand forreadwhen only a URL or ID is provided.bird replies <tweet-id-or-url> [--json]— list replies to a tweet.bird thread <tweet-id-or-url> [--json]— show the full conversation thread.bird search "<query>" [-n count] [--json]— search for tweets matching a query.bird mentions [-n count] [--user @handle] [--json]— find tweets mentioning a user (defaults to the authenticated user).bird whoami— print which Twitter account your cookies belong to.bird check— show which credentials are available and where they were sourced from.
Global options:
--timeout <ms>: abort requests after the given timeout (milliseconds).--plain: stable output (no emoji, no color).--no-emoji: disable emoji output.--no-color: disable ANSI colors (or setNO_COLOR=1).--cookie-source <safari|chrome|firefox>: choose browser cookie source (repeatable; order matters).
GraphQL mode uses your existing X/Twitter web session (no password prompt). It sends requests to internal
X endpoints and authenticates via cookies (auth_token, ct0).
Write operations:
tweet/replyprimarily use GraphQL (CreateTweet).- If GraphQL returns error
226(“automated request”),birdfalls back to the legacystatuses/update.jsonendpoint.
bird resolves credentials in this order:
- CLI flags:
--auth-token,--ct0 - Environment variables:
AUTH_TOKEN,CT0(fallback:TWITTER_AUTH_TOKEN,TWITTER_CT0) - Browser cookies (macOS): Safari, Chrome, Firefox (override via
--cookie-sourceorder)
Browser cookie sources:
- Safari:
~/Library/Cookies/Cookies.binarycookies(fallback:~/Library/Containers/com.apple.Safari/Data/Library/Cookies/Cookies.binarycookies) - Chrome:
~/Library/Application Support/Google/Chrome/<Profile>/Cookies - Firefox:
~/Library/Application Support/Firefox/Profiles/<profile>/cookies.sqlite
Config precedence: CLI flags > env vars > project config > global config.
- Global:
~/.config/bird/config.json5 - Project:
./.birdrc.json5
Example ~/.config/bird/config.json5:
{
// Cookie source order for browser extraction (string or array)
cookieSource: ["firefox", "safari"],
firefoxProfile: "default-release",
timeoutMs: 20000
}Environment shortcuts:
BIRD_TIMEOUT_MS
--jsonprints raw tweet objects for read/replies/thread/search/mentions.readreturns full text for Notes and Articles when present.- Use
--plainfor stable, script-friendly output (no emoji, no color).
X rotates GraphQL “query IDs” frequently. Each GraphQL operation is addressed as:
operationName(e.g.TweetDetail,CreateTweet)queryId(rotating ID baked into X’s web client bundles)
bird ships with a baseline mapping in src/lib/query-ids.json (copied into dist/ on build). At runtime,
it can refresh that mapping by scraping X’s public web client bundles and caching the result on disk.
Runtime cache:
- Default path:
~/.config/bird/query-ids-cache.json - Override path:
BIRD_QUERY_IDS_CACHE=/path/to/file.json - TTL: 24h (stale cache is still used, but marked “not fresh”)
Auto-recovery:
- On GraphQL
404(query ID invalid),birdforces a refresh once and retries. - For
TweetDetail/SearchTimeline,birdalso rotates through a small set of known fallback IDs to reduce breakage while refreshing.
Refresh on demand:
bird query-ids --freshExit codes:
0: success1: runtime error (network/auth/etc)2: invalid usage/validation (e.g. bad--userhandle)
bird --version prints package.json version plus current git sha when available, e.g. 0.3.0 (3df7969b).
- Attach media with
--media(repeatable) and optional--altper item. - Up to 4 images/GIFs, or 1 video (no mixing). Supported: jpg, jpeg, png, webp, gif, mp4, mov.
- Images/GIFs + 1 video supported (uploads via Twitter legacy upload endpoint + cookies; video may take longer to process).
Example:
bird tweet "hi" --media img.png --alt "desc"cd ~/Projects/bird
pnpm install
pnpm run build # dist/ + bun binary
pnpm run build:dist # dist/ only
pnpm run build:binary
pnpm run dev tweet "Test"
pnpm run dev -- --plain check
pnpm test
pnpm run lint- GraphQL uses internal X endpoints and can be rate limited (429).
- Query IDs rotate; refresh at runtime with
bird query-ids --fresh(or update the baked baseline viapnpm run graphql:update).