Skip to main content

Birdapp: a Twitter/X CLI tool

A command-line tool for posting tweets to Twitter/X from the command line.

Setup

This repo uses the uv package manager to manage dependencies. If you don't already have uv installed, you can install it with the following curl command:

curl -LsSf https://astral.sh/uv/install.sh | sh

To verify install, use:

uv --version

Consult the uv installation docs for more detailed instructions and troubleshooting.

Installation

You can install the CLI tool globally using uv:

uv tool install -U birdapp

After installation, you can use:

birdapp auth config
birdapp tweet --text "Hello world!"

Configuration

There are two login flows available through birdapp: OAuth1 and OAuth2. Both require creating an X "app" in the X Developer Dashboard.

Important: The X API no longer has a free tier. All API usage is billed on a usage basis. You will need to enable billing in your X Developer Dashboard and add funds to your account before you can make API calls.

When creating your app, X requires a Website URL and a Callback URI:

  • Website URL: You can enter any valid URL here (e.g., https://example.com).
  • Callback URI: Set this to http://127.0.0.1:8080/callback. Birdapp starts a local server at this address to capture the OAuth2 callback automatically.

Once you've created your app, click the "Keys and Tokens" button for the app to generate authentication credentials.

With OAuth1, you generate a "Consumer Key" and "Secret Key" along with an "Access Token" and "Access Token Secret" that provide API access to a single X account. Store these in your birdapp config, and they work forever.

With OAuth2, you generate a "Client ID" and "Client Secret" for your X app, store these app secrets in your birdapp config, and login to your X accounts via a two-step flow that involves authorizing the app per-account in your browser.

In general, OAuth1 is simpler for tweeting from a single account, while OAuth2 is better for tweeting from multiple accounts. (With OAuth1 you would need a separate developer account for each account you want to use.)

OAuth2 is also generally more secure, because it doesn't involve storing secrets that could give an attacker permanent and sweeping access to your account.

Setting Up Credentials

Run the configuration command to set up your credentials: birdapp auth config

  • Choose OAuth1 or OAuth2 based on your app registration and security posture.
  • OAuth1: run birdapp auth config --oauth1 per profile.
  • OAuth2: run birdapp auth config --oauth2 once, then birdapp auth login per account.
    • Optional: birdapp auth whoami to verify the token after login.

This will prompt you for your Twitter API credentials and store them securely in ~/.config/birdapp/config.json.

To view your current configuration status (without showing secrets):

birdapp auth config --show

Profiles

Birdapp stores credentials by username profile. Each profile is keyed by the X username (without @).

How profiles are created:

  • OAuth1: created when you run birdapp auth config --oauth1 and enter a username.
  • OAuth2: created when you run birdapp auth login (the username comes from the login).

How profiles are selected:

  • Set the active profile with birdapp profile use <username>.
  • Use --profile <username> to override the active profile for a single command.
  • To list available profiles, run birdapp profile list.

Usage

Posting Tweets

To post a tweet:

birdapp tweet --text "Your tweet content here"

To post a tweet with media:

birdapp tweet --text "Check out this image!" --media /path/to/image.jpg

To post a media-only tweet (no text):

birdapp tweet --media /path/to/image.jpg

Replying to Tweets

To reply to a tweet using its ID:

birdapp tweet --text "Great point!" --reply-to 1234567890

To reply to a tweet using its URL:

birdapp tweet --text "I agree!" --reply-to "https://x.com/user/status/1234567890"

You can also include media in replies:

birdapp tweet --text "Here's my response" --media /path/to/image.jpg --reply-to 1234567890

Getting Tweets

To retrieve tweets by ID (up to 100 at a time):

birdapp get 1234567890
birdapp get 1234567890 9876543210 --format detailed
birdapp get 1234567890 --json

Looking Up Users

To look up users by username or ID (up to 100 at a time):

birdapp user elonmusk
birdapp user @nasa @spacex
birdapp user 44196397 --by-id
birdapp user elonmusk --format detailed --fields public_metrics created_at

birdapp supports bulk import of your tweets from Twitter/X’s “Download your data” export ZIP:

birdapp import-archive --path /path/to/twitter-archive.zip

To get the ZIP from Twitter/X:

  • Request the export: go to Settings → Your account → Download an archive of your data (wording may vary) and request the archive.
  • Wait for processing: it can take ~24 hours.
  • Download: you’ll get an email with a download link once it’s ready.

Importing from the Twitter Community Archive (optional)

If you have shared your tweets with the public via the Twitter Community Archive, birdapp reads that account from the archive's PostgREST API and imports it into SQLite:

birdapp import-archive --username yourusername

The public per-user archive.json file is no longer published. Username import pages tweets, likes, followers, and following (1,000 rows at a time). It stores tweet text, timestamps, engagement counts, replies, URLs, media, and mentions. Language, source, hashtags, symbols, and note-tweet payloads are not part of the public API, so those fields stay empty.

A saved archive.json, or a Twitter data-export ZIP, can still be imported from disk. The importer auto-detects the file type and safely parses the JSON payloads:

birdapp import-archive --path /path/to/archive.json

Multi-account support

You can import multiple archives into the same database.

birdapp import-archive --username alice
birdapp import-archive --username bob

Searching stored tweets (keyword)

Keyword search uses SQLite FTS5 for full-text search across imported tweets:

birdapp search "machine learning" --limit 20
birdapp search "climate policy" --author @alice
birdapp search "startup" --since 2024-01-01 --until 2024-06-30
birdapp search "distributed systems" --json

Semantic search (embeddings)

Semantic search is opt-in and uses embeddings. It requires OPENAI_API_KEY and the sqlite-vec extension. You can optionally override the model with BIRDAPP_EMBEDDING_MODEL.

To configure these durably:

birdapp embed config --api-key sk-... --model text-embedding-3-small
birdapp embed config --show

Environment variables still take precedence if set.

Generate embeddings for stored tweets:

birdapp embed
birdapp embed --db sqlite:////path/to/birdapp.db --model text-embedding-3-small

Then run semantic search:

birdapp search "productivity systems" --semantic --limit 10
birdapp search "startup hiring" --semantic --author @alice

You can also embed immediately after import:

birdapp import-archive --username yourusername --embed

Help

To see all available commands:

birdapp --help

To see help for a specific command:

birdapp tweet --help
birdapp auth --help
birdapp get --help
birdapp user --help

Contributing

Pull requests are welcome! Please open an issue first to discuss any changes you want to make.

To run the tests, first capture test fixtures:

uv run tests/capture_oauth2_fixtures.py

Then run the tests:

uv run pytest

To lint and type check:

uv run ruff check --fix
uv run ty check

Commit messages must follow the Conventional Commits specification.

Metadata

Release files for birdapp 2.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for birdapp 2.2.0
File Size Uploaded
birdapp-2.2.0.tar.gz 110.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for birdapp 2.2.0
File Interpreter ABI Platform
birdapp-2.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 155.7 kB

Release files / birdapp-2.2.0.tar.gz

Download URL birdapp-2.2.0.tar.gz
Size 110.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e3c727ef633f8524a10910116ea77545633dd1fd30b878523744b834ecd24759
BLAKE2b-256 checksum
How to use checksums
88e3292f33bbe7cdcb098514695ae84e81b36c95ef2239a903416a5c3cb0dd8e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / birdapp-2.2.0-py3-none-any.whl

Download URL birdapp-2.2.0-py3-none-any.whl
Size 45.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
078d578a40eba14f6403cc2f9043c25293ff03ebe573a6d6ec1b35c27caab758
BLAKE2b-256 checksum
How to use checksums
7b0ec6657be663c9f9c4518fea8d02bfc410ca533e6458a053366aa577189602
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.2.0 This release

2 release files

2.1.4

2 release files

2.1.3

2 release files

2.1.2

2 release files

2.1.1

2 release files

2.1.0

2 release files

2.0.0

2 release files

1.4.3

2 release files

1.4.2

2 release files

1.4.1

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page