Skip to content

Command Reference

All commands support --json for structured output and -p, --profile <name> for multi-account usage.

Feed

bsky timeline / bsky tl

Display your home timeline.

bsky tl                     # default feed
bsky tl -n 50               # show 50 posts
bsky tl -H alice.bsky.social  # view another user's feed
bsky tl --json              # JSON output
Flag Description
-H, --handle <handle> View a specific user's feed
-n, --count <number> Number of posts to show

bsky stream

Stream the firehose in real time. Optionally filter posts with a regex pattern.

bsky stream                          # stream everything
bsky stream --pattern "typescript"   # filter by keyword
bsky stream --pattern "rust|go" --pattern-flags "gi"  # case-insensitive
bsky stream -H alice.bsky.social     # stream a specific user
bsky stream --cursor 123             # resume from a cursor
Flag Description
--pattern <regex> Filter posts matching this regex
--pattern-flags <flags> RegExp flags (default: gi). Supported: g, i, m, s, u, v, d, y
--cursor <value> Resume from a specific cursor
-H, --handle <handle> Stream a specific user

Warning

Flags u and v cannot be used together. Using y with g will produce a warning (sticky makes global meaningless).

bsky thread

Display a thread starting from a post URI.

bsky thread at://did:plc:abc123/app.bsky.feed.post/xyz
bsky thread at://did:plc:abc123/app.bsky.feed.post/xyz -n 10
Flag Description
-n, --depth <number> Maximum thread depth

Posting

bsky post

Create a new post with optional media attachments.

bsky post "Hello world!"
bsky post "Check this out" -i photo.jpg --image-alt "A photo"
bsky post --stdin < message.txt
bsky post "Watch this" --video clip.mp4 --video-alt "A video clip"
Flag Description
--stdin Read post text from stdin
--draft Save as draft instead of publishing
-i, --image <path...> Attach images (up to 4)
--image-alt <text...> Alt text for images (one per image)
--video <path> Attach a video
--video-alt <text> Alt text for the video

bsky reply

Reply to an existing post.

bsky reply at://did:plc:abc123/app.bsky.feed.post/xyz "Great post!"

bsky quote

Quote an existing post.

bsky quote at://did:plc:abc123/app.bsky.feed.post/xyz "This is interesting"

bsky create-thread

Create a thread from long text. Text is split at sentence boundaries and posted as a self-reply chain.

bsky create-thread "Long text that exceeds 300 characters..."
bsky create-thread --stdin < essay.txt
bsky create-thread "Text..." --thread-label          # add 🧵 1/N labels
bsky create-thread "Text..." --draft                 # save as draft
bsky create-thread "Text..." --no-preview            # skip interactive preview
bsky create-thread "Text..." --skip-validation       # bypass 301-375 char edge case
bsky create-thread "Text..." -i a.jpg b.jpg          # distribute images across posts
bsky create-thread "Text..." --reply-to at://...     # first post replies to URI
Flag Description
--stdin Read text from stdin
--draft Save as draft instead of publishing
--thread-label Add 🧵 1/N label to each post
--prepend-thread-label Put label at start (default: append)
-i, --image <files...> Images distributed across posts in order
--image-alt <alts...> Alt text for images
--video <file> Video (first post only)
--video-alt <alt> Alt text for video
--link <urls...> Link embeds distributed across posts
--media-all Attach same media to every post
--reply-to <uri> First post replies to this URI
--quote <uri> First post quotes this URI
--no-preview Skip interactive preview
--skip-validation Skip edge-case validation for 301-375 char text

Tip

Text between 301-375 characters triggers an edge case flow. You'll see a split preview and can choose to post anyway, trim the text, or save as a draft. Use --skip-validation to skip this and split directly.

Interactive preview

By default, threads show a preview with commands: [c]onfirm, [e]dit <N> (opens $EDITOR), [d]elete <N>, [q]uit (offers to save as draft). Disable with --no-preview or in non-TTY environments.

Partial failure recovery

If posting fails mid-thread, the remaining posts are saved as a draft with the reply chain intact. Use bsky drafts send <id> to resume.

bsky delete

Delete one or more of your posts.

bsky delete at://did:plc:abc123/app.bsky.feed.post/xyz
bsky delete <uri1> <uri2> <uri3>

Drafts

Drafts are saved locally when posting fails (network errors, edge cases) or when --draft is used. Network drafts are automatically offered for sending next time you run a command while online.

bsky drafts list / bsky drafts ls

bsky drafts list
bsky drafts ls --json

bsky drafts show

Show full contents of a draft, including individual posts for thread drafts.

bsky drafts show <id>
bsky drafts show 1741392    # unique prefix match

bsky drafts send

Publish a saved draft. For thread drafts, posts are sent sequentially with reply chaining. Drafts saved from partial failures resume from where they left off.

bsky drafts send <id>

bsky drafts delete / bsky drafts rm

bsky drafts delete <id>
bsky drafts rm <id>

Scheduling

Schedule posts for future publication, with optional recurring support and cross-platform automation.

bsky schedule post

Schedule a post for future publication. You'll be prompted to choose a date and time.

bsky schedule post "Hello world!"
bsky schedule post "Check this out" -i photo.jpg --image-alt "A photo"
bsky schedule post --stdin < message.txt
Flag Description
--stdin Read post text from stdin
-i, --image <path...> Attach images (up to 4)
--image-alt <text...> Alt text for images
--video <path> Attach a video
--video-alt <text> Alt text for the video
--repeat <frequency> Repeat: hourly, daily, fortnightly, monthly, annually
--times <count> Number of repetitions (number or word, e.g. 5 or three)

Recurring posts

Use --repeat to create posts that automatically re-schedule after each publication:

bsky schedule post "Daily update" --repeat daily --times 5
bsky schedule post "Weekly digest" --repeat fortnightly --times "three"
bsky schedule post "Good morning!" --repeat daily              # forever (until deleted)
Frequency Interval
hourly Every hour
daily Every day
fortnightly Every 2 weeks
monthly Every month
annually Every year

When --times is omitted, the post repeats indefinitely until manually deleted. You can also leave the interactive "How many times?" prompt blank for the same effect.

How recurring posts work

Each recurring post is a single file that gets updated in place. After publishing, the scheduled date advances to the next occurrence and the remaining count decrements. On the last occurrence, the file is deleted. Recurrence rules are stored as RFC 5545 RRULE strings.

First-use onboarding

The first time you schedule a post, you'll be offered to enable the background scheduler automatically. You can also set it up later with bsky schedule enable.

bsky schedule list / bsky schedule ls

List scheduled posts, sorted by date (soonest first by default).

bsky schedule list
bsky schedule ls -a                # show all
bsky schedule list -n 10           # show 10
bsky schedule list -o desc         # latest first
bsky schedule list --json          # JSON output
Flag Description
-n, --number <num> Number of posts to show (default: 5)
-a, --all Show all scheduled posts
-o, --order <order> Sort order: asc (default) or desc

bsky schedule edit

Interactively edit a scheduled post's text, date/time, or recurrence.

bsky schedule edit        # select from list
bsky schedule edit 1      # edit post #1 directly

For recurring posts, an additional (r)ecurrence option lets you change the frequency, remaining count, or switch between finite and infinite repeat.

bsky schedule delete / bsky schedule rm

Delete a scheduled post with confirmation. Offers to save it as a draft.

bsky schedule delete      # select from list
bsky schedule rm 1        # delete post #1 directly

bsky schedule run

Post all scheduled items that are due. Designed for use with external cron jobs or task schedulers.

bsky schedule run

bsky schedule watch

Run a foreground watcher that checks for due posts on a cron schedule. Stays open until you press Ctrl+C.

bsky schedule watch                             # every minute (default)
bsky schedule watch --interval "*/5 * * * *"    # every 5 minutes
Flag Description
--interval <cron> Cron expression (default: * * * * *)

Info

The watcher uses croner with protect: true, which prevents overlapping ticks if a previous check is still running.

bsky schedule enable

Set up an OS-level background scheduler that runs bsky schedule run automatically. Works on Linux (crontab), macOS (launchd), and Windows (Task Scheduler).

bsky schedule enable                  # every 1 minute (default)
bsky schedule enable --interval 5     # every 5 minutes
Flag Description
--interval <minutes> Check interval in minutes (default: 1)

bsky schedule disable

Pause the background scheduler without removing its configuration. The crontab entry, launchd plist, or scheduled task is preserved but deactivated.

bsky schedule disable

bsky schedule status

Show whether the background scheduler is enabled, disabled, or not installed.

bsky schedule status
bsky schedule status --json

bsky schedule uninstall

Permanently remove the background scheduler configuration. Prompts for confirmation (default: no).

bsky schedule uninstall

Engagement

bsky like

Like one or more posts.

bsky like at://did:plc:abc123/app.bsky.feed.post/xyz
bsky like <uri1> <uri2>

bsky likes

View who liked a post.

bsky likes at://did:plc:abc123/app.bsky.feed.post/xyz

bsky repost

Repost one or more posts.

bsky repost at://did:plc:abc123/app.bsky.feed.post/xyz

bsky reposts

View who reposted a post.

bsky reposts at://did:plc:abc123/app.bsky.feed.post/xyz

Bookmarks

Bookmarks are stored locally and don't sync to the Bluesky server.

bsky bookmarks create

bsky bookmarks create at://did:plc:abc123/app.bsky.feed.post/xyz
bsky bookmarks create <uri1> <uri2>

bsky bookmarks delete

bsky bookmarks delete at://did:plc:abc123/app.bsky.feed.post/xyz

bsky bookmarks get

bsky bookmarks get
bsky bookmarks get -n 20

Direct Messages

bsky dm list

List conversations.

bsky dm list
bsky dm list -n 10
bsky dm list --unread
bsky dm list --requests
bsky dm list --json
Option Description
-n, --count <number> Number of conversations (default: 50)
--unread Only show unread conversations
--requests Show conversation requests

bsky dm read

Read messages in a conversation. Accepts a handle or conversation ID.

bsky dm read alice.bsky.social
bsky dm read alice.bsky.social -n 10
bsky dm read convo123 --json
Option Description
-n, --count <number> Number of messages (default: 30)

bsky dm send

Send a direct message.

bsky dm send alice.bsky.social "Hello!"
echo "Hello!" | bsky dm send alice.bsky.social --stdin
Option Description
--stdin Read message text from stdin

bsky dm delete

Delete a message (for yourself only).

bsky dm delete convo123 msg001

bsky dm mute / bsky dm unmute

Mute or unmute a conversation.

bsky dm mute convo123
bsky dm unmute convo123

bsky dm accept

Accept a conversation request.

bsky dm accept convo123

bsky dm mark-read

Mark conversation(s) as read.

bsky dm mark-read convo123
bsky dm mark-read --all
Option Description
--all Mark all conversations as read

Social

bsky follow / bsky unfollow

bsky follow alice.bsky.social
bsky follow alice.bsky.social bob.bsky.social
bsky unfollow alice.bsky.social

bsky follows / bsky followers

bsky follows                        # your follows
bsky follows -H alice.bsky.social   # someone else's follows
bsky followers
bsky followers -H alice.bsky.social

bsky block / bsky unblock / bsky blocks

bsky block spammer.bsky.social
bsky unblock spammer.bsky.social
bsky blocks                          # list all blocks

bsky mute

bsky mute noisy.bsky.social

Discovery

Search for posts.

bsky search "typescript cli"
bsky search "bluesky api" -n 20

bsky search-users

Search for users.

bsky search-users "alice"
bsky search-users "developer" -n 10

Account

bsky profile

View profile information.

bsky profile                        # your profile
bsky profile -H alice.bsky.social   # someone else's

bsky profile-update

Update your profile.

bsky profile-update "Display Name" "Bio text"
bsky profile-update --avatar photo.jpg
bsky profile-update --banner banner.jpg

bsky session

View the current session information.

bsky notifs / bsky notification

View notifications.

bsky notifs
bsky notifs -a    # show all (including read)

bsky invite-codes

View your invite codes.

bsky invite-codes
bsky invite-codes --used    # include used codes

bsky app-password

Manage app passwords.

bsky app-password list
bsky app-password add
bsky app-password revoke

bsky report

Report a user.

bsky report spammer.bsky.social --comment "Spam account"

bsky mod-list

Create a moderation list.

bsky mod-list user1.bsky.social user2.bsky.social --name "My Block List" --desc "Spammers"

Configuration

bsky-cli supports a TOML config file for setting persistent defaults. CLI flags always take precedence over config values.

bsky config init

Create the default config file with all options documented and commented out.

bsky config init

bsky config path

Print the resolved config file path.

bsky config path

bsky config show

Print the current config file contents.

bsky config show

bsky config edit

Open the config file in $EDITOR (falls back to vi).

bsky config edit

Config file location

The config file lives at the platform default config directory:

  • Linux: ~/.config/bsky-cli/config.toml
  • macOS: ~/Library/Application Support/bsky-cli/config.toml
  • Windows: %APPDATA%/bsky-cli/config.toml

Override with -c / --config: bsky -c /path/to/config.toml timeline

Precedence

CLI flags > environment variables > config file > defaults

Global Flags

These flags work with all commands:

Flag Description
--json Output as JSON
-p, --profile <name> Use a named profile
-v, --verbose Verbose output
-c, --config <path> Path to config file
--version Show version
--help Show help