Skip to content

Bluesky provider

Configuration

Use either an existing access token and repository DID, or an identifier/app-password pair:

- module: cb_social_plugin.bluesky
  config:
    identifier: "publisher.example"
    app_password: "${BLUESKY_APP_PASSWORD}"
    state_db_path: "/srv/data/social-publications.db"
    media_group_wait_seconds: 2

Equivalent direct credentials are access_token + repo. service_url defaults to https://bsky.social.

Actions and API contracts

Action Remote operation
bluesky.create_post com.atproto.repo.createRecord
bluesky.update_post com.atproto.repo.putRecord
bluesky.delete_post com.atproto.repo.deleteRecord
bluesky.upload_blob com.atproto.repo.uploadBlob
bluesky.mirror_telegram_message deterministic putRecord mirror

For app-password authentication the plugin first calls com.atproto.server.createSession and uses the returned DID as the repository.

Mirror behavior

The mirror derives a deterministic AT Protocol record key from the Telegram publication key. Both initial publication and later edits use putRecord, so a retry targets the same record instead of creating a new one. The original source creation time is retained across edits.

HTTP links become Bluesky facets. Facet offsets are calculated in UTF-8 bytes, not Python character indexes, so text before a URL may safely contain non-ASCII characters.

Up to four downloaded images are embedded. The mirror currently enforces a 1,000,000-byte limit per image before upload; with media_required: true, an oversized image fails the action instead of being omitted.

Limitations

  • The shared mirror path handles images, not video/GIF uploads.
  • The provider-level deterministic record key improves retry behavior, but generic Call Baxter action replay remains fail-closed until complete idempotency/authorization evidence is recorded.
  • HTTP/provider errors, including rate limiting, propagate as action failures.