bird 🐦 — fast X CLI for tweeting, replying, and reading
bird is a fast X CLI for tweeting, replying, and reading. It uses either GraphQL cookies or the Sweetistics API.
Install
npm install -g @steipete/bird
# or
pnpm add -g @steipete/bird
Quickstart
# 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 --fresh
Commands
bird 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.
Engines
--engine auto(default) — use GraphQL first; if a Sweetistics API key is available, fall back on errors.--engine graphql— use Twitter/X GraphQL with cookies (Chrome/Firefox/env/flags).--engine sweetistics— use Sweetistics API key (no browser cookies needed).
Note: fallback to Sweetistics only happens in --engine auto. --engine graphql is strict (no fallback).
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).
Authentication (GraphQL)
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).
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): Firefox or Chrome profiles
Browser cookie sources:
- Firefox (default):
~/Library/Application Support/Firefox/Profiles/<profile>/cookies.sqlite - Chrome:
~/Library/Application Support/Google/Chrome/<Profile>/Cookies
Config (JSON5)
Config precedence: CLI flags > env vars > project config > global config.
- Global:
~/.config/bird/config.json5 - Project:
./.birdrc.json5
Example ~/.config/bird/config.json5:
{
engine: "auto",
firefoxProfile: "default-release",
sweetisticsApiKey: "sweet-...",
allowFirefox: true,
allowChrome: false,
timeoutMs: 20000
}
Environment shortcuts:
SWEETISTICS_API_KEY,SWEETISTICS_BASE_URLBIRD_ENGINE,BIRD_TIMEOUT_MS
Output
--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).
Query IDs (GraphQL)
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 --fresh
Exit codes:
0: success1: runtime error (network/auth/etc)2: invalid usage/validation (e.g. bad--userhandle)
Version
bird --version prints package.json version plus current git sha when available, e.g. 0.2.0 (3df7969b).
Media uploads
- 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.
--engine graphql: images/GIFs + 1 video supported (uploads via Twitter legacy upload endpoint + cookies; video may take longer to process).--engine sweetistics: images + video supported (requiresSWEETISTICS_API_KEY).
Example:
bird --engine sweetistics tweet "hi" --media img.png --alt "desc"
Development
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
Notes
- GraphQL uses internal X endpoints and can be rate limited (429).
- Query IDs rotate; refresh them with
pnpm run graphql:update.