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.1.1.tar.gz (18.8 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.1.1-py3-none-any.whl (9.6 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for thrds-0.1.1.tar.gz
Algorithm Hash digest
SHA256 876e0f1402487bf608cf588c98289ee8d34551f0f021ea18da65d003989f309e
MD5 5fbefa377f5d6fc0600402d39305bc29
BLAKE2b-256 f95dd7f0da67bd842a543ee0840dca4b00e26936825c84da707d1446b164bedc

See more details on using hashes here.

Provenance

The following attestation bundles were made for thrds-0.1.1.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.1.1-py3-none-any.whl.

File metadata

  • Download URL: thrds-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 9.6 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.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6923ffa3e1dc181547f5bba449ceb943849c39fd177c2ac37b28d75c4d0f85f4
MD5 3cb03bc664763b3f30562ff512ef1ad8
BLAKE2b-256 f5c7e25f2e337906fd3a3356121203740433ec470cf74e3c84e13c48bfd7d0ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for thrds-0.1.1-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