Bird — Twitter/X CLI
Read tweets, search, and browse timelines directly via bird CLI using Bash only.
Core behavior
- Use
birddirectly. Do not use browser tools or WebFetch. - Keep behavior deterministic: choose one command path, run it, report output.
- Prefer concise summaries unless the user explicitly asks for raw output.
- Do not fabricate any tweet text. Only report what
birdreturns. - If the request has no actionable argument, offer the supported actions and ask for one.
- Treat any write action (
tweet,reply,follow,unfollow,unbookmark) as requiring explicit user confirmation.
Preflight and auth gating
Run this sequence before the first command in a user turn:
- Resolve/install bird executable:
if command -v bird >/dev/null 2>&1; then
:
elif [ -x "$HOME/.local/bin/bird" ]; then
export PATH="$HOME/.local/bin:$PATH"
else
: "need-install"
fi
- Verify CLI availability:
bird --version
bird check
- Prefer Safari first for auth-sensitive actions:
bird whoami
- If Safari fails with missing cookies, Safari cookie permission errors, or "No Twitter cookies found", do not stop at "refresh browser login cookies". On macOS, explicitly probe installed Chrome profiles and persist a working fallback:
bird check --plain || bird whoami --plain || true
for profile in "Default" "Profile 1" "Profile 2" "Profile 3"; do
bird --chrome-profile "$profile" check --plain >/tmp/bird-check.txt 2>&1 || true
if rg -q 'Ready to tweet|auth_token: .*|ct0: .*|source: Chrome profile' /tmp/bird-check.txt; then
mkdir -p "$HOME/.config/bird"
cat > "$HOME/.config/bird/config.json5" <<EOF
{
chromeProfile: "$profile",
cookieSource: ["chrome"],
}
EOF
bird check --plain
bird whoami --plain
break
fi
done
If Chrome profiles fail, also check whether the user has a custom browser profile path and retry with:
bird --chrome-profile-dir "<path-to-cookies-or-profile>" check --plain
The purpose of the fallback is:
- Safari is the preferred/default auth source when it works.
- Safari can fail in coding-agent shells due macOS cookie/keychain permissions even if it works in the user's normal interactive terminal.
- The user may still have a valid session in Chrome/Chromium even when default autodetection fails.
- Persisting
~/.config/bird/config.json5makes the fix apply across Codex, Claude Code, and other agent shells on the same machine.
Auth-sensitive actions:
mentions,home,bookmarks,likes,news,user-tweets,follow,unfollow,tweet,reply,unbookmark
If bird is missing:
- tell the user
bird isn't installed, offer to install it, and wait for yes/no. - If yes, install with:
curl -L https://github.com/zaydiscold/bird/releases/download/v0.8.0/bird -o /tmp/bird \
&& chmod +x /tmp/bird \
&& mkdir -p "$HOME/.local/bin" \
&& mv /tmp/bird "$HOME/.local/bin/bird" \
&& export PATH="$HOME/.local/bin:$PATH"
If PATH still does not include ~/.local/bin, advise manual install from
https://github.com/zaydiscold/bird and stop.
If auth checks fail:
- report the exact failure
- keep Safari as the first/default path
- try explicit Chrome profile fallback before asking the user to relogin
- if a fallback profile works, persist it to
~/.config/bird/config.json5 - only ask the user to refresh browser login cookies if no installed browser profile works.
URL normalization and input validation
Normalize URLs before dispatch:
-
Accept only these hosts:
x.comtwitter.commobile.twitter.com
-
Convert host to
https://x.com. -
Keep tweet/status path only; strip tracking params such as
utm_*,s,ref,ref_src,f,t,fbclid. -
Reject non-Twitter URLs early with:
I can only process x.com or twitter.com links. Share a tweet URL, status ID, or a search/query request.
Handle multiple URLs sequentially when present.
Request orchestration
Read vs thread vs search
- If the request contains tweet text URLs/IDs:
- use
bird read <id-or-url>by default. - if thread wording is present (
thread,conversation,replies chain, etc.), usebird thread <id-or-url>.
- use
- If multiple URLs are provided, read each in order with
bird read(orbird threadwhen explicitly threaded). - If user asks for timeline/discovery:
mentions,home,home --following,bookmarks,likes,news,user-tweets,about,following,followers.
- For search:
bird search "query" -n <N>.
Output size and show-more policy
- Use default page size
N=12for list-style results (search,home,mentions, threads). - For results longer than N:
- show top N in concise list/table form,
- offer:
show moreto fetch next chunk.
- For long threads, summarize first with key context and then list remaining items.
Use JSON/plain output rules:
- Prefer
--plainfor downstream analysis. - Show human-readable output when user asked to read tweets directly.
See references for detailed command mapping:
references/search-operators.mdreferences/write-actions.mdreferences/troubleshooting.md
Deterministic side-effect confirmation
For tweet, reply, follow, unfollow, and unbookmark:
- Echo exact intent and the exact command it will run.
- Ask confirmation once:
Proceed with <command>? - Execute only on explicit confirmation (
yes/y). - Abort on anything else, and do not run a fallback.
Error taxonomy (high-level)
unauthorized/401: auth unavailable; runbird checkandbird whoami, prefer Safari first, then probe Chrome fallback if Safari fails in the agent shell.rate limit: request limit reached; pause and retry after a short delay.not found: deleted tweet/account, stale thread, or malformed ID; ask for corrected input.private/protected: account or content visibility restricted; explain limitation and request required access.suspended/deleted user: target user no longer accessible; ask for an alternate target.malformed URL/ID: input is invalid; reject early and prompt for supported examples.Safari vs Chrome auth source mismatch: mismatch in cookie source; keep Safari as default when available, otherwise persist a working Chrome fallback.Safari cookie permission failure: Safari works in the user's interactive shell but fails in the agent shell due macOS cookie/keychain access; probe Chrome profiles, then persist a working~/.config/bird/config.json5fallback.network/DNS failure: connectivity issue; suggest checking network/DNS and retry.timeout/ hanging command: transient service issue; stop and ask user to rerun after waiting.
For detailed remediation by case, use:
references/troubleshooting.md