Skip to main content

Declarative thread sync for Slack, Discord, and Bluesky

Project description

thrds

Declarative thread sync for Slack, Discord, and Bluesky.

Given a desired thread state (list of message contents), diffs against existing messages and applies minimal edits/posts/deletes to converge.

Install

pip install thrds            # Core only (zero deps)
pip install thrds[bsky]      # + Bluesky (atproto)

Slack and Discord clients use only stdlib (urllib) and curl subprocess respectively — no extra deps needed.

Usage

from thrds import SlackClient, Thread

slack = SlackClient(token="xoxb-...", channel="C0AQC2VKEJF")
thread = Thread(messages=["OP text", "Reply 1", "Reply 2"])

# Create new thread
result = slack.sync(thread)

# Update existing thread (edits changed messages, appends new, deletes extras)
result = slack.sync(thread, thread_ts="1775516040.743629")

Discord

from thrds import DiscordClient, Thread

discord = DiscordClient(token="your-bot-token", channel_id="1489279547689140505")
thread = Thread(messages=["OP text", "Reply 1", "Reply 2"])
result = discord.sync(thread, thread_id="1490821926288097503")

Bluesky

from thrds import BskyClient, Thread

bsky = BskyClient(handle="you.bsky.social", password="app-password")
thread = Thread(messages=["Root post", "Reply 1"])
result = bsky.sync(thread)

Bluesky doesn't support editing posts — the sync algorithm automatically falls back to delete+repost when content changes.

Dry run

result = slack.sync(thread, thread_ts="...", dry_run=True)
for action in result.actions:
    print(action.type, action.index, action.content)

Sync algorithm

Given desired messages M and existing thread messages N:

  1. Delete extras from the end (backwards — replies before OP)
  2. Edit overlapping messages where content changed (skip unchanged)
  3. Post new messages at the end

This ensures minimal API calls, preserved ordering, and no orphaned thread parents.

Features

  • Rate limit handling: Slack 429 retry with Retry-After, configurable pacing between API calls
  • Edit rate limit fallback: Discord's 30046 error (edit limit on old messages) triggers automatic delete+repost
  • Unfurl suppression: Slack link previews suppressed by default
  • Discord system message filtering: Thread starter messages filtered from list_messages
  • Bot token prefix: Discord Bot prefix auto-prepended
  • Metadata support: Slack message metadata passthrough

Used by

API

SyncResult

@dataclass
class SyncResult:
    thread_id: str          # thread_ts (Slack), thread channel ID (Discord), AT URI (Bluesky)
    message_ids: list[str]  # Per-message IDs
    actions: list[Action]   # What was done: Edit, Post, Delete, Skip

SyncOptions

Option Default Description
dry_run False Print actions without executing
pace 0.0 Seconds between mutating API calls
suppress_embeds False Discord: suppress link previews
suppress_unfurls True Slack: suppress link previews

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

thrds-0.2.0.tar.gz (27.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

thrds-0.2.0-py3-none-any.whl (14.1 kB view details)

Uploaded Python 3

File details

Details for the file thrds-0.2.0.tar.gz.

File metadata

  • Download URL: thrds-0.2.0.tar.gz
  • Upload date:
  • Size: 27.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for thrds-0.2.0.tar.gz
Algorithm Hash digest
SHA256 1609414cfe6c4f100c0efa146be54cac3f2aa6bfeb507456219ea007acb147de
MD5 ae21a516ecbba76cf40d58e588fab0e6
BLAKE2b-256 c46cbaa9eb3757d8cdcf654cf767dbd5cb81fef18e6e6af95f528116769c98cf

See more details on using hashes here.

Provenance

The following attestation bundles were made for thrds-0.2.0.tar.gz:

Publisher: release.yml on runsascoded/thrds

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file thrds-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: thrds-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 14.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for thrds-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3bf4bdfa8f39678bafc8aab67de8d6ca6e7d0f38d695f42143a502d174888651
MD5 62b96d7374284669a28c41e97754deed
BLAKE2b-256 00faa7d0014e594002eadb68da1e05067d8de978d6abecbe505da946dda3b3c2

See more details on using hashes here.

Provenance

The following attestation bundles were made for thrds-0.2.0-py3-none-any.whl:

Publisher: release.yml on runsascoded/thrds

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page