Skip to content
/ birdy Public

Bloomberg Terminal for X: Multi-account proxy for the bird CLI to reduce rate-limit risk

License

Notifications You must be signed in to change notification settings

guzus/birdy

Repository files navigation

birdy

Multi-account proxy for the bird CLI. Store multiple X/Twitter auth tokens and automatically rotate between accounts to reduce rate-limit risk.

First Run (Install + Open TUI)

curl -fsSL https://raw.githubusercontent.com/guzus/birdy/main/install.sh | bash && birdy account add main && birdy tui

birdy account add main will prompt you for auth_token and ct0 from your X/Twitter browser session.

Interactive TUI

Launch the full-screen terminal interface with AI-powered chat:

birdy tui

birdy TUI

The TUI features:

  • Chat — Ask birdy to read your timeline, search tweets, post, and more via Claude
  • Deep browsing — Say "dive deeper" and birdy will autonomously explore threads, replies, and user profiles
  • Account management — Add, remove, and view accounts with tab
  • Chat history — Conversations are saved as markdown in ~/.config/birdy/chats/ (set BIRDY_TUI_HIDE_HISTORY=1 to disable)

Hosted Web TUI

Run birdy as a browser-accessible terminal session:

birdy host --addr 0.0.0.0:8787

birdy will print the local URL:

http://127.0.0.1:8787

Users must enter an invite code to connect.

Notes:

  • The host runs the same birdy tui session in a web terminal.
  • Set invite code with --invite-code or BIRDY_HOST_INVITE_CODE.
  • For public deployments, set BIRDY_READ_ONLY=1.
  • This is a shared session: everyone who knows the invite code can see/control the same TUI.

Deploy on Railway

This repo now includes a Railway-ready container setup:

  • Dockerfile
  • scripts/entrypoint-railway.sh
  • .env.railway.example

1. Create service

Create a Railway service from this repo. Railway will detect and build the Dockerfile.

2. Add required variables

Set these in Railway Variables:

# Required: invite code users enter in the browser
BIRDY_HOST_INVITE_CODE=replace-with-long-random-secret

# Recommended for public deployments: disable write actions
BIRDY_READ_ONLY=1

# Optional: lock websocket origins to specific public domains
# BIRDY_HOST_ALLOWED_ORIGINS=https://your-domain.example,https://<railway-domain>

# Optional: hide/disable local chat history UI + persistence (recommended for public deploys)
BIRDY_TUI_HIDE_HISTORY=1

# Required: X/Twitter accounts as JSON (single line)
BIRDY_ACCOUNTS=[{"name":"main","auth_token":"x_auth_token_here","ct0":"x_ct0_here"}]

# Required for AI chat (pick one auth method)
CLAUDE_CODE_OAUTH_TOKEN=replace-with-claude-code-oauth-token
# or
# ANTHROPIC_API_KEY=replace-with-anthropic-api-key
# or
# ANTHROPIC_AUTH_TOKEN=replace-with-anthropic-auth-token

3. Add persistent volume

Mount a Railway volume at:

/data

This preserves:

  • ~/.config/birdy/accounts.json
  • ~/.config/birdy/state.json
  • ~/.config/birdy/chats/

4. Deploy and open

After deploy, open your Railway public URL and enter your invite code:

https://<your-service-domain>

Railway notes

  • Keep this service at 1 replica (session is shared and stateful).
  • The container uses Node 22 + Claude Code CLI + bundled bird CLI.
  • Rotate BIRDY_HOST_INVITE_CODE if it leaks.

How it works

birdy sits in front of the bird CLI. When you run a bird command through birdy, it:

  1. Picks an account from your stored credentials using a rotation strategy
  2. Injects the AUTH_TOKEN and CT0 environment variables
  3. Forwards the command to bird
  4. Tracks usage per account for smart rotation

Install

curl -fsSL https://raw.githubusercontent.com/guzus/birdy/main/install.sh | bash

Requires the GitHub CLI (gh). To install a specific version, pass it as an argument: ... | bash -s v0.2.0

Alternatives

# From source (requires Go)
go install github.com/guzus/birdy@latest

# Build locally
git clone https://github.com/guzus/birdy.git && cd birdy && make build

If you install via go install, only the birdy binary is installed, so you still need bird available on your PATH (or set BIRDY_BIRD_PATH).

If you build from a git clone, bird is vendored under third_party/@steipete/bird/ (requires Node >= 22).

Prerequisites

  • The installer bundles the upstream bird CLI and installs it as birdy-bird (birdy will auto-detect it). The bundled bird requires Node >= 22.
  • Claude Code (claude CLI) — required for the interactive TUI (birdy tui)

To force a specific bird binary, set BIRDY_BIRD_PATH=/path/to/bird.

Quick start

# Add accounts (you'll be prompted for auth_token and ct0)
birdy account add personal
birdy account add work
birdy account add alt

# Or pass credentials directly
birdy account add bot --auth-token "xxx" --ct0 "yyy"

# Now use bird commands through birdy - accounts rotate automatically
birdy read 1234567890
birdy search "golang"
birdy home
birdy mentions

# See which account was used with --verbose
birdy -v home

# Use a specific account
birdy --account personal whoami

# Check rotation status
birdy status

# List accounts
birdy account list

Account management

birdy account add <name>       # Add account (interactive or with --auth-token/--ct0)
birdy account list              # List all accounts with usage stats
birdy account update <name>     # Update credentials for an account
birdy account remove <name>     # Remove an account

Rotation strategies

Control how birdy picks the next account with --strategy / -s:

Strategy Description
round-robin (default) Cycles through accounts in order
least-recently-used Picks the account used longest ago
least-used Picks the account with the fewest total uses
random Picks a random account
birdy -s least-used search "rust"
birdy -s random home

Getting auth tokens

You need two cookies from an active X/Twitter web session:

  1. Open X/Twitter in your browser and log in
  2. Open Developer Tools (F12) > Application > Cookies > https://x.com
  3. Copy the values of auth_token and ct0

Repeat for each account you want to add.

GitHub Actions / CI

In CI environments where there's no interactive terminal, set the BIRDY_ACCOUNTS env var with a JSON array of accounts:

export BIRDY_ACCOUNTS='[{"name":"bot1","auth_token":"xxx","ct0":"yyy"},{"name":"bot2","auth_token":"aaa","ct0":"bbb"}]'
birdy -v read 1234567890

When BIRDY_ACCOUNTS is set and no accounts file exists on disk, birdy runs in ephemeral mode — accounts are loaded from the env var and nothing is written to disk.

If an accounts file also exists, env accounts are merged in (overriding any file account with the same name).

GitHub Actions example

Store the JSON as a repository secret named BIRDY_ACCOUNTS, then use it in your workflow:

- name: Read a tweet
  env:
    BIRDY_ACCOUNTS: ${{ secrets.BIRDY_ACCOUNTS }}
  run: birdy -v read 1234567890

See .github/workflows/example.yml for a full workflow.

Config location

Accounts are stored in ~/.config/birdy/accounts.json with 0600 permissions (owner-only read/write). Rotation state is tracked in ~/.config/birdy/state.json.

License

MIT

About

Bloomberg Terminal for X: Multi-account proxy for the bird CLI to reduce rate-limit risk

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •