chirpie
Post to X, Bluesky, LinkedIn, Threads, Mastodon, Instagram, Facebook and Telegram from your terminal. Chirpie handles the OAuth, the token refresh and the media upload, so every platform is the same command.
Install
npm install -g chirpie
Or run it without installing: npx chirpie <command>.
Authenticate
chirpie login
chirpie whoami
Or set a key from the dashboard in the environment:
export CHIRPIE_API_KEY=chirpie_sk_...
CHIRPIE_API_KEY takes precedence over the config file. chirpie auth --key ... stores one non-interactively, and chirpie logout removes it.
Commands
chirpie login / logout / auth / whoami | Manage credentials |
chirpie post <text> | Create a post. -a account (repeat it for several accounts), -m media files or URLs, --alt descriptions, --config per-account overrides, --first-comment a comment published under the post as soon as it goes out, -s schedule, --draft save without sending |
chirpie thread <post> <post> ... | Create a 2 to 25 post thread, or 1 to 25 with --draft. -a is repeatable, --config takes per-account posts, --first-comment posts a comment under the last part, -f takes a JSON payload file |
chirpie posts | List posts. --status, --account, --group, --limit, --include-hidden |
chirpie posts get <id> | Fetch one post |
chirpie posts update <id> | Edit a post that has not published yet, or finish a draft. --text, --media, --alt, --clear-media, --first-comment ("" removes it), --schedule-at, --keep-draft. Leaving --schedule-at out keeps the time it already has |
chirpie posts publish <id> | Send a saved draft now. -t sets the final text first |
chirpie posts first-comment <id> | Post a first comment that failed, again. It re-sends the text the post already carries |
chirpie posts delete <id> | Take a post down from the platform. Chirpie keeps it, marked deleted. Deleting any post of a scheduled thread cancels the thread. Instagram and TikTok offer no delete API and refuse with delete_unsupported |
chirpie posts hide <id> / unhide <id> | Hide a post from your Chirpie listings, or show it again. Nothing reaches the platform |
chirpie accounts | List connected accounts, active and inactive |
chirpie accounts activate <id> / deactivate <id> | Choose which accounts publish. Deactivating cancels that account's scheduled posts |
chirpie accounts disconnect <id> | End a connection. Cancels that account's scheduled posts, frees a plan slot, and removes the stored credential, so reconnecting means authorizing again. Asks first; -y skips the prompt |
chirpie accounts connect-x | Start the X OAuth flow and print the URL |
chirpie accounts connect-bluesky | Connect Bluesky with an app password |
chirpie accounts connect-linkedin / connect-mastodon | Start that platform's OAuth flow |
chirpie accounts connect-threads / connect-instagram / connect-facebook | Start that platform's OAuth flow (coming soon) |
chirpie accounts connect-linkedin --pages | Connect the LinkedIn Pages you administer, each as its own account (coming soon) |
chirpie accounts connect-telegram | Connect a Telegram bot to a channel or group |
chirpie accounts x-keys set / status / remove | Use your own X developer app |
chirpie analytics <post_id> | Engagement metrics for a published post |
chirpie keys / keys create / keys revoke <id> | Manage API keys |
Run chirpie <command> --help for the full option list. Threads, Instagram, Facebook, Pinterest, TikTok, YouTube and Google Business Profile are coming soon. Accounts already connected keep posting and scheduling as normal.
Examples
chirpie post "Shipped a new release."
chirpie post "Look at this" -a 550e8400-e29b-41d4-a716-446655440000 -m ./shot.png --alt "The new dashboard"
chirpie post "Later" -s 2026-04-01T14:00:00Z
chirpie thread "One" "Two" "Three" -a 550e8400-e29b-41d4-a716-446655440000
chirpie posts --status scheduled
chirpie post "We rebuilt scheduling this week." \
--first-comment "Full write-up: https://example.com/blog/scheduling"
chirpie posts first-comment "$POST_ID"
Drafts
--draft saves a post or a thread without sending it. Nothing reaches the platform and nothing counts against your quota until you promote it. Anything that would go wrong is printed back, one warning per line.
chirpie post "Half an idea" --draft
chirpie thread "Opening line" --draft
chirpie posts --status draft
chirpie posts update "$POST_ID" --schedule-at 2027-04-02T09:00:00Z --keep-draft
chirpie posts update "$POST_ID" --schedule-at 2027-04-02T09:00:00Z
chirpie posts publish "$POST_ID"
Promoting runs every rule a normal post runs and takes the quota, so a draft that would be refused stays a draft, unchanged. A draft thread is promoted whole.
Several accounts at once
Repeat -a to publish the same post to up to 25 accounts in one call.
chirpie post "Shipped a new release." -a "$X_ACCOUNT" -a "$BSKY_ACCOUNT"
chirpie post "Shipped a new release." -a "$X_ACCOUNT" -a "$BSKY_ACCOUNT" \
--config "{\"$BSKY_ACCOUNT\":{\"text\":\"Shorter, for Bluesky\"}}"
chirpie post "Shipped a new release." -a "$X_ACCOUNT" -a "$BSKY_ACCOUNT" --config ./overrides.json
chirpie thread "One" "Two" -a "$X_ACCOUNT" -a "$BSKY_ACCOUNT" \
--config "{\"$BSKY_ACCOUNT\":{\"posts\":[{\"text\":\"A\"},{\"text\":\"B\"}]}}"
chirpie posts --group 550e8400-e29b-41d4-a716-446655440000
One line is printed per account, with a group ID above them. An account the platform refused is shown with its error while the others stay published, and the command leaves with a non-zero status when any account failed. An override says only what differs, and naming media replaces the shared media for that account.
JSON output
Every command accepts --json and prints the raw API response, which is what you want in a script:
chirpie accounts --json | jq -r '.[0].id'
chirpie posts --status scheduled --json | jq length
Put --json on the command you are actually running. For a subcommand, both placements work: chirpie accounts deactivate <id> --json and chirpie accounts --json deactivate <id> are equivalent.
Documentation
Also available: the TypeScript SDK and the MCP server.
MIT